Compare commits
45 Commits
feature/dy
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1ddbd2cf1 | ||
|
|
81b331e5da | ||
|
|
1ebee17880 | ||
|
|
4649d5f77b | ||
|
|
d3c1d6cc34 | ||
|
|
ee24ec8d5c | ||
|
|
372325fab7 | ||
|
|
8f036d9293 | ||
|
|
e345cdd1a7 | ||
|
|
fca570a163 | ||
|
|
ff64d1989f | ||
|
|
d3f5db2479 | ||
|
|
fa587060f1 | ||
|
|
b137c75eb2 | ||
|
|
05c1361283 | ||
|
|
c6835dad70 | ||
|
|
e7fa1dde97 | ||
|
|
eb62588b79 | ||
|
|
29332cbd45 | ||
|
|
172eb70551 | ||
|
|
7322df98f5 | ||
| 70af5a31cd | |||
| 0ab2f59fe8 | |||
| ab84cdb790 | |||
| da9041823b | |||
| 2d7cfc6c59 | |||
| cee4fe67fc | |||
| 53f90f5a1d | |||
| bab2dd5c69 | |||
| 3b9efc11d0 | |||
| 182d3b0a6a | |||
|
|
ed38e989b1 | ||
|
|
1bc6f422c5 | ||
|
|
4909d15c20 | ||
|
|
e725795a17 | ||
|
|
d8a21608c3 | ||
|
|
396fc131e0 | ||
|
|
40130076b2 | ||
|
|
9f54927a82 | ||
|
|
f7ea46e49e | ||
|
|
bc46c9a7d5 | ||
|
|
a1e2c58afc | ||
|
|
4e73e933db | ||
|
|
9f8e75f680 | ||
|
|
e17119254b |
56
.github/workflows/sphinx_deploy.yml
vendored
Normal file
56
.github/workflows/sphinx_deploy.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: Deploy docs site with Sphinx
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
||||||
|
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
||||||
|
concurrency:
|
||||||
|
group: "pages"
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
# Default to bash
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Setup Pages
|
||||||
|
id: pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
- name: Sphinx build
|
||||||
|
uses: jsix-os/sphinx-action@master
|
||||||
|
with:
|
||||||
|
docs-folder: "docs/"
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ./docs/_build/html
|
||||||
|
|
||||||
|
# Deployment job
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,3 +16,4 @@ compile_commands.json
|
|||||||
buddy_allocs.txt
|
buddy_allocs.txt
|
||||||
frame_allocs.txt
|
frame_allocs.txt
|
||||||
heap_allocs.txt
|
heap_allocs.txt
|
||||||
|
/docs/_build
|
||||||
|
|||||||
3
assets/build/config.release.yaml
Normal file
3
assets/build/config.release.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ccflags: [
|
||||||
|
"-O3",
|
||||||
|
]
|
||||||
@@ -21,6 +21,7 @@ ccflags: [
|
|||||||
cxxflags: [
|
cxxflags: [
|
||||||
"-fno-exceptions",
|
"-fno-exceptions",
|
||||||
"-fno-rtti",
|
"-fno-rtti",
|
||||||
|
"-isystem", "${source_root}/sysroot/include/c++/v1",
|
||||||
]
|
]
|
||||||
|
|
||||||
ldflags: [
|
ldflags: [
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ ccflags: [
|
|||||||
cxxflags: [
|
cxxflags: [
|
||||||
"-fno-exceptions",
|
"-fno-exceptions",
|
||||||
"-fno-rtti",
|
"-fno-rtti",
|
||||||
|
"-isystem", "${source_root}/sysroot/include/c++/v1",
|
||||||
]
|
]
|
||||||
|
|
||||||
ldflags: [
|
ldflags: [
|
||||||
|
|||||||
@@ -501,6 +501,18 @@ class LinkedListPrinter:
|
|||||||
return self.items
|
return self.items
|
||||||
|
|
||||||
|
|
||||||
|
class IsRunning(gdb.Function):
|
||||||
|
def __init__(self):
|
||||||
|
super(IsRunning, self).__init__("is_running")
|
||||||
|
|
||||||
|
def invoke(self):
|
||||||
|
inferior = gdb.selected_inferior()
|
||||||
|
return \
|
||||||
|
inferior is not None and \
|
||||||
|
inferior.is_valid() and \
|
||||||
|
len(inferior.threads()) > 0
|
||||||
|
|
||||||
|
|
||||||
def build_pretty_printers():
|
def build_pretty_printers():
|
||||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix")
|
pp = gdb.printing.RegexpCollectionPrettyPrinter("jsix")
|
||||||
pp.add_printer("cap table", '^cap_table$', CapTablePrinter)
|
pp.add_printer("cap table", '^cap_table$', CapTablePrinter)
|
||||||
@@ -520,9 +532,10 @@ GetThreadsCommand()
|
|||||||
PrintProfilesCommand()
|
PrintProfilesCommand()
|
||||||
DumpLogCommand()
|
DumpLogCommand()
|
||||||
ShowCurrentProcessCommand()
|
ShowCurrentProcessCommand()
|
||||||
|
IsRunning()
|
||||||
|
|
||||||
gdb.execute("display/i $rip")
|
gdb.execute("display/i $rip")
|
||||||
gdb.execute("define hook-quit\nkill\nend")
|
gdb.execute("define hook-quit\nif $is_running()\n kill\nend\nend")
|
||||||
if not gdb.selected_inferior().was_attached:
|
if not gdb.selected_inferior().was_attached:
|
||||||
gdb.execute("add-symbol-file build/panic.serial.elf")
|
gdb.execute("add-symbol-file build/panic.serial.elf")
|
||||||
gdb.execute("target remote :1234")
|
gdb.execute("target remote :1234")
|
||||||
|
|||||||
14
assets/manifests/minimal.yaml
Normal file
14
assets/manifests/minimal.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
location: jsix
|
||||||
|
init: srv.init
|
||||||
|
initrd:
|
||||||
|
name: initrd.dat
|
||||||
|
format: zstd
|
||||||
|
panic:
|
||||||
|
- panic.serial
|
||||||
|
services:
|
||||||
|
- srv.logger
|
||||||
|
drivers:
|
||||||
|
- drv.uart
|
||||||
|
libs:
|
||||||
|
- ld.so
|
||||||
14
assets/manifests/shell.yaml
Normal file
14
assets/manifests/shell.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
location: jsix
|
||||||
|
init: srv.init
|
||||||
|
initrd:
|
||||||
|
name: initrd.dat
|
||||||
|
format: zstd
|
||||||
|
panic:
|
||||||
|
- panic.serial
|
||||||
|
services:
|
||||||
|
- 6s
|
||||||
|
drivers:
|
||||||
|
- drv.uart
|
||||||
|
libs:
|
||||||
|
- ld.so
|
||||||
@@ -1,29 +1,38 @@
|
|||||||
---
|
---
|
||||||
- name: linear
|
- name: linear
|
||||||
|
desc: Linearly-mapped physical memory
|
||||||
size: 64T
|
size: 64T
|
||||||
shared: true
|
shared: true
|
||||||
|
|
||||||
- name: bitmap
|
- name: bitmap
|
||||||
|
desc: Used/free page tracking bitmap
|
||||||
size: 1T
|
size: 1T
|
||||||
shared: true
|
shared: true
|
||||||
|
|
||||||
- name: heapmap
|
- name: heapmap
|
||||||
|
desc: Kernel heap accounting structures
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: heap
|
- name: heap
|
||||||
|
desc: Kernel heap
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: capsmap
|
- name: capsmap
|
||||||
|
desc: Capabilities accounting structures
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: caps
|
- name: caps
|
||||||
|
desc: Capabilities
|
||||||
size: 32G
|
size: 32G
|
||||||
|
|
||||||
- name: stacks
|
- name: stacks
|
||||||
|
desc: Kernel thread stacks
|
||||||
size: 64G
|
size: 64G
|
||||||
|
|
||||||
- name: buffers
|
- name: buffers
|
||||||
|
desc: Kernel buffers
|
||||||
size: 64G
|
size: 64G
|
||||||
|
|
||||||
- name: logs
|
- name: logs
|
||||||
|
desc: Kernel logs circular buffer
|
||||||
size: 2G
|
size: 2G
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# An ``event`` is a simple synchronization object. It contains up to 64 signals
|
||||||
|
# that threads can wait for and signal in parallel.
|
||||||
|
|
||||||
object event : object {
|
object event : object {
|
||||||
uid f441e03da5516b1a
|
uid f441e03da5516b1a
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ object mailbox : object {
|
|||||||
method call [cap:send] {
|
method call [cap:send] {
|
||||||
param tag uint64 [inout]
|
param tag uint64 [inout]
|
||||||
param data buffer [optional inout]
|
param data buffer [optional inout]
|
||||||
param data_in_len size # number of bytes in data used for input
|
param data_size size # number of total bytes in data buffer
|
||||||
param handles ref object [optional inout handle list]
|
param handles ref object [optional inout handle list]
|
||||||
|
param handles_size size # total size of handles buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
# Respond to a message sent using call, and wait for another
|
# Respond to a message sent using call, and wait for another
|
||||||
@@ -31,8 +32,9 @@ object mailbox : object {
|
|||||||
method respond [cap:receive] {
|
method respond [cap:receive] {
|
||||||
param tag uint64 [inout]
|
param tag uint64 [inout]
|
||||||
param data buffer [optional inout]
|
param data buffer [optional inout]
|
||||||
param data_in_len size # number of bytes in data used for input
|
param data_size size # number of total bytes in data buffer
|
||||||
param handles ref object [optional inout handle list]
|
param handles ref object [optional inout handle list]
|
||||||
|
param handles_size size # total size of handles buffer
|
||||||
param reply_tag uint64 [inout]
|
param reply_tag uint64 [inout]
|
||||||
param flags uint64
|
param flags uint64
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
# The base type of all kernel-exposed objects
|
# All kernel-exposed objects inherit from the base ``object`` type, so the
|
||||||
|
# ``object`` syscalls can be used with any object's handle.
|
||||||
|
|
||||||
object object [virtual] {
|
object object [virtual] {
|
||||||
uid 667f61fb2cd57bb4
|
uid 667f61fb2cd57bb4
|
||||||
cname kobject
|
cname kobject
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import "objects/object.def"
|
import "objects/object.def"
|
||||||
|
|
||||||
# Processes are a collection of handles and a virtual memory
|
# A ``process`` object represents a process running on the system, and allows
|
||||||
# space inside which threads are run.
|
# control over the threads, handles, and virtual memory space of that process.
|
||||||
|
|
||||||
object process : object {
|
object process : object {
|
||||||
uid 0c69ee0b7502ba31
|
uid 0c69ee0b7502ba31
|
||||||
@@ -12,14 +12,16 @@ object process : object {
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Create a new empty process
|
# Create a new empty process
|
||||||
method create [constructor]
|
method create [constructor] {
|
||||||
|
param name string
|
||||||
|
}
|
||||||
|
|
||||||
# Stop all threads and exit the given process
|
# Stop all threads and exit the given process
|
||||||
method kill [destructor cap:kill]
|
method kill [destructor cap:kill]
|
||||||
|
|
||||||
# Stop all threads and exit the current process
|
# Stop all threads and exit the current process
|
||||||
method exit [static noreturn] {
|
method exit [static noreturn] {
|
||||||
param result int32 # The result to retrun to the parent process
|
param result int64 # The result to retrun to the parent process
|
||||||
}
|
}
|
||||||
|
|
||||||
# Give the given process a handle that points to the same
|
# Give the given process a handle that points to the same
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# The system object represents a handle to kernel functionality
|
# The singular ``system`` object represents a handle to kernel functionality
|
||||||
# needed by drivers and other priviledged services
|
# needed by drivers and other priviledged services.
|
||||||
|
|
||||||
object system : object {
|
object system : object {
|
||||||
uid fa72506a2cf71a30
|
uid fa72506a2cf71a30
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
# A ``thread`` object represents a thread of execution within a process running
|
||||||
|
# on the system. The actual thread does not need to be currently running to
|
||||||
|
# hold a handle to it.
|
||||||
|
|
||||||
object thread : object {
|
object thread : object {
|
||||||
uid 11f23e593d5761bd
|
uid 11f23e593d5761bd
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import "objects/process.def"
|
import "objects/process.def"
|
||||||
|
|
||||||
|
# A ``vma`` object represents a single virtual memory area, which may be shared
|
||||||
|
# between several processes. A process having a handle to a ``vma`` does not
|
||||||
|
# necessarily mean that it is mapped into that process' virtual memory space.
|
||||||
|
|
||||||
object vma : object {
|
object vma : object {
|
||||||
uid d6a12b63b3ed3937
|
uid d6a12b63b3ed3937
|
||||||
cname vm_area
|
cname vm_area
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ interface syscalls [syscall] {
|
|||||||
|
|
||||||
# Write a message to the kernel log
|
# Write a message to the kernel log
|
||||||
function log {
|
function log {
|
||||||
|
param area uint8
|
||||||
|
param severity uint8
|
||||||
param message string
|
param message string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +44,11 @@ interface syscalls [syscall] {
|
|||||||
param mask uint32 # The capability bitmask
|
param mask uint32 # The capability bitmask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Close the handle to an object
|
||||||
|
function handle_close {
|
||||||
|
param hnd ref object [handle] # The handle to close
|
||||||
|
}
|
||||||
|
|
||||||
# Block waiting on a futex
|
# Block waiting on a futex
|
||||||
function futex_wait [static] {
|
function futex_wait [static] {
|
||||||
param address uint32* # Address of the futex value
|
param address uint32* # Address of the futex value
|
||||||
|
|||||||
23
docs/Makefile
Normal file
23
docs/Makefile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line, and also
|
||||||
|
# from the environment for the first two.
|
||||||
|
SPHINXOPTS ?=
|
||||||
|
SPHINXBUILD ?= sphinx-build
|
||||||
|
SOURCEDIR = .
|
||||||
|
BUILDDIR = _build
|
||||||
|
ROOTDIR = $(SOURCEDIR)/..
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
|
%: Makefile
|
||||||
|
PYTHONPATH=$(ROOTDIR)/scripts cog -r -D definitions_path=$(ROOTDIR)/definitions -c syscall_interface.rst
|
||||||
|
PYTHONPATH=$(ROOTDIR)/scripts cog -r -D definitions_path=$(ROOTDIR)/definitions -c kernel_memory.rst
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
254
docs/_static/custom.css
vendored
Normal file
254
docs/_static/custom.css
vendored
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
/* custom.css - jsix version */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background-color: #181820;
|
||||||
|
--link-color: #7070e0;
|
||||||
|
--link-hover-color: #9090ff;
|
||||||
|
--text-color: #3d3d3d;
|
||||||
|
--text-literal-color: #d26a98;
|
||||||
|
}
|
||||||
|
.wy-nav-side {
|
||||||
|
background: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1100px) {
|
||||||
|
.wy-nav-content-wrap {
|
||||||
|
background: var(--background-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: var(--link-hover-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: var(--link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content code.literal {
|
||||||
|
color: var(--text-literal-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content tt.literal {
|
||||||
|
color: var(--text-literal-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .note {
|
||||||
|
color: #003274;
|
||||||
|
background: #ccddf3;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .note .admonition-title {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .warning {
|
||||||
|
color: #605000;
|
||||||
|
background: #fcf4cc;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .warning .admonition-title {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content .highlight {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-scroll {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search input[type="text"] {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 0px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical a {
|
||||||
|
font-size: 100%;
|
||||||
|
color: #d9d9d9;
|
||||||
|
padding-top: 0.6rem;
|
||||||
|
padding-bottom: 0.6rem;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical a:hover {
|
||||||
|
background-color: unset;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a span.toctree-expand {
|
||||||
|
display: block;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a span.toctree-expand:before {
|
||||||
|
display: block;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a span.toctree-expand:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a:hover {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.current > a:hover span.toctree-expand {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical .toctree-l1 {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical .toctree-l1:hover {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l1.current {
|
||||||
|
opacity: 1;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l1.current > a {
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical .toctree-l2:hover {
|
||||||
|
background-color: #566673;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current > a {
|
||||||
|
background-color: #566673;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a {
|
||||||
|
background-color: #e4e7ea;
|
||||||
|
color: #838383;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover span.toctree-expand {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current > a {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a {
|
||||||
|
border: 0px;
|
||||||
|
background-color: #566673;
|
||||||
|
color: #d9d9d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a span.toctree-expand {
|
||||||
|
display: block;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a span.toctree-expand:before {
|
||||||
|
display: block;
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a span.toctree-expand:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a:hover {
|
||||||
|
color: white;
|
||||||
|
background-color: #566673;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l3.current > a {
|
||||||
|
background-color: #e4e7ea;
|
||||||
|
color: #838383;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a {
|
||||||
|
background-color: #e4e7ea;
|
||||||
|
color: #838383;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-menu-vertical li.toctree-l3.current li.toctree-l4.current > a {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-nav-top {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--text-color);
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 0;
|
||||||
|
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||||
|
box-shadow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-neutral {
|
||||||
|
background: unset !important;
|
||||||
|
color: #838383 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-neutral:active {
|
||||||
|
padding: 0.375rem 0.75rem;
|
||||||
|
box-shadow: unset;
|
||||||
|
}
|
||||||
50
docs/conf.py
Normal file
50
docs/conf.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# For the full list of built-in configuration values, see the documentation:
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||||
|
|
||||||
|
project = 'jsix'
|
||||||
|
copyright = '2024, Justin C. Miller'
|
||||||
|
author = 'Justin C. Miller'
|
||||||
|
release = '0.8'
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
||||||
|
extensions = ['sphinx.ext.todo']
|
||||||
|
primary_domain = 'cpp'
|
||||||
|
todo_include_todos = True
|
||||||
|
|
||||||
|
templates_path = ['_templates']
|
||||||
|
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||||
|
|
||||||
|
html_theme = 'renku'
|
||||||
|
html_title = 'jsix'
|
||||||
|
html_logo = 'jsix_transparent.svg'
|
||||||
|
html_static_path = ['_static']
|
||||||
|
html_css_files = ['custom.css']
|
||||||
|
html_theme_options = {
|
||||||
|
"description": "The jsix description",
|
||||||
|
"github_repo": "https://github.com/justinian/jsix",
|
||||||
|
"logo_only": True,
|
||||||
|
"footer_icons": [
|
||||||
|
{
|
||||||
|
"name": "GitHub",
|
||||||
|
"url": "https://github.com/justinian/jsix",
|
||||||
|
"html": """
|
||||||
|
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
|
||||||
|
</svg>
|
||||||
|
""",
|
||||||
|
"class": "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
81
docs/index.rst
Normal file
81
docs/index.rst
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
.. jsix documentation master file
|
||||||
|
.. |amd64| replace:: :abbr:`amd64 (aka x86_64)`
|
||||||
|
|
||||||
|
The jsix Operating System
|
||||||
|
=========================
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
**jsix** is a custom multi-core x64 operating system being built from scratch,
|
||||||
|
supporting modern [#]_ Intel or AMD CPUs, and UEFI firmware. It was initially
|
||||||
|
created out of a desire to explore UEFI and to explore what's possible with a
|
||||||
|
microkernel architecture on modern 64-bit architectures.
|
||||||
|
|
||||||
|
Most of jsix is written in C++ (C++17, using `LLVM <https://llvm.org>`_), but
|
||||||
|
you'll also find some assembly (in `NASM <https://nasm.us>`_ syntax) and Python
|
||||||
|
for development tooling.
|
||||||
|
|
||||||
|
jsix can be found `on GitHub <https://github.com/justinian/jsix>`_, and is
|
||||||
|
released under the terms of the `MPL 2.0 <https://mozilla.org/MPL/2.0/>`_.
|
||||||
|
|
||||||
|
.. admonition:: A note on the name
|
||||||
|
|
||||||
|
This kernel was originally named Popcorn, but I have since discovered that
|
||||||
|
the Popcorn Linux project is also developing a kernel with that name,
|
||||||
|
started around the same time as this project. So I've renamed this kernel
|
||||||
|
jsix as an homage to L4, xv6, and my wonderful wife.
|
||||||
|
|
||||||
|
The name jsix is always styled *jsix* or ``j6``, never capitalized.
|
||||||
|
|
||||||
|
.. [#] jsix aims to support amd64 (x86_64) CPUs released in the last 10 years.
|
||||||
|
|
||||||
|
Current Features
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The jsix kernel is quite far along now, but the userland systems are still lacking.
|
||||||
|
|
||||||
|
- Platform: |amd64|
|
||||||
|
- UEFI bootloader
|
||||||
|
- Multi-core & multi-tasking microkernel
|
||||||
|
|
||||||
|
- Work-stealing SMP scheduler
|
||||||
|
- Pluggable panic handler modules
|
||||||
|
|
||||||
|
- Capability-style object-oriented syscall API
|
||||||
|
|
||||||
|
- Custom IDL for specifying and documenting syscalls
|
||||||
|
|
||||||
|
- Virtual memory based on sharable Virtual Memory Area objects (VMAs)
|
||||||
|
- Kernel API library (libj6), also provides features built on kernel primitives:
|
||||||
|
|
||||||
|
- Channels (async stream IPC) built on shared memory and futexes
|
||||||
|
- Ring buffers via doubly-mapped pages
|
||||||
|
|
||||||
|
- Custom libc
|
||||||
|
- Runtime dynamic linker
|
||||||
|
- Init service
|
||||||
|
|
||||||
|
- Built-in VFS service for the initrd
|
||||||
|
- ELF loader
|
||||||
|
- Service-lookup protocol service
|
||||||
|
|
||||||
|
- Userland UART driver
|
||||||
|
- Userland UEFI framebuffer driver
|
||||||
|
- Userland kernel log output service
|
||||||
|
- Userland unit test runner
|
||||||
|
- Build configuration system (bonnibel)
|
||||||
|
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: Site Contents:
|
||||||
|
|
||||||
|
syscall_interface
|
||||||
|
kernel_memory
|
||||||
|
process_initialization
|
||||||
|
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
||||||
|
|
||||||
12
docs/jsix_transparent.svg
Normal file
12
docs/jsix_transparent.svg
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Gravit.io -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="isolation:isolate" viewBox="176.562 356.069 211.11 113" width="211.11pt" height="113pt">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d=" M 212.981 372.36 L 219.564 376.16 L 226.147 379.961 L 226.147 387.563 L 226.147 395.164 L 219.564 398.965 L 212.981 402.766 L 206.398 398.965 L 199.815 395.164 L 199.815 387.563 L 199.815 379.961 L 206.398 376.16 L 212.981 372.36 L 212.981 372.36 L 212.981 372.36 Z M 256.292 397.366 L 262.875 401.166 L 269.458 404.967 L 269.458 412.569 L 269.458 420.17 L 262.875 423.971 L 256.292 427.772 L 249.709 423.971 L 243.126 420.17 L 243.126 412.569 L 243.126 404.967 L 249.709 401.166 L 256.292 397.366 L 256.292 397.366 Z M 183.622 387.283 L 205.52 374.64 L 227.418 361.997 L 249.316 374.64 L 271.214 387.283 L 271.214 412.569 L 271.214 437.854 L 249.316 450.497 L 227.418 463.14 L 205.52 450.497 L 183.622 437.854 L 183.622 412.569 L 183.622 387.283 L 183.622 387.283 L 183.622 387.283 Z M 241.855 372.36 L 248.438 376.16 L 255.021 379.961 L 255.021 387.563 L 255.021 395.164 L 248.438 398.965 L 241.855 402.766 L 235.272 398.965 L 228.689 395.164 L 228.689 387.563 L 228.689 379.961 L 235.272 376.16 L 241.855 372.36 Z " fill-rule="evenodd" fill="rgb(49,79,128)"/>
|
||||||
|
<path d=" M 298.642 379.579 L 291.621 379.579 L 291.621 372.558 L 298.642 372.558 L 298.642 379.579 Z M 285.214 446.718 L 285.214 441.452 L 287.32 441.452 L 287.32 441.452 Q 289.339 441.452 290.524 440.092 L 290.524 440.092 L 290.524 440.092 Q 291.708 438.731 291.708 436.625 L 291.708 436.625 L 291.708 387.039 L 298.729 387.039 L 298.729 436.011 L 298.729 436.011 Q 298.729 440.925 295.921 443.822 L 295.921 443.822 L 295.921 443.822 Q 293.113 446.718 288.286 446.718 L 288.286 446.718 L 285.214 446.718 Z M 306.628 432.676 L 306.628 427.41 L 314.088 427.41 L 314.088 427.41 Q 317.862 427.41 319.573 425.347 L 319.573 425.347 L 319.573 425.347 Q 321.285 423.285 321.285 419.95 L 321.285 419.95 L 321.285 419.95 Q 321.285 417.317 319.705 415.474 L 319.705 415.474 L 319.705 415.474 Q 318.125 413.631 314.966 411.174 L 314.966 411.174 L 314.966 411.174 Q 312.245 408.98 310.621 407.356 L 310.621 407.356 L 310.621 407.356 Q 308.998 405.732 307.813 403.319 L 307.813 403.319 L 307.813 403.319 Q 306.628 400.905 306.628 397.746 L 306.628 397.746 L 306.628 397.746 Q 306.628 393.095 309.744 390.067 L 309.744 390.067 L 309.744 390.067 Q 312.859 387.039 318.125 387.039 L 318.125 387.039 L 325.76 387.039 L 325.76 392.305 L 319.441 392.305 L 319.441 392.305 Q 313.21 392.305 313.21 398.185 L 313.21 398.185 L 313.21 398.185 Q 313.21 400.467 314.615 402.134 L 314.615 402.134 L 314.615 402.134 Q 316.019 403.802 319.003 406.083 L 319.003 406.083 L 319.003 406.083 Q 321.723 408.19 323.479 409.901 L 323.479 409.901 L 323.479 409.901 Q 325.234 411.613 326.463 414.202 L 326.463 414.202 L 326.463 414.202 Q 327.691 416.791 327.691 420.301 L 327.691 420.301 L 327.691 420.301 Q 327.691 426.532 324.4 429.604 L 324.4 429.604 L 324.4 429.604 Q 321.109 432.676 315.141 432.676 L 315.141 432.676 L 306.628 432.676 Z M 342.611 379.579 L 335.59 379.579 L 335.59 372.558 L 342.611 372.558 L 342.611 379.579 Z M 342.611 432.676 L 335.59 432.676 L 335.59 387.039 L 342.611 387.039 L 342.611 432.676 Z M 356.126 432.676 L 348.754 432.676 L 361.392 409.77 L 349.632 387.039 L 356.39 387.039 L 364.639 403.187 L 372.977 387.039 L 379.735 387.039 L 367.974 409.77 L 380.612 432.676 L 373.24 432.676 L 364.639 416.001 L 356.126 432.676 Z " fill="rgb(49,79,128)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
178
docs/kernel_memory.rst
Normal file
178
docs/kernel_memory.rst
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
.. jsix syscall interface.
|
||||||
|
.. Automatically updated from the definition files using cog!
|
||||||
|
|
||||||
|
.. [[[cog code generation
|
||||||
|
.. from os.path import join
|
||||||
|
.. from memory import Layout, unit
|
||||||
|
..
|
||||||
|
.. layout = Layout(join(definitions_path, "memory_layout.yaml"))
|
||||||
|
.. l = max([len(r.name) for r in layout.regions])
|
||||||
|
.. ]]]
|
||||||
|
.. [[[end]]] (checksum: d41d8cd98f00b204e9800998ecf8427e)
|
||||||
|
|
||||||
|
Kernel memory
|
||||||
|
=============
|
||||||
|
|
||||||
|
While jsix probably should eventually use KASLR to randomize its memory layout,
|
||||||
|
currently the layout is mostly fixed. (Kernel code locations are not consistent
|
||||||
|
but aren't explicitly randomized.)
|
||||||
|
|
||||||
|
.. [[[cog code generation
|
||||||
|
.. line_size = 128 * 1024**3 # Each line represents up to 32 GiB
|
||||||
|
.. max_lines = 32
|
||||||
|
.. totals = sum([r.size for r in layout.regions])
|
||||||
|
.. remain = unit((128 * 1024**4) - totals)
|
||||||
|
..
|
||||||
|
.. def split(val):
|
||||||
|
.. return f"0x {val >> 48:04x} {(val >> 32) & 0xffff:04x} {(val >> 16) & 0xffff:04x} {val & 0xffff:04x}"
|
||||||
|
..
|
||||||
|
.. cog.outl()
|
||||||
|
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||||
|
.. cog.outl(f"| | Address | Size | Use |")
|
||||||
|
.. cog.outl(f"+=+=============================+==========+=======================================+")
|
||||||
|
..
|
||||||
|
.. for region in layout.regions:
|
||||||
|
.. cog.outl(f"| | ``{split(region.start)}`` | {unit(region.size):>8} | {region.desc:37} |")
|
||||||
|
.. lines = min(max_lines, region.size // line_size)
|
||||||
|
.. for i in range(1, lines):
|
||||||
|
.. cog.outl(f"+-+ | | |")
|
||||||
|
.. cog.outl(f"| | | | |")
|
||||||
|
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||||
|
..
|
||||||
|
.. cog.outl(f"| | ... | | |")
|
||||||
|
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||||
|
.. cog.outl(f"| | ``0x ffff 0000 0000 0000`` | | Kernel code / headers |")
|
||||||
|
.. cog.outl(f"+-+-----------------------------+----------+---------------------------------------+")
|
||||||
|
.. cog.outl("")
|
||||||
|
.. cog.outl("")
|
||||||
|
.. cog.outl(f"Un-reserved virtual memory address space in the higher half: {remain}")
|
||||||
|
.. cog.outl("")
|
||||||
|
..
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | Address | Size | Use |
|
||||||
|
+=+=============================+==========+=======================================+
|
||||||
|
| | ``0x ffff c000 0000 0000`` | 64 TiB | Linearly-mapped physical memory |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bf00 0000 0000`` | 1 TiB | Used/free page tracking bitmap |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff be00 0000 0000`` | 1 TiB | Per-page state tracking structures |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+ | | |
|
||||||
|
| | | | |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bdf8 0000 0000`` | 32 GiB | Kernel heap accounting structures |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bdf0 0000 0000`` | 32 GiB | Kernel heap |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bde8 0000 0000`` | 32 GiB | Capabilities accounting structures |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bde0 0000 0000`` | 32 GiB | Capabilities |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bdd0 0000 0000`` | 64 GiB | Kernel thread stacks |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bdc0 0000 0000`` | 64 GiB | Kernel buffers |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff bdbf 8000 0000`` | 2 GiB | Kernel logs circular buffer |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ... | | |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
| | ``0x ffff 0000 0000 0000`` | | Kernel code / headers |
|
||||||
|
+-+-----------------------------+----------+---------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
Un-reserved virtual memory address space in the higher half: 61 TiB
|
||||||
|
|
||||||
|
.. [[[end]]] (checksum: 8c336cc8151beba1a79c8d3b653f1109)
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
||||||
7
docs/modd.conf
Normal file
7
docs/modd.conf
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
** !_build/** ../definitions/**.def {
|
||||||
|
prep: rm -rf _build; make html
|
||||||
|
}
|
||||||
|
|
||||||
|
_build/html/** {
|
||||||
|
daemon: devd -m _build/html
|
||||||
|
}
|
||||||
42
docs/process_initialization.rst
Normal file
42
docs/process_initialization.rst
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
.. jsix process initialization in userspace
|
||||||
|
|
||||||
|
Process Initialization
|
||||||
|
======================
|
||||||
|
|
||||||
|
jsix follows the `System V ABI`_ on the ``amd64`` architecture. All arguments
|
||||||
|
needed for program initialization are passed to the program's initial thread on
|
||||||
|
the stack.
|
||||||
|
|
||||||
|
Note that jsix adds a number of additional auxiliary vector entry types for
|
||||||
|
passing jsix-specific data to a program. The jsix-specific auxiliary vector type
|
||||||
|
codes (what the ABI document refers to as ``a_type``) start from ``0xf000``. See
|
||||||
|
the header file ``<j6/init.h>`` for more detail.
|
||||||
|
|
||||||
|
.. _System V ABI: https://gitlab.com/x86-psABIs/x86-64-ABI
|
||||||
|
|
||||||
|
The initial stack frame
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
============== ==================== ============ =======
|
||||||
|
Address Value Bytes Notes
|
||||||
|
============== ==================== ============ =======
|
||||||
|
``top`` Stack top (out of stack bounds)
|
||||||
|
``top`` - 16 0 16 Stack sentinel
|
||||||
|
\ ``envp`` string data ?
|
||||||
|
\ ``argv`` string data ?
|
||||||
|
\ ... ? Possible padding
|
||||||
|
\ 0, 0 (``AT_NULL``) 16 Aux vector sentinel
|
||||||
|
\ Aux vectors 16 * `m` ``AT_NULL``-terminated array of Aux vectors
|
||||||
|
\ 0 8 Environment sentinel
|
||||||
|
\ ``envp`` 8 * `n` 0-terminated array of environment
|
||||||
|
string pointers
|
||||||
|
\ 0 8 Args sentinel
|
||||||
|
\ ``argv`` 8 * ``argc`` Pointers to argument strings
|
||||||
|
``rsp`` ``argc`` 8 Number of elements in argv
|
||||||
|
============== ==================== ============ =======
|
||||||
|
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
||||||
|
|
||||||
5
docs/requirements.txt
Normal file
5
docs/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
cogapp >= 3
|
||||||
|
pyyaml >= 5.4
|
||||||
|
lark == 0.12.0
|
||||||
|
sphinx
|
||||||
|
renku-sphinx-theme
|
||||||
444
docs/syscall_interface.rst
Normal file
444
docs/syscall_interface.rst
Normal file
@@ -0,0 +1,444 @@
|
|||||||
|
.. jsix syscall interface.
|
||||||
|
.. Automatically updated from the definition files using cog!
|
||||||
|
|
||||||
|
.. [[[cog code generation
|
||||||
|
.. from textwrap import indent
|
||||||
|
.. from definitions.context import Context
|
||||||
|
..
|
||||||
|
.. ctx = Context(definitions_path)
|
||||||
|
.. ctx.parse("syscalls.def")
|
||||||
|
.. syscalls = ctx.interfaces["syscalls"]
|
||||||
|
..
|
||||||
|
.. def caplist(caps):
|
||||||
|
.. return ', '.join([f"``{c}``" for c in caps])
|
||||||
|
.. ]]]
|
||||||
|
.. [[[end]]] (checksum: d41d8cd98f00b204e9800998ecf8427e)
|
||||||
|
|
||||||
|
Syscall interface
|
||||||
|
=================
|
||||||
|
|
||||||
|
The jsix kernel's syscall design is based around object handles. Object handles
|
||||||
|
are also a collection of capabilities, encoding certain rights over the object
|
||||||
|
they reference.
|
||||||
|
|
||||||
|
Very few syscalls in jsix can be made without some handle, and most of them are
|
||||||
|
requests to the kernel to create a given kind of object. This is analogous to
|
||||||
|
methods on an object in an object-oriented programming language.
|
||||||
|
|
||||||
|
.. [[[cog code generation
|
||||||
|
.. cog.outl()
|
||||||
|
.. for obj in syscalls.exposes:
|
||||||
|
.. cog.outl(f"``{obj.name}`` syscalls")
|
||||||
|
.. cog.outl(f"-------------------------")
|
||||||
|
.. desc = obj.desc or "Undocumented"
|
||||||
|
.. cog.outl(desc)
|
||||||
|
.. cog.outl()
|
||||||
|
.. cog.outl(f":capabilites: {caplist(obj.caps)}")
|
||||||
|
.. cog.outl()
|
||||||
|
.. for method in obj.methods:
|
||||||
|
.. args = []
|
||||||
|
.. if method.constructor:
|
||||||
|
.. args.append("j6_handle_t *self")
|
||||||
|
.. elif not method.static:
|
||||||
|
.. args.append("j6_handle_t self")
|
||||||
|
..
|
||||||
|
.. for param in method.params:
|
||||||
|
.. for type, suffix in param.type.c_names(param.options):
|
||||||
|
.. args.append(f"{type} {param.name}{suffix}")
|
||||||
|
..
|
||||||
|
.. cog.outl(f".. cpp:function:: j6_result_t j6_{obj.name}_{method.name} ({', '.join(args)})")
|
||||||
|
.. cog.outl()
|
||||||
|
.. desc = method.desc or "Undocumented"
|
||||||
|
.. cog.outl(indent(desc, " "))
|
||||||
|
.. cog.outl()
|
||||||
|
.. if "cap" in method.options:
|
||||||
|
.. cog.outl(f" :capabilities: {caplist(method.options['cap'])}")
|
||||||
|
.. cog.outl()
|
||||||
|
.. if method.constructor:
|
||||||
|
.. cog.outl(f" :param self: *[out]* Handle to the new {obj.name} object")
|
||||||
|
.. elif not method.static:
|
||||||
|
.. cog.outl(f" :param self: Handle to the {obj.name} object")
|
||||||
|
.. for param in method.params:
|
||||||
|
.. opts = param.options and f"*[{', '.join(param.options)}]*" or ""
|
||||||
|
.. desc = param.desc or 'Undocumented'
|
||||||
|
.. cog.outl(f" :param {param.name}: {opts} {desc}")
|
||||||
|
.. cog.outl()
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
``object`` syscalls
|
||||||
|
-------------------------
|
||||||
|
All kernel-exposed objects inherit from the base ``object`` type, so the
|
||||||
|
``object`` syscalls can be used with any object's handle.
|
||||||
|
|
||||||
|
:capabilites: ``clone``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_object_koid (j6_handle_t self, uint64_t * koid)
|
||||||
|
|
||||||
|
Get the internal kernel object id of an object
|
||||||
|
|
||||||
|
:param self: Handle to the object object
|
||||||
|
:param koid: *[out]* Undocumented
|
||||||
|
|
||||||
|
``event`` syscalls
|
||||||
|
-------------------------
|
||||||
|
An ``event`` is a simple synchronization object. It contains up to 64 signals
|
||||||
|
that threads can wait for and signal in parallel.
|
||||||
|
|
||||||
|
:capabilites: ``signal``, ``wait``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_event_create (j6_handle_t *self)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new event object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_event_signal (j6_handle_t self, uint64_t signals)
|
||||||
|
|
||||||
|
Signal events on this object
|
||||||
|
|
||||||
|
:capabilities: ``signal``
|
||||||
|
|
||||||
|
:param self: Handle to the event object
|
||||||
|
:param signals: A bitset of which events to signal
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_event_wait (j6_handle_t self, uint64_t * signals, uint64_t timeout)
|
||||||
|
|
||||||
|
Wait for signaled events on this object
|
||||||
|
|
||||||
|
:capabilities: ``wait``
|
||||||
|
|
||||||
|
:param self: Handle to the event object
|
||||||
|
:param signals: *[out]* A bitset of which events were signaled
|
||||||
|
:param timeout: Wait timeout in nanoseconds
|
||||||
|
|
||||||
|
``mailbox`` syscalls
|
||||||
|
-------------------------
|
||||||
|
Mailboxes are objects that enable synchronous IPC via arbitrary
|
||||||
|
message-passing of tagged data and/or handles. Not as efficient
|
||||||
|
as shared memory channels, but more flexible.
|
||||||
|
|
||||||
|
:capabilites: ``send``, ``receive``, ``close``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_mailbox_create (j6_handle_t *self)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new mailbox object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_mailbox_close (j6_handle_t self)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``close``
|
||||||
|
|
||||||
|
:param self: Handle to the mailbox object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_mailbox_call (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_size, j6_handle_t * handles, size_t * handles_count, size_t handles_size)
|
||||||
|
|
||||||
|
Send a message to the reciever, and block until a response is
|
||||||
|
sent. Note that getting this response does not require the
|
||||||
|
receive capability.
|
||||||
|
|
||||||
|
:capabilities: ``send``
|
||||||
|
|
||||||
|
:param self: Handle to the mailbox object
|
||||||
|
:param tag: *[inout]* Undocumented
|
||||||
|
:param data: *[optional, inout]* Undocumented
|
||||||
|
:param data_size: number of total bytes in data buffer
|
||||||
|
:param handles: *[optional, inout, handle, list]* Undocumented
|
||||||
|
:param handles_size: total size of handles buffer
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_mailbox_respond (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_size, j6_handle_t * handles, size_t * handles_count, size_t handles_size, uint64_t * reply_tag, uint64_t flags)
|
||||||
|
|
||||||
|
Respond to a message sent using call, and wait for another
|
||||||
|
message to arrive. Note that this does not require the send
|
||||||
|
capability. A reply tag of 0 skips the reply and goes directly
|
||||||
|
to waiting for a new message.
|
||||||
|
|
||||||
|
:capabilities: ``receive``
|
||||||
|
|
||||||
|
:param self: Handle to the mailbox object
|
||||||
|
:param tag: *[inout]* Undocumented
|
||||||
|
:param data: *[optional, inout]* Undocumented
|
||||||
|
:param data_size: number of total bytes in data buffer
|
||||||
|
:param handles: *[optional, inout, handle, list]* Undocumented
|
||||||
|
:param handles_size: total size of handles buffer
|
||||||
|
:param reply_tag: *[inout]* Undocumented
|
||||||
|
:param flags: Undocumented
|
||||||
|
|
||||||
|
``process`` syscalls
|
||||||
|
-------------------------
|
||||||
|
A ``process`` object represents a process running on the system, and allows
|
||||||
|
control over the threads, handles, and virtual memory space of that process.
|
||||||
|
|
||||||
|
:capabilites: ``kill``, ``create_thread``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_process_create (j6_handle_t *self)
|
||||||
|
|
||||||
|
Create a new empty process
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new process object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_process_kill (j6_handle_t self)
|
||||||
|
|
||||||
|
Stop all threads and exit the given process
|
||||||
|
|
||||||
|
:capabilities: ``kill``
|
||||||
|
|
||||||
|
:param self: Handle to the process object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_process_exit (int64_t result)
|
||||||
|
|
||||||
|
Stop all threads and exit the current process
|
||||||
|
|
||||||
|
:param result: The result to retrun to the parent process
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_process_give_handle (j6_handle_t self, j6_handle_t target)
|
||||||
|
|
||||||
|
Give the given process a handle that points to the same
|
||||||
|
object as the specified handle.
|
||||||
|
|
||||||
|
:param self: Handle to the process object
|
||||||
|
:param target: *[handle]* A handle in the caller process to send
|
||||||
|
|
||||||
|
``system`` syscalls
|
||||||
|
-------------------------
|
||||||
|
The singular ``system`` object represents a handle to kernel functionality
|
||||||
|
needed by drivers and other priviledged services.
|
||||||
|
|
||||||
|
:capabilites: ``get_log``, ``bind_irq``, ``map_phys``, ``change_iopl``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_system_get_log (j6_handle_t self, uint64_t seen, void * buffer, size_t * buffer_len)
|
||||||
|
|
||||||
|
Get the next log line from the kernel log
|
||||||
|
|
||||||
|
:capabilities: ``get_log``
|
||||||
|
|
||||||
|
:param self: Handle to the system object
|
||||||
|
:param seen: Last seen log id
|
||||||
|
:param buffer: *[out, zero_ok]* Buffer for the log message data structure
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_system_bind_irq (j6_handle_t self, j6_handle_t dest, unsigned irq, unsigned signal)
|
||||||
|
|
||||||
|
Ask the kernel to send this process messages whenever
|
||||||
|
the given IRQ fires
|
||||||
|
|
||||||
|
:capabilities: ``bind_irq``
|
||||||
|
|
||||||
|
:param self: Handle to the system object
|
||||||
|
:param dest: Event object that will receive messages
|
||||||
|
:param irq: IRQ number to bind
|
||||||
|
:param signal: Signal number on the event to bind to
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_system_map_phys (j6_handle_t self, j6_handle_t * area, uintptr_t phys, size_t size, uint32_t flags)
|
||||||
|
|
||||||
|
Create a VMA and map an area of physical memory into it,
|
||||||
|
also mapping that VMA into the current process
|
||||||
|
|
||||||
|
:capabilities: ``map_phys``
|
||||||
|
|
||||||
|
:param self: Handle to the system object
|
||||||
|
:param area: *[out]* Receives a handle to the VMA created
|
||||||
|
:param phys: The physical address of the area
|
||||||
|
:param size: Size of the area, in bytes
|
||||||
|
:param flags: Flags to apply to the created VMA
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_system_request_iopl (j6_handle_t self, unsigned iopl)
|
||||||
|
|
||||||
|
Request the kernel change the IOPL for this process. The only values
|
||||||
|
that make sense are 0 and 3.
|
||||||
|
|
||||||
|
:capabilities: ``change_iopl``
|
||||||
|
|
||||||
|
:param self: Handle to the system object
|
||||||
|
:param iopl: The IOPL to set for this process
|
||||||
|
|
||||||
|
``thread`` syscalls
|
||||||
|
-------------------------
|
||||||
|
A ``thread`` object represents a thread of execution within a process running
|
||||||
|
on the system. The actual thread does not need to be currently running to
|
||||||
|
hold a handle to it.
|
||||||
|
|
||||||
|
:capabilites: ``kill``, ``join``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_thread_create (j6_handle_t *self, j6_handle_t process, uintptr_t stack_top, uintptr_t entrypoint, uint64_t arg0, uint64_t arg1)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new thread object
|
||||||
|
:param process: *[optional, cap]* Undocumented
|
||||||
|
:param stack_top: Undocumented
|
||||||
|
:param entrypoint: Undocumented
|
||||||
|
:param arg0: Undocumented
|
||||||
|
:param arg1: Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_thread_kill (j6_handle_t self)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``kill``
|
||||||
|
|
||||||
|
:param self: Handle to the thread object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_thread_join (j6_handle_t self)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``join``
|
||||||
|
|
||||||
|
:param self: Handle to the thread object
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_thread_exit ()
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_thread_sleep (uint64_t duration)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:param duration: Undocumented
|
||||||
|
|
||||||
|
``vma`` syscalls
|
||||||
|
-------------------------
|
||||||
|
A ``vma`` object represents a single virtual memory area, which may be shared
|
||||||
|
between several processes. A process having a handle to a ``vma`` does not
|
||||||
|
necessarily mean that it is mapped into that process' virtual memory space.
|
||||||
|
|
||||||
|
:capabilites: ``map``, ``unmap``, ``resize``
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_vma_create (j6_handle_t *self, size_t size, uint32_t flags)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new vma object
|
||||||
|
:param size: Undocumented
|
||||||
|
:param flags: Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_vma_create_map (j6_handle_t *self, size_t size, uintptr_t * address, uint32_t flags)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``map``
|
||||||
|
|
||||||
|
:param self: *[out]* Handle to the new vma object
|
||||||
|
:param size: Undocumented
|
||||||
|
:param address: *[inout]* Undocumented
|
||||||
|
:param flags: Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_vma_map (j6_handle_t self, j6_handle_t process, uintptr_t * address, uint32_t flags)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``map``
|
||||||
|
|
||||||
|
:param self: Handle to the vma object
|
||||||
|
:param process: *[optional]* Undocumented
|
||||||
|
:param address: *[inout]* Undocumented
|
||||||
|
:param flags: Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_vma_unmap (j6_handle_t self, j6_handle_t process)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``unmap``
|
||||||
|
|
||||||
|
:param self: Handle to the vma object
|
||||||
|
:param process: *[optional]* Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_vma_resize (j6_handle_t self, size_t * size)
|
||||||
|
|
||||||
|
Undocumented
|
||||||
|
|
||||||
|
:capabilities: ``resize``
|
||||||
|
|
||||||
|
:param self: Handle to the vma object
|
||||||
|
:param size: *[inout]* New size for the VMA, or 0 to query the current size without changing
|
||||||
|
|
||||||
|
.. [[[end]]] (checksum: cb17f54e443d1d3b85995870f3e8dbf2)
|
||||||
|
|
||||||
|
Non-object syscalls
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The following are the system calls that aren't constructors for objects, and
|
||||||
|
either do not require an object handle, or operate generically on handles.
|
||||||
|
|
||||||
|
.. [[[cog code generation
|
||||||
|
.. cog.outl()
|
||||||
|
.. for func in syscalls.functions:
|
||||||
|
.. args = []
|
||||||
|
.. for param in func.params:
|
||||||
|
.. for type, suffix in param.type.c_names(param.options):
|
||||||
|
.. args.append(f"{type} {param.name}{suffix}")
|
||||||
|
..
|
||||||
|
.. cog.outl(f".. cpp:function:: j6_result_t j6_{func.name} ({', '.join(args)})")
|
||||||
|
.. cog.outl()
|
||||||
|
.. desc = func.desc or "Undocumented"
|
||||||
|
.. cog.outl(indent(desc, " "))
|
||||||
|
.. cog.outl()
|
||||||
|
.. for param in func.params:
|
||||||
|
.. opts = param.options and f"*[{', '.join(param.options)}]*" or ""
|
||||||
|
.. desc = param.desc or 'Undocumented'
|
||||||
|
.. cog.outl(f" :param {param.name}: {opts} {desc}")
|
||||||
|
.. cog.outl()
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_noop ()
|
||||||
|
|
||||||
|
Simple no-op syscall for testing
|
||||||
|
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_log (uint8_t area, uint8_t severity, const char * message)
|
||||||
|
|
||||||
|
Write a message to the kernel log
|
||||||
|
|
||||||
|
:param area: Undocumented
|
||||||
|
:param severity: Undocumented
|
||||||
|
:param message: Undocumented
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_handle_list (struct j6_handle_descriptor * handles, size_t * handles_size)
|
||||||
|
|
||||||
|
Get a list of handles owned by this process. If the
|
||||||
|
supplied list is not big enough, will set the size
|
||||||
|
needed in `size` and return j6_err_insufficient
|
||||||
|
|
||||||
|
:param handles: *[list, inout, zero_ok]* A list of handles to be filled
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_handle_clone (j6_handle_t orig, j6_handle_t * clone, uint32_t mask)
|
||||||
|
|
||||||
|
Create a clone of an existing handle, possibly with
|
||||||
|
some capabilities masked out.
|
||||||
|
|
||||||
|
:param orig: *[handle, cap]* The handle to clone
|
||||||
|
:param clone: *[out]* The new handle
|
||||||
|
:param mask: The capability bitmask
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_handle_close (j6_handle_t hnd)
|
||||||
|
|
||||||
|
Close the handle to an object
|
||||||
|
|
||||||
|
:param hnd: *[handle]* The handle to close
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_futex_wait (const uint32_t * address, uint32_t current, uint64_t timeout)
|
||||||
|
|
||||||
|
Block waiting on a futex
|
||||||
|
|
||||||
|
:param address: Address of the futex value
|
||||||
|
:param current: Current value of the futex
|
||||||
|
:param timeout: Wait timeout in nanoseconds
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_futex_wake (const uint32_t * address, uint64_t count)
|
||||||
|
|
||||||
|
Wake threads waiting on a futex
|
||||||
|
|
||||||
|
:param address: Address of the futex value
|
||||||
|
:param count: Number of threads to wake, or 0 for all
|
||||||
|
|
||||||
|
.. cpp:function:: j6_result_t j6_test_finish (uint32_t exit_code)
|
||||||
|
|
||||||
|
Testing mode only: Have the kernel finish and exit QEMU with the given exit code
|
||||||
|
|
||||||
|
:param exit_code: Undocumented
|
||||||
|
|
||||||
|
.. [[[end]]] (checksum: 0b9d051972abcbb6de408f411331785f)
|
||||||
|
|
||||||
6
qemu.sh
6
qemu.sh
@@ -41,7 +41,7 @@ while true; do
|
|||||||
-r | --remote)
|
-r | --remote)
|
||||||
shift
|
shift
|
||||||
vnchost="${1:-${VNCHOST:-"localhost:5500"}}"
|
vnchost="${1:-${VNCHOST:-"localhost:5500"}}"
|
||||||
gfx="-vnc ${vnchost},reverse"
|
gfx="-vnc ${vnchost},reverse=on"
|
||||||
vga=""
|
vga=""
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
@@ -117,13 +117,13 @@ if [[ -n $TMUX ]]; then
|
|||||||
tmux split-window -h -l $log_width "$debugcon_cmd"
|
tmux split-window -h -l $log_width "$debugcon_cmd"
|
||||||
tmux last-pane
|
tmux last-pane
|
||||||
fi
|
fi
|
||||||
tmux split-window -l 10 "sleep 1; telnet localhost 45454"
|
tmux split-window -l 10 "sleep 1; nc localhost 45454"
|
||||||
fi
|
fi
|
||||||
elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
elif [[ $DESKTOP_SESSION = "i3" ]]; then
|
||||||
if [[ -n $debug ]]; then
|
if [[ -n $debug ]]; then
|
||||||
i3-msg exec i3-sensible-terminal -- -e "gdb ${debugtarget}" &
|
i3-msg exec i3-sensible-terminal -- -e "gdb ${debugtarget}" &
|
||||||
else
|
else
|
||||||
i3-msg exec i3-sensible-terminal -- -e 'telnet localhost 45454' &
|
i3-msg exec i3-sensible-terminal -- -e 'nc localhost 45454' &
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -7,3 +7,5 @@ pure-cdb == 4
|
|||||||
pyzstd == 0.15
|
pyzstd == 0.15
|
||||||
pyelftools
|
pyelftools
|
||||||
iced-x86
|
iced-x86
|
||||||
|
sphinx
|
||||||
|
renku-sphinx-theme
|
||||||
|
|||||||
21
scripts/codegen/__init__.py
Normal file
21
scripts/codegen/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import cog
|
||||||
|
|
||||||
|
supported_architectures = {
|
||||||
|
"amd64": "__amd64__",
|
||||||
|
}
|
||||||
|
|
||||||
|
def arch_includes(header, root=""):
|
||||||
|
from pathlib import Path
|
||||||
|
root = Path(root)
|
||||||
|
header = Path(header)
|
||||||
|
|
||||||
|
prefix = "if"
|
||||||
|
for arch, define in supported_architectures.items():
|
||||||
|
path = root / "arch" / arch / header
|
||||||
|
cog.outl(f"#{prefix} defined({define})")
|
||||||
|
cog.outl(f"#include <{path}>")
|
||||||
|
prefix = "elif"
|
||||||
|
cog.outl("#else")
|
||||||
|
cog.outl('#error "Unsupported platform"')
|
||||||
|
cog.outl("#endif")
|
||||||
|
|
||||||
@@ -1,18 +1,5 @@
|
|||||||
import cog
|
import cog
|
||||||
|
|
||||||
supported_architectures = {
|
|
||||||
"amd64": "__amd64__",
|
|
||||||
}
|
|
||||||
|
|
||||||
def arch_includes(header):
|
|
||||||
prefix = "if"
|
|
||||||
for arch, define in supported_architectures.items():
|
|
||||||
cog.outl(f"#{prefix} defined({define})")
|
|
||||||
cog.outl(f"#include <__j6libc/arch/{arch}/{header}>")
|
|
||||||
prefix = "elif"
|
|
||||||
cog.outl("#endif")
|
|
||||||
|
|
||||||
|
|
||||||
int_widths = (8, 16, 32, 64)
|
int_widths = (8, 16, 32, 64)
|
||||||
int_mods = ("fast", "least")
|
int_mods = ("fast", "least")
|
||||||
|
|
||||||
@@ -1,6 +1,18 @@
|
|||||||
|
|
||||||
|
def unit(size):
|
||||||
|
units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB']
|
||||||
|
|
||||||
|
o = 0
|
||||||
|
while size >= 1024 and o < len(units):
|
||||||
|
o += 1
|
||||||
|
size = size >> 10
|
||||||
|
|
||||||
|
return f"{size} {units[o]}"
|
||||||
|
|
||||||
|
|
||||||
class Layout:
|
class Layout:
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
Region = namedtuple("Region", ("name", "start", "size", "shared"))
|
Region = namedtuple("Region", ("name", "desc", "start", "size", "shared"))
|
||||||
|
|
||||||
sizes = {'G': 1024 ** 3, 'T': 1024 ** 4}
|
sizes = {'G': 1024 ** 3, 'T': 1024 ** 4}
|
||||||
|
|
||||||
@@ -26,7 +38,7 @@ class Layout:
|
|||||||
for r in data:
|
for r in data:
|
||||||
size = Layout.get_size(r["size"])
|
size = Layout.get_size(r["size"])
|
||||||
addr -= size
|
addr -= size
|
||||||
regions.append(Layout.Region(r["name"], addr, size,
|
regions.append(Layout.Region(r["name"], r["desc"], addr, size,
|
||||||
r.get("shared", False)))
|
r.get("shared", False)))
|
||||||
|
|
||||||
self.regions = tuple(regions)
|
self.regions = tuple(regions)
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ def add_dir(path, files, dirs, inode_data, dir_inodes, output, compress):
|
|||||||
compressed = uncompressed
|
compressed = uncompressed
|
||||||
comp_size = uncomp_size
|
comp_size = uncomp_size
|
||||||
|
|
||||||
output.write(uncompressed)
|
output.write(compressed)
|
||||||
inode_data.append((inode_type_dir, offset, comp_size, uncomp_size))
|
inode_data.append((inode_type_dir, offset, comp_size, uncomp_size))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ read_string(util::buffer &data)
|
|||||||
static void
|
static void
|
||||||
read_descriptor(descriptor &e, util::buffer &data)
|
read_descriptor(descriptor &e, util::buffer &data)
|
||||||
{
|
{
|
||||||
e.flags = static_cast<desc_flags>(*util::read<uint16_t>(data));
|
e.flags = util::bitset16 {*util::read<uint16_t>(data)};
|
||||||
e.path = read_string(data);
|
e.path = read_string(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <bootproto/bootconfig.h>
|
#include <bootproto/bootconfig.h>
|
||||||
|
#include <util/bitset.h>
|
||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
|
|
||||||
namespace uefi {
|
namespace uefi {
|
||||||
@@ -14,7 +15,7 @@ namespace boot {
|
|||||||
using desc_flags = bootproto::desc_flags;
|
using desc_flags = bootproto::desc_flags;
|
||||||
|
|
||||||
struct descriptor {
|
struct descriptor {
|
||||||
desc_flags flags;
|
util::bitset16 flags;
|
||||||
wchar_t const *path;
|
wchar_t const *path;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ public:
|
|||||||
/// Constructor. Loads bootconfig from the given buffer.
|
/// Constructor. Loads bootconfig from the given buffer.
|
||||||
bootconfig(util::buffer data, uefi::boot_services *bs);
|
bootconfig(util::buffer data, uefi::boot_services *bs);
|
||||||
|
|
||||||
inline uint16_t flags() const { return m_flags; }
|
inline util::bitset16 flags() const { return m_flags; }
|
||||||
inline const descriptor & kernel() const { return m_kernel; }
|
inline const descriptor & kernel() const { return m_kernel; }
|
||||||
inline const descriptor & init() const { return m_init; }
|
inline const descriptor & init() const { return m_init; }
|
||||||
inline const wchar_t * initrd() const { return m_initrd; }
|
inline const wchar_t * initrd() const { return m_initrd; }
|
||||||
@@ -35,7 +36,7 @@ public:
|
|||||||
inline const descriptors & panics() { return m_panics; }
|
inline const descriptors & panics() { return m_panics; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t m_flags;
|
util::bitset16 m_flags;
|
||||||
descriptor m_kernel;
|
descriptor m_kernel;
|
||||||
descriptor m_init;
|
descriptor m_init;
|
||||||
descriptors m_panics;
|
descriptors m_panics;
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ parse_program(const wchar_t *name, util::const_buffer data, bootproto::program &
|
|||||||
section.phys_addr = elf.base() + seg.offset;
|
section.phys_addr = elf.base() + seg.offset;
|
||||||
section.virt_addr = seg.vaddr;
|
section.virt_addr = seg.vaddr;
|
||||||
section.size = seg.mem_size;
|
section.size = seg.mem_size;
|
||||||
section.type = static_cast<bootproto::section_flags>(seg.flags);
|
section.type = seg.flags;
|
||||||
|
|
||||||
if (seg.mem_size != seg.file_size)
|
if (seg.mem_size != seg.file_size)
|
||||||
section.phys_addr = allocate_bss(seg);
|
section.phys_addr = allocate_bss(seg);
|
||||||
@@ -128,8 +128,6 @@ load_program(
|
|||||||
paging::pager &pager,
|
paging::pager &pager,
|
||||||
bool verify)
|
bool verify)
|
||||||
{
|
{
|
||||||
using util::bits::has;
|
|
||||||
|
|
||||||
status_line status(L"Loading program", name);
|
status_line status(L"Loading program", name);
|
||||||
|
|
||||||
elf::file elf {data};
|
elf::file elf {data};
|
||||||
@@ -155,8 +153,8 @@ load_program(
|
|||||||
|
|
||||||
pager.map_pages(phys_addr, seg.vaddr,
|
pager.map_pages(phys_addr, seg.vaddr,
|
||||||
memory::bytes_to_pages(seg.mem_size),
|
memory::bytes_to_pages(seg.mem_size),
|
||||||
has(seg.flags, elf::segment_flags::write),
|
seg.flags.get(elf::segment_flags::write),
|
||||||
has(seg.flags, elf::segment_flags::exec));
|
seg.flags.get(elf::segment_flags::exec));
|
||||||
}
|
}
|
||||||
|
|
||||||
return elf.entrypoint();
|
return elf.entrypoint();
|
||||||
|
|||||||
@@ -82,9 +82,8 @@ load_resources(
|
|||||||
util::buffer kernel = loader::load_file(disk, bc.kernel().path);
|
util::buffer kernel = loader::load_file(disk, bc.kernel().path);
|
||||||
uintptr_t kentry = loader::load_program(kernel, L"jsix kernel", pager, true);
|
uintptr_t kentry = loader::load_program(kernel, L"jsix kernel", pager, true);
|
||||||
|
|
||||||
args->flags = static_cast<bootproto::boot_flags>(bc.flags());
|
args->flags = bc.flags();
|
||||||
|
|
||||||
namespace bits = util::bits;
|
|
||||||
using bootproto::desc_flags;
|
using bootproto::desc_flags;
|
||||||
|
|
||||||
bool has_panic = false;
|
bool has_panic = false;
|
||||||
@@ -96,7 +95,7 @@ load_resources(
|
|||||||
// Find the screen-specific panic handler first to
|
// Find the screen-specific panic handler first to
|
||||||
// give it priority
|
// give it priority
|
||||||
for (const descriptor &d : bc.panics()) {
|
for (const descriptor &d : bc.panics()) {
|
||||||
if (bits::has(d.flags, desc_flags::graphical)) {
|
if (d.flags.get(desc_flags::graphical)) {
|
||||||
panic = loader::load_file(disk, d.path);
|
panic = loader::load_file(disk, d.path);
|
||||||
has_panic = true;
|
has_panic = true;
|
||||||
break;
|
break;
|
||||||
@@ -106,7 +105,7 @@ load_resources(
|
|||||||
|
|
||||||
if (!has_panic) {
|
if (!has_panic) {
|
||||||
for (const descriptor &d : bc.panics()) {
|
for (const descriptor &d : bc.panics()) {
|
||||||
if (!bits::has(d.flags, desc_flags::graphical)) {
|
if (!d.flags.get(desc_flags::graphical)) {
|
||||||
panic = loader::load_file(disk, d.path);
|
panic = loader::load_file(disk, d.path);
|
||||||
has_panic = true;
|
has_panic = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -71,21 +71,19 @@ lapic::get_id()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapic::send_ipi(ipi mode, isr vector, uint8_t dest)
|
lapic::send_ipi(util::bitset32 mode, isr vector, uint8_t dest)
|
||||||
{
|
{
|
||||||
// Wait until the APIC is ready to send
|
// Wait until the APIC is ready to send
|
||||||
ipi_wait();
|
ipi_wait();
|
||||||
|
|
||||||
uint32_t command =
|
uint32_t command = util::bitset32::from(vector) | mode;
|
||||||
static_cast<uint32_t>(vector) |
|
|
||||||
static_cast<uint32_t>(mode);
|
|
||||||
|
|
||||||
apic_write(m_base, lapic_icr_high, static_cast<uint32_t>(dest) << 24);
|
apic_write(m_base, lapic_icr_high, static_cast<uint32_t>(dest) << 24);
|
||||||
apic_write(m_base, lapic_icr_low, command);
|
apic_write(m_base, lapic_icr_low, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
lapic::send_ipi_broadcast(ipi mode, bool self, isr vector)
|
lapic::send_ipi_broadcast(util::bitset32 mode, bool self, isr vector)
|
||||||
{
|
{
|
||||||
// Wait until the APIC is ready to send
|
// Wait until the APIC is ready to send
|
||||||
ipi_wait();
|
ipi_wait();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
/// Classes to control both local and I/O APICs.
|
/// Classes to control both local and I/O APICs.
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/enum_bitfields.h>
|
#include <util/bitset.h>
|
||||||
|
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
|
|
||||||
@@ -33,33 +33,30 @@ public:
|
|||||||
/// Get the local APIC's ID
|
/// Get the local APIC's ID
|
||||||
uint8_t get_id();
|
uint8_t get_id();
|
||||||
|
|
||||||
enum class ipi : uint32_t
|
enum class ipi_flags
|
||||||
{
|
{
|
||||||
// Delivery modes
|
logical = 11,
|
||||||
fixed = 0x0000,
|
pending = 12,
|
||||||
smi = 0x0200,
|
assert = 14,
|
||||||
nmi = 0x0400,
|
level = 15,
|
||||||
init = 0x0500,
|
|
||||||
startup = 0x0600,
|
|
||||||
|
|
||||||
// Flags
|
|
||||||
deassert = 0x0000,
|
|
||||||
assert = 0x4000,
|
|
||||||
edge = 0x0000, ///< edge-triggered
|
|
||||||
level = 0x8000, ///< level-triggered
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// IPI flags based on delivery mode (bits 8-10)
|
||||||
|
static constexpr util::bitset32 ipi_fixed = 0;
|
||||||
|
static constexpr util::bitset32 ipi_init = 0x500;
|
||||||
|
static constexpr util::bitset32 ipi_sipi = 0x600;
|
||||||
|
|
||||||
/// Send an inter-processor interrupt.
|
/// Send an inter-processor interrupt.
|
||||||
/// \arg mode The sending mode
|
/// \arg mode The sending mode
|
||||||
/// \arg vector The interrupt vector
|
/// \arg vector The interrupt vector
|
||||||
/// \arg dest The APIC ID of the destination
|
/// \arg dest The APIC ID of the destination
|
||||||
void send_ipi(ipi mode, isr vector, uint8_t dest);
|
void send_ipi(util::bitset32 mode, isr vector, uint8_t dest);
|
||||||
|
|
||||||
/// Send an inter-processor broadcast interrupt to all other CPUs
|
/// Send an inter-processor broadcast interrupt to all other CPUs
|
||||||
/// \arg mode The sending mode
|
/// \arg mode The sending mode
|
||||||
/// \arg self If true, include this CPU in the broadcast
|
/// \arg self If true, include this CPU in the broadcast
|
||||||
/// \arg vector The interrupt vector
|
/// \arg vector The interrupt vector
|
||||||
void send_ipi_broadcast(ipi mode, bool self, isr vector);
|
void send_ipi_broadcast(util::bitset32 mode, bool self, isr vector);
|
||||||
|
|
||||||
/// Wait for an IPI to finish sending. This is done automatically
|
/// Wait for an IPI to finish sending. This is done automatically
|
||||||
/// before sending another IPI with send_ipi().
|
/// before sending another IPI with send_ipi().
|
||||||
@@ -145,6 +142,3 @@ private:
|
|||||||
uint8_t m_id;
|
uint8_t m_id;
|
||||||
uint8_t m_version;
|
uint8_t m_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
is_bitfield(lapic::ipi);
|
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ cpu_early_init(cpu_data *cpu)
|
|||||||
set_xcr0(xcr0_val);
|
set_xcr0(xcr0_val);
|
||||||
|
|
||||||
// Set initial floating point state
|
// Set initial floating point state
|
||||||
const util::bitset32 mxcsr_val {
|
const util::bitset32 mxcsr_val = util::bitset32::of(
|
||||||
mxcsr::DAZ,
|
mxcsr::DAZ,
|
||||||
mxcsr::IM,
|
mxcsr::IM,
|
||||||
mxcsr::DM,
|
mxcsr::DM,
|
||||||
@@ -126,8 +126,7 @@ cpu_early_init(cpu_data *cpu)
|
|||||||
mxcsr::OM,
|
mxcsr::OM,
|
||||||
mxcsr::UM,
|
mxcsr::UM,
|
||||||
mxcsr::PM,
|
mxcsr::PM,
|
||||||
mxcsr::FTZ,
|
mxcsr::FTZ);
|
||||||
};
|
|
||||||
asm ( "ldmxcsr %0" :: "m"(mxcsr_val) );
|
asm ( "ldmxcsr %0" :: "m"(mxcsr_val) );
|
||||||
|
|
||||||
// Install the GS base pointint to the cpu_data
|
// Install the GS base pointint to the cpu_data
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ void
|
|||||||
output(j6_log_entry *entry)
|
output(j6_log_entry *entry)
|
||||||
{
|
{
|
||||||
char buffer [256];
|
char buffer [256];
|
||||||
size_t dlen = util::format({buffer, sizeof(buffer)}, "\e[38;5;%dm%7s %7s\e[38;5;14m|\e[38;5;%dm ",
|
size_t dlen = util::format({buffer, sizeof(buffer)}, "\e[38;5;%dm%7s %7s\e[38;5;14m\u2502\e[38;5;%dm ",
|
||||||
level_colors[entry->severity],
|
level_colors[entry->severity],
|
||||||
area_names[entry->area],
|
area_names[entry->area],
|
||||||
level_names[entry->severity],
|
level_names[entry->severity],
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/misc.h> // for checksum
|
#include <util/misc.h> // for checksum
|
||||||
#include <util/pointers.h>
|
#include <util/pointers.h>
|
||||||
#include <arch/acpi/tables.h>
|
#include <acpi/tables.h>
|
||||||
|
|
||||||
#include "kassert.h"
|
#include "kassert.h"
|
||||||
#include "apic.h"
|
#include "apic.h"
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ static constexpr uint8_t tss_index = 6; // Note that this takes TWO GDT en
|
|||||||
static util::no_construct<GDT> __g_bsp_gdt_storage;
|
static util::no_construct<GDT> __g_bsp_gdt_storage;
|
||||||
GDT &g_bsp_gdt = __g_bsp_gdt_storage.value;
|
GDT &g_bsp_gdt = __g_bsp_gdt_storage.value;
|
||||||
|
|
||||||
|
static constexpr util::bitset8 ring3 = util::bitset8::of( GDT::type::ring1, GDT::type::ring2 );
|
||||||
|
static constexpr util::bitset8 rw = util::bitset8::of( GDT::type::read_write );
|
||||||
|
static constexpr util::bitset8 rwx = util::bitset8::of( GDT::type::read_write, GDT::type::execute );
|
||||||
|
|
||||||
GDT::GDT(TSS *tss) :
|
GDT::GDT(TSS *tss) :
|
||||||
m_tss(tss)
|
m_tss(tss)
|
||||||
@@ -32,13 +35,13 @@ GDT::GDT(TSS *tss) :
|
|||||||
m_ptr.base = &m_entries[0];
|
m_ptr.base = &m_entries[0];
|
||||||
|
|
||||||
// Kernel CS/SS - always 64bit
|
// Kernel CS/SS - always 64bit
|
||||||
set(kern_cs_index, 0, 0xfffff, true, type::read_write | type::execute);
|
set(kern_cs_index, 0, 0xfffff, true, rwx);
|
||||||
set(kern_ss_index, 0, 0xfffff, true, type::read_write);
|
set(kern_ss_index, 0, 0xfffff, true, rw);
|
||||||
|
|
||||||
// User CS32/SS/CS64 - layout expected by SYSRET
|
// User CS32/SS/CS64 - layout expected by SYSRET
|
||||||
set(user_cs32_index, 0, 0xfffff, false, type::ring3 | type::read_write | type::execute);
|
set(user_cs32_index, 0, 0xfffff, false, ring3 | rwx);
|
||||||
set(user_ss_index, 0, 0xfffff, true, type::ring3 | type::read_write);
|
set(user_ss_index, 0, 0xfffff, true, ring3 | rw);
|
||||||
set(user_cs64_index, 0, 0xfffff, true, type::ring3 | type::read_write | type::execute);
|
set(user_cs64_index, 0, 0xfffff, true, ring3 | rwx);
|
||||||
|
|
||||||
set_tss(tss);
|
set_tss(tss);
|
||||||
}
|
}
|
||||||
@@ -61,7 +64,7 @@ GDT::install() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GDT::set(uint8_t i, uint32_t base, uint64_t limit, bool is64, type t)
|
GDT::set(uint8_t i, uint32_t base, uint64_t limit, bool is64, util::bitset8 t)
|
||||||
{
|
{
|
||||||
m_entries[i].limit_low = limit & 0xffff;
|
m_entries[i].limit_low = limit & 0xffff;
|
||||||
m_entries[i].size = (limit >> 16) & 0xf;
|
m_entries[i].size = (limit >> 16) & 0xf;
|
||||||
@@ -71,7 +74,9 @@ GDT::set(uint8_t i, uint32_t base, uint64_t limit, bool is64, type t)
|
|||||||
m_entries[i].base_mid = (base >> 16) & 0xff;
|
m_entries[i].base_mid = (base >> 16) & 0xff;
|
||||||
m_entries[i].base_high = (base >> 24) & 0xff;
|
m_entries[i].base_high = (base >> 24) & 0xff;
|
||||||
|
|
||||||
m_entries[i].type = t | type::system | type::present;
|
static constexpr util::bitset8 sp = util::bitset8::of( type::system, type::present );
|
||||||
|
m_entries[i].type = t;
|
||||||
|
m_entries[i].type |= sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tss_descriptor
|
struct tss_descriptor
|
||||||
@@ -79,7 +84,7 @@ struct tss_descriptor
|
|||||||
uint16_t limit_low;
|
uint16_t limit_low;
|
||||||
uint16_t base_00;
|
uint16_t base_00;
|
||||||
uint8_t base_16;
|
uint8_t base_16;
|
||||||
GDT::type type;
|
util::bitset8 type;
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
uint8_t base_24;
|
uint8_t base_24;
|
||||||
uint32_t base_32;
|
uint32_t base_32;
|
||||||
@@ -102,11 +107,9 @@ GDT::set_tss(TSS *tss)
|
|||||||
tssd.base_32 = (base >> 32) & 0xffffffff;
|
tssd.base_32 = (base >> 32) & 0xffffffff;
|
||||||
tssd.reserved = 0;
|
tssd.reserved = 0;
|
||||||
|
|
||||||
tssd.type =
|
static constexpr util::bitset8 tss_mark =
|
||||||
type::accessed |
|
util::bitset8::of(type::accessed, type::execute, type::present);
|
||||||
type::execute |
|
tssd.type = ring3 | tss_mark;
|
||||||
type::ring3 |
|
|
||||||
type::present;
|
|
||||||
|
|
||||||
memcpy(&m_entries[tss_index], &tssd, sizeof(tss_descriptor));
|
memcpy(&m_entries[tss_index], &tssd, sizeof(tss_descriptor));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
/// Definitions relating to a CPU's GDT table
|
/// Definitions relating to a CPU's GDT table
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/enum_bitfields.h>
|
#include <util/bitset.h>
|
||||||
|
|
||||||
class TSS;
|
class TSS;
|
||||||
|
|
||||||
@@ -25,21 +25,20 @@ public:
|
|||||||
/// \arg index Which entry to print, or -1 for all entries
|
/// \arg index Which entry to print, or -1 for all entries
|
||||||
void dump(unsigned index = -1) const;
|
void dump(unsigned index = -1) const;
|
||||||
|
|
||||||
enum class type : uint8_t
|
enum class type
|
||||||
{
|
{
|
||||||
accessed = 0x01,
|
accessed,
|
||||||
read_write = 0x02,
|
read_write,
|
||||||
conforming = 0x04,
|
conforming,
|
||||||
execute = 0x08,
|
execute,
|
||||||
system = 0x10,
|
system,
|
||||||
ring1 = 0x20,
|
ring1,
|
||||||
ring2 = 0x40,
|
ring2,
|
||||||
ring3 = 0x60,
|
present
|
||||||
present = 0x80
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void set(uint8_t i, uint32_t base, uint64_t limit, bool is64, type t);
|
void set(uint8_t i, uint32_t base, uint64_t limit, bool is64, util::bitset8 t);
|
||||||
void set_tss(TSS *tss);
|
void set_tss(TSS *tss);
|
||||||
|
|
||||||
struct descriptor
|
struct descriptor
|
||||||
@@ -47,7 +46,7 @@ private:
|
|||||||
uint16_t limit_low;
|
uint16_t limit_low;
|
||||||
uint16_t base_low;
|
uint16_t base_low;
|
||||||
uint8_t base_mid;
|
uint8_t base_mid;
|
||||||
type type;
|
util::bitset8 type;
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
uint8_t base_high;
|
uint8_t base_high;
|
||||||
} __attribute__ ((packed, align(8)));
|
} __attribute__ ((packed, align(8)));
|
||||||
@@ -63,5 +62,3 @@ private:
|
|||||||
|
|
||||||
ptr m_ptr;
|
ptr m_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
is_bitfield(GDT::type);
|
|
||||||
|
|||||||
@@ -117,4 +117,5 @@ ISR (0xe1, 0, isrLINT0)
|
|||||||
ISR (0xe2, 0, isrLINT1)
|
ISR (0xe2, 0, isrLINT1)
|
||||||
ISR (0xe3, 0, isrAPICError)
|
ISR (0xe3, 0, isrAPICError)
|
||||||
ISR (0xe4, 0, ipiSchedule)
|
ISR (0xe4, 0, ipiSchedule)
|
||||||
|
ISR (0xe5, 0, ipiShootdown)
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ constexpr uintptr_t apic_eoi_addr = 0xfee000b0 + mem::linear_offset;
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
void isr_handler(cpu_state*);
|
void isr_handler(cpu_state*);
|
||||||
void irq_handler(cpu_state*);
|
void irq_handler(cpu_state*);
|
||||||
|
void _reload_cr3();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
@@ -123,9 +124,10 @@ isr_handler(cpu_state *regs)
|
|||||||
uintptr_t cr2 = 0;
|
uintptr_t cr2 = 0;
|
||||||
__asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2));
|
__asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2));
|
||||||
|
|
||||||
|
// The zero page is always invalid
|
||||||
|
if (cr2 > mem::frame_size) {
|
||||||
bool user = cr2 < mem::kernel_offset;
|
bool user = cr2 < mem::kernel_offset;
|
||||||
vm_space::fault_type ft =
|
util::bitset8 ft = regs->errorcode;
|
||||||
static_cast<vm_space::fault_type>(regs->errorcode);
|
|
||||||
|
|
||||||
vm_space &space = user
|
vm_space &space = user
|
||||||
? obj::process::current().space()
|
? obj::process::current().space()
|
||||||
@@ -133,6 +135,7 @@ isr_handler(cpu_state *regs)
|
|||||||
|
|
||||||
if (cr2 && space.handle_fault(cr2, ft))
|
if (cr2 && space.handle_fault(cr2, ft))
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
util::format({message, sizeof(message)},
|
util::format({message, sizeof(message)},
|
||||||
"Page fault: %016lx%s%s%s%s%s", cr2,
|
"Page fault: %016lx%s%s%s%s%s", cr2,
|
||||||
@@ -185,6 +188,11 @@ isr_handler(cpu_state *regs)
|
|||||||
scheduler::get().schedule();
|
scheduler::get().schedule();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case isr::ipiShootdown:
|
||||||
|
// TODO: Real shootdown algorithm
|
||||||
|
_reload_cr3();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
util::format({message, sizeof(message)}, "Unknown interrupt 0x%lx", regs->interrupt);
|
util::format({message, sizeof(message)}, "Unknown interrupt 0x%lx", regs->interrupt);
|
||||||
kassert(false, message, regs);
|
kassert(false, message, regs);
|
||||||
|
|||||||
@@ -1,49 +1,142 @@
|
|||||||
#include <j6/memutils.h>
|
#include <j6/memutils.h>
|
||||||
#include <util/basic_types.h>
|
#include <util/basic_types.h>
|
||||||
|
|
||||||
|
#include "kassert.h"
|
||||||
#include "ipc_message.h"
|
#include "ipc_message.h"
|
||||||
|
#include "j6/types.h"
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
|
|
||||||
message::message() : tag {0}, data {nullptr, 0}, handles {nullptr, 0} {}
|
message::message() : tag {0}, data_size {0}, handle_count {0}, out_of_band {0} {}
|
||||||
|
|
||||||
|
|
||||||
message::message(
|
message::message(
|
||||||
uint64_t in_tag,
|
uint64_t in_tag,
|
||||||
const util::buffer &in_data,
|
const util::buffer &in_data,
|
||||||
const util::counted<j6_handle_t> &in_handles) :
|
const util::counted<j6_handle_t> &in_handles) :
|
||||||
tag {in_tag}, data {nullptr, in_data.count}, handles {nullptr, in_handles.count}
|
out_of_band {0}
|
||||||
{
|
{
|
||||||
if (data.count) {
|
set(in_tag, in_data, in_handles);
|
||||||
data.pointer = new uint8_t [data.count];
|
|
||||||
memcpy(data.pointer, in_data.pointer, data.count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handles.count) {
|
|
||||||
handles.pointer = new j6_handle_t [handles.count];
|
message::message(message &&other) {
|
||||||
memcpy(handles.pointer, in_handles.pointer, handles.count * sizeof(j6_handle_t));
|
*this = util::move(other);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message::message(message &&other) { *this = util::move(other); }
|
|
||||||
|
|
||||||
message::~message()
|
message::~message()
|
||||||
{
|
{
|
||||||
delete [] reinterpret_cast<uint8_t*>(data.pointer);
|
clear_oob();
|
||||||
delete [] handles.pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
util::buffer
|
||||||
|
message::data()
|
||||||
|
{
|
||||||
|
uint8_t *buf = content + (handle_count * sizeof(j6_handle_t));
|
||||||
|
if (out_of_band)
|
||||||
|
buf = reinterpret_cast<uint8_t**>(content)[handle_count];
|
||||||
|
|
||||||
|
return {
|
||||||
|
.pointer = buf,
|
||||||
|
.count = data_size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
util::const_buffer
|
||||||
|
message::data() const
|
||||||
|
{
|
||||||
|
const uint8_t *buf = content + (handle_count * sizeof(j6_handle_t));
|
||||||
|
if (out_of_band)
|
||||||
|
buf = reinterpret_cast<uint8_t *const *const>(content)[handle_count];
|
||||||
|
|
||||||
|
return {
|
||||||
|
.pointer = buf,
|
||||||
|
.count = data_size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
util::counted<j6_handle_t>
|
||||||
|
message::handles()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
.pointer = reinterpret_cast<j6_handle_t*>(content),
|
||||||
|
.count = handle_count,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
util::counted<const j6_handle_t>
|
||||||
|
message::handles() const
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
.pointer = reinterpret_cast<const j6_handle_t*>(content),
|
||||||
|
.count = data_size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
message &
|
message &
|
||||||
message::operator=(message &&other)
|
message::operator=(message &&other)
|
||||||
{
|
{
|
||||||
|
clear_oob();
|
||||||
|
|
||||||
tag = other.tag;
|
tag = other.tag;
|
||||||
other.tag = 0;
|
other.tag = 0;
|
||||||
|
|
||||||
data = other.data;
|
data_size = other.data_size;
|
||||||
other.data = {nullptr, 0};
|
other.data_size = 0;
|
||||||
|
|
||||||
handles = other.handles;
|
handle_count = other.handle_count;
|
||||||
other.handles = {nullptr, 0};
|
other.handle_count = 0;
|
||||||
|
|
||||||
|
out_of_band = other.out_of_band;
|
||||||
|
other.out_of_band = 0;
|
||||||
|
|
||||||
|
memcpy(content, other.content, sizeof(content));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
message::set(
|
||||||
|
uint64_t in_tag,
|
||||||
|
const util::buffer &in_data,
|
||||||
|
const util::counted<j6_handle_t> &in_handles)
|
||||||
|
{
|
||||||
|
clear_oob();
|
||||||
|
tag = in_tag;
|
||||||
|
handle_count = in_handles.count;
|
||||||
|
data_size = in_data.count;
|
||||||
|
|
||||||
|
if (in_handles.count) {
|
||||||
|
kassert(in_handles.count < (sizeof(content) / sizeof(j6_handle_t)) - sizeof(void*));
|
||||||
|
util::counted<j6_handle_t> handlebuf = handles();
|
||||||
|
memcpy(handlebuf.pointer, in_handles.pointer, handlebuf.count * sizeof(j6_handle_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_data.count) {
|
||||||
|
if (in_data.count > sizeof(content) - (handle_count * sizeof(j6_handle_t))) {
|
||||||
|
out_of_band = 1;
|
||||||
|
auto *buf = new uint8_t [in_data.count];
|
||||||
|
reinterpret_cast<uint8_t**>(content)[handle_count] = buf;
|
||||||
|
}
|
||||||
|
util::buffer databuf = data();
|
||||||
|
memcpy(databuf.pointer, in_data.pointer, databuf.count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
message::clear_oob()
|
||||||
|
{
|
||||||
|
if (out_of_band) {
|
||||||
|
uint8_t *buf = reinterpret_cast<uint8_t**>(content)[handle_count];
|
||||||
|
delete [] buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
@@ -5,14 +5,29 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <j6/types.h>
|
#include <j6/types.h>
|
||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
|
#include <util/pointers.h>
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
|
|
||||||
|
static constexpr size_t message_size = 64;
|
||||||
|
|
||||||
struct message
|
struct message
|
||||||
{
|
{
|
||||||
uint64_t tag;
|
uint64_t tag;
|
||||||
util::buffer data;
|
uint16_t data_size;
|
||||||
util::counted<j6_handle_t> handles;
|
|
||||||
|
uint16_t handle_count : 4;
|
||||||
|
uint16_t out_of_band : 1;
|
||||||
|
|
||||||
|
uint32_t _reserved;
|
||||||
|
|
||||||
|
uint8_t content[ message_size - 8 ];
|
||||||
|
|
||||||
|
util::buffer data();
|
||||||
|
util::const_buffer data() const;
|
||||||
|
|
||||||
|
util::counted<j6_handle_t> handles();
|
||||||
|
util::counted<const j6_handle_t> handles() const;
|
||||||
|
|
||||||
message();
|
message();
|
||||||
message(uint64_t in_tag, const util::buffer &in_data, const util::counted<j6_handle_t> &in_handles);
|
message(uint64_t in_tag, const util::buffer &in_data, const util::counted<j6_handle_t> &in_handles);
|
||||||
@@ -20,6 +35,13 @@ struct message
|
|||||||
~message();
|
~message();
|
||||||
|
|
||||||
message & operator=(message &&other);
|
message & operator=(message &&other);
|
||||||
|
|
||||||
|
void set(uint64_t in_tag, const util::buffer &in_data, const util::counted<j6_handle_t> &in_handles);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void clear_oob();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using message_ptr = util::unique_ptr<message>;
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
@@ -5,7 +5,7 @@ kernel = module("kernel",
|
|||||||
basename = "jsix",
|
basename = "jsix",
|
||||||
targets = [ "kernel" ],
|
targets = [ "kernel" ],
|
||||||
description = "jsix kernel",
|
description = "jsix kernel",
|
||||||
deps = [ "util", "cpu", "bootproto", "j6" ],
|
deps = [ "util", "cpu", "bootproto", "j6", "acpi" ],
|
||||||
static = True,
|
static = True,
|
||||||
ld_script = "kernel.ld",
|
ld_script = "kernel.ld",
|
||||||
sources = [
|
sources = [
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <j6/memutils.h>
|
#include <j6/memutils.h>
|
||||||
@@ -54,7 +53,7 @@ kernel_main(bootproto::args *args)
|
|||||||
bsp_late_init();
|
bsp_late_init();
|
||||||
|
|
||||||
using bootproto::boot_flags;
|
using bootproto::boot_flags;
|
||||||
bool enable_test = util::bits::has(args->flags, boot_flags::test);
|
bool enable_test = args->flags.get(boot_flags::test);
|
||||||
syscall_initialize(enable_test);
|
syscall_initialize(enable_test);
|
||||||
|
|
||||||
device_manager &devices = device_manager::get();
|
device_manager &devices = device_manager::get();
|
||||||
@@ -87,7 +86,7 @@ load_init_server(bootproto::program &program, uintptr_t modules_address)
|
|||||||
using bootproto::section_flags;
|
using bootproto::section_flags;
|
||||||
using obj::vm_flags;
|
using obj::vm_flags;
|
||||||
|
|
||||||
obj::process *p = new obj::process;
|
obj::process *p = new obj::process {"srv.init"};
|
||||||
|
|
||||||
j6_handle_t sys_handle =
|
j6_handle_t sys_handle =
|
||||||
g_cap_table.create(&obj::system::get(), obj::system::init_caps);
|
g_cap_table.create(&obj::system::get(), obj::system::init_caps);
|
||||||
@@ -95,12 +94,15 @@ load_init_server(bootproto::program &program, uintptr_t modules_address)
|
|||||||
|
|
||||||
vm_space &space = p->space();
|
vm_space &space = p->space();
|
||||||
for (const auto § : program.sections) {
|
for (const auto § : program.sections) {
|
||||||
vm_flags flags =
|
util::bitset32 flags = util::bitset32::of(vm_flags::exact);
|
||||||
((sect.type && section_flags::execute) ? vm_flags::exec : vm_flags::none) |
|
if (sect.type.get(section_flags::execute))
|
||||||
((sect.type && section_flags::write) ? vm_flags::write : vm_flags::none);
|
flags.set(vm_flags::exec);
|
||||||
|
|
||||||
|
if (sect.type.get(section_flags::write))
|
||||||
|
flags.set(vm_flags::write);
|
||||||
|
|
||||||
obj::vm_area *vma = new obj::vm_area_fixed(sect.phys_addr, sect.size, flags);
|
obj::vm_area *vma = new obj::vm_area_fixed(sect.phys_addr, sect.size, flags);
|
||||||
space.add(sect.virt_addr, vma, obj::vm_flags::exact);
|
space.add(sect.virt_addr, vma, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t iopl = (3ull << 12);
|
uint64_t iopl = (3ull << 12);
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
#include "kassert.h"
|
#include "kassert.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "objects/system.h"
|
|
||||||
#include "objects/thread.h"
|
|
||||||
|
|
||||||
// The logger is initialized _before_ global constructors are called,
|
// The logger is initialized _before_ global constructors are called,
|
||||||
// so that we can start log output immediately. Keep its constructor
|
// so that we can start log output immediately. Keep its constructor
|
||||||
@@ -124,7 +122,8 @@ LOG_LEVEL_FUNCTION(info);
|
|||||||
LOG_LEVEL_FUNCTION(warn);
|
LOG_LEVEL_FUNCTION(warn);
|
||||||
LOG_LEVEL_FUNCTION(error);
|
LOG_LEVEL_FUNCTION(error);
|
||||||
|
|
||||||
void fatal(logs area, const char *fmt, ...)
|
void
|
||||||
|
fatal(logs area, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
logger *l = logger::s_log;
|
logger *l = logger::s_log;
|
||||||
if (!l) return;
|
if (!l) return;
|
||||||
@@ -137,4 +136,19 @@ void fatal(logs area, const char *fmt, ...)
|
|||||||
kassert(false, "log::fatal");
|
kassert(false, "log::fatal");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
log(logs area, level severity, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
logger *l = logger::s_log;
|
||||||
|
if (!l) return;
|
||||||
|
|
||||||
|
level limit = l->get_level(area);
|
||||||
|
if (severity > limit) return;
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
l->output(severity, area, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace log
|
} // namespace log
|
||||||
|
|||||||
@@ -5,10 +5,11 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <j6/types.h>
|
||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
|
|
||||||
#include "objects/event.h"
|
#include "wait_queue.h"
|
||||||
|
|
||||||
enum class logs : uint8_t {
|
enum class logs : uint8_t {
|
||||||
#define LOG(name, lvl) name,
|
#define LOG(name, lvl) name,
|
||||||
@@ -77,6 +78,7 @@ private:
|
|||||||
friend void warn (logs area, const char *fmt, ...);
|
friend void warn (logs area, const char *fmt, ...);
|
||||||
friend void error (logs area, const char *fmt, ...);
|
friend void error (logs area, const char *fmt, ...);
|
||||||
friend void fatal (logs area, const char *fmt, ...);
|
friend void fatal (logs area, const char *fmt, ...);
|
||||||
|
friend void log (logs area, level severity, const char *fmt, ...);
|
||||||
|
|
||||||
void output(level severity, logs area, const char *fmt, va_list args);
|
void output(level severity, logs area, const char *fmt, va_list args);
|
||||||
|
|
||||||
@@ -113,6 +115,8 @@ void warn (logs area, const char *fmt, ...);
|
|||||||
void error (logs area, const char *fmt, ...);
|
void error (logs area, const char *fmt, ...);
|
||||||
void fatal (logs area, const char *fmt, ...);
|
void fatal (logs area, const char *fmt, ...);
|
||||||
|
|
||||||
|
void log (logs area, level severity, const char *fmt, ...);
|
||||||
|
|
||||||
} // namespace log
|
} // namespace log
|
||||||
|
|
||||||
extern log::logger &g_logger;
|
extern log::logger &g_logger;
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ extern "C" {
|
|||||||
|
|
||||||
using bootproto::allocation_register;
|
using bootproto::allocation_register;
|
||||||
|
|
||||||
using obj::vm_flags;
|
inline constexpr util::bitset32 vm_flag_write = util::bitset32::of(obj::vm_flags::write);
|
||||||
|
inline constexpr util::bitset32 vm_flag_exact = util::bitset32::of(obj::vm_flags::exact);
|
||||||
|
|
||||||
// These objects are initialized _before_ global constructors are called,
|
// These objects are initialized _before_ global constructors are called,
|
||||||
// so we don't want them to have global constructors at all, lest they
|
// so we don't want them to have global constructors at all, lest they
|
||||||
@@ -53,7 +54,7 @@ obj::vm_area_guarded g_kernel_buffers {
|
|||||||
mem::buffers_offset,
|
mem::buffers_offset,
|
||||||
mem::kernel_buffer_pages,
|
mem::kernel_buffer_pages,
|
||||||
mem::buffers_size,
|
mem::buffers_size,
|
||||||
vm_flags::write};
|
vm_flag_write};
|
||||||
|
|
||||||
void * operator new(size_t size) { return g_kernel_heap.allocate(size); }
|
void * operator new(size_t size) { return g_kernel_heap.allocate(size); }
|
||||||
void * operator new [] (size_t size) { return g_kernel_heap.allocate(size); }
|
void * operator new [] (size_t size) { return g_kernel_heap.allocate(size); }
|
||||||
@@ -97,30 +98,30 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
|||||||
|
|
||||||
// Create the heap space and heap allocator
|
// Create the heap space and heap allocator
|
||||||
obj::vm_area *heap = new (&g_kernel_heap_area)
|
obj::vm_area *heap = new (&g_kernel_heap_area)
|
||||||
obj::vm_area_untracked(mem::heap_size, vm_flags::write);
|
obj::vm_area_untracked(mem::heap_size, vm_flag_write);
|
||||||
|
|
||||||
obj::vm_area *heap_map = new (&g_kernel_heapmap_area)
|
obj::vm_area *heap_map = new (&g_kernel_heapmap_area)
|
||||||
obj::vm_area_untracked(mem::heapmap_size, vm_flags::write);
|
obj::vm_area_untracked(mem::heapmap_size, vm_flag_write);
|
||||||
|
|
||||||
vm.add(mem::heap_offset, heap, vm_flags::exact);
|
vm.add(mem::heap_offset, heap, vm_flag_exact);
|
||||||
vm.add(mem::heapmap_offset, heap_map, vm_flags::exact);
|
vm.add(mem::heapmap_offset, heap_map, vm_flag_exact);
|
||||||
|
|
||||||
new (&g_kernel_heap) heap_allocator {mem::heap_offset, mem::heap_size, mem::heapmap_offset};
|
new (&g_kernel_heap) heap_allocator {mem::heap_offset, mem::heap_size, mem::heapmap_offset};
|
||||||
|
|
||||||
// Set up the log area and logger
|
// Set up the log area and logger
|
||||||
size_t log_buffer_size = log::log_pages * arch::frame_size;
|
size_t log_buffer_size = log::log_pages * arch::frame_size;
|
||||||
obj::vm_area *logs = new (&g_kernel_log_area)
|
obj::vm_area *logs = new (&g_kernel_log_area)
|
||||||
obj::vm_area_ring(log_buffer_size, vm_flags::write);
|
obj::vm_area_ring(log_buffer_size, vm_flag_write);
|
||||||
vm.add(mem::logs_offset, logs, vm_flags::exact);
|
vm.add(mem::logs_offset, logs, vm_flag_exact);
|
||||||
|
|
||||||
new (&g_logger) log::logger(
|
new (&g_logger) log::logger(
|
||||||
util::buffer::from(mem::logs_offset, log_buffer_size));
|
util::buffer::from(mem::logs_offset, log_buffer_size));
|
||||||
|
|
||||||
// Set up the capability tables
|
// Set up the capability tables
|
||||||
obj::vm_area *caps = new (&g_cap_table_area)
|
obj::vm_area *caps = new (&g_cap_table_area)
|
||||||
obj::vm_area_untracked(mem::caps_size, vm_flags::write);
|
obj::vm_area_untracked(mem::caps_size, vm_flag_write);
|
||||||
|
|
||||||
vm.add(mem::caps_offset, caps, vm_flags::exact);
|
vm.add(mem::caps_offset, caps, vm_flag_exact);
|
||||||
|
|
||||||
new (&g_cap_table) cap_table {mem::caps_offset};
|
new (&g_cap_table) cap_table {mem::caps_offset};
|
||||||
|
|
||||||
@@ -128,8 +129,8 @@ memory_initialize_pre_ctors(bootproto::args &kargs)
|
|||||||
mem::stacks_offset,
|
mem::stacks_offset,
|
||||||
mem::kernel_stack_pages,
|
mem::kernel_stack_pages,
|
||||||
mem::stacks_size,
|
mem::stacks_size,
|
||||||
vm_flags::write};
|
vm_flag_write};
|
||||||
vm.add(mem::stacks_offset, &g_kernel_stacks, vm_flags::exact);
|
vm.add(mem::stacks_offset, &g_kernel_stacks, vm_flag_exact);
|
||||||
|
|
||||||
// Clean out any remaning bootloader page table entries
|
// Clean out any remaning bootloader page table entries
|
||||||
for (unsigned i = 0; i < arch::kernel_root_index; ++i)
|
for (unsigned i = 0; i < arch::kernel_root_index; ++i)
|
||||||
@@ -140,7 +141,7 @@ void
|
|||||||
memory_initialize_post_ctors(bootproto::args &kargs)
|
memory_initialize_post_ctors(bootproto::args &kargs)
|
||||||
{
|
{
|
||||||
vm_space &vm = vm_space::kernel_space();
|
vm_space &vm = vm_space::kernel_space();
|
||||||
vm.add(mem::buffers_offset, &g_kernel_buffers, vm_flags::exact);
|
vm.add(mem::buffers_offset, &g_kernel_buffers, vm_flag_exact);
|
||||||
|
|
||||||
g_frame_allocator.free(
|
g_frame_allocator.free(
|
||||||
get_physical_page(kargs.page_tables.pointer),
|
get_physical_page(kargs.page_tables.pointer),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
#include <j6/memutils.h>
|
#include <j6/memutils.h>
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
#include "objects/mailbox.h"
|
#include "objects/mailbox.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
|
|
||||||
@@ -26,6 +27,8 @@ mailbox::close()
|
|||||||
bool was_closed = __atomic_exchange_n(&m_closed, true, __ATOMIC_ACQ_REL);
|
bool was_closed = __atomic_exchange_n(&m_closed, true, __ATOMIC_ACQ_REL);
|
||||||
if (was_closed) return;
|
if (was_closed) return;
|
||||||
|
|
||||||
|
log::spam(logs::ipc, "mbx[%2x] closing...", obj_id());
|
||||||
|
|
||||||
m_callers.clear(j6_status_closed);
|
m_callers.clear(j6_status_closed);
|
||||||
m_responders.clear(j6_status_closed);
|
m_responders.clear(j6_status_closed);
|
||||||
|
|
||||||
@@ -44,14 +47,20 @@ mailbox::call()
|
|||||||
m_callers.add_thread(¤t);
|
m_callers.add_thread(¤t);
|
||||||
|
|
||||||
thread *responder = m_responders.pop_next();
|
thread *responder = m_responders.pop_next();
|
||||||
if (responder)
|
if (responder) {
|
||||||
|
log::spam(logs::ipc, "thread[%2x]:: mbx[%2x] call() waking thread[%2x]...",
|
||||||
|
current.obj_id(), obj_id(), responder->obj_id());
|
||||||
responder->wake(j6_status_ok);
|
responder->wake(j6_status_ok);
|
||||||
|
} else {
|
||||||
|
log::spam(logs::ipc, "thread[%2x]:: mbx[%2x] call() found no responder yet.",
|
||||||
|
current.obj_id(), obj_id());
|
||||||
|
}
|
||||||
|
|
||||||
return current.block();
|
return current.block();
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
mailbox::receive(ipc::message &data, reply_tag_t &reply_tag, bool block)
|
mailbox::receive(ipc::message_ptr &data, reply_tag_t &reply_tag, bool block)
|
||||||
{
|
{
|
||||||
if (closed())
|
if (closed())
|
||||||
return j6_status_closed;
|
return j6_status_closed;
|
||||||
@@ -67,6 +76,9 @@ mailbox::receive(ipc::message &data, reply_tag_t &reply_tag, bool block)
|
|||||||
if (!block)
|
if (!block)
|
||||||
return j6_status_would_block;
|
return j6_status_would_block;
|
||||||
|
|
||||||
|
log::spam(logs::ipc, "thread[%2x]:: mbx[%2x] receive() blocking waiting for a caller",
|
||||||
|
current.obj_id(), obj_id());
|
||||||
|
|
||||||
m_responders.add_thread(¤t);
|
m_responders.add_thread(¤t);
|
||||||
j6_status_t s = current.block();
|
j6_status_t s = current.block();
|
||||||
if (s != j6_status_ok)
|
if (s != j6_status_ok)
|
||||||
@@ -78,12 +90,15 @@ mailbox::receive(ipc::message &data, reply_tag_t &reply_tag, bool block)
|
|||||||
m_reply_map.insert({ reply_tag, caller });
|
m_reply_map.insert({ reply_tag, caller });
|
||||||
lock.release();
|
lock.release();
|
||||||
|
|
||||||
|
log::spam(logs::ipc, "thread[%2x]:: mbx[%2x] receive() found caller thread[%2x], rt = %x",
|
||||||
|
current.obj_id(), obj_id(), caller->obj_id(), reply_tag);
|
||||||
|
|
||||||
data = caller->get_message_data();
|
data = caller->get_message_data();
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
mailbox::reply(reply_tag_t reply_tag, ipc::message &&data)
|
mailbox::reply(reply_tag_t reply_tag, ipc::message_ptr data)
|
||||||
{
|
{
|
||||||
if (closed())
|
if (closed())
|
||||||
return j6_status_closed;
|
return j6_status_closed;
|
||||||
@@ -97,6 +112,10 @@ mailbox::reply(reply_tag_t reply_tag, ipc::message &&data)
|
|||||||
m_reply_map.erase(reply_tag);
|
m_reply_map.erase(reply_tag);
|
||||||
lock.release();
|
lock.release();
|
||||||
|
|
||||||
|
thread ¤t = thread::current();
|
||||||
|
log::spam(logs::ipc, "thread[%2x]:: mbx[%2x] reply() to caller thread[%2x], rt = %x",
|
||||||
|
current.obj_id(), obj_id(), caller->obj_id(), reply_tag);
|
||||||
|
|
||||||
caller->set_message_data(util::move(data));
|
caller->set_message_data(util::move(data));
|
||||||
caller->wake(j6_status_ok);
|
caller->wake(j6_status_ok);
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ class mailbox :
|
|||||||
public kobject
|
public kobject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
using reply_tag_t = uint64_t;
|
using reply_tag_t = uint64_t;
|
||||||
|
|
||||||
/// Capabilities on a newly constructed mailbox handle
|
/// Capabilities on a newly constructed mailbox handle
|
||||||
@@ -48,18 +47,18 @@ public:
|
|||||||
j6_status_t call();
|
j6_status_t call();
|
||||||
|
|
||||||
/// Receive the next available message, optionally blocking if no messages are available.
|
/// Receive the next available message, optionally blocking if no messages are available.
|
||||||
/// \arg data [out] an ipc::message structure to fill
|
/// \arg data [out] the message
|
||||||
/// \arg reply_tag [out] the reply_tag to use when replying to this message
|
/// \arg reply_tag [out] the reply_tag to use when replying to this message
|
||||||
/// \arg block True if this call should block when no messages are available.
|
/// \arg block True if this call should block when no messages are available.
|
||||||
/// \returns j6_status_ok if a message was received
|
/// \returns j6_status_ok if a message was received
|
||||||
j6_status_t receive(ipc::message &data, reply_tag_t &reply_tag, bool block);
|
j6_status_t receive(ipc::message_ptr &data, reply_tag_t &reply_tag, bool block);
|
||||||
|
|
||||||
/// Find a given pending message to be responded to. Returns a replyer object, which will
|
/// Find a given pending message to be responded to. Returns a replyer object, which will
|
||||||
/// wake the calling read upon destruction.
|
/// wake the calling read upon destruction.
|
||||||
/// \arg reply_tag The reply tag in the original message
|
/// \arg reply_tag The reply tag in the original message
|
||||||
/// \arg data Message data to pass on to the caller
|
/// \arg data Message data to pass on to the caller
|
||||||
/// \returns j6_status_ok if the reply was successfully sent
|
/// \returns j6_status_ok if the reply was successfully sent
|
||||||
j6_status_t reply(reply_tag_t reply_tag, ipc::message &&data);
|
j6_status_t reply(reply_tag_t reply_tag, ipc::message_ptr data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wait_queue m_callers;
|
wait_queue m_callers;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <j6/memutils.h>
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "kassert.h"
|
#include "kassert.h"
|
||||||
@@ -18,10 +19,18 @@ obj::process &g_kernel_process = __g_kernel_process_storage.value;
|
|||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
|
|
||||||
process::process() :
|
process::process(const char *name) :
|
||||||
kobject {kobject::type::process},
|
kobject {kobject::type::process},
|
||||||
m_state {state::running}
|
m_state {state::running}
|
||||||
{
|
{
|
||||||
|
if constexpr(__use_process_names) {
|
||||||
|
memset(m_name, 0, sizeof(m_name));
|
||||||
|
if (name) {
|
||||||
|
static constexpr size_t charlen = sizeof(m_name) - 1;
|
||||||
|
for (size_t i = 0; i < charlen && name[i]; ++i)
|
||||||
|
m_name[i] = name[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The "kernel process"-only constructor
|
// The "kernel process"-only constructor
|
||||||
@@ -30,6 +39,11 @@ process::process(page_table *kpml4) :
|
|||||||
m_space {kpml4},
|
m_space {kpml4},
|
||||||
m_state {state::running}
|
m_state {state::running}
|
||||||
{
|
{
|
||||||
|
if constexpr(__use_process_names) {
|
||||||
|
static constexpr char kernel[] = "KERNEL";
|
||||||
|
memcpy(m_name, kernel, sizeof(kernel));
|
||||||
|
memset(m_name + sizeof(kernel), 0, sizeof(m_name) - sizeof(kernel));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
process::~process()
|
process::~process()
|
||||||
@@ -46,7 +60,7 @@ process::create_kernel_process(page_table *pml4)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
process::exit(int32_t code)
|
process::exit(int64_t code)
|
||||||
{
|
{
|
||||||
if (m_state == state::exited)
|
if (m_state == state::exited)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -13,6 +13,14 @@
|
|||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
|
|
||||||
|
static constexpr bool __use_process_names =
|
||||||
|
#ifdef __jsix_config_debug
|
||||||
|
true;
|
||||||
|
#else
|
||||||
|
false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class process :
|
class process :
|
||||||
public kobject
|
public kobject
|
||||||
{
|
{
|
||||||
@@ -32,7 +40,7 @@ public:
|
|||||||
static constexpr kobject::type type = kobject::type::process;
|
static constexpr kobject::type type = kobject::type::process;
|
||||||
|
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
process();
|
process(const char *name);
|
||||||
|
|
||||||
/// Destructor.
|
/// Destructor.
|
||||||
virtual ~process();
|
virtual ~process();
|
||||||
@@ -42,11 +50,14 @@ public:
|
|||||||
|
|
||||||
/// Terminate this process.
|
/// Terminate this process.
|
||||||
/// \arg code The return code to exit with.
|
/// \arg code The return code to exit with.
|
||||||
void exit(int32_t code);
|
void exit(int64_t code);
|
||||||
|
|
||||||
/// Get the process' virtual memory space
|
/// Get the process' virtual memory space
|
||||||
vm_space & space() { return m_space; }
|
vm_space & space() { return m_space; }
|
||||||
|
|
||||||
|
/// Get the debugging name of the process
|
||||||
|
const char *name() { if constexpr(__use_process_names) return m_name; else return nullptr; }
|
||||||
|
|
||||||
/// Create a new thread in this process
|
/// Create a new thread in this process
|
||||||
/// \args rsp3 If non-zero, sets the ring3 stack pointer to this value
|
/// \args rsp3 If non-zero, sets the ring3 stack pointer to this value
|
||||||
/// \args priority The new thread's scheduling priority
|
/// \args priority The new thread's scheduling priority
|
||||||
@@ -95,7 +106,7 @@ private:
|
|||||||
// This constructor is called by create_kernel_process
|
// This constructor is called by create_kernel_process
|
||||||
process(page_table *kpml4);
|
process(page_table *kpml4);
|
||||||
|
|
||||||
int32_t m_return_code;
|
int64_t m_return_code;
|
||||||
|
|
||||||
vm_space m_space;
|
vm_space m_space;
|
||||||
|
|
||||||
@@ -107,6 +118,15 @@ private:
|
|||||||
|
|
||||||
enum class state : uint8_t { running, exited };
|
enum class state : uint8_t { running, exited };
|
||||||
state m_state;
|
state m_state;
|
||||||
|
|
||||||
|
static constexpr size_t max_name_len =
|
||||||
|
#ifdef __jsix_config_debug
|
||||||
|
32;
|
||||||
|
#else
|
||||||
|
0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char m_name[max_name_len];
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace obj
|
} // namespace obj
|
||||||
|
|||||||
@@ -111,9 +111,6 @@ thread::wake_only()
|
|||||||
set_state(state::ready);
|
set_state(state::ready);
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread::set_message_data(ipc::message &&md) { m_message = util::move(md); }
|
|
||||||
ipc::message && thread::get_message_data() { return util::move(m_message); }
|
|
||||||
|
|
||||||
void
|
void
|
||||||
thread::exit()
|
thread::exit()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
/// Definition of thread kobject types
|
/// Definition of thread kobject types
|
||||||
|
|
||||||
#include <j6/cap_flags.h>
|
#include <j6/cap_flags.h>
|
||||||
#include <util/enum_bitfields.h>
|
|
||||||
#include <util/linked_list.h>
|
#include <util/linked_list.h>
|
||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
|
|
||||||
@@ -122,8 +121,8 @@ public:
|
|||||||
/// \returns The clock time at which to wake. 0 for no timeout.
|
/// \returns The clock time at which to wake. 0 for no timeout.
|
||||||
inline uint64_t wake_timeout() const { return m_wake_timeout; }
|
inline uint64_t wake_timeout() const { return m_wake_timeout; }
|
||||||
|
|
||||||
void set_message_data(ipc::message &&md);
|
inline void set_message_data(ipc::message_ptr md) { m_message = util::move(md); }
|
||||||
ipc::message && get_message_data();
|
inline ipc::message_ptr get_message_data() { return util::move(m_message); }
|
||||||
|
|
||||||
inline bool has_state(state s) const {
|
inline bool has_state(state s) const {
|
||||||
return __atomic_load_n(reinterpret_cast<const uint8_t*>(&m_state), __ATOMIC_ACQUIRE) &
|
return __atomic_load_n(reinterpret_cast<const uint8_t*>(&m_state), __ATOMIC_ACQUIRE) &
|
||||||
@@ -197,7 +196,7 @@ private:
|
|||||||
uint64_t m_wake_value;
|
uint64_t m_wake_value;
|
||||||
uint64_t m_wake_timeout;
|
uint64_t m_wake_timeout;
|
||||||
|
|
||||||
ipc::message m_message;
|
ipc::message_ptr m_message;
|
||||||
|
|
||||||
wait_queue m_join_queue;
|
wait_queue m_join_queue;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ namespace obj {
|
|||||||
|
|
||||||
using mem::frame_size;
|
using mem::frame_size;
|
||||||
|
|
||||||
vm_area::vm_area(size_t size, vm_flags flags) :
|
vm_area::vm_area(size_t size, util::bitset32 flags) :
|
||||||
m_size {size},
|
m_size {mem::page_count(size) * mem::frame_size},
|
||||||
m_flags {flags},
|
m_flags {flags},
|
||||||
m_spaces {m_vector_static, 0, static_size},
|
m_spaces {m_vector_static, 0, static_size},
|
||||||
kobject {kobject::type::vma}
|
kobject {kobject::type::vma}
|
||||||
@@ -34,6 +34,10 @@ void
|
|||||||
vm_area::remove_from(vm_space *space)
|
vm_area::remove_from(vm_space *space)
|
||||||
{
|
{
|
||||||
m_spaces.remove_swap(space);
|
m_spaces.remove_swap(space);
|
||||||
|
|
||||||
|
// If we were keeping this space around after its refcount
|
||||||
|
// dropped to zero because it was mapped, check if we should
|
||||||
|
// clean it up now.
|
||||||
if (!m_spaces.count() && !handle_count())
|
if (!m_spaces.count() && !handle_count())
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
@@ -62,7 +66,7 @@ vm_area::can_resize(size_t size)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_area_fixed::vm_area_fixed(uintptr_t start, size_t size, vm_flags flags) :
|
vm_area_fixed::vm_area_fixed(uintptr_t start, size_t size, util::bitset32 flags) :
|
||||||
m_start {start},
|
m_start {start},
|
||||||
vm_area {size, flags}
|
vm_area {size, flags}
|
||||||
{
|
{
|
||||||
@@ -70,7 +74,7 @@ vm_area_fixed::vm_area_fixed(uintptr_t start, size_t size, vm_flags flags) :
|
|||||||
|
|
||||||
vm_area_fixed::~vm_area_fixed()
|
vm_area_fixed::~vm_area_fixed()
|
||||||
{
|
{
|
||||||
if (m_flags && vm_flags::mmio)
|
if (m_flags.get(vm_flags::mmio))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
size_t pages = mem::page_count(m_size);
|
size_t pages = mem::page_count(m_size);
|
||||||
@@ -94,7 +98,7 @@ vm_area_fixed::get_page(uintptr_t offset, uintptr_t &phys, bool alloc)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_area_untracked::vm_area_untracked(size_t size, vm_flags flags) :
|
vm_area_untracked::vm_area_untracked(size_t size, util::bitset32 flags) :
|
||||||
vm_area {size, flags}
|
vm_area {size, flags}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -127,7 +131,7 @@ vm_area_untracked::add_to(vm_space *space)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vm_area_open::vm_area_open(size_t size, vm_flags flags) :
|
vm_area_open::vm_area_open(size_t size, util::bitset32 flags) :
|
||||||
m_mapped {nullptr},
|
m_mapped {nullptr},
|
||||||
vm_area {size, flags}
|
vm_area {size, flags}
|
||||||
{
|
{
|
||||||
@@ -154,7 +158,7 @@ vm_area_open::add_existing(uintptr_t offset, uintptr_t phys)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vm_area_guarded::vm_area_guarded(uintptr_t start, size_t buf_pages, size_t size, vm_flags flags) :
|
vm_area_guarded::vm_area_guarded(uintptr_t start, size_t buf_pages, size_t size, util::bitset32 flags) :
|
||||||
m_pages {buf_pages + 1}, // Sections are N+1 pages for the leading guard page
|
m_pages {buf_pages + 1}, // Sections are N+1 pages for the leading guard page
|
||||||
m_stacks {start, m_pages*mem::frame_size},
|
m_stacks {start, m_pages*mem::frame_size},
|
||||||
vm_area_open {size, flags}
|
vm_area_open {size, flags}
|
||||||
@@ -191,7 +195,7 @@ vm_area_guarded::get_page(uintptr_t offset, uintptr_t &phys, bool alloc)
|
|||||||
return vm_area_open::get_page(offset, phys, alloc);
|
return vm_area_open::get_page(offset, phys, alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_area_ring::vm_area_ring(size_t size, vm_flags flags) :
|
vm_area_ring::vm_area_ring(size_t size, util::bitset32 flags) :
|
||||||
vm_area_open {size * 2, flags},
|
vm_area_open {size * 2, flags},
|
||||||
m_bufsize {size}
|
m_bufsize {size}
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <j6/cap_flags.h>
|
#include <j6/cap_flags.h>
|
||||||
|
#include <util/bitset.h>
|
||||||
#include <util/vector.h>
|
#include <util/vector.h>
|
||||||
#include <util/enum_bitfields.h>
|
|
||||||
|
|
||||||
#include "block_allocator.h"
|
#include "block_allocator.h"
|
||||||
#include "objects/kobject.h"
|
#include "objects/kobject.h"
|
||||||
@@ -17,16 +17,15 @@ class vm_space;
|
|||||||
|
|
||||||
namespace obj {
|
namespace obj {
|
||||||
|
|
||||||
enum class vm_flags : uint32_t
|
enum class vm_flags
|
||||||
{
|
{
|
||||||
#define VM_FLAG(name, v) name = v,
|
#define VM_FLAG(name, v) name = v,
|
||||||
#include <j6/tables/vm_flags.inc>
|
#include <j6/tables/vm_flags.inc>
|
||||||
#undef VM_FLAG
|
#undef VM_FLAG
|
||||||
driver_mask = 0x00ff'ffff, ///< flags allowed via syscall for drivers
|
|
||||||
user_mask = 0x000f'ffff, ///< flags allowed via syscall for non-drivers
|
|
||||||
};
|
};
|
||||||
is_bitfield(vm_flags);
|
|
||||||
|
|
||||||
|
inline constexpr util::bitset32 vm_driver_mask = 0x00ff'ffff; ///< flags allowed via syscall for drivers
|
||||||
|
inline constexpr util::bitset32 vm_user_mask = 0x000f'ffff; ///< flags allowed via syscall for non-drivers
|
||||||
|
|
||||||
/// Virtual memory areas allow control over memory allocation
|
/// Virtual memory areas allow control over memory allocation
|
||||||
class vm_area :
|
class vm_area :
|
||||||
@@ -40,7 +39,7 @@ public:
|
|||||||
/// Constructor.
|
/// Constructor.
|
||||||
/// \arg size Initial virtual size of the memory area
|
/// \arg size Initial virtual size of the memory area
|
||||||
/// \arg flags Flags for this memory area
|
/// \arg flags Flags for this memory area
|
||||||
vm_area(size_t size, vm_flags flags = vm_flags::none);
|
vm_area(size_t size, util::bitset32 flags = 0);
|
||||||
|
|
||||||
virtual ~vm_area();
|
virtual ~vm_area();
|
||||||
|
|
||||||
@@ -48,7 +47,7 @@ public:
|
|||||||
inline size_t size() const { return m_size; }
|
inline size_t size() const { return m_size; }
|
||||||
|
|
||||||
/// Get the flags set for this area
|
/// Get the flags set for this area
|
||||||
inline vm_flags flags() const { return m_flags; }
|
inline util::bitset32 flags() const { return m_flags; }
|
||||||
|
|
||||||
/// Track that this area was added to a vm_space
|
/// Track that this area was added to a vm_space
|
||||||
/// \arg space The space to add this area to
|
/// \arg space The space to add this area to
|
||||||
@@ -83,7 +82,7 @@ protected:
|
|||||||
bool can_resize(size_t size);
|
bool can_resize(size_t size);
|
||||||
|
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
vm_flags m_flags;
|
util::bitset32 m_flags;
|
||||||
util::vector<vm_space*> m_spaces;
|
util::vector<vm_space*> m_spaces;
|
||||||
|
|
||||||
// Initial static space for m_spaces - most areas will never grow
|
// Initial static space for m_spaces - most areas will never grow
|
||||||
@@ -103,7 +102,7 @@ public:
|
|||||||
/// \arg start Starting physical address of this area
|
/// \arg start Starting physical address of this area
|
||||||
/// \arg size Size of the physical memory area
|
/// \arg size Size of the physical memory area
|
||||||
/// \arg flags Flags for this memory area
|
/// \arg flags Flags for this memory area
|
||||||
vm_area_fixed(uintptr_t start, size_t size, vm_flags flags = vm_flags::none);
|
vm_area_fixed(uintptr_t start, size_t size, util::bitset32 flags = 0);
|
||||||
virtual ~vm_area_fixed();
|
virtual ~vm_area_fixed();
|
||||||
|
|
||||||
virtual size_t resize(size_t size) override;
|
virtual size_t resize(size_t size) override;
|
||||||
@@ -122,7 +121,7 @@ public:
|
|||||||
/// Constructor.
|
/// Constructor.
|
||||||
/// \arg size Initial virtual size of the memory area
|
/// \arg size Initial virtual size of the memory area
|
||||||
/// \arg flags Flags for this memory area
|
/// \arg flags Flags for this memory area
|
||||||
vm_area_open(size_t size, vm_flags flags);
|
vm_area_open(size_t size, util::bitset32 flags);
|
||||||
virtual ~vm_area_open();
|
virtual ~vm_area_open();
|
||||||
|
|
||||||
virtual bool get_page(uintptr_t offset, uintptr_t &phys, bool alloc = true) override;
|
virtual bool get_page(uintptr_t offset, uintptr_t &phys, bool alloc = true) override;
|
||||||
@@ -144,7 +143,7 @@ public:
|
|||||||
/// Constructor.
|
/// Constructor.
|
||||||
/// \arg size Initial virtual size of the memory area
|
/// \arg size Initial virtual size of the memory area
|
||||||
/// \arg flags Flags for this memory area
|
/// \arg flags Flags for this memory area
|
||||||
vm_area_untracked(size_t size, vm_flags flags);
|
vm_area_untracked(size_t size, util::bitset32 flags);
|
||||||
virtual ~vm_area_untracked();
|
virtual ~vm_area_untracked();
|
||||||
|
|
||||||
virtual bool add_to(vm_space *space) override;
|
virtual bool add_to(vm_space *space) override;
|
||||||
@@ -166,7 +165,7 @@ public:
|
|||||||
uintptr_t start,
|
uintptr_t start,
|
||||||
size_t sec_pages,
|
size_t sec_pages,
|
||||||
size_t size,
|
size_t size,
|
||||||
vm_flags flags);
|
util::bitset32 flags);
|
||||||
|
|
||||||
virtual ~vm_area_guarded();
|
virtual ~vm_area_guarded();
|
||||||
|
|
||||||
@@ -194,7 +193,7 @@ public:
|
|||||||
/// \arg size Virtual size of the ring buffer. Note that
|
/// \arg size Virtual size of the ring buffer. Note that
|
||||||
/// the VMA size will be double this value.
|
/// the VMA size will be double this value.
|
||||||
/// \arg flags Flags for this memory area
|
/// \arg flags Flags for this memory area
|
||||||
vm_area_ring(size_t size, vm_flags flags);
|
vm_area_ring(size_t size, util::bitset32 flags);
|
||||||
virtual ~vm_area_ring();
|
virtual ~vm_area_ring();
|
||||||
|
|
||||||
virtual bool get_page(uintptr_t offset, uintptr_t &phys, bool alloc = true) override;
|
virtual bool get_page(uintptr_t offset, uintptr_t &phys, bool alloc = true) override;
|
||||||
|
|||||||
@@ -14,10 +14,7 @@ free_page_header * page_table::s_page_cache = nullptr;
|
|||||||
util::spinlock page_table::s_lock;
|
util::spinlock page_table::s_lock;
|
||||||
constexpr size_t page_table::entry_sizes[4];
|
constexpr size_t page_table::entry_sizes[4];
|
||||||
|
|
||||||
|
inline constexpr util::bitset64 table_flags = page_flags::present | page_flags::write;
|
||||||
constexpr page_table::flag table_flags =
|
|
||||||
page_table::flag::present |
|
|
||||||
page_table::flag::write;
|
|
||||||
|
|
||||||
|
|
||||||
page_table::iterator::iterator(uintptr_t virt, page_table *pml4) :
|
page_table::iterator::iterator(uintptr_t virt, page_table *pml4) :
|
||||||
@@ -140,9 +137,9 @@ page_table::iterator::ensure_table(level l)
|
|||||||
uintptr_t phys = reinterpret_cast<uintptr_t>(table) & ~linear_offset;
|
uintptr_t phys = reinterpret_cast<uintptr_t>(table) & ~linear_offset;
|
||||||
|
|
||||||
uint64_t &parent = entry(l - 1);
|
uint64_t &parent = entry(l - 1);
|
||||||
flag flags = table_flags;
|
util::bitset64 flags = table_flags;
|
||||||
if (m_index[0] < arch::kernel_root_index)
|
if (m_index[0] < arch::kernel_root_index)
|
||||||
flags |= flag::user;
|
flags.set(flag::user);
|
||||||
|
|
||||||
m_table[unsigned(l)] = table;
|
m_table[unsigned(l)] = table;
|
||||||
parent = (phys & ~0xfffull) | flags;
|
parent = (phys & ~0xfffull) | flags;
|
||||||
|
|||||||
@@ -4,11 +4,33 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <arch/memory.h>
|
#include <arch/memory.h>
|
||||||
#include <util/enum_bitfields.h>
|
#include <util/bitset.h>
|
||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
|
|
||||||
struct free_page_header;
|
struct free_page_header;
|
||||||
|
|
||||||
|
namespace page_flags {
|
||||||
|
inline constexpr util::bitset64 none = 0x0000;
|
||||||
|
inline constexpr util::bitset64 present = 0x0001; /// Entry is present in the table
|
||||||
|
inline constexpr util::bitset64 write = 0x0002; /// Section may be written
|
||||||
|
inline constexpr util::bitset64 user = 0x0004; /// User-accessible
|
||||||
|
inline constexpr util::bitset64 pat0 = 0x0008; /// PAT selector bit 0
|
||||||
|
inline constexpr util::bitset64 pat1 = 0x0010; /// PAT selector bit 1
|
||||||
|
inline constexpr util::bitset64 accessed = 0x0020; /// Entry has been accessed
|
||||||
|
inline constexpr util::bitset64 dirty = 0x0040; /// Page has been written to
|
||||||
|
inline constexpr util::bitset64 page = 0x0080; /// Entry is a large page
|
||||||
|
inline constexpr util::bitset64 pat2 = 0x0080; /// PAT selector bit 2 on PT entries
|
||||||
|
inline constexpr util::bitset64 global = 0x0100; /// Entry is not PCID-specific
|
||||||
|
inline constexpr util::bitset64 pat2_lg = 0x1000; /// PAT selector bit 2 on large/huge pages
|
||||||
|
|
||||||
|
inline constexpr util::bitset64 wb = 0;
|
||||||
|
inline constexpr util::bitset64 wt = pat0;
|
||||||
|
inline constexpr util::bitset64 uc_ = pat1;
|
||||||
|
inline constexpr util::bitset64 uc = pat0 | pat1;
|
||||||
|
inline constexpr util::bitset64 wc = pat0 | pat1 | pat2;
|
||||||
|
inline constexpr util::bitset64 wc_lg = pat0 | pat1 | pat2_lg;
|
||||||
|
} // page_flags
|
||||||
|
|
||||||
/// Struct to allow easy accessing of a memory page being used as a page table.
|
/// Struct to allow easy accessing of a memory page being used as a page table.
|
||||||
struct page_table
|
struct page_table
|
||||||
{
|
{
|
||||||
@@ -16,27 +38,19 @@ struct page_table
|
|||||||
enum class level : unsigned { pml4, pdp, pd, pt, page };
|
enum class level : unsigned { pml4, pdp, pd, pt, page };
|
||||||
|
|
||||||
/// Page entry flags
|
/// Page entry flags
|
||||||
enum class flag : uint64_t
|
enum class flag
|
||||||
{
|
{
|
||||||
none = 0x0000,
|
present = 0, /// Entry is present in the table
|
||||||
present = 0x0001, /// Entry is present in the table
|
write = 1, /// Section may be written
|
||||||
write = 0x0002, /// Section may be written
|
user = 2, /// User-accessible
|
||||||
user = 0x0004, /// User-accessible
|
pat0 = 3, /// PAT selector bit 0
|
||||||
pat0 = 0x0008, /// PAT selector bit 0
|
pat1 = 4, /// PAT selector bit 1
|
||||||
pat1 = 0x0010, /// PAT selector bit 1
|
accessed = 5, /// Entry has been accessed
|
||||||
accessed = 0x0020, /// Entry has been accessed
|
dirty = 6, /// Page has been written to
|
||||||
dirty = 0x0040, /// Page has been written to
|
page = 7, /// Entry is a large page
|
||||||
page = 0x0080, /// Entry is a large page
|
pat2 = 7, /// PAT selector bit 2 on PT entries
|
||||||
pat2 = 0x0080, /// PAT selector bit 2 on PT entries
|
global = 8, /// Entry is not PCID-specific
|
||||||
global = 0x0100, /// Entry is not PCID-specific
|
pat2_lg = 12, /// PAT selector bit 2 on large/huge pages
|
||||||
pat2_lg = 0x1000, /// PAT selector bit 2 on large/huge pages
|
|
||||||
|
|
||||||
wb = none,
|
|
||||||
wt = pat0,
|
|
||||||
uc_ = pat1,
|
|
||||||
uc = pat0 | pat1,
|
|
||||||
wc = pat0 | pat1 | pat2,
|
|
||||||
wc_lg = pat0 | pat1 | pat2_lg,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Helper for getting the next level value
|
/// Helper for getting the next level value
|
||||||
@@ -194,5 +208,3 @@ inline bool operator<(page_table::level a, page_table::level b) {
|
|||||||
|
|
||||||
inline page_table::level& operator++(page_table::level& l) { l = l + 1; return l; }
|
inline page_table::level& operator++(page_table::level& l) { l = l + 1; return l; }
|
||||||
inline page_table::level& operator--(page_table::level& l) { l = l - 1; return l; }
|
inline page_table::level& operator--(page_table::level& l) { l = l - 1; return l; }
|
||||||
|
|
||||||
is_bitfield(page_table::flag);
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
#include "kernel.dir/memory.h"
|
||||||
#include "objects/process.h"
|
#include "objects/process.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
@@ -9,6 +10,44 @@
|
|||||||
|
|
||||||
namespace panicking {
|
namespace panicking {
|
||||||
|
|
||||||
|
template <typename T> inline bool
|
||||||
|
check_pointer(T p)
|
||||||
|
{
|
||||||
|
static constexpr uint64_t large_flag = (1<<7);
|
||||||
|
static constexpr uint64_t pointer_mask = 0x0000fffffffff000;
|
||||||
|
static constexpr uintptr_t canon_mask = 0xffff800000000000;
|
||||||
|
|
||||||
|
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
|
||||||
|
|
||||||
|
uintptr_t canon_bits = addr & canon_mask;
|
||||||
|
if (canon_bits && canon_bits != canon_mask)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uintptr_t pml4 = 0;
|
||||||
|
asm volatile ( "mov %%cr3, %0" : "=r" (pml4) );
|
||||||
|
pml4 += mem::linear_offset;
|
||||||
|
|
||||||
|
uint64_t *table = reinterpret_cast<uint64_t*>(pml4);
|
||||||
|
unsigned shift = 39;
|
||||||
|
|
||||||
|
while (table) {
|
||||||
|
unsigned index = (addr >> shift) & 0x1ffull;
|
||||||
|
uint64_t entry = table[index];
|
||||||
|
|
||||||
|
if ((entry & 0x1) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((entry & large_flag) || shift <= 12)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
uint64_t next = (entry & pointer_mask) + mem::linear_offset;
|
||||||
|
table = reinterpret_cast<uint64_t*>(next);
|
||||||
|
shift -= 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const char *clear = "\e[0m\n";
|
const char *clear = "\e[0m\n";
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -40,23 +79,17 @@ print_cpu(serial_port &out, cpu_data &cpu)
|
|||||||
{
|
{
|
||||||
uint32_t process = cpu.process ? cpu.process->obj_id() : 0;
|
uint32_t process = cpu.process ? cpu.process->obj_id() : 0;
|
||||||
uint32_t thread = cpu.thread ? cpu.thread->obj_id() : 0;
|
uint32_t thread = cpu.thread ? cpu.thread->obj_id() : 0;
|
||||||
|
const char *name = cpu.process ? cpu.process->name() : "<Unknown>";
|
||||||
|
|
||||||
out.write("\n \e[0;31m==[ CPU: ");
|
out.write("\n \e[0;31m==[ CPU: ");
|
||||||
|
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
util::format({buffer, sizeof(buffer)}, "%4d <%02lx:%02lx>",
|
size_t len = util::format({buffer, sizeof(buffer)}, "%4d <%02lx:%02lx> ]: %s ",
|
||||||
cpu.id + 1, process, thread);
|
cpu.id + 1, process, thread, name);
|
||||||
out.write(buffer);
|
out.write(buffer);
|
||||||
|
|
||||||
out.write(" ]=============================================================\n");
|
for (size_t i = 0; i < (74-len); ++i) out.write("=");
|
||||||
}
|
out.write("\n");
|
||||||
|
|
||||||
template <typename T> inline bool
|
|
||||||
canonical(T p)
|
|
||||||
{
|
|
||||||
static constexpr uintptr_t mask = 0xffff800000000000;
|
|
||||||
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
|
|
||||||
return (addr & mask) == mask || (addr & mask) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -65,18 +98,26 @@ print_callstack(serial_port &out, symbol_table &syms, frame const *fp)
|
|||||||
char message[512];
|
char message[512];
|
||||||
unsigned count = 0;
|
unsigned count = 0;
|
||||||
|
|
||||||
while (canonical(fp) && fp && fp->return_addr) {
|
while (fp && check_pointer(fp)) {
|
||||||
char const *name = syms.find_symbol(fp->return_addr);
|
const uintptr_t ret = fp->return_addr;
|
||||||
|
char const *name = ret ? syms.find_symbol(ret) : "<END>";
|
||||||
if (!name)
|
if (!name)
|
||||||
name = canonical(fp->return_addr) ? "<unknown>" : "<corrupt>";
|
name = check_pointer(fp->return_addr) ? "<unknown>" : "<unmapped>";
|
||||||
|
|
||||||
util::format({message, sizeof(message)},
|
util::format({message, sizeof(message)},
|
||||||
" \e[0;33mframe %2d: <0x%016lx> \e[1;33m%s\n",
|
" \e[0;33mframe %2d: <0x%016lx> <0x%016lx> \e[1;33m%s\n",
|
||||||
count++, fp->return_addr, name);
|
count++, fp, fp->return_addr, name);
|
||||||
|
|
||||||
out.write(message);
|
out.write(message);
|
||||||
|
|
||||||
|
if (!ret) return;
|
||||||
fp = fp->prev;
|
fp = fp->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *result = fp ? " <inaccessible>" : "";
|
||||||
|
util::format({message, sizeof(message)}, " \e[0mfinal <0x%016lx>%s\n",
|
||||||
|
fp, result);
|
||||||
|
out.write(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -339,5 +339,5 @@ scheduler::maybe_schedule(TCB *t)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
current_cpu().apic->send_ipi(
|
current_cpu().apic->send_ipi(
|
||||||
lapic::ipi::fixed, isr::ipiSchedule, cpu->id);
|
lapic::ipi_fixed, isr::ipiSchedule, cpu->id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,8 +57,11 @@ start(cpu_data &bsp, void *kpml4)
|
|||||||
// Copy the startup code somwhere the real mode trampoline can run
|
// Copy the startup code somwhere the real mode trampoline can run
|
||||||
uintptr_t addr = 0x8000; // TODO: find a valid address, rewrite addresses
|
uintptr_t addr = 0x8000; // TODO: find a valid address, rewrite addresses
|
||||||
isr vector = static_cast<isr>(addr >> 12);
|
isr vector = static_cast<isr>(addr >> 12);
|
||||||
obj::vm_area *vma = new obj::vm_area_fixed(addr, 0x1000, vm_flags::write);
|
|
||||||
vm_space::kernel_space().add(addr, vma, obj::vm_flags::exact);
|
constexpr util::bitset32 flags = util::bitset32::of(vm_flags::write, vm_flags::exact);
|
||||||
|
obj::vm_area *vma = new obj::vm_area_fixed(addr, 0x1000, flags);
|
||||||
|
vm_space::kernel_space().add(addr, vma, flags);
|
||||||
|
|
||||||
memcpy(
|
memcpy(
|
||||||
reinterpret_cast<void*>(addr),
|
reinterpret_cast<void*>(addr),
|
||||||
reinterpret_cast<void*>(&ap_startup),
|
reinterpret_cast<void*>(&ap_startup),
|
||||||
@@ -67,7 +70,7 @@ start(cpu_data &bsp, void *kpml4)
|
|||||||
size_t free_stack_count = 0;
|
size_t free_stack_count = 0;
|
||||||
|
|
||||||
lapic &apic = *bsp.apic;
|
lapic &apic = *bsp.apic;
|
||||||
lapic::ipi mode = lapic::ipi::init | lapic::ipi::level | lapic::ipi::assert;
|
util::bitset32 mode = lapic::ipi_init + lapic::ipi_flags::level + lapic::ipi_flags::assert;
|
||||||
apic.send_ipi_broadcast(mode, false, static_cast<isr>(0));
|
apic.send_ipi_broadcast(mode, false, static_cast<isr>(0));
|
||||||
|
|
||||||
for (uint8_t id : ids) {
|
for (uint8_t id : ids) {
|
||||||
@@ -90,7 +93,7 @@ start(cpu_data &bsp, void *kpml4)
|
|||||||
size_t current_count = ap_startup_count;
|
size_t current_count = ap_startup_count;
|
||||||
log::verbose(logs::boot, "Starting AP %d: stack %llx", cpu->index, stack_end);
|
log::verbose(logs::boot, "Starting AP %d: stack %llx", cpu->index, stack_end);
|
||||||
|
|
||||||
lapic::ipi startup = lapic::ipi::startup | lapic::ipi::assert;
|
util::bitset32 startup = lapic::ipi_sipi + lapic::ipi_flags::assert;
|
||||||
|
|
||||||
apic.send_ipi(startup, vector, id);
|
apic.send_ipi(startup, vector, id);
|
||||||
for (unsigned i = 0; i < 20; ++i) {
|
for (unsigned i = 0; i < 20; ++i) {
|
||||||
|
|||||||
@@ -32,4 +32,13 @@ handle_clone(j6_handle_t orig, j6_handle_t *clone, uint32_t mask)
|
|||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
j6_status_t
|
||||||
|
handle_close(j6_handle_t hnd)
|
||||||
|
{
|
||||||
|
process &p = process::current();
|
||||||
|
p.remove_handle(hnd);
|
||||||
|
return j6_status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace syscalls
|
} // namespace syscalls
|
||||||
|
|||||||
@@ -35,16 +35,17 @@ mailbox_call(
|
|||||||
uint64_t *tag,
|
uint64_t *tag,
|
||||||
void *in_data,
|
void *in_data,
|
||||||
size_t *data_len,
|
size_t *data_len,
|
||||||
size_t data_in_len,
|
size_t data_size,
|
||||||
j6_handle_t *in_handles,
|
j6_handle_t *in_handles,
|
||||||
size_t *handles_count)
|
size_t *handles_count,
|
||||||
|
size_t handles_size)
|
||||||
{
|
{
|
||||||
thread &cur = thread::current();
|
thread &cur = thread::current();
|
||||||
|
|
||||||
util::buffer data {in_data, data_in_len};
|
util::buffer data {in_data, *data_len};
|
||||||
util::counted<j6_handle_t> handles {in_handles, *handles_count};
|
util::counted<j6_handle_t> handles {in_handles, *handles_count};
|
||||||
|
|
||||||
ipc::message message(*tag, data, handles);
|
ipc::message_ptr message = new ipc::message {*tag, data, handles};
|
||||||
cur.set_message_data(util::move(message));
|
cur.set_message_data(util::move(message));
|
||||||
|
|
||||||
j6_status_t s = self->call();
|
j6_status_t s = self->call();
|
||||||
@@ -52,19 +53,20 @@ mailbox_call(
|
|||||||
return s;
|
return s;
|
||||||
|
|
||||||
message = cur.get_message_data();
|
message = cur.get_message_data();
|
||||||
|
util::counted<j6_handle_t> msg_handles = message->handles();
|
||||||
|
util::buffer msg_data = message->data();
|
||||||
|
|
||||||
if (message.handles) {
|
if (message->handle_count) {
|
||||||
for (unsigned i = 0; i < message.handles.count; ++i)
|
for (unsigned i = 0; i < msg_handles.count; ++i)
|
||||||
process::current().add_handle(message.handles[i]);
|
process::current().add_handle(msg_handles[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
*tag = message.tag;
|
*tag = message->tag;
|
||||||
*data_len = *data_len > message.data.count ? message.data.count : *data_len;
|
*data_len = data_size > msg_data.count ? msg_data.count : data_size;
|
||||||
memcpy(in_data, message.data.pointer, *data_len);
|
memcpy(in_data, msg_data.pointer, *data_len);
|
||||||
|
|
||||||
size_t handles_min = *handles_count > message.handles.count ? message.handles.count : *handles_count;
|
*handles_count = handles_size > msg_handles.count ? msg_handles.count : handles_size;
|
||||||
*handles_count = handles_min;
|
memcpy(in_handles, msg_handles.pointer, *handles_count * sizeof(j6_handle_t));
|
||||||
memcpy(in_handles, message.handles.pointer, handles_min * sizeof(j6_handle_t));
|
|
||||||
|
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
@@ -75,18 +77,20 @@ mailbox_respond(
|
|||||||
uint64_t *tag,
|
uint64_t *tag,
|
||||||
void *in_data,
|
void *in_data,
|
||||||
size_t *data_len,
|
size_t *data_len,
|
||||||
size_t data_in_len,
|
size_t data_size,
|
||||||
j6_handle_t *in_handles,
|
j6_handle_t *in_handles,
|
||||||
size_t *handles_count,
|
size_t *handles_count,
|
||||||
|
size_t handles_size,
|
||||||
uint64_t *reply_tag,
|
uint64_t *reply_tag,
|
||||||
uint64_t flags)
|
uint64_t flags)
|
||||||
{
|
{
|
||||||
util::buffer data {in_data, data_in_len};
|
util::buffer data {in_data, *data_len};
|
||||||
util::counted<j6_handle_t> handles {in_handles, *handles_count};
|
util::counted<j6_handle_t> handles {in_handles, *handles_count};
|
||||||
|
|
||||||
ipc::message message(*tag, data, handles);
|
ipc::message_ptr message;
|
||||||
|
|
||||||
if (*reply_tag) {
|
if (*reply_tag) {
|
||||||
|
message = new ipc::message {*tag, data, handles};
|
||||||
j6_status_t s = self->reply(*reply_tag, util::move(message));
|
j6_status_t s = self->reply(*reply_tag, util::move(message));
|
||||||
if (s != j6_status_ok)
|
if (s != j6_status_ok)
|
||||||
return s;
|
return s;
|
||||||
@@ -97,18 +101,20 @@ mailbox_respond(
|
|||||||
if (s != j6_status_ok)
|
if (s != j6_status_ok)
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
if (message.handles) {
|
util::counted<j6_handle_t> msg_handles = message->handles();
|
||||||
for (unsigned i = 0; i < message.handles.count; ++i)
|
util::buffer msg_data = message->data();
|
||||||
process::current().add_handle(message.handles[i]);
|
|
||||||
|
if (msg_handles) {
|
||||||
|
for (unsigned i = 0; i < msg_handles.count; ++i)
|
||||||
|
process::current().add_handle(msg_handles[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
*tag = message.tag;
|
*tag = message->tag;
|
||||||
*data_len = *data_len > message.data.count ? message.data.count : *data_len;
|
*data_len = data_size > msg_data.count ? msg_data.count : data_size;
|
||||||
memcpy(in_data, message.data.pointer, *data_len);
|
memcpy(in_data, msg_data.pointer, *data_len);
|
||||||
|
|
||||||
size_t handles_min = *handles_count > message.handles.count ? message.handles.count : *handles_count;
|
*handles_count = handles_size > msg_handles.count ? msg_handles.count : handles_size;
|
||||||
*handles_count = handles_min;
|
memcpy(in_handles, msg_handles.pointer, *handles_count * sizeof(j6_handle_t));
|
||||||
memcpy(in_handles, message.handles.pointer, handles_min * sizeof(j6_handle_t));
|
|
||||||
|
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ using namespace obj;
|
|||||||
namespace syscalls {
|
namespace syscalls {
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
process_create(j6_handle_t *self)
|
process_create(j6_handle_t *self, const char *path)
|
||||||
{
|
{
|
||||||
process *p = construct_handle<process>(self);
|
process *p = construct_handle<process>(self, path);
|
||||||
log::info(logs::task, "Process <%02lx> created", p->obj_id());
|
log::info(logs::task, "Process <%02lx> created", p->obj_id());
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
@@ -29,10 +29,10 @@ process_kill(process *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
process_exit(int32_t status)
|
process_exit(int64_t status)
|
||||||
{
|
{
|
||||||
process &p = process::current();
|
process &p = process::current();
|
||||||
log::info(logs::task, "Process <%02lx> exiting with code %d", p.obj_id(), status);
|
log::info(logs::task, "Process <%02lx> exiting with code %#lx", p.obj_id(), status);
|
||||||
|
|
||||||
p.exit(status);
|
p.exit(status);
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ namespace syscalls {
|
|||||||
using system = class ::system;
|
using system = class ::system;
|
||||||
|
|
||||||
j6_status_t
|
j6_status_t
|
||||||
log(const char *message)
|
log(uint8_t area, uint8_t severity, const char *message)
|
||||||
{
|
{
|
||||||
|
const char *name = process::current().name();
|
||||||
thread &th = thread::current();
|
thread &th = thread::current();
|
||||||
log::info(logs::syscall, "Message <%02lx:%02lx>: %s", th.parent().obj_id(), th.obj_id(), message);
|
log::log(static_cast<logs>(area), static_cast<log::level>(severity),
|
||||||
|
"<%02lx:%02lx> %s: %s", th.parent().obj_id(), th.obj_id(), name, message);
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,12 +68,11 @@ system_map_phys(system *self, j6_handle_t * area, uintptr_t phys, size_t size, u
|
|||||||
{
|
{
|
||||||
// TODO: check to see if frames are already used? How would that collide with
|
// TODO: check to see if frames are already used? How would that collide with
|
||||||
// the bootloader's allocated pages already being marked used?
|
// the bootloader's allocated pages already being marked used?
|
||||||
if (!(flags & vm_flags::mmio))
|
util::bitset32 f = flags & vm_driver_mask;
|
||||||
|
if (!f.get(vm_flags::mmio))
|
||||||
frame_allocator::get().used(phys, mem::page_count(size));
|
frame_allocator::get().used(phys, mem::page_count(size));
|
||||||
|
|
||||||
vm_flags vmf = (static_cast<vm_flags>(flags) & vm_flags::driver_mask);
|
construct_handle<vm_area_fixed>(area, phys, size, f);
|
||||||
construct_handle<vm_area_fixed>(area, phys, size, vmf);
|
|
||||||
|
|
||||||
return j6_status_ok;
|
return j6_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ namespace syscalls {
|
|||||||
j6_status_t
|
j6_status_t
|
||||||
vma_create(j6_handle_t *self, size_t size, uint32_t flags)
|
vma_create(j6_handle_t *self, size_t size, uint32_t flags)
|
||||||
{
|
{
|
||||||
vm_flags f = vm_flags::user_mask & flags;
|
util::bitset32 f = flags & vm_user_mask;
|
||||||
if (util::bits::has(f, vm_flags::ring))
|
if (f.get(vm_flags::ring))
|
||||||
construct_handle<vm_area_ring>(self, size, f);
|
construct_handle<vm_area_ring>(self, size, f);
|
||||||
else
|
else
|
||||||
construct_handle<vm_area_open>(self, size, f);
|
construct_handle<vm_area_open>(self, size, f);
|
||||||
@@ -26,8 +26,8 @@ j6_status_t
|
|||||||
vma_create_map(j6_handle_t *self, size_t size, uintptr_t *base, uint32_t flags)
|
vma_create_map(j6_handle_t *self, size_t size, uintptr_t *base, uint32_t flags)
|
||||||
{
|
{
|
||||||
vm_area *a = nullptr;
|
vm_area *a = nullptr;
|
||||||
vm_flags f = vm_flags::user_mask & flags;
|
util::bitset32 f = flags & vm_user_mask;
|
||||||
if (util::bits::has(f, vm_flags::ring))
|
if (f.get(vm_flags::ring))
|
||||||
a = construct_handle<vm_area_ring>(self, size, f);
|
a = construct_handle<vm_area_ring>(self, size, f);
|
||||||
else
|
else
|
||||||
a = construct_handle<vm_area_open>(self, size, f);
|
a = construct_handle<vm_area_open>(self, size, f);
|
||||||
@@ -40,7 +40,7 @@ j6_status_t
|
|||||||
vma_map(vm_area *self, process *proc, uintptr_t *base, uint32_t flags)
|
vma_map(vm_area *self, process *proc, uintptr_t *base, uint32_t flags)
|
||||||
{
|
{
|
||||||
vm_space &space = proc ? proc->space() : process::current().space();
|
vm_space &space = proc ? proc->space() : process::current().space();
|
||||||
vm_flags f = vm_flags::user_mask & flags;
|
util::bitset32 f = flags & vm_user_mask;
|
||||||
*base = space.add(*base, self, f);
|
*base = space.add(*base, self, f);
|
||||||
return *base ? j6_status_ok : j6_err_collision;
|
return *base ? j6_status_ok : j6_err_collision;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,3 +91,10 @@ _current_gsbase:
|
|||||||
mov rax, [gs:CPU_DATA.self]
|
mov rax, [gs:CPU_DATA.self]
|
||||||
ret
|
ret
|
||||||
.end:
|
.end:
|
||||||
|
|
||||||
|
global _reload_cr3: function hidden (_reload_cr3.end - _reload_cr3)
|
||||||
|
_reload_cr3:
|
||||||
|
mov rax, cr3
|
||||||
|
mov cr3, rax
|
||||||
|
ret
|
||||||
|
.end:
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <j6/memutils.h>
|
#include <j6/memutils.h>
|
||||||
#include <arch/memory.h>
|
#include <arch/memory.h>
|
||||||
|
|
||||||
|
#include "apic.h"
|
||||||
#include "kassert.h"
|
#include "kassert.h"
|
||||||
#include "frame_allocator.h"
|
#include "frame_allocator.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
@@ -55,9 +56,9 @@ vm_space::vm_space() :
|
|||||||
obj::vm_area *sysc = new obj::vm_area_fixed(
|
obj::vm_area *sysc = new obj::vm_area_fixed(
|
||||||
g_sysconf_phys,
|
g_sysconf_phys,
|
||||||
sizeof(system_config),
|
sizeof(system_config),
|
||||||
vm_flags::none);
|
0);
|
||||||
|
|
||||||
add(sysconf_user_address, sysc, vm_flags::exact);
|
add(sysconf_user_address, sysc, util::bitset32::of(vm_flags::exact));
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_space::~vm_space()
|
vm_space::~vm_space()
|
||||||
@@ -81,32 +82,31 @@ vm_space::kernel_space()
|
|||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t
|
uintptr_t
|
||||||
vm_space::add(uintptr_t base, obj::vm_area *area, obj::vm_flags flags)
|
vm_space::add(uintptr_t base, obj::vm_area *new_area, util::bitset32 flags)
|
||||||
{
|
{
|
||||||
if (!base)
|
if (!base)
|
||||||
base = min_auto_address;
|
base = min_auto_address;
|
||||||
|
|
||||||
uintptr_t end = base + area->size();
|
|
||||||
|
|
||||||
//TODO: optimize find/insert
|
//TODO: optimize find/insert
|
||||||
bool exact = util::bits::has(flags, j6_vm_flag_exact);
|
bool exact = flags.get(vm_flags::exact);
|
||||||
for (size_t i = 0; i < m_areas.count(); ++i) {
|
for (size_t i = 0; i < m_areas.count(); ++i) {
|
||||||
const vm_space::area &a = m_areas[i];
|
const vm_space::area &cur = m_areas[i];
|
||||||
uintptr_t aend = a.base + a.area->size();
|
uintptr_t cur_end = cur.base + cur.area->size();
|
||||||
if (base >= aend)
|
if (base >= cur_end)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (end <= a.base)
|
uintptr_t end = base + new_area->size();
|
||||||
|
if (end <= cur.base)
|
||||||
break;
|
break;
|
||||||
else if (exact)
|
else if (exact)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
base = aend;
|
base = cur_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_areas.sorted_insert({base, area});
|
m_areas.sorted_insert({base, new_area});
|
||||||
area->add_to(this);
|
new_area->add_to(this);
|
||||||
area->handle_retain();
|
new_area->handle_retain();
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ vm_space::copy_from(const vm_space &source, const obj::vm_area &vma)
|
|||||||
|
|
||||||
while (count--) {
|
while (count--) {
|
||||||
uint64_t &e = dit.entry(page_table::level::pt);
|
uint64_t &e = dit.entry(page_table::level::pt);
|
||||||
if (e & page_table::flag::present) {
|
if (util::bitset64::from(e) & page_flags::present) {
|
||||||
// TODO: handle clobbering mapping
|
// TODO: handle clobbering mapping
|
||||||
}
|
}
|
||||||
e = sit.entry(page_table::level::pt);
|
e = sit.entry(page_table::level::pt);
|
||||||
@@ -210,11 +210,11 @@ vm_space::page_in(const obj::vm_area &vma, uintptr_t offset, uintptr_t phys, siz
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
uintptr_t virt = base + offset;
|
uintptr_t virt = base + offset;
|
||||||
page_table::flag flags =
|
util::bitset64 flags =
|
||||||
page_table::flag::present |
|
page_flags::present |
|
||||||
(m_kernel ? page_table::flag::none : page_table::flag::user) |
|
(m_kernel ? page_flags::none : page_flags::user) |
|
||||||
((vma.flags() && vm_flags::write) ? page_table::flag::write : page_table::flag::none) |
|
(vma.flags().get(vm_flags::write) ? page_flags::write : page_flags::none) |
|
||||||
((vma.flags() && vm_flags::write_combine) ? page_table::flag::wc : page_table::flag::none);
|
(vma.flags().get(vm_flags::write_combine) ? page_flags::wc : page_flags::none);
|
||||||
|
|
||||||
page_table::iterator it {virt, m_pml4};
|
page_table::iterator it {virt, m_pml4};
|
||||||
|
|
||||||
@@ -222,7 +222,7 @@ vm_space::page_in(const obj::vm_area &vma, uintptr_t offset, uintptr_t phys, siz
|
|||||||
uint64_t &entry = it.entry(page_table::level::pt);
|
uint64_t &entry = it.entry(page_table::level::pt);
|
||||||
entry = (phys + i * frame_size) | flags;
|
entry = (phys + i * frame_size) | flags;
|
||||||
log::spam(logs::paging, "Setting entry for %016llx: %016llx [%04llx]",
|
log::spam(logs::paging, "Setting entry for %016llx: %016llx [%04llx]",
|
||||||
it.vaddress(), (phys + i * frame_size), flags);
|
it.vaddress(), (phys + i * frame_size), flags.value());
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,14 +247,14 @@ vm_space::clear(const obj::vm_area &vma, uintptr_t offset, size_t count, bool fr
|
|||||||
while (count--) {
|
while (count--) {
|
||||||
uint64_t &e = it.entry(page_table::level::pt);
|
uint64_t &e = it.entry(page_table::level::pt);
|
||||||
uintptr_t phys = e & ~0xfffull;
|
uintptr_t phys = e & ~0xfffull;
|
||||||
|
util::bitset64 flags = e;
|
||||||
|
|
||||||
if (e & page_table::flag::present) {
|
if (flags & page_flags::present) {
|
||||||
uint64_t orig = e;
|
|
||||||
e = 0;
|
e = 0;
|
||||||
if (orig & page_table::flag::accessed) {
|
|
||||||
auto *addr = reinterpret_cast<const uint8_t *>(it.vaddress());
|
auto *addr = reinterpret_cast<const uint8_t *>(it.vaddress());
|
||||||
asm ( "invlpg %0" :: "m"(*addr) : "memory" );
|
asm ( "invlpg %0" :: "m"(*addr) : "memory" );
|
||||||
}
|
|
||||||
if (free_count && phys == free_start + (free_count * frame_size)) {
|
if (free_count && phys == free_start + (free_count * frame_size)) {
|
||||||
++free_count;
|
++free_count;
|
||||||
} else {
|
} else {
|
||||||
@@ -268,6 +268,9 @@ vm_space::clear(const obj::vm_area &vma, uintptr_t offset, size_t count, bool fr
|
|||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current_cpu().apic->send_ipi_broadcast(
|
||||||
|
lapic::ipi_fixed, false, isr::ipiShootdown);
|
||||||
|
|
||||||
if (free && free_count)
|
if (free && free_count)
|
||||||
fa.free(free_start, free_count);
|
fa.free(free_start, free_count);
|
||||||
}
|
}
|
||||||
@@ -290,11 +293,11 @@ vm_space::lock(const obj::vm_area &vma, uintptr_t offset, size_t count)
|
|||||||
while (count--) {
|
while (count--) {
|
||||||
uint64_t &e = it.entry(page_table::level::pt);
|
uint64_t &e = it.entry(page_table::level::pt);
|
||||||
uintptr_t phys = e & ~0xfffull;
|
uintptr_t phys = e & ~0xfffull;
|
||||||
|
util::bitset64 flags = e;
|
||||||
|
|
||||||
if (e & page_table::flag::present) {
|
if (flags & page_flags::present) {
|
||||||
uint64_t orig = e;
|
|
||||||
e = locked_page_tag;
|
e = locked_page_tag;
|
||||||
if (orig & page_table::flag::accessed) {
|
if (flags & page_flags::accessed) {
|
||||||
auto *addr = reinterpret_cast<const uint8_t *>(it.vaddress());
|
auto *addr = reinterpret_cast<const uint8_t *>(it.vaddress());
|
||||||
asm ( "invlpg %0" :: "m"(*addr) : "memory" );
|
asm ( "invlpg %0" :: "m"(*addr) : "memory" );
|
||||||
}
|
}
|
||||||
@@ -338,10 +341,10 @@ vm_space::initialize_tcb(TCB &tcb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
vm_space::handle_fault(uintptr_t addr, fault_type fault)
|
vm_space::handle_fault(uintptr_t addr, util::bitset8 fault)
|
||||||
{
|
{
|
||||||
// TODO: Handle more fult types
|
// TODO: Handle more fult types
|
||||||
if (fault && fault_type::present)
|
if (fault.get(fault_type::present))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uintptr_t page = (addr & ~0xfffull);
|
uintptr_t page = (addr & ~0xfffull);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <j6/flags.h>
|
#include <j6/flags.h>
|
||||||
#include <util/enum_bitfields.h>
|
#include <util/bitset.h>
|
||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
#include <util/vector.h>
|
#include <util/vector.h>
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ public:
|
|||||||
/// \arg area The area to add
|
/// \arg area The area to add
|
||||||
/// \arg flags Flags for the operation (exact, clobber, etc)
|
/// \arg flags Flags for the operation (exact, clobber, etc)
|
||||||
/// \returns The base address the area was added at
|
/// \returns The base address the area was added at
|
||||||
uintptr_t add(uintptr_t base, obj::vm_area *area, obj::vm_flags flags);
|
uintptr_t add(uintptr_t base, obj::vm_area *area, util::bitset32 flags);
|
||||||
|
|
||||||
/// Remove a virtual memory area from this address space
|
/// Remove a virtual memory area from this address space
|
||||||
/// \arg area The area to remove
|
/// \arg area The area to remove
|
||||||
@@ -88,15 +88,6 @@ public:
|
|||||||
/// Set this space as the current active space
|
/// Set this space as the current active space
|
||||||
void activate() const;
|
void activate() const;
|
||||||
|
|
||||||
enum class fault_type : uint8_t {
|
|
||||||
none = 0x00,
|
|
||||||
present = 0x01,
|
|
||||||
write = 0x02,
|
|
||||||
user = 0x04,
|
|
||||||
reserved = 0x08,
|
|
||||||
fetch = 0x10
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Allocate pages into virtual memory. May allocate less than requested.
|
/// Allocate pages into virtual memory. May allocate less than requested.
|
||||||
/// \arg virt The virtual address at which to allocate
|
/// \arg virt The virtual address at which to allocate
|
||||||
/// \arg count The number of pages to allocate
|
/// \arg count The number of pages to allocate
|
||||||
@@ -104,11 +95,13 @@ public:
|
|||||||
/// \returns The number of pages actually allocated
|
/// \returns The number of pages actually allocated
|
||||||
size_t allocate(uintptr_t virt, size_t count, uintptr_t *phys);
|
size_t allocate(uintptr_t virt, size_t count, uintptr_t *phys);
|
||||||
|
|
||||||
|
enum class fault_type { present, write, user, reserved, fetch };
|
||||||
|
|
||||||
/// Handle a page fault.
|
/// Handle a page fault.
|
||||||
/// \arg addr Address which caused the fault
|
/// \arg addr Address which caused the fault
|
||||||
/// \arg ft Flags from the interrupt about the kind of fault
|
/// \arg ft Flags from the interrupt about the kind of fault
|
||||||
/// \returns True if the fault was successfully handled
|
/// \returns True if the fault was successfully handled
|
||||||
bool handle_fault(uintptr_t addr, fault_type fault);
|
bool handle_fault(uintptr_t addr, util::bitset8 fault);
|
||||||
|
|
||||||
/// Set up a TCB to operate in this address space.
|
/// Set up a TCB to operate in this address space.
|
||||||
void initialize_tcb(TCB &tcb);
|
void initialize_tcb(TCB &tcb);
|
||||||
@@ -156,5 +149,3 @@ private:
|
|||||||
|
|
||||||
util::spinlock m_lock;
|
util::spinlock m_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
is_bitfield(vm_space::fault_type);
|
|
||||||
|
|||||||
79
src/libraries/acpi/acpi.cpp
Normal file
79
src/libraries/acpi/acpi.cpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#include <acpi/acpi.h>
|
||||||
|
#include <acpi/tables.h>
|
||||||
|
#include <j6/syslog.hh>
|
||||||
|
|
||||||
|
namespace acpi {
|
||||||
|
|
||||||
|
system::system(const void* phys, const void *virt) :
|
||||||
|
m_offset { util::get_offset(phys, virt) },
|
||||||
|
m_root { reinterpret_cast<const rsdp2*>(virt) }
|
||||||
|
{}
|
||||||
|
|
||||||
|
system::iterator
|
||||||
|
system::begin() const
|
||||||
|
{
|
||||||
|
const xsdt *sdt =
|
||||||
|
acpi::check_get_table<xsdt>(m_root->xsdt_address);
|
||||||
|
|
||||||
|
if (!sdt)
|
||||||
|
return {nullptr, 0};
|
||||||
|
|
||||||
|
return {&sdt->headers[0], m_offset};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
system::iterator
|
||||||
|
system::end() const
|
||||||
|
{
|
||||||
|
const xsdt *sdt =
|
||||||
|
acpi::check_get_table<xsdt>(m_root->xsdt_address);
|
||||||
|
|
||||||
|
if (!sdt)
|
||||||
|
return {nullptr, 0};
|
||||||
|
|
||||||
|
size_t nheaders = table_entries<xsdt>(sdt, sizeof(table_header*));
|
||||||
|
return {&sdt->headers[nheaders], m_offset};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
load_acpi(j6_handle_t sys, const bootproto::module *mod)
|
||||||
|
{
|
||||||
|
const bootproto::acpi *info = mod->data<bootproto::acpi>();
|
||||||
|
const util::const_buffer ®ion = info->region;
|
||||||
|
|
||||||
|
map_phys(sys, region.pointer, region.count);
|
||||||
|
|
||||||
|
const void *root_table = info->root;
|
||||||
|
if (!root_table) {
|
||||||
|
j6::syslog(j6::logs::srv, j6::log_level::error, "null ACPI root table pointer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const acpi::rsdp2 *acpi2 =
|
||||||
|
reinterpret_cast<const acpi::rsdp2 *>(root_table);
|
||||||
|
|
||||||
|
const auto *xsdt =
|
||||||
|
acpi::check_get_table<acpi::xsdt>(acpi2->xsdt_address);
|
||||||
|
|
||||||
|
size_t num_tables = acpi::table_entries(xsdt, sizeof(void*));
|
||||||
|
for (size_t i = 0; i < num_tables; ++i) {
|
||||||
|
const acpi::table_header *header = xsdt->headers[i];
|
||||||
|
if (!header->validate()) {
|
||||||
|
j6::syslog(j6::logs::srv, j6::log_level::error, "ACPI table at %lx failed validation", header);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (header->type) {
|
||||||
|
case acpi::mcfg::type_id:
|
||||||
|
load_mcfg(sys, header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace acpi
|
||||||
12
src/libraries/acpi/acpi.module
Normal file
12
src/libraries/acpi/acpi.module
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# vim: ft=python
|
||||||
|
|
||||||
|
module("acpi",
|
||||||
|
kind = "lib",
|
||||||
|
deps = [ "util", "j6" ],
|
||||||
|
sources = [
|
||||||
|
"acpi.cpp",
|
||||||
|
],
|
||||||
|
public_headers = [
|
||||||
|
"acpi/acpi.h",
|
||||||
|
"acpi/tables.h",
|
||||||
|
])
|
||||||
53
src/libraries/acpi/include/acpi/acpi.h
Normal file
53
src/libraries/acpi/include/acpi/acpi.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file acpi.h
|
||||||
|
/// Routines for loading and parsing ACPI tables
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <acpi/tables.h>
|
||||||
|
#include <util/pointers.h>
|
||||||
|
|
||||||
|
namespace acpi {
|
||||||
|
|
||||||
|
struct system
|
||||||
|
{
|
||||||
|
system(const void* phys, const void *virt);
|
||||||
|
|
||||||
|
/// Iterator for all tables in the system
|
||||||
|
struct iterator
|
||||||
|
{
|
||||||
|
iterator(const table_header *const *addr, ptrdiff_t off) : m_addr {addr}, m_off {off} {};
|
||||||
|
|
||||||
|
operator const table_header *() const { return m_addr ? offset(*m_addr) : nullptr; }
|
||||||
|
const table_header * operator*() const { return m_addr ? offset(*m_addr) : nullptr; }
|
||||||
|
const table_header * operator->() const { return m_addr ? offset(*m_addr) : nullptr; }
|
||||||
|
|
||||||
|
iterator & operator++() { increment(); return *this; }
|
||||||
|
iterator operator++(int) { iterator old = *this; increment(); return old; }
|
||||||
|
|
||||||
|
friend bool operator==(const iterator &a, const iterator &b) { return a.m_addr == b.m_addr; }
|
||||||
|
friend bool operator!=(const iterator &a, const iterator &b) { return a.m_addr != b.m_addr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void increment() { if (m_addr) ++m_addr; }
|
||||||
|
|
||||||
|
table_header const * const * m_addr;
|
||||||
|
ptrdiff_t m_off;
|
||||||
|
|
||||||
|
inline const table_header * offset(const table_header * addr) const {
|
||||||
|
return util::offset_pointer(addr, m_off);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
iterator begin() const;
|
||||||
|
iterator end() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const xsdt * get_xsdt() {
|
||||||
|
return check_get_table<xsdt>(util::offset_pointer(m_root->xsdt_address, m_offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrdiff_t m_offset;
|
||||||
|
const rsdp2* m_root;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace acpi
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <util/enum_bitfields.h>
|
#include <util/bitset.h>
|
||||||
#include <util/misc.h> // for byteswap32
|
#include <util/misc.h> // for byteswap32
|
||||||
|
|
||||||
namespace acpi {
|
namespace acpi {
|
||||||
@@ -21,6 +21,7 @@ struct table_header
|
|||||||
uint32_t creator_revision;
|
uint32_t creator_revision;
|
||||||
|
|
||||||
bool validate() const { return util::checksum(this, length) == 0; }
|
bool validate() const { return util::checksum(this, length) == 0; }
|
||||||
|
bool validate(uint32_t sig) const { return type == sig && validate(); }
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
@@ -62,32 +63,31 @@ struct gas
|
|||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
enum class fadt_flags : uint32_t
|
enum class fadt_flags
|
||||||
{
|
{
|
||||||
wbinvd = 0x00000001,
|
wbinvd,
|
||||||
wbinvd_flush = 0x00000002,
|
wbinvd_flush,
|
||||||
proc_c1 = 0x00000004,
|
proc_c1,
|
||||||
p_lvl2_up = 0x00000008,
|
p_lvl2_up,
|
||||||
pwr_button = 0x00000010,
|
pwr_button,
|
||||||
slp_button = 0x00000020,
|
slp_button,
|
||||||
fix_rtc = 0x00000040,
|
fix_rtc,
|
||||||
rtc_s4 = 0x00000080,
|
rtc_s4,
|
||||||
tmr_val_ext = 0x00000100,
|
tmr_val_ext,
|
||||||
dck_cap = 0x00000200,
|
dck_cap,
|
||||||
reset_reg_sup = 0x00000400,
|
reset_reg_sup,
|
||||||
sealed_case = 0x00000800,
|
sealed_case,
|
||||||
headless = 0x00001000,
|
headless,
|
||||||
cpu_sw_slp = 0x00002000,
|
cpu_sw_slp,
|
||||||
pci_exp_wak = 0x00004000,
|
pci_exp_wak,
|
||||||
use_plat_clock = 0x00008000,
|
use_plat_clock,
|
||||||
s4_rtc_sts_val = 0x00010000,
|
s4_rtc_sts_val,
|
||||||
remote_pwr_cap = 0x00020000,
|
remote_pwr_cap,
|
||||||
apic_cluster = 0x00040000,
|
apic_cluster,
|
||||||
apic_physical = 0x00080000,
|
apic_physical,
|
||||||
hw_reduced_acpi = 0x00100000,
|
hw_reduced_acpi,
|
||||||
low_pwr_s0_idle = 0x00200000
|
low_pwr_s0_idle
|
||||||
};
|
};
|
||||||
is_bitfield(fadt_flags);
|
|
||||||
|
|
||||||
struct fadt
|
struct fadt
|
||||||
{
|
{
|
||||||
@@ -134,7 +134,7 @@ struct fadt
|
|||||||
|
|
||||||
uint16_t iapc_boot_arch;
|
uint16_t iapc_boot_arch;
|
||||||
uint8_t reserved1;
|
uint8_t reserved1;
|
||||||
fadt_flags flags;
|
util::bitset32 flags;
|
||||||
|
|
||||||
gas reset_reg;
|
gas reset_reg;
|
||||||
uint8_t reset_value;
|
uint8_t reset_value;
|
||||||
@@ -3,15 +3,9 @@
|
|||||||
/// Data structures for reading jsix_boot.dat
|
/// Data structures for reading jsix_boot.dat
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/enum_bitfields.h>
|
|
||||||
|
|
||||||
namespace bootproto {
|
namespace bootproto {
|
||||||
|
|
||||||
enum class desc_flags : uint16_t {
|
enum class desc_flags { graphical, panic, symbols };
|
||||||
graphical = 0x0001,
|
|
||||||
panic = 0x0002,
|
|
||||||
symbols = 0x0004,
|
|
||||||
};
|
|
||||||
is_bitfield(desc_flags);
|
|
||||||
|
|
||||||
} // namespace bootproto
|
} // namespace bootproto
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <util/bitset.h>
|
||||||
#include <util/counted.h>
|
#include <util/counted.h>
|
||||||
#include <util/enum_bitfields.h>
|
|
||||||
|
|
||||||
namespace bootproto {
|
namespace bootproto {
|
||||||
|
|
||||||
@@ -18,19 +18,13 @@ constexpr uint64_t header_magic = 0x4c454e52454b366aull; // 'j6KERNEL'
|
|||||||
constexpr uint16_t header_version = 2;
|
constexpr uint16_t header_version = 2;
|
||||||
constexpr uint16_t min_header_version = 2;
|
constexpr uint16_t min_header_version = 2;
|
||||||
|
|
||||||
enum class section_flags : uint32_t {
|
enum class section_flags { none, execute, write, read };
|
||||||
none = 0,
|
|
||||||
execute = 1,
|
|
||||||
write = 2,
|
|
||||||
read = 4,
|
|
||||||
};
|
|
||||||
is_bitfield(section_flags);
|
|
||||||
|
|
||||||
struct program_section {
|
struct program_section {
|
||||||
uintptr_t phys_addr;
|
uintptr_t phys_addr;
|
||||||
uintptr_t virt_addr;
|
uintptr_t virt_addr;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
section_flags type;
|
util::bitset32 type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct program {
|
struct program {
|
||||||
@@ -112,18 +106,13 @@ struct frame_block
|
|||||||
uint64_t *bitmap;
|
uint64_t *bitmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class boot_flags : uint16_t {
|
enum class boot_flags { none, debug, test };
|
||||||
none = 0x0000,
|
|
||||||
debug = 0x0001,
|
|
||||||
test = 0x0002,
|
|
||||||
};
|
|
||||||
is_bitfield(boot_flags);
|
|
||||||
|
|
||||||
struct args
|
struct args
|
||||||
{
|
{
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
boot_flags flags;
|
util::bitset16 flags;
|
||||||
|
|
||||||
void *pml4;
|
void *pml4;
|
||||||
util::counted<void> page_tables;
|
util::counted<void> page_tables;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ enum class feature {
|
|||||||
max
|
max
|
||||||
};
|
};
|
||||||
|
|
||||||
using features = util::bitset<(unsigned)feature::max>;
|
using features = util::sized_bitset<(unsigned)feature::max>;
|
||||||
|
|
||||||
class cpu_id
|
class cpu_id
|
||||||
{
|
{
|
||||||
|
|||||||
11
src/libraries/edit/edit.module
Normal file
11
src/libraries/edit/edit.module
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# vim: ft=python
|
||||||
|
|
||||||
|
module("edit",
|
||||||
|
kind = "lib",
|
||||||
|
deps = [ "j6", "libc" ],
|
||||||
|
sources = [
|
||||||
|
"line.cpp",
|
||||||
|
],
|
||||||
|
public_headers = [
|
||||||
|
"edit/line.h",
|
||||||
|
])
|
||||||
34
src/libraries/edit/include/edit/line.h
Normal file
34
src/libraries/edit/include/edit/line.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file line.h
|
||||||
|
/// Declaration of line-based editing class
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <util/api.h>
|
||||||
|
|
||||||
|
namespace edit {
|
||||||
|
|
||||||
|
class API source
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual size_t read(char const **data) = 0;
|
||||||
|
virtual void consume(size_t size) = 0;
|
||||||
|
virtual void write(char const *data, size_t len) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class API line
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
line(source &s);
|
||||||
|
~line();
|
||||||
|
|
||||||
|
/// Get a finished line from the editor.
|
||||||
|
size_t read(char *buffer, size_t size, char const *prompt = nullptr, size_t prompt_len = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t parse_command(char const *data, size_t len);
|
||||||
|
|
||||||
|
source &m_source;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace edit
|
||||||
111
src/libraries/edit/line.cpp
Normal file
111
src/libraries/edit/line.cpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
#include <edit/line.h>
|
||||||
|
#include <j6/memutils.h>
|
||||||
|
#include <j6/syslog.hh>
|
||||||
|
|
||||||
|
static inline size_t min(size_t a, size_t b) { return a > b ? a : b; }
|
||||||
|
|
||||||
|
namespace edit {
|
||||||
|
|
||||||
|
static constexpr char ESC = '\x1b';
|
||||||
|
static constexpr char BACKSPACE = '\x08';
|
||||||
|
static constexpr char DEL = '\x7f';
|
||||||
|
|
||||||
|
static const char init_line[] = "\x1b[999D\x1b[K";
|
||||||
|
static const size_t init_line_len = sizeof(init_line) - 1;
|
||||||
|
|
||||||
|
static const char get_pos[] = "\x1b[n";
|
||||||
|
static const size_t get_pos_len = sizeof(get_pos) - 1;
|
||||||
|
|
||||||
|
static const char backspace[] = "\x1b[D\x1b[K";
|
||||||
|
static const size_t backspace_len = sizeof(backspace) - 1;
|
||||||
|
|
||||||
|
line::line(source &s) :
|
||||||
|
m_source {s}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
line::~line()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
line::read(char *buffer, size_t size, char const *prompt, size_t prompt_len)
|
||||||
|
{
|
||||||
|
m_source.write(init_line, init_line_len);
|
||||||
|
if (prompt && prompt_len)
|
||||||
|
m_source.write(prompt, prompt_len);
|
||||||
|
|
||||||
|
size_t in = 0;
|
||||||
|
|
||||||
|
while (in < size) {
|
||||||
|
char const *input = nullptr;
|
||||||
|
size_t inlen = m_source.read(&input);
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
size_t sub_len = 0;
|
||||||
|
while (i < inlen) {
|
||||||
|
switch (input[i]) {
|
||||||
|
case ESC:
|
||||||
|
sub_len = parse_command(input + i, inlen - i);
|
||||||
|
if (!sub_len)
|
||||||
|
goto reread;
|
||||||
|
i += sub_len;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BACKSPACE:
|
||||||
|
case DEL:
|
||||||
|
if (in > 0) {
|
||||||
|
--in;
|
||||||
|
m_source.write(backspace, backspace_len);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
m_source.consume(++i);
|
||||||
|
m_source.write("\n", 1);
|
||||||
|
buffer[in] = 0;
|
||||||
|
return in;
|
||||||
|
|
||||||
|
default:
|
||||||
|
m_source.write(input + i, 1);
|
||||||
|
buffer[in++] = input[i++];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reread:
|
||||||
|
m_source.consume(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
line::parse_command(char const *data, size_t len)
|
||||||
|
{
|
||||||
|
size_t i = 2;
|
||||||
|
|
||||||
|
char buf[60];
|
||||||
|
char *p = buf;
|
||||||
|
|
||||||
|
while (i < len) {
|
||||||
|
if ((data[i] >= '0' && data[i] <= '9') || data[i] == ';') {
|
||||||
|
*p++ = data[i];
|
||||||
|
} else {
|
||||||
|
*p++ = data[i];
|
||||||
|
*p = 0;
|
||||||
|
j6::syslog(j6::logs::app, j6::log_level::verbose,
|
||||||
|
"line edit got command: ESC[%s", buf);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace line
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/enum_bitfields.h>
|
#include <util/bitset.h>
|
||||||
|
|
||||||
namespace elf {
|
namespace elf {
|
||||||
|
|
||||||
@@ -54,19 +54,12 @@ struct file_header
|
|||||||
|
|
||||||
|
|
||||||
enum class segment_type : uint32_t { null, load, dynamic, interpreter, note };
|
enum class segment_type : uint32_t { null, load, dynamic, interpreter, note };
|
||||||
enum class segment_flags : uint32_t
|
enum class segment_flags { exec, write, read };
|
||||||
{
|
|
||||||
none = 0x00,
|
|
||||||
exec = 0x01,
|
|
||||||
write = 0x02,
|
|
||||||
read = 0x04,
|
|
||||||
};
|
|
||||||
is_bitfield(segment_flags);
|
|
||||||
|
|
||||||
struct segment_header
|
struct segment_header
|
||||||
{
|
{
|
||||||
segment_type type;
|
segment_type type;
|
||||||
segment_flags flags;
|
util::bitset32 flags;
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
|
|
||||||
uint64_t vaddr;
|
uint64_t vaddr;
|
||||||
@@ -80,18 +73,13 @@ struct segment_header
|
|||||||
|
|
||||||
|
|
||||||
enum class section_type : uint32_t { null, progbits };
|
enum class section_type : uint32_t { null, progbits };
|
||||||
enum class section_flags : uint64_t
|
enum class section_flags { write, alloc, exec };
|
||||||
{
|
|
||||||
write = 0x01,
|
|
||||||
alloc = 0x02,
|
|
||||||
exec = 0x04,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct section_header
|
struct section_header
|
||||||
{
|
{
|
||||||
uint32_t name_offset;
|
uint32_t name_offset;
|
||||||
section_type type;
|
section_type type;
|
||||||
section_flags flags;
|
util::bitset64 flags;
|
||||||
uint64_t addr;
|
uint64_t addr;
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
@@ -102,5 +90,3 @@ struct section_header
|
|||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
} // namespace elf
|
} // namespace elf
|
||||||
|
|
||||||
is_bitfield(elf::section_flags);
|
|
||||||
|
|||||||
@@ -12,136 +12,180 @@
|
|||||||
#include <j6/syscalls.h>
|
#include <j6/syscalls.h>
|
||||||
#include <j6/syslog.hh>
|
#include <j6/syslog.hh>
|
||||||
#include <util/spinlock.h>
|
#include <util/spinlock.h>
|
||||||
|
#include <util/bip_buffer.h>
|
||||||
|
#include <util/new.h>
|
||||||
|
|
||||||
namespace j6 {
|
namespace j6 {
|
||||||
|
|
||||||
static uintptr_t channel_addr = 0x6000'0000;
|
struct channel_memory_area
|
||||||
static util::spinlock addr_spinlock;
|
|
||||||
|
|
||||||
struct channel::header
|
|
||||||
{
|
{
|
||||||
size_t size;
|
j6::mutex mutex;
|
||||||
size_t read_index;
|
j6::condition waiting;
|
||||||
size_t write_index;
|
util::bip_buffer buf;
|
||||||
|
|
||||||
mutex mutex;
|
|
||||||
condition read_waiting;
|
|
||||||
condition write_waiting;
|
|
||||||
|
|
||||||
uint8_t data[0];
|
|
||||||
|
|
||||||
inline const void* read_at() const { return &data[read_index & (size - 1)]; }
|
|
||||||
inline void* write_at() { return &data[write_index & (size - 1)]; }
|
|
||||||
|
|
||||||
inline size_t read_avail() const { return write_index - read_index; }
|
|
||||||
inline size_t write_avail() const { return size - read_avail(); }
|
|
||||||
|
|
||||||
inline void consume(size_t n) { read_index += n; }
|
|
||||||
inline void commit(size_t n) { write_index += n; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
channel *
|
|
||||||
channel::create(size_t size)
|
static bool
|
||||||
|
check_channel_size(size_t s)
|
||||||
{
|
{
|
||||||
j6_status_t result;
|
if (s < arch::frame_size || (s & (s - 1)) != 0) {
|
||||||
j6_handle_t vma = j6_handle_invalid;
|
syslog(j6::logs::ipc, j6::log_level::error, "Bad channel size: %lx", s);
|
||||||
|
return false;
|
||||||
if (size < arch::frame_size || (size & (size - 1)) != 0) {
|
}
|
||||||
syslog("Bad channel size: %lx", size);
|
return true;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
util::scoped_lock lock {addr_spinlock};
|
|
||||||
uintptr_t addr = channel_addr;
|
|
||||||
channel_addr += size * 2; // account for ring buffer virtual space doubling
|
|
||||||
lock.release();
|
|
||||||
|
|
||||||
result = j6_vma_create_map(&vma, size, &addr, j6_vm_flag_write|j6_vm_flag_ring);
|
static uintptr_t
|
||||||
|
create_channel_vma(j6_handle_t &vma, size_t size)
|
||||||
|
{
|
||||||
|
uintptr_t addr = 0;
|
||||||
|
j6_status_t result = j6_vma_create_map(&vma, size, &addr, j6_vm_flag_write);
|
||||||
if (result != j6_status_ok) {
|
if (result != j6_status_ok) {
|
||||||
syslog("Failed to create channel VMA. Error: %lx", result);
|
syslog(j6::logs::ipc, j6::log_level::error, "Failed to create channel VMA. Error: %lx", result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
syslog(j6::logs::ipc, j6::log_level::verbose, "Created channel VMA at 0x%lx size 0x%lx", addr, size);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_channel_memory_area(channel_memory_area *area, size_t size)
|
||||||
|
{
|
||||||
|
new (&area->mutex) j6::mutex;
|
||||||
|
new (&area->waiting) j6::condition;
|
||||||
|
new (&area->buf) util::bip_buffer {size - sizeof(*area)};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
channel *
|
||||||
|
channel::create(size_t tx_size, size_t rx_size)
|
||||||
|
{
|
||||||
|
if (!rx_size)
|
||||||
|
rx_size = tx_size;
|
||||||
|
|
||||||
|
if (!check_channel_size(tx_size) || !check_channel_size(rx_size))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
j6_status_t result;
|
||||||
|
j6_handle_t tx_vma = j6_handle_invalid;
|
||||||
|
j6_handle_t rx_vma = j6_handle_invalid;
|
||||||
|
|
||||||
|
uintptr_t tx_addr = create_channel_vma(tx_vma, tx_size);
|
||||||
|
if (!tx_addr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
uintptr_t rx_addr = create_channel_vma(rx_vma, rx_size);
|
||||||
|
if (!rx_addr) {
|
||||||
|
j6_vma_unmap(tx_vma, 0);
|
||||||
|
j6_handle_close(tx_vma);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
header *h = reinterpret_cast<header*>(addr);
|
channel_memory_area *tx = reinterpret_cast<channel_memory_area*>(tx_addr);
|
||||||
memset(h, 0, sizeof(*h));
|
channel_memory_area *rx = reinterpret_cast<channel_memory_area*>(rx_addr);
|
||||||
h->size = size;
|
init_channel_memory_area(tx, tx_size);
|
||||||
|
init_channel_memory_area(rx, rx_size);
|
||||||
|
|
||||||
return new channel {vma, h};
|
j6::syslog(logs::ipc, log_level::info, "Created new channel with handles {%x, %x}", tx_vma, rx_vma);
|
||||||
|
|
||||||
|
return new channel {{tx_vma, rx_vma}, *tx, *rx};
|
||||||
}
|
}
|
||||||
|
|
||||||
channel *
|
channel *
|
||||||
channel::open(j6_handle_t vma)
|
channel::open(const channel_def &def)
|
||||||
{
|
{
|
||||||
j6_status_t result;
|
j6_status_t result;
|
||||||
|
|
||||||
util::scoped_lock lock {addr_spinlock};
|
uintptr_t tx_addr = 0;
|
||||||
uintptr_t addr = channel_addr;
|
result = j6_vma_map(def.tx, 0, &tx_addr, 0);
|
||||||
|
|
||||||
result = j6_vma_map(vma, 0, &addr, 0);
|
|
||||||
if (result != j6_status_ok) {
|
if (result != j6_status_ok) {
|
||||||
syslog("Failed to map channel VMA. Error: %lx", result);
|
syslog(j6::logs::ipc, j6::log_level::error, "Failed to map channel VMA. Error: %lx", result);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
header *h = reinterpret_cast<header*>(addr);
|
uintptr_t rx_addr = 0;
|
||||||
channel_addr += h->size;
|
result = j6_vma_map(def.rx, 0, &rx_addr, 0);
|
||||||
lock.release();
|
if (result != j6_status_ok) {
|
||||||
|
j6_vma_unmap(def.tx, 0);
|
||||||
return new channel {vma, h};
|
j6_handle_close(def.tx);
|
||||||
|
syslog(j6::logs::ipc, j6::log_level::error, "Failed to map channel VMA. Error: %lx", result);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
channel::channel(j6_handle_t vma, header *h) :
|
channel_memory_area *tx = reinterpret_cast<channel_memory_area*>(tx_addr);
|
||||||
m_vma {vma},
|
channel_memory_area *rx = reinterpret_cast<channel_memory_area*>(rx_addr);
|
||||||
m_size {h->size},
|
|
||||||
m_header {h}
|
j6::syslog(logs::ipc, log_level::info, "Opening existing channel with handles {%x:0x%lx, %x:0x%lx}", def.tx, tx, def.rx, rx);
|
||||||
|
return new channel { def, *tx, *rx };
|
||||||
|
}
|
||||||
|
|
||||||
|
channel::channel(
|
||||||
|
const channel_def &def,
|
||||||
|
channel_memory_area &tx,
|
||||||
|
channel_memory_area &rx) :
|
||||||
|
m_def {def},
|
||||||
|
m_tx {tx},
|
||||||
|
m_rx {rx}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
|
||||||
channel::send(const void *buffer, size_t len, bool block)
|
size_t
|
||||||
|
channel::reserve(size_t size, uint8_t **area, bool block)
|
||||||
{
|
{
|
||||||
if (len > m_header->size)
|
if (size > m_tx.buf.buffer_size())
|
||||||
return j6_err_insufficient;
|
return j6_err_insufficient;
|
||||||
|
|
||||||
j6::scoped_lock lock {m_header->mutex};
|
j6::scoped_lock lock {m_tx.mutex};
|
||||||
while (m_header->write_avail() < len) {
|
while (m_tx.buf.write_available() < size) {
|
||||||
if (!block)
|
if (!block) return 0;
|
||||||
return j6_status_would_block;
|
|
||||||
|
|
||||||
lock.release();
|
lock.release();
|
||||||
m_header->write_waiting.wait();
|
m_tx.waiting.wait();
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(m_header->write_at(), buffer, len);
|
return m_tx.buf.reserve(size, area);
|
||||||
m_header->commit(len);
|
|
||||||
m_header->read_waiting.wake();
|
|
||||||
|
|
||||||
return j6_status_ok;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
j6_status_t
|
void
|
||||||
channel::receive(void *buffer, size_t *size, bool block)
|
channel::commit(size_t size)
|
||||||
{
|
{
|
||||||
j6::scoped_lock lock {m_header->mutex};
|
j6::scoped_lock lock {m_tx.mutex};
|
||||||
while (!m_header->read_avail()) {
|
m_tx.buf.commit(size);
|
||||||
if (!block)
|
if (!size) return;
|
||||||
return j6_status_would_block;
|
|
||||||
|
m_tx.waiting.wake();
|
||||||
|
j6::syslog(logs::ipc, log_level::spam,
|
||||||
|
"Sending %d bytes to channel on {%x}", size, m_def.tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
channel::get_block(uint8_t const **area, bool block) const
|
||||||
|
{
|
||||||
|
j6::scoped_lock lock {m_rx.mutex};
|
||||||
|
while (!m_rx.buf.size()) {
|
||||||
|
if (!block) return 0;
|
||||||
|
|
||||||
lock.release();
|
lock.release();
|
||||||
m_header->read_waiting.wait();
|
m_rx.waiting.wait();
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t avail = m_header->read_avail();
|
return m_rx.buf.get_block(area);
|
||||||
size_t read = *size > avail ? avail : *size;
|
}
|
||||||
|
|
||||||
memcpy(buffer, m_header->read_at(), read);
|
void
|
||||||
m_header->consume(read);
|
channel::consume(size_t size)
|
||||||
m_header->write_waiting.wake();
|
{
|
||||||
|
j6::scoped_lock lock {m_tx.mutex};
|
||||||
|
m_rx.buf.consume(size);
|
||||||
|
if (!size) return;
|
||||||
|
|
||||||
*size = read;
|
m_rx.waiting.wake();
|
||||||
return j6_status_ok;
|
j6::syslog(logs::ipc, log_level::spam,
|
||||||
|
"Read %d bytes from channel on {%x}", size, m_def.rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace j6
|
} // namespace j6
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace j6 {
|
|||||||
void
|
void
|
||||||
condition::wait()
|
condition::wait()
|
||||||
{
|
{
|
||||||
j6::syslog("Waiting on condition %lx", this);
|
j6::syslog(j6::logs::app, j6::log_level::verbose, "Waiting on condition %lx", this);
|
||||||
uint32_t v = __atomic_add_fetch(&m_state, 1, __ATOMIC_ACQ_REL);
|
uint32_t v = __atomic_add_fetch(&m_state, 1, __ATOMIC_ACQ_REL);
|
||||||
j6_status_t s = j6_futex_wait(&m_state, v, 0);
|
j6_status_t s = j6_futex_wait(&m_state, v, 0);
|
||||||
while (s == j6_status_futex_changed) {
|
while (s == j6_status_futex_changed) {
|
||||||
@@ -20,7 +20,7 @@ condition::wait()
|
|||||||
if (v == 0) break;
|
if (v == 0) break;
|
||||||
s = j6_futex_wait(&m_state, v, 0);
|
s = j6_futex_wait(&m_state, v, 0);
|
||||||
}
|
}
|
||||||
j6::syslog("Woke on condition %lx", this);
|
j6::syslog(j6::logs::app, j6::log_level::verbose, "Woke on condition %lx", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -10,41 +10,66 @@
|
|||||||
#include <j6/types.h>
|
#include <j6/types.h>
|
||||||
#include <util/api.h>
|
#include <util/api.h>
|
||||||
|
|
||||||
|
namespace util {
|
||||||
|
class bip_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
namespace j6 {
|
namespace j6 {
|
||||||
|
|
||||||
|
/// Descriptor of VMAs for a channel.
|
||||||
|
struct channel_def
|
||||||
|
{
|
||||||
|
j6_handle_t tx;
|
||||||
|
j6_handle_t rx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct channel_memory_area;
|
||||||
|
|
||||||
class API channel
|
class API channel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Create a new channel of the given size.
|
/// Create a new channel.
|
||||||
static channel * create(size_t size);
|
/// \arg tx_size Size of the transmit buffer (sending from this thread)
|
||||||
|
/// \arg rx_size Size of the receive buffer (sending from remote thread),
|
||||||
|
/// or 0 for equal sized buffers.
|
||||||
|
static channel * create(size_t tx_size, size_t rx_size = 0);
|
||||||
|
|
||||||
/// Open an existing channel for which we have a VMA handle
|
/// Open an existing channel for which we have VMA handles
|
||||||
static channel * open(j6_handle_t vma);
|
static channel * open(const channel_def &def);
|
||||||
|
|
||||||
/// Send data into the channel.
|
/// Reserve an area of the output buffer for a write.
|
||||||
/// \arg buffer The buffer from which to read data
|
/// \arg size Requested size, in bytes
|
||||||
/// \arg len The number of bytes to read from `buffer`
|
/// \arg area [out] Pointer to returned area
|
||||||
/// \arg block If true, block this thread if there aren't `len` bytes of space available
|
/// \arg block If true, block this thread until there are size bytes free
|
||||||
j6_status_t send(const void *buffer, size_t len, bool block = true);
|
/// \returns Size of returned area, in bytes, or 0 on failure
|
||||||
|
size_t reserve(size_t size, uint8_t **area, bool block = true);
|
||||||
|
|
||||||
/// Read data out of the channel.
|
/// Commit a pending write started by reserve()
|
||||||
/// \arg buffer The buffer to receive channel data
|
/// \arg size Amount of data used, in bytes
|
||||||
/// \arg size [in] The size of `buffer` [out] the amount read into `buffer`
|
void commit(size_t size);
|
||||||
/// \arg block If true, block this thread if there is no data to read yet
|
|
||||||
j6_status_t receive(void *buffer, size_t *size, bool block = true);
|
|
||||||
|
|
||||||
/// Get the VMA handle for sharing with other processes
|
/// Get a pointer to a block of data in the buffer.
|
||||||
j6_handle_t handle() const { return m_vma; }
|
/// \arg area [out] Pointer to the retuned area
|
||||||
|
/// \arg block If true, block this thread until there is data available
|
||||||
|
/// \returns Size of the returned area, in bytes
|
||||||
|
size_t get_block(uint8_t const **area, bool block = true) const;
|
||||||
|
|
||||||
|
/// Mark a number of bytes as consumed, freeing buffer space
|
||||||
|
/// \arg size Number of bytes to consume
|
||||||
|
void consume(size_t size);
|
||||||
|
|
||||||
|
/// Get the channel_def for creating the remote end
|
||||||
|
inline channel_def remote_def() const { return {m_def.rx, m_def.tx}; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct header;
|
channel(
|
||||||
|
const channel_def &def,
|
||||||
|
channel_memory_area &tx,
|
||||||
|
channel_memory_area &rx);
|
||||||
|
|
||||||
channel(j6_handle_t vma, header *h);
|
channel_def m_def;
|
||||||
|
channel_memory_area &m_tx;
|
||||||
j6_handle_t m_vma;
|
channel_memory_area &m_rx;
|
||||||
|
|
||||||
size_t m_size;
|
|
||||||
header *m_header;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace j6
|
} // namespace j6
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
/// Enums used as flags for syscalls
|
/// Enums used as flags for syscalls
|
||||||
|
|
||||||
enum j6_vm_flags {
|
enum j6_vm_flags {
|
||||||
#define VM_FLAG(name, v) j6_vm_flag_ ## name = v,
|
j6_vm_flag_none = 0,
|
||||||
|
#define VM_FLAG(name, v) j6_vm_flag_ ## name = (1ul << v),
|
||||||
#include <j6/tables/vm_flags.inc>
|
#include <j6/tables/vm_flags.inc>
|
||||||
#undef VM_FLAG
|
#undef VM_FLAG
|
||||||
j6_vm_flag_MAX
|
j6_vm_flag_MAX
|
||||||
|
|||||||
@@ -12,44 +12,53 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
enum j6_aux_type {
|
||||||
#define add_header(name) \
|
// The SysV ABI-specified aux vector types
|
||||||
static constexpr j6_arg_type type_id = j6_arg_type_ ## name; \
|
j6_aux_null, // AT_NULL
|
||||||
j6_arg_header header;
|
j6_aux_ignore, // AT_IGNORE
|
||||||
#else
|
j6_aux_execfd, // AD_EXECFD - File descriptor of the exe to load
|
||||||
#define add_header(name) \
|
j6_aux_phdr, // AD_PHDR - Program headers pointer for the exe to load
|
||||||
j6_arg_header header;
|
j6_aux_phent, // AD_PHENT - Size of a program header entry
|
||||||
#endif
|
j6_aux_phnum, // AD_PHNUM - Number of program header entries
|
||||||
|
j6_aux_pagesz, // AD_PAGESZ - System page size
|
||||||
|
j6_aux_base, // AD_BASE - Base address of dynamic loader
|
||||||
|
j6_aux_flags, // AD_FLAGS - Flags
|
||||||
|
j6_aux_entry, // AD_ENTRY - Entrypoint for the exe to load
|
||||||
|
j6_aux_notelf, // AD_NOTELF - If non-zero, this program is not ELF
|
||||||
|
j6_aux_uid, // AD_UID - User ID
|
||||||
|
j6_aux_euid, // AD_EUID - Effective User ID
|
||||||
|
j6_aux_gid, // AD_GID - Group ID
|
||||||
|
j6_aux_egid, // AD_EGID - Effective Group ID
|
||||||
|
|
||||||
enum j6_arg_type {
|
j6_aux_start = 0xf000,
|
||||||
j6_arg_type_none,
|
j6_aux_handles, // Pointer to a j6_arg_handles structure
|
||||||
j6_arg_type_sysv_init,
|
j6_aux_device, // Pointer to a j6_arg_driver structure
|
||||||
j6_arg_type_loader,
|
j6_aux_loader, // Pointer to a j6_arg_loader structure
|
||||||
j6_arg_type_driver,
|
|
||||||
j6_arg_type_handles,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct j6_arg_header
|
struct j6_aux
|
||||||
{
|
{
|
||||||
uint32_t size;
|
uint64_t type;
|
||||||
uint16_t type;
|
union {
|
||||||
|
uint64_t value;
|
||||||
|
void *pointer;
|
||||||
|
void (*func)();
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct j6_arg_loader
|
struct j6_arg_loader
|
||||||
{
|
{
|
||||||
add_header(loader);
|
|
||||||
uintptr_t loader_base;
|
uintptr_t loader_base;
|
||||||
uintptr_t image_base;
|
uintptr_t image_base;
|
||||||
uintptr_t *got;
|
uintptr_t *got;
|
||||||
uintptr_t entrypoint;
|
uintptr_t entrypoint;
|
||||||
uintptr_t start_addr;
|
uintptr_t start_addr;
|
||||||
uintptr_t other;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct j6_arg_driver
|
struct j6_arg_driver
|
||||||
{
|
{
|
||||||
add_header(driver);
|
|
||||||
uint64_t device;
|
uint64_t device;
|
||||||
|
uint32_t size;
|
||||||
uint8_t data [0];
|
uint8_t data [0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -61,29 +70,13 @@ struct j6_arg_handle_entry
|
|||||||
|
|
||||||
struct j6_arg_handles
|
struct j6_arg_handles
|
||||||
{
|
{
|
||||||
add_header(handles);
|
|
||||||
size_t nhandles;
|
size_t nhandles;
|
||||||
j6_arg_handle_entry handles[0];
|
j6_arg_handle_entry handles[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct j6_init_args
|
/// Find the first handle tagged with the given proto in the process init args
|
||||||
{
|
j6_handle_t API j6_find_init_handle(uint64_t proto);
|
||||||
uint64_t args[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Find the first handle of the given type held by this process
|
|
||||||
j6_handle_t API j6_find_first_handle(j6_object_type obj_type);
|
|
||||||
|
|
||||||
/// Get the init args
|
|
||||||
const j6_init_args * j6_get_init_args();
|
|
||||||
|
|
||||||
/// Drivers may use driver_main instead of main
|
|
||||||
int driver_main(unsigned, const char **, const char **, const j6_init_args *);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef add_header
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <j6/protocols/service_locator.h>
|
#include <j6/protocols/service_locator.h>
|
||||||
#include <j6/types.h>
|
#include <j6/types.h>
|
||||||
#include <util/api.h>
|
#include <util/api.h>
|
||||||
|
#include <util/counted.h>
|
||||||
|
|
||||||
namespace j6::proto::sl {
|
namespace j6::proto::sl {
|
||||||
|
|
||||||
@@ -13,13 +14,13 @@ public:
|
|||||||
|
|
||||||
/// Register a handle as a service with the locator.
|
/// Register a handle as a service with the locator.
|
||||||
/// \arg proto_id The protocol this handle supports
|
/// \arg proto_id The protocol this handle supports
|
||||||
/// \arg handle The mailbox or channel handle
|
/// \arg handles The mailbox or channel handles
|
||||||
j6_status_t register_service(uint64_t proto_id, j6_handle_t handle);
|
j6_status_t register_service(uint64_t proto_id, util::counted<j6_handle_t> handles);
|
||||||
|
|
||||||
/// Look up a handle with the locator service.
|
/// Look up a handle with the locator service.
|
||||||
/// \arg proto_id The protocol to look for
|
/// \arg proto_id The protocol to look for
|
||||||
/// \arg handle [out] The mailbox or channel handle
|
/// \arg handles [out] The mailbox or channel handles
|
||||||
j6_status_t lookup_service(uint64_t proto_id, j6_handle_t &handle);
|
j6_status_t lookup_service(uint64_t proto_id, util::counted<j6_handle_t> &handles);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
j6_handle_t m_service;
|
j6_handle_t m_service;
|
||||||
|
|||||||
@@ -8,4 +8,6 @@ enum j6_proto_vfs_tag
|
|||||||
{
|
{
|
||||||
j6_proto_vfs_load = j6_proto_base_first_proto_id,
|
j6_proto_vfs_load = j6_proto_base_first_proto_id,
|
||||||
j6_proto_vfs_file,
|
j6_proto_vfs_file,
|
||||||
|
j6_proto_vfs_get_tag,
|
||||||
|
j6_proto_vfs_tag,
|
||||||
};
|
};
|
||||||
@@ -13,7 +13,13 @@ class API client
|
|||||||
public:
|
public:
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
/// \arg vfs_mb Handle to the VFS service's mailbox
|
/// \arg vfs_mb Handle to the VFS service's mailbox
|
||||||
client(j6_handle_t vfs_mb);
|
client(j6_handle_t vfs_mb = 0);
|
||||||
|
|
||||||
|
/// Copy constructor
|
||||||
|
client(const client& c);
|
||||||
|
|
||||||
|
/// Check if this client's handle is valid
|
||||||
|
inline bool valid() const { return m_service != j6_handle_invalid; }
|
||||||
|
|
||||||
/// Load a file into a VMA
|
/// Load a file into a VMA
|
||||||
/// \arg path Path of the file to load
|
/// \arg path Path of the file to load
|
||||||
@@ -21,6 +27,11 @@ public:
|
|||||||
/// \arg size [out] Size of the file
|
/// \arg size [out] Size of the file
|
||||||
j6_status_t load_file(char *path, j6_handle_t &vma, size_t &size);
|
j6_status_t load_file(char *path, j6_handle_t &vma, size_t &size);
|
||||||
|
|
||||||
|
/// Get fs tag
|
||||||
|
/// \arg tag [out] The filesystem's tag
|
||||||
|
/// \arg size [inout] Size of the input buffer, length of the returned string
|
||||||
|
j6_status_t get_tag(char *tag, size_t &len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
j6_handle_t m_service;
|
j6_handle_t m_service;
|
||||||
};
|
};
|
||||||
|
|||||||
55
src/libraries/j6/include/j6/ring_buffer.hh
Normal file
55
src/libraries/j6/include/j6/ring_buffer.hh
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
/// \file j6/ring_buffer.hh
|
||||||
|
/// Helper class for managing ring buffers in doubly-mapped VMAs
|
||||||
|
|
||||||
|
// The kernel depends on libj6 for some shared code,
|
||||||
|
// but should not include the user-specific code.
|
||||||
|
#ifndef __j6kernel
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <j6/types.h>
|
||||||
|
#include <util/api.h>
|
||||||
|
|
||||||
|
namespace j6 {
|
||||||
|
|
||||||
|
API class ring_buffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ring_buffer(size_t pages);
|
||||||
|
|
||||||
|
inline bool valid() const { return m_data != nullptr; }
|
||||||
|
inline size_t size() const { return 1<<m_bits; }
|
||||||
|
inline size_t used() const { return m_write-m_read; }
|
||||||
|
inline size_t free() const { return size()-used(); }
|
||||||
|
|
||||||
|
inline const char * read_ptr() const { return get(m_read); }
|
||||||
|
inline char * write_ptr() { return get(m_write); }
|
||||||
|
|
||||||
|
inline void commit(size_t &n) {
|
||||||
|
if (n > free()) n = free();
|
||||||
|
m_write += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char * consume(size_t &n) {
|
||||||
|
if (n > used()) n = used();
|
||||||
|
size_t i = m_read;
|
||||||
|
m_read += n;
|
||||||
|
return get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline size_t mask() const { return (1<<m_bits)-1;}
|
||||||
|
inline size_t index(size_t i) const { return i & mask(); }
|
||||||
|
|
||||||
|
inline char * get(size_t i) { return m_data + index(i); }
|
||||||
|
inline const char * get(size_t i) const { return m_data + index(i); }
|
||||||
|
|
||||||
|
size_t m_bits;
|
||||||
|
size_t m_write;
|
||||||
|
size_t m_read;
|
||||||
|
j6_handle_t m_vma;
|
||||||
|
char *m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace j6
|
||||||
|
#endif // __j6kernel
|
||||||
|
|
||||||
@@ -2,15 +2,26 @@
|
|||||||
/// \file j6/syslog.hh
|
/// \file j6/syslog.hh
|
||||||
/// Utility function for writing messages to the kernel log
|
/// Utility function for writing messages to the kernel log
|
||||||
|
|
||||||
#include <util/api.h>
|
|
||||||
|
|
||||||
// The kernel depends on libj6 for some shared code,
|
// The kernel depends on libj6 for some shared code,
|
||||||
// but should not include the user-specific code.
|
// but should not include the user-specific code.
|
||||||
#ifndef __j6kernel
|
#ifndef __j6kernel
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <util/api.h>
|
||||||
|
|
||||||
namespace j6 {
|
namespace j6 {
|
||||||
|
|
||||||
void API syslog(const char *fmt, ...);
|
enum class logs : uint8_t {
|
||||||
|
#define LOG(name, lvl) name,
|
||||||
|
#include <j6/tables/log_areas.inc>
|
||||||
|
#undef LOG
|
||||||
|
COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class log_level : uint8_t {
|
||||||
|
silent, fatal, error, warn, info, verbose, spam, max
|
||||||
|
};
|
||||||
|
|
||||||
|
void API syslog(logs area, log_level severity, const char *fmt, ...);
|
||||||
|
|
||||||
} // namespace j6
|
} // namespace j6
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
LOG(apic, info)
|
LOG(apic, info)
|
||||||
LOG(boot, info)
|
LOG(boot, info)
|
||||||
LOG(device, spam)
|
LOG(device, info)
|
||||||
LOG(irq, info)
|
LOG(irq, info)
|
||||||
LOG(memory, info)
|
LOG(memory, info)
|
||||||
LOG(objs, info)
|
LOG(objs, info)
|
||||||
@@ -9,3 +9,7 @@ LOG(sched, info)
|
|||||||
LOG(syscall,info)
|
LOG(syscall,info)
|
||||||
LOG(task, verbose)
|
LOG(task, verbose)
|
||||||
LOG(timer, info)
|
LOG(timer, info)
|
||||||
|
LOG(ipc, spam)
|
||||||
|
LOG(app, spam)
|
||||||
|
LOG(proto, spam)
|
||||||
|
LOG(srv, info)
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
VM_FLAG( none, 0x00000000 )
|
VM_FLAG( write, 0 )
|
||||||
|
VM_FLAG( exec, 1 )
|
||||||
|
|
||||||
VM_FLAG( write, 0x00000001 )
|
VM_FLAG( contiguous, 4 )
|
||||||
VM_FLAG( exec, 0x00000002 )
|
VM_FLAG( large_pages, 5 )
|
||||||
|
VM_FLAG( huge_pages, 6 )
|
||||||
|
|
||||||
VM_FLAG( contiguous, 0x00000010 )
|
VM_FLAG( write_combine, 8 )
|
||||||
VM_FLAG( large_pages, 0x00000020 )
|
|
||||||
VM_FLAG( huge_pages, 0x00000040 )
|
|
||||||
|
|
||||||
VM_FLAG( write_combine, 0x00000100 )
|
VM_FLAG( mmio, 12 )
|
||||||
|
|
||||||
VM_FLAG( mmio, 0x00001000 )
|
VM_FLAG( exact, 16 )
|
||||||
|
VM_FLAG( ring, 17 )
|
||||||
VM_FLAG( exact, 0x00010000 )
|
|
||||||
VM_FLAG( ring, 0x00020000 )
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
// The kernel depends on libj6 for some shared code,
|
// The kernel depends on libj6 for some shared code,
|
||||||
// but should not include the user-specific code.
|
// but should not include the user-specific code.
|
||||||
|
#include "j6/init.h"
|
||||||
|
#include "j6/types.h"
|
||||||
#ifndef __j6kernel
|
#ifndef __j6kernel
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -10,44 +12,45 @@
|
|||||||
#include <j6/types.h>
|
#include <j6/types.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr size_t static_arr_count = 32;
|
char const * const *envp = nullptr;
|
||||||
j6_handle_descriptor handle_array[static_arr_count];
|
const j6_aux *aux = nullptr;
|
||||||
j6_init_args init_args;
|
|
||||||
|
const j6_aux * find_aux(uint64_t type) {
|
||||||
|
if (!aux) return nullptr;
|
||||||
|
for (j6_aux const *p = aux; p->type; ++p)
|
||||||
|
if (p->type == type) return p;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
j6_handle_t
|
j6_handle_t
|
||||||
j6_find_first_handle(j6_object_type obj_type)
|
j6_find_init_handle(uint64_t proto)
|
||||||
{
|
{
|
||||||
size_t count = static_arr_count;
|
const j6_aux *aux_handles = find_aux(j6_aux_handles);
|
||||||
j6_handle_descriptor *handles = handle_array;
|
if (!aux_handles)
|
||||||
j6_status_t s = j6_handle_list(handles, &count);
|
|
||||||
|
|
||||||
if (s != j6_err_insufficient && s != j6_status_ok)
|
|
||||||
return j6_handle_invalid;
|
return j6_handle_invalid;
|
||||||
|
|
||||||
if (count > static_arr_count)
|
const j6_arg_handles *arg = reinterpret_cast<const j6_arg_handles*>(aux_handles->pointer);
|
||||||
count = static_arr_count;
|
for (unsigned i = 0; i < arg->nhandles; ++i) {
|
||||||
|
const j6_arg_handle_entry &ent = arg->handles[i];
|
||||||
for (size_t i = 0; i < count; ++i) {
|
if (ent.proto == proto)
|
||||||
j6_handle_descriptor &desc = handle_array[i];
|
return ent.handle;
|
||||||
if (desc.type == obj_type) return desc.handle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return j6_handle_invalid;
|
return j6_handle_invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const j6_init_args * API
|
|
||||||
j6_get_init_args()
|
|
||||||
{
|
|
||||||
return &init_args;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void API
|
extern "C" void API
|
||||||
__init_libj6(uint64_t arg0, uint64_t arg1)
|
__init_libj6(const uint64_t *stack)
|
||||||
{
|
{
|
||||||
init_args.args[0] = arg0;
|
// Walk the stack to get the aux vector
|
||||||
init_args.args[1] = arg1;
|
uint64_t argc = *stack++;
|
||||||
|
stack += argc + 1; // Skip argv's and sentinel
|
||||||
|
|
||||||
|
envp = reinterpret_cast<char const * const *>(stack);
|
||||||
|
while (*stack++); // Skip envp's and sentinel
|
||||||
|
|
||||||
|
aux = reinterpret_cast<const j6_aux*>(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // __j6kernel
|
#endif // __j6kernel
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
extern driver_main
|
|
||||||
global main:function weak (main.end - main)
|
|
||||||
main:
|
|
||||||
jmp driver_main
|
|
||||||
main.end:
|
|
||||||
|
|
||||||
@@ -8,10 +8,12 @@ j6 = module("j6",
|
|||||||
"condition.cpp",
|
"condition.cpp",
|
||||||
"init.cpp",
|
"init.cpp",
|
||||||
"memutils.cpp",
|
"memutils.cpp",
|
||||||
|
"memutils.s",
|
||||||
"mutex.cpp",
|
"mutex.cpp",
|
||||||
"protocol_ids.cpp",
|
"protocol_ids.cpp",
|
||||||
"protocols/service_locator.cpp",
|
"protocols/service_locator.cpp",
|
||||||
"protocols/vfs.cpp",
|
"protocols/vfs.cpp",
|
||||||
|
"ring_buffer.cpp",
|
||||||
"syscalls.s.cog",
|
"syscalls.s.cog",
|
||||||
"sysconf.cpp.cog",
|
"sysconf.cpp.cog",
|
||||||
"syslog.cpp",
|
"syslog.cpp",
|
||||||
@@ -28,6 +30,7 @@ j6 = module("j6",
|
|||||||
"j6/protocols.h",
|
"j6/protocols.h",
|
||||||
"j6/protocols/service_locator.h",
|
"j6/protocols/service_locator.h",
|
||||||
"j6/protocols/service_locator.hh",
|
"j6/protocols/service_locator.hh",
|
||||||
|
"j6/ring_buffer.hh",
|
||||||
"j6/syscalls.h.cog",
|
"j6/syscalls.h.cog",
|
||||||
"j6/sysconf.h.cog",
|
"j6/sysconf.h.cog",
|
||||||
"j6/syslog.hh",
|
"j6/syslog.hh",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user