blob: 42898d868e4ea6a11dfc72be98cd1dc1aa418cc9 [file]
.. _module-pw_kernel-tour:
=================
Tour of pw_kernel
=================
.. pigweed-module-subpage::
:name: pw_kernel
This tour provides a conceptual overview of the software architecture of
embedded systems built on top of ``pw_kernel``. It walks through the
:cs:`adventure <pw_kernel/examples/adventure>` example to keep the discussion
focused and concrete.
-----
Setup
-----
See :ref:`module-pw_kernel-quickstart` if you'd like to run the adventure
example yourself. This tour starts exactly where the quickstart left off.
--------
Overview
--------
.. To update the diagrams:
.. 1. Go to https://excalidraw.com
.. 2. Menu > Open (or Ctrl+o)
.. 3. Select //docs/sphinx/_static/svg/pw_kernel-tour-light.svg
.. 4. Make your edits in Excalidraw
.. 5. Menu > Save to current file (or Ctrl+S)
.. 6. Menu > Export image (or Ctrl+Shift+E), enable the "dark mode"
.. option, make sure that the "embed scene" option is enabled, click
.. the "SVG" button, and then replace
.. //docs/sphinx/_static/svg/pw_kernel-tour-dark.svg
..
.. TODO: b/525058207 - Enable images.
..
.. .. image:: ../_static/svg/pw_kernel-tour-light.svg
.. :class: only-light
..
.. .. image:: ../_static/svg/pw_kernel-tour-dark.svg
.. :class: only-dark
The adventure example is a multi-process system composed of three userspace
applications:
* **Supervisor**: watches other processes and restarts them when they fail.
* **UART driver**: userspace UART driver implementing the server-side of the
streaming protocol and handles UART interrupts in userspace.
* **Game**: runs game logic and communicates with the UART driver for input/output.
-----------------------------
System generation and startup
-----------------------------
When creating a system on top of ``pw_kernel`` you define the entire system
declaratively in a file like :cs:`system.json5
<:pw_kernel/examples/adventure/targets/riscv_qemu/simulated/system.json5>`.
This includes not only the physical layout:
.. literalinclude:: ./examples/adventure/targets/riscv_qemu/simulated/system.json5
:language: text
:start-after: // DOCSTAG: [layout]
:end-before: // DOCSTAG: [layout]
:dedent:
But also logical definitions, such as how processes are allowed to communicate
with each other over IPC:
.. literalinclude:: ./examples/adventure/targets/riscv_qemu/hardware/system.json5
:language: text
:start-after: // DOCSTAG: [ipc]
:end-before: // DOCSTAG: [ipc]
:dedent:
The end-to-end system is built, linked, and optimized into a single image with a Bazel
macro such as ``system_image``.
.. literalinclude:: ./examples/adventure/targets/riscv_qemu/simulated/BUILD.bazel
:language: text
:start-after: # DOCSTAG: [sys]
:end-before: # DOCSTAG: [sys]
:dedent:
You start up the system by invoking a codegen'd ``start()`` function. See
:cs:`target.rs <:pw_kernel/examples/adventure/targets/riscv_qemu/simulated/target.rs>`
for example. At this point, ``pw_kernel`` constructs and starts the system as
defined in ``system.json5``: allocating kernel-side representations of processes,
setting up IPC channels, defining memory access permissions, etc.
----------
Supervisor
----------
The ``supervisor`` process acts as the system's orchestrator, running in its own
unprivileged process but with special permissions to monitor and control the
lifecycles of the UART driver and game processes. The supervisor uses wait groups
to wait on signals from the other processes.
.. literalinclude:: ./examples/adventure/apps/supervisor/main.rs
:language: rs
:start-after: // DOCSTAG: [tour]
:end-before: // DOCSTAG: [tour]
:dedent:
-------------
Streaming IPC
-------------
The game process communicates with the UART driver process via an IPC channel.
In ``pw_kernel`` IPC channels are synchronous and asymmetric. Only one side
of the channel (the initiator) can start transactions. The other side
(the handler) listens and acts upon read/write requests from the initiator.
In the adventure example the game process functions as the client using the
initiator side of the IPC channel, and the UART driver is the server using
the handler side of the channel. When the driver receives new data from the
UART hardware, it sets the ``USER`` signal to inform the game process that new
data is ready and therefore it should start a new IPC transaction.
.. literalinclude:: ./examples/adventure/lib/stream_protocol/server.rs
:language: rs
:start-after: // DOCSTAG: [tour]
:end-before: // DOCSTAG: [tour]
:dedent: