diff --git a/.gitignore b/.gitignore
index 050966a..0f1cda1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,4 @@ compile_commands.json
buddy_allocs.txt
frame_allocs.txt
heap_allocs.txt
+/docs/_build
diff --git a/definitions/objects/event.def b/definitions/objects/event.def
index 85e5f5c..7826d7a 100644
--- a/definitions/objects/event.def
+++ b/definitions/objects/event.def
@@ -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 {
uid f441e03da5516b1a
diff --git a/definitions/objects/object.def b/definitions/objects/object.def
index 7b8eb3c..ebe8a27 100644
--- a/definitions/objects/object.def
+++ b/definitions/objects/object.def
@@ -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] {
uid 667f61fb2cd57bb4
cname kobject
diff --git a/definitions/objects/process.def b/definitions/objects/process.def
index 998fce7..770dbe9 100644
--- a/definitions/objects/process.def
+++ b/definitions/objects/process.def
@@ -1,7 +1,7 @@
import "objects/object.def"
-# Processes are a collection of handles and a virtual memory
-# space inside which threads are run.
+# A ``process`` object represents a process running on the system, and allows
+# control over the threads, handles, and virtual memory space of that process.
object process : object {
uid 0c69ee0b7502ba31
diff --git a/definitions/objects/system.def b/definitions/objects/system.def
index adb7aa2..ac0b9cf 100644
--- a/definitions/objects/system.def
+++ b/definitions/objects/system.def
@@ -1,5 +1,6 @@
-# The system object represents a handle to kernel functionality
-# needed by drivers and other priviledged services
+# The singular ``system`` object represents a handle to kernel functionality
+# needed by drivers and other priviledged services.
+
object system : object {
uid fa72506a2cf71a30
diff --git a/definitions/objects/thread.def b/definitions/objects/thread.def
index b382fbd..39596c7 100644
--- a/definitions/objects/thread.def
+++ b/definitions/objects/thread.def
@@ -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 {
uid 11f23e593d5761bd
diff --git a/definitions/objects/vma.def b/definitions/objects/vma.def
index 6e29419..73dd7fb 100644
--- a/definitions/objects/vma.def
+++ b/definitions/objects/vma.def
@@ -1,5 +1,9 @@
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 {
uid d6a12b63b3ed3937
cname vm_area
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..5f87581
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,22 @@
+# 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
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/docs/_static/custom.css b/docs/_static/custom.css
new file mode 100644
index 0000000..efb03a6
--- /dev/null
+++ b/docs/_static/custom.css
@@ -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;
+}
\ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..a6d874d
--- /dev/null
+++ b/docs/conf.py
@@ -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": """
+
+ """,
+ "class": "",
+ },
+ ],
+}
\ No newline at end of file
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..8c3fceb
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,80 @@
+.. 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 `_), but
+you'll also find some assembly (in `NASM `_ syntax) and Python
+for development tooling.
+
+jsix can be found `on GitHub `_, and is
+released under the terms of the `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:
+
+ index
+ syscall_interface
+
+
+* :ref:`genindex`
+* :ref:`search`
+
+
diff --git a/docs/jsix_transparent.svg b/docs/jsix_transparent.svg
new file mode 100644
index 0000000..b65b006
--- /dev/null
+++ b/docs/jsix_transparent.svg
@@ -0,0 +1,12 @@
+
+
+
diff --git a/docs/modd.conf b/docs/modd.conf
new file mode 100644
index 0000000..863825f
--- /dev/null
+++ b/docs/modd.conf
@@ -0,0 +1,7 @@
+** !_build/** ../definitions/**.def {
+ prep: rm -rf _build; make html
+}
+
+_build/html/** {
+ daemon: devd -m _build/html
+}
diff --git a/docs/syscall_interface.rst b/docs/syscall_interface.rst
new file mode 100644
index 0000000..62a8620
--- /dev/null
+++ b/docs/syscall_interface.rst
@@ -0,0 +1,436 @@
+.. jsix syscall interface.
+.. Automatically update 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)
+
+The jsix syscall interface
+==========================
+
+The jsix kernel's syscall design is based around object handles. Object handles
+are also a collections 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_in_len, j6_handle_t * handles, size_t * handles_count)
+
+ 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_in_len: number of bytes in data used for input
+ :param handles: *[optional, inout, handle, list]* Undocumented
+
+.. cpp:function:: j6_result_t j6_mailbox_respond (j6_handle_t self, uint64_t * tag, void * data, size_t * data_len, size_t data_in_len, j6_handle_t * handles, size_t * handles_count, 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_in_len: number of bytes in data used for input
+ :param handles: *[optional, inout, handle, list]* Undocumented
+ :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 (int32_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: fe448e541c009a1bcf8bdc44f4760e32)
+
+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_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: b8b12e99a4a00c99b3859f05000a7bfd)
+
diff --git a/requirements.txt b/requirements.txt
index b03b585..ba198c4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,3 +7,5 @@ pure-cdb == 4
pyzstd == 0.15
pyelftools
iced-x86
+sphinx
+renku-sphinx-theme