diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..e281335 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,52 @@ +name: Documentation + +on: + push: + branches: + - main + workflow_dispatch: + +# Allow the workflow to deploy to GitHub Pages. +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment. +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install dependencies + run: pip install --no-cache-dir -r doc/requirements.txt + + - name: Build documentation + run: sphinx-build -b html doc/source/ public/ + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: public + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index c546b06..9d289f2 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,7 @@ filesystem/work #TaMPLate files for the man documentation !*.tmpl + +# GitHub Actions workflows +!.github +!.github/** diff --git a/doc/.gitlab-ci.yml b/doc/.gitlab-ci.yml deleted file mode 100644 index d736b77..0000000 --- a/doc/.gitlab-ci.yml +++ /dev/null @@ -1,13 +0,0 @@ -image: gitlab.edgemtech.ch:5050/overall/infrabase/infrabase/edgem-build:latest - -pages: - tags: - - sphinx - stage: deploy - script: - - sphinx-build -b html doc/source/ public/ - artifacts: - paths: - - public - only: - - main \ No newline at end of file diff --git a/doc/source/architecture.rst b/doc/source/architecture.rst new file mode 100644 index 0000000..9b02b3a --- /dev/null +++ b/doc/source/architecture.rst @@ -0,0 +1,36 @@ +.. _architecture: + +Architecture +############ + +The overall approach combines the *SOO* mobile entity concept with the *SO3* +operating system, running on top of the *Agency Virtualizer (AVZ)* hypervisor. +Micro-services are deployed as **SO3 capsules** — strongly isolated containers +that run alongside a full Linux environment (the *agency domain*). + +.. figure:: img/micofe-architecture.png + :name: _fig-architecture + :alt: General architecture of the edge environment + :width: 720px + :align: center + + General architecture of the edge environment + +The dashed *MICOFE* rectangle in the figure above highlights the components +developed as part of the project. With the exception of Rust support — which +could not be delivered due to time and budget constraints — all other components +were implemented, tested, and validated. + +The main building blocks are: + +* The :ref:`EMISO ` engine, running in the agency domain user space, which + manages the lifecycle of the SO3 capsules. +* :ref:`Portainer `, used as the *Container Orchestration User Interface* + (COUI), running on the host PC. +* The :ref:`MUSL libc ` runtime and the SO3 syscall layer, which allow + standard applications to run unmodified inside capsules. +* The :ref:`C++ ` user-space runtime, built on top of the MUSL-aligned C + runtime. +* The :ref:`capsule / LVGL integration `, which gives graphical capsules + access to the display through a backend/frontend driver pair and the AVZ + hypervisor. diff --git a/doc/source/base_extension/armbian.rst b/doc/source/base_extension/armbian.rst deleted file mode 100644 index 94278e1..0000000 --- a/doc/source/base_extension/armbian.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. _armbian: - -******************** -Armbian full system -******************** - -Introduction -============ -`Armbian `__ is a framework to quickly build a full system for msot ARM platform. It can produce kernel-only images or a ready-to-burn full image with rootfs and bootloader. - -Build a system -============== -The `Armbian `__ repo is the base tool to generate the images. Follow the steps in the link for more details about how to use it. - - -Usability in the EDGEMTech framework -==================================== -Armbian is powerfull but only generate full system images. - -Pros: - - - Uses config.txt to configure the system at boot time. - - APT compatible. - - Zero effort to flash. - -Cons: - - - No rootfs customization - - Needs the raspberry linux kernel. - - -In the end, it is nice to have it for quick tests, but becomes quickly limitating when we want to customize the environnement a bit. - diff --git a/doc/source/base_extension/base_extension.rst b/doc/source/base_extension/base_extension.rst deleted file mode 100644 index b1cb595..0000000 --- a/doc/source/base_extension/base_extension.rst +++ /dev/null @@ -1,20 +0,0 @@ - - -.. _base_extension: - -########################################## -Base environnement extension for Infrabase -########################################## - -.. toctree:: - :maxdepth: 5 - :hidden: - - armbian - debootstrap - raspberrypiOS - buildroot - uboot - -This section presents the different approaches available to deploy a functionnal system running the Infrabase Framework. - diff --git a/doc/source/base_extension/buildroot.rst b/doc/source/base_extension/buildroot.rst deleted file mode 100644 index 7e39727..0000000 --- a/doc/source/base_extension/buildroot.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _buildroot2: - -Buildroot -######### - -Introduction -************ -`Buildroot `__ is a framework to generate distroless linux system. - -Generating a rootfs -******************* -Buildroot can be used to only generate a rootfs and/or the kernel/bootloader. It allows to have custom environnement, using a separate kernel. - - -Usability in the Infrabase framework -************************************ -Buildroot is powerfull and well known, but it lacks the availability of APT to ease the developpement. - -Pros: - - - Very small (167M). - - Easy to customize. - -Cons: - - - No APT support. - diff --git a/doc/source/base_extension/debootstrap.rst b/doc/source/base_extension/debootstrap.rst deleted file mode 100644 index 258c04b..0000000 --- a/doc/source/base_extension/debootstrap.rst +++ /dev/null @@ -1,34 +0,0 @@ -.. _debootstrap: - -Debootstrap rootfs -################## - -Introduction -************ - -`Debootstrap `__ is a rootfs generator able to produce full distribution (Ubuntu or Debian based) rootfs. It can be used directly on the target or cross-compiled from a host computer. - -Generating a rootfs -******************* -The procedure showed on the linux-sunxi in the Introduction explain how to quickly setup deboostrap and how to use it. The result is a folder containing the cross-compiled rootfs. -In our repo, the directory agency/debootsrap_rootfs contains the script to generate an Ubuntu 20.04 focal distro for arm64. - - -Usability in the Infrabase framework -************************************ -Debootstrap is one of the simplest tool to generate an ARM based rootfs. - -Pros: - - - Generate a distro based rootfs in < 30-min - - Can generate on the host or the target - - chroot customization, so it is really quick to tweak the rootfs on the host - - Small (592M Debootstrap vs 2.3G Armbian) - -Cons: - - - Limited in the distros list - - Need some manual tweaks after the base creation to have a fully functional system. - - -This framework is really usefull to quickly bring up a full distro rootfs. Its ability to script its creation easily and to customize it in a chroot like manner is what make it stand out. \ No newline at end of file diff --git a/doc/source/base_extension/raspberrypiOS.rst b/doc/source/base_extension/raspberrypiOS.rst deleted file mode 100644 index 0468eab..0000000 --- a/doc/source/base_extension/raspberrypiOS.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. _raspberrypiOS: - - -Raspberry Pi OS -############### - -Introduction -************ -The `Raspberry Pi OS `__ is a full system image containing the whole system to boot on the RPi4. It is based on Ubuntu and comes in many flavors (headless, 64bit, desktop, ...). - -Usability in the Infrabase framework -************************************ -The Raspberry Pi OS is usefull to quickly deploy a functionnal system on the board. Here is an overview of the pros and cons - -Pros: - - - Uses config.txt to configure the system at boot time. - - APT compatible. - - Zero effort to flash. - -Cons: - - - No rootfs customization - - Needs the raspberry linux kernel. - - -In the end, it is nice to have it for quick tests, but becomes quickly limitating when we want to customize the environnement a bit. - diff --git a/doc/source/base_extension/uboot.rst b/doc/source/base_extension/uboot.rst deleted file mode 100644 index f082694..0000000 --- a/doc/source/base_extension/uboot.rst +++ /dev/null @@ -1,23 +0,0 @@ -.. _uboot: - - -U-Boot modifications -#################### -In order to support the boot from the ITB while using the DTB prepared by the RPi bootloader, we needed to modify U-Boot. -The original could only boot from one or the other method. - -The RPi bootloader patches the DTB using the overlays specified in the config.txt file. When U-Boot takes the hand, the env variable ``fdt_addr`` is set to the address of the modified DTB. -The fix was to add a configuration ``CONFIG_USE_RPI4_DTB_WITH_FIT`` to be able to bypass the DTB retrieval in the FIT image (ITB). -We also need U-Boot to fill it with initrd information for Linux to be able to mount it. - -All the modifications are done in ``common/bootm.c``: - - * line 283: If we use the new config, U-Boot sets its internal ``fdt_addr`` and ``fdt_len`` not by reading the ITB and parsinbg the DTB, but by reading the ``fdtaddr`` variable. - * line 762: With the new configuration, it ignores the state check when configuring the DTB, it allow to configure it even without a DTB in the FIT image. - - -Further improvements -#################### -These modifications where implemented in a quick way to be able to use the custom DTB. However, it lacks some checks made by the classical path. -It is usable but still need some refining in how we handle the DTB loading. - diff --git a/doc/source/build_system/build_system.rst b/doc/source/build_system/build_system.rst deleted file mode 100644 index 827b312..0000000 --- a/doc/source/build_system/build_system.rst +++ /dev/null @@ -1,236 +0,0 @@ - -.. _build_system: - -Build System -############ - -This chapter gives an overview of the Infrabase build system. -The build commands are given in the :ref:`user guide chapter `. - -The ``Infrabase`` build system relies on various scripts and methods, but is mainly -driven by ``bitbake`` receipes. - -We call ``standard scripts`` those used so far as ``./build.sh``, ``./deploy.sh``, ``./mount.sh``, etc. - -The main concepts of *bitbake* are: ``layers``, ``configurations``, ``classes``, ``recipes`` and ``tasks``. - -A layer can be defined as a collection of *configurations*, *classes* and *recipes* associated to -a component. It describes the overall build process with the different tasks belonging to recipes. - -Classes are configuration-independent functionalities/tasks and can have hierarchies (a base class -can be inherited by other classes). - -Receipes contain rules to be executed for a specific application or component. - -Tasks are defined in classes or receipes and are the core functions managed by the build system. -Tasks are either (**bash**) shell script or **python** functions - -Configurations are everyhwere, but the ``local.conf`` file located in ``build/conf/`` directory contains the -general configuration. Typically, this file contains the definition of ``PLATFORM`` -Configurations contain definition of *bitbake* variables that can be used by all recipes of the build system. - - -Bitbake environment -******************* - -Infrabase build system relies on `Bitbake `_ which is the -underlying build system used by Yocto. The overall architecture is depicted on the figure below. - -.. figure:: /img/Infrabase-Build_System.drawio.png - :align: center - - Differences between Yocto and Infrabase in the build system architecture - -While Yocto is mainly distribution oriented (and Poky is the distribution reference on top of Yocto), Infrabase -enables the building of various distributions, for example based on **buildroot** or **debootstrap**. - -**Open-embedded** is constituted of various meta files which enhance the *bitbake* build system and it -has to be considered as part of the build system. - -Infrabase build system -********************** - -In *Infrabase*, *bitbake* and some small parts of *openembedded* are used to build -the initial environment and to reconciliate patches of components after some modifications of source code. - -After the initial clone of the repository, *bitbake* allows to build all components by fetching the -code from the original location and applying related patchsets. - -The updates of patches following some modifications of the repository are part of :ref:`the development flow `. - -We differ *bitbake* script from :term:`standard script`. During the development, the standard scripts -available at the root directory and subdirectory (like *rootfs/* or *linux/usr*) should be used. - -Build system directory organization -*********************************** - -All build system files (except the standard scripts) are located in the ``build/`` directory. - -.. warning:: - - Do not erase the ``build/`` directory. It is not automatically generated but - is stored *git*. - -Actually, *bitbake* creates a ``tmp/`` subdirectory within ``build/``. If a complete re-build is required, -you can delete *tmp/* at any time. - -.. figure:: /img/Infrabase-IB_Architecture.drawio.png - :align: center - - Build system directory organization as stored in git - -In *bitbake*, a layer corresponds to a ``meta`` directory entry. For example, the *meta/* directory is -a generic layer which is used by all other layers. - -We focus on the **meta-linux** layer as an example. - -Directory ``conf/`` -=================== - -This directory is general to the build system and defines the main configuration for *bitbake* (in *bitbake.conf*) -and for the project (in *local.conf*). - -Each new layer must be added in *bitbake.conf* in order to tell *bitbake* to consider the recipes describes in this layer. - -In ``local.conf``, most variables are specific to *infrabase*, like: - - - IB_PLATFORM - - IB_STORAGE - - IB_TOOLCHAIN - - *etc.* - -Directory ``meta-linux/classes`` -================================ - -It defines the generic tasks/functions that are used by the recipe, like ``do_configure`` and ``do_build`` (two -examples of tasks) - -Directory ``meta-linux/conf`` -============================= - -Each layer has a very similar file called ``layer.conf`` which tell *bitbake* further information -about the dependencies between layers and their priorities in the build process. Currently, -all layers are processed with the same priority (4). - -Directory ``recipes-*`` -======================= - -These are the recipes of the layer. In most cases, there is one recipe by layer (except for *rootfs*) which -describes how to build the target component associated to the layer. Of course, depending on the number -of releases/versions, there can be several recipes as well. - -Each recipe may have several subdirectories. Typically, a directory with the name of the component (*linux*) -which contains the recipe files and a ``files/`` directory which contains additional files like patches. - -The recipe ----------- - -The configuration and requirements of a recipe is given in a file with the ``.bb`` extension (for -example ``linux-5.10.bb`` in our case). - -Patchset --------- - -A *patchset* is a collection pf patches which are processed during the build, with the ``do_patch`` tasks. -In *Infrabase*, the list of patches to be applied is contained in a file with ``.inc`` extension within -the *files/* directory. And the list of *.inc* files to be considered in the recipe is described in the -recipe file (*linux-5.10.bb*). - -Directory ``tmp`` -================= - -*Bitbake* automatically creates a ``tmp/`` directory in *build/* for his management and project-related -files. The figure above shows the contents of this directory. - -.. figure:: /img/Infrabase-Folders_tmp.drawio.png - :align: center - - Directory tree of the *tmp/* directory in *build/* - -Once a task is executed successfully, a stamp file (0 byte) is created so that *bitbake* will not re-execute - -.. note:: - - Note that standard scripts remove the stamp files associated to the component to be re-built. - Only the *bsp* recipe does not delete the stamps for individual components except the one - corresponding to itself. - - -Infrabase Basic workflow -************************ - -The initial build can be achieved by meas of the ``./build.sh -a`` command. It will fetch, patch, prepare -the environment and build everything (kernel, rootfs, apps, etc.). - -In the build process, there is a particular task called ``do_attach_infrabase`` which perform a copy -of source code in the root environment of *infrabase*. Hence, the development can be done independently -of the ``tmp/`` directory managed by *bitbake*. - -Therefore, the development is done on the source code related to the branch while the original files -are not modified (in *tmp/work/*) directories. - -This will allow the developers to perform a *diff* (using the ``do_updiff`` task) which will generate -the patches for the differences. - -.. warning:: - - It has to be noted that the generated patches are issued from the difference between the local - files and the original **patched** files. This leads to an incremental patching process. - The *diff* process is always done against the directory which is stored in ``tmp/work//`` - - -Building a patchset -=================== - -Following a development sprint, patchsets have to be (re-)generated in order to keep track of the -code evolution. This is achieved by means of the ``do_updiff`` task. It has to be executed in the -``build`` directory. For example, if we do changes in linux, the patchset will be generated -with the following command: - -.. code-block:: bash - - ~/infrabase/build$ bitbake linux -c updiff - -As result, the patchset is generated in ``build/meta-linux/recipes-linux/linux/files`` directory with -the file ``000x-linux-5.10-r0-patches.inc`` and its associated directory called ``000x-linux-5.10-r0`` -in which the set of patches is located. - -The prefix is made of four digits and is incremented at each patchset generation. - -Based on these two elements, the patchset can be manually worked out. - -To include a patchset in a recipe, the recipe file has to include the following lines: - -.. code-block:: bash - - FILESPATH:prepend: := "${THISDIR}/files/0001-${PF}:" - - require files/0001-${PF}-patches.inc - -Each recipe can have one or several patchsets according to the patch organization, and -the first patchset should be called with prefix ``0001-`` - -Infrabase recipes -***************** - -General comments -================ - -If a task requires ``sudo`` to execute a command, it has to be configured so that no password is required. -To do this, the following entry in the file ``/etc/sudoers`` should be added: - -.. code-block:: bash - - ALL=(ALL) NOPASSWD: ALL - -Currently, the use of *fakeroot* commands, that could avoid setting no password with sudo, -does not allow to use ``losetup`` correctly. - - -.. warning:: - - Using ``sudo`` in a task involves to set the attribute ``network`` of this task to ``"1"``. For example: - *do_init_storage[network] = "1"* - - - diff --git a/doc/source/coding_conventions.rst b/doc/source/coding_conventions.rst deleted file mode 100644 index 8b91e04..0000000 --- a/doc/source/coding_conventions.rst +++ /dev/null @@ -1,650 +0,0 @@ -.. _coding_conventions: - -.. note:: - - This coding style document has been borrowed from the Linux coding style. - -Infrabase coding conventions -############################ - -Indentation -*********** - -Tabs are 8 characters, and thus indentations are also 8 characters. - -Rationale: The whole idea behind indentation is to clearly define where -a block of control starts and ends. Especially when you've been looking -at your screen for 20 straight hours, you'll find it a lot easier to see -how the indentation works if you have large indentations. - -Now, some people will claim that having 8-character indentations makes -the code move too far to the right, and makes it hard to read on a -80-character terminal screen. The answer to that is that if you need -more than 3 levels of indentation, you're screwed anyway, and should fix -your program. - -In short, 8-char indents make things easier to read, and have the added -benefit of warning you when you're nesting your functions too deep. -Heed that warning. - -The preferred way to ease multiple indentation levels in a switch statement is -to align the ``switch`` and its subordinate ``case`` labels in the same column -instead of ``double-indenting`` the ``case`` labels. E.g.: - -.. code-block:: c - - switch (suffix) { - case 'G': - case 'g': - mem <<= 30; - break; - case 'M': - case 'm': - mem <<= 20; - break; - case 'K': - case 'k': - mem <<= 10; - /* fall through */ - default: - break; - } - -Don't put multiple statements on a single line unless you have -something to hide: - -.. code-block:: c - - if (condition) do_this; - do_something_everytime; - -Don't put multiple assignments on a single line either. Coding style -is super simple. Avoid tricky expressions. - -Outside of comments, documentation and except in some files where it is required -like Kconfig Linux kernel, spaces are never used for indentation, -and the above example is deliberately broken. - -Get a decent editor and don't leave whitespace at the end of lines. - - -Breaking long lines and strings -******************************* - -Coding style is all about readability and maintainability using commonly -available tools. - -The limit on the length of lines should correspond to what a modern screen and -editor is reasonibly able to display before the reader has to scroll horizontally -(even if it is acceptable to scroll over a few characters). - -Statements too long will be broken into sensible chunks. -Descendants are always substantially shorter than the parent and -are placed substantially to the right. The same applies to function headers -with a long argument list. However, avoid to break user-visible strings such as -printk messages, because that breaks the ability to grep for them. - - -Placing Braces and Spaces -************************* - -The other issue that always comes up in C styling is the placement of -braces. Unlike the indent size, there are few technical reasons to -choose one placement strategy over the other, but the preferred way, as -shown to us by the prophets Kernighan and Ritchie, is to put the opening -brace last on the line, and put the closing brace first, thusly: - -.. code-block:: c - - if (x is true) { - we do y - } - -This applies to all non-function statement blocks (if, switch, for, -while, do). E.g.: - -.. code-block:: c - - switch (action) { - case KOBJ_ADD: - return "add"; - case KOBJ_REMOVE: - return "remove"; - case KOBJ_CHANGE: - return "change"; - default: - return NULL; - } - -However, there is one special case, namely functions: they may have the -opening brace at the beginning of the next line, thus: - -.. code-block:: c - - int function(int x) - { - body of function - } - -Note that the closing brace is empty on a line of its own, **except** in -the cases where it is followed by a continuation of the same statement, -ie a ``while`` in a do-statement or an ``else`` in an if-statement, like -this: - -.. code-block:: c - - do { - body of do-loop - } while (condition); - -and - -.. code-block:: c - - if (x == y) { - .. - } else if (x > y) { - ... - } else { - .... - } - -Rationale: K&R. - -Also, note that this brace-placement also minimizes the number of empty -(or almost empty) lines, without any loss of readability. - -Do not unnecessarily use braces where a single statement will do. - -.. code-block:: c - - if (condition) - action(); - -and - -.. code-block:: none - - if (condition) - do_this(); - else - do_that(); - -Also, prefer using braces when a loop contains more than a single simple statement: - -.. code-block:: c - - while (condition) { - if (test) - do_something(); - } - -Spaces -====== - -Use a space after (most) keywords. The notable exceptions are sizeof, typeof, alignof, -and __attribute__, which look somewhat like functions (and are usually used with parentheses in Linux, -although they are not required in the language, as in: ``sizeof info`` after -``struct fileinfo info;`` is declared). - -So use a space after these keywords:: - - if, switch, case, for, do, while - -but not with sizeof, typeof, alignof, or __attribute__. E.g., - -.. code-block:: c - - - s = sizeof(struct file); - -Do not add spaces around (inside) parenthesized expressions. This example is -**bad**: - -.. code-block:: c - - - s = sizeof( struct file ); - -When declaring pointer data or a function that returns a pointer type, the -preferred use of ``*`` is adjacent to the data name or function name and not -adjacent to the type name. Examples: - -.. code-block:: c - - - char *linux_banner; - unsigned long long memparse(char *ptr, char **retptr); - char *match_strdup(substring_t *s); - -Use one space around (on each side of) most binary and ternary operators, -such as any of these:: - - = + - < > * / % | & ^ <= >= == != ? : - -but no space after unary operators:: - - & * + - ~ ! sizeof typeof alignof __attribute__ defined - -no space before the postfix increment & decrement unary operators:: - - ++ -- - -no space after the prefix increment & decrement unary operators:: - - ++ -- - -and no space around the ``.`` and ``->`` structure member operators. - -Do not leave trailing whitespace at the ends of lines. Some editors with -``smart`` indentation will insert whitespace at the beginning of new lines as -appropriate, so you can start typing the next line of code right away. -However, some such editors do not remove the whitespace if you end up not -putting a line of code there, such as if you leave a blank line. As a result, -you end up with lines containing trailing whitespace. - -Git will warn you about patches that introduce trailing whitespace, and can -optionally strip the trailing whitespace for you; however, if applying a series -of patches, this may make later patches in the series fail by changing their -context lines. - - -Naming -****** - -C is a Spartan language, and so should your naming be. Unlike Modula-2 -and Pascal programmers, C programmers do not use cute names like -ThisVariableIsATemporaryCounter. A C programmer would call that -variable ``tmp``, which is much easier to write, and not the least more -difficult to understand. - -HOWEVER, while mixed-case names are frowned upon, descriptive names for -global variables are a must. To call a global function ``foo`` is a -shooting offense. - -GLOBAL variables (to be used only if you **really** need them) need to -have descriptive names, as do global functions. If you have a function -that counts the number of active users, you should call that -``count_active_users()`` or similar, you should **not** call it ``cntusr()``. - -Encoding the type of a function into the name (so-called Hungarian -notation) is brain damaged - the compiler knows the types anyway and can -check those, and it only confuses the programmer. No wonder MicroSoft -makes buggy programs. - -LOCAL variable names should be short, and to the point. If you have -some random integer loop counter, it should probably be called ``i``. -Calling it ``loop_counter`` is non-productive, if there is no chance of it -being mis-understood. Similarly, ``tmp`` can be just about any type of -variable that is used to hold a temporary value. - -If you are afraid to mix up your local variable names, you have another -problem, which is called the function-growth-hormone-imbalance syndrome. -See chapter 6 (Functions). - - -Typedefs -******** - -The definition of a type should be either to hide the platform-dependent -definition of a type or to define a struct and having a more readable -type rather than *struct sensor*. Put a ``_t`` as suffix of a type -definition. For example, ``sensor_t``. - -Regarding the platform-dependent definition, it helps to define clear integer types, -where the abstraction **helps** avoid confusion whether it is ``int`` or ``long``. -u8/u16/u32 are perfectly fine typedefs - -NEVER use a typedef to hide a pointer except for the pointer to a function. -For example: - -.. code-block:: c - - typedef (void)(*sigint_fn_t)(int sig) - -is a correct usage of typedef. - - -Functions -********* - -Functions should be short and sweet, and do just one thing. - -The maximum length of a function is inversely proportional to the -complexity and indentation level of that function. So, if you have a -conceptually simple function that is just one long (but simple) -case-statement, where you have to do lots of small things for a lot of -different cases, it's OK to have a longer function. - -Another measure of the function is the number of local variables. They -shouldn't exceed 5-10, or you're doing something wrong. Re-think the -function, and split it into smaller pieces. A human brain can -generally easily keep track of about 7 different things, anything more -and it gets confused. You know you're brilliant, but maybe you'd like -to understand what you did 2 weeks from now. - -In source files, separate functions with one blank line. If the function is -exported, the **EXPORT** macro for it should follow immediately after the -closing function brace line. E.g.: - -.. code-block:: c - - int system_is_up(void) - { - return system_state == SYSTEM_RUNNING; - } - EXPORT_SYMBOL(system_is_up); - -In function prototypes, include parameter names with their data types. -Although this is not required by the C language, it is preferred -because it is a simple way to add valuable information for the reader. - - -Centralized exiting of functions -******************************** - -Albeit deprecated by some people, the equivalent of the goto statement is -used frequently by compilers in form of the unconditional jump instruction. - -The goto statement comes in handy when a function exits from multiple -locations and some common work such as cleanup has to be done. If there is no -cleanup needed then just return directly. - -Choose label names which say what the goto does or why the goto exists. An -example of a good name could be ``out_free_buffer:`` if the goto frees ``buffer``. -Avoid using GW-BASIC names like ``err1:`` and ``err2:``, as you would have to -renumber them if you ever add or remove exit paths, and they make correctness -difficult to verify anyway. - -The rationale for using gotos is: - -- unconditional statements are easier to understand and follow -- nesting is reduced -- errors by not updating individual exit points when making - modifications are prevented -- saves the compiler work to optimize redundant code away ;) - -.. code-block:: c - - int fun(int a) - { - int result = 0; - char *buffer; - - buffer = kmalloc(SIZE, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - if (condition1) { - while (loop1) { - ... - } - result = 1; - goto out_free_buffer; - } - ... - out_free_buffer: - kfree(buffer); - return result; - } - -A common type of bug to be aware of is ``one err bugs`` which look like this: - -.. code-block:: c - - err: - kfree(foo->bar); - kfree(foo); - return ret; - -The bug in this code is that on some exit paths ``foo`` is NULL. Normally the -fix for this is to split it up into two error labels ``err_free_bar:`` and -``err_free_foo:``: - -.. code-block:: c - - err_free_bar: - kfree(foo->bar); - err_free_foo: - kfree(foo); - return ret; - -Ideally you should simulate errors to test all exit paths. - - -Commenting -********** - -Comments are good, but there is also a danger of over-commenting. NEVER -try to explain HOW your code works in a comment: it's much better to -write the code so that the **working** is obvious, and it's a waste of -time to explain badly written code. - -Generally, you want your comments to tell WHAT your code does, not HOW. -Also, try to avoid putting comments inside a function body: if the -function is so complex that you need to separately comment parts of it, -you should probably go back to chapter 6 for a while. You can make -small comments to note or warn about something particularly clever (or -ugly), but try to avoid excess. Instead, put the comments at the head -of the function, telling people what it does, and possibly WHY it does -it. - -The preferred style for long (multi-line) comments is: - -.. code-block:: c - - /* - * This is the preferred style for multi-line - * comments in the source code. Please use it consistently. - * - * Description: A column of asterisks on the left side, - * with beginning and ending almost-blank lines. - */ - -It's also important to comment data, whether they are basic types or derived -types. To this end, use just one data declaration per line (no commas for -multiple data declarations). This leaves you room for a small comment on each -item, explaining its use. - - -Macros, Enums and RTL -********************* - -Names of macros defining constants and labels in enums are capitalized. - -.. code-block:: c - - #define CONSTANT 0x12345 - -Enums are preferred when defining several related constants. - -CAPITALIZED macro names are appreciated but macros resembling functions -may be named in lower case. - -Generally, inline functions are preferable to macros resembling functions. - -Macros with multiple statements should be enclosed in a do - while block: - -.. code-block:: c - - #define macrofun(a, b, c) \ - do { \ - if (a == 5) \ - do_this(b, c); \ - } while (0) - -Things to avoid when using macros: - -1) macros that affect control flow: - -.. code-block:: c - - #define FOO(x) \ - do { \ - if (blah(x) < 0) \ - return -EBUGGERED; \ - } while (0) - -is a **very** bad idea. It looks like a function call but exits the ``calling`` -function; don't break the internal parsers of those who will read the code. - -2) macros that depend on having a local variable with a magic name: - -.. code-block:: c - - #define FOO(val) bar(index, val) - -might look like a good thing, but it's confusing as hell when one reads the -code and it's prone to breakage from seemingly innocent changes. - -3) macros with arguments that are used as l-values: FOO(x) = y; will -bite you if somebody e.g. turns FOO into an inline function. - -4) forgetting about precedence: macros defining constants using expressions -must enclose the expression in parentheses. Beware of similar issues with -macros using parameters. - -.. code-block:: c - - #define CONSTANT 0x4000 - #define CONSTEXP (CONSTANT | 3) - -5) namespace collisions when defining local variables in macros resembling -functions: - -.. code-block:: c - - #define FOO(x) \ - ({ \ - typeof(x) ret; \ - ret = calc_ret(x); \ - (ret); \ - }) - -ret is a common name for a local variable - __foo_ret is less likely -to collide with an existing variable. - -The cpp manual deals with macros exhaustively. The gcc internals manual also -covers RTL which is used frequently with assembly language in the kernel. - - -Printing logging messages -************************* - -Do mind the spelling of messages to make a good impression. Do not use crippled -words like ``dont``; use ``do not`` or ``don't`` instead. Make the messages -concise, clear, and unambiguous. - -Usually, messages do not have to be terminated with a period. - -Coming up with good debugging messages can be quite a challenge; and once -you have them, they can be a huge help for remote troubleshooting. However -debug message printing is handled differently than printing other non-debug -messages. - -Syslog-ng -========= - -Syslog-ng enables logging messages in various forms and configurations. -It can be used to log message on the console and/or in files typically -stored in ``/var/log`` directory. - -Function return values and names -******************************** - -Functions can return values of many different kinds, and one of the -most common is a value indicating whether the function succeeded or -failed. Such a value can be represented as an error-code integer -(-Exxx = failure, 0 = success) or a ``succeeded`` boolean (0 = failure, -non-zero = success). - -Mixing up these two sorts of representations is a fertile source of -difficult-to-find bugs. If the C language included a strong distinction -between integers and booleans then the compiler would find these mistakes -for us... but it doesn't. To help prevent such bugs, always follow this -convention:: - - If the name of a function is an action or an imperative command, - the function should return an error-code integer. If the name - is a predicate, the function should return a "succeeded" boolean. - -For example, ``add work`` is a command, and the add_work() function returns 0 -for success or -EBUSY for failure. In the same way, ``PCI device present`` is -a predicate, and the pci_dev_present() function returns 1 if it succeeds in -finding a matching device or 0 if it doesn't. - -Functions whose return value is the actual result of a computation, rather -than an indication of whether the computation succeeded, are not subject to -this rule. Generally they indicate failure by returning some out-of-range -result. Typical examples would be functions that return pointers; they use -NULL to report failure. - -Inline assembly -*************** - -In architecture-specific code, you may need to use inline assembly to interface -with CPU or platform functionality. Don't hesitate to do so when necessary. -However, don't use inline assembly gratuitously when C can do the job. You can -and should poke hardware from C when possible. - -Consider writing simple helper functions that wrap common bits of inline -assembly, rather than repeatedly writing them with slight variations. Remember -that inline assembly can use C parameters. - -Large, non-trivial assembly functions should go in .S files, with corresponding -C prototypes defined in C header files. The C prototypes for assembly -functions should use ``asmlinkage``. - -You may need to mark your asm statement as volatile, to prevent GCC from -removing it if GCC doesn't notice any side effects. You don't always need to -do so, though, and doing so unnecessarily can limit optimization. - -When writing a single inline assembly statement containing multiple -instructions, put each instruction on a separate line in a separate quoted -string, and end each string except the last with ``\n\t`` to properly indent -the next instruction in the assembly output: - -.. code-block:: c - - asm ("magic %reg1, #42\n\t" - "more_magic %reg2, %reg3" - : /* outputs */ : /* inputs */ : /* clobbers */); - - -Conditional Compilation -*********************** - -Using #if or #ifdef block should always have a comment on the #else or #endif -statement with the name of the condition, like this: - -.. code-block:: c - - #ifdef CONFIG_SOMETHING - - ... - - #else /* CONFIG_SOMETHING */ - - ... - - #endif /* !CONFIG_SOMETHING */ - -It will greatly help the reading of the code. - - -Function header -*************** - -To have a common function header, we also use Doxygen style: - -.. code-block:: c - - /** - * @brief - * - * @param - * @return - */ - -The Doxygen Documentation extension for VSCode allows to automatically generate such header, already pre-filled with some information. -To do this, type ``/**`` before a function, and type ``Enter``. diff --git a/doc/source/conf.py b/doc/source/conf.py index 56c2167..0d1de00 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -38,15 +38,11 @@ 'sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', - 'sphinxcontrib.plantuml', 'rstFlatTable', 'sphinx.ext.extlinks', 'sphinx.ext.imgmath' ] -plantuml = 'java --add-exports java.desktop/com.sun.imageio.plugins.png=ALL-UNNAMED -jar %s -t' % os.path.join(os.path.dirname(__file__), "../utils", "plantuml.jar") -plantuml_output_format = 'svg' - # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -60,9 +56,9 @@ master_doc = 'index' # General information about the project. -project = u'Infrabase' +project = u'MICOFE' -copyright = u'2022-2025, EDGEMTech Ltd (Switzerland)' +copyright = u'2022-2026, REDS Institute (HEIG-VD)' # The version info for the project you're documenting, acts as replacement for @@ -125,7 +121,6 @@ try: import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] def setup(app): # app.add_stylesheet('style.css') app.add_css_file('style.css') @@ -146,6 +141,9 @@ def setup(app): html_static_path = ['_static'] html_css_files = ['theme_overrides.css'] +# Logo shown at the top of the sidebar (REDS Institute - HEIG-VD). +html_logo = 'img/REDS_HEIG-VD_logotype_rouge-rvb.png' + # -- Options for HTMLHelp output ------------------------------------------ # If not None, a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. @@ -209,7 +207,7 @@ def setup(app): # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [('index', 'Infrabase.tex', u'Infrabase Documentation', u'EDGEMTech Ltd', 'manual')] +latex_documents = [('index', 'MICOFE.tex', u'MICOFE Documentation', u'REDS Institute', 'manual')] # A dictionary that contains LaTeX snippets that override those Sphinx usually @@ -235,7 +233,7 @@ def setup(app): # The name of an image file (relative to this directory) to place at the top of # the title page. -#latex_logo = None +latex_logo = 'img/REDS_HEIG-VD_logotype_rouge-rvb.png' # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. @@ -262,7 +260,7 @@ def setup(app): # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [('index', 'doc', u'Infrabase Documentation', [u'EDGEMTech Ltd'], 1)] +man_pages = [('index', 'doc', u'MICOFE Documentation', [u'REDS Institute'], 1)] # -- Additional options -------------------------------------------------------- diff --git a/doc/source/cpp.rst b/doc/source/cpp.rst new file mode 100644 index 0000000..fbf0314 --- /dev/null +++ b/doc/source/cpp.rst @@ -0,0 +1,135 @@ +.. _cpp: + +Integration of C++ in SO3 user space +##################################### + +C++ support in SO3 user space is built as a direct extension of the C runtime +foundation described in :ref:`MUSL libc support `. Once the kernel +interface and startup environment are sufficiently aligned with MUSL expectations, +most of the mechanisms required by C++ applications become accessible as well, +because the C++ runtime ultimately depends on the same process startup model, +memory management primitives, thread support, and error-handling conventions. + +This means that the *syscall* adaptation effort undertaken for MUSL is reused +almost entirely by C++ workloads. In practice, the project did not implement an +independent C++ execution environment; instead, it enabled C++ by making the +underlying C/POSIX runtime robust enough to support the additional language +services expected by a C++ compiler and its runtime libraries. + +Main runtime requirements +************************* + +Compared with plain C applications, C++ introduces several additional runtime +requirements that must be handled correctly by the loader, the linker, and the +low-level runtime support. The most visible difference is that a C++ program is +not limited to calling a single entry point and using flat procedural code: it +may rely on object construction before ``main``, destruction after program +termination, compiler-generated helper routines, and richer type-system services. + +* **Constructor and destructor sections.** Sections such as ``.ctors``, ``.dtors``, + or their modern equivalents contain initialization and finalization routines + associated with global and static objects. They must be discovered and executed + in the correct order during program startup and shutdown; otherwise, C++ objects + may remain uninitialized or be destroyed incorrectly, which would make even + simple applications unreliable. + +* **Compiler support routines.** Low-level runtime libraries such as ``libgcc`` + provide helper functions for integer arithmetic, stack unwinding metadata, + object-layout support, and other compiler-emitted constructs — even when + exceptions are disabled. In an embedded environment, these dependencies must be + understood and provided explicitly rather than assumed to exist implicitly as + they would on a desktop Linux system. + +* **Runtime Type Information (RTTI).** RTTI provides services such as + ``dynamic_cast`` and ``typeid``, which are useful when software components use + inheritance and polymorphism. In resource-constrained embedded systems, RTTI is + often made optional, but the platform must still be able to support it correctly + when developers decide that the application architecture benefits from it. + +* **Thread-local and synchronization services.** These must behave correctly, + especially when higher-level C++ abstractions are implemented internally on top + of *pthread* or *libc* primitives. This links C++ support back to the MUSL + compatibility effort: if thread creation, TLS setup, memory allocation, or + synchronization behavior are not sufficiently aligned with Linux/MUSL + expectations, C++ applications will fail in ways that are often difficult to + diagnose. + +Compiler and runtime integration +******************************** + +The project toolchain was extended so that, in addition to the C compiler and +MUSL-based runtime, it also produces the C++ compiler components and the +associated low-level support libraries. In practice, this includes the compiler +driver for C++ compilation as well as the ``libgcc`` support routines required by +generated code. The objective is not merely to compile isolated C++ files, but to +make standard cross-compilation workflows available for complete SO3 user-space +applications. + +This integration has consequences both at build time and at runtime. At build +time, the toolchain must expose the expected compiler front-end, headers, startup +objects, and libraries. At runtime, the generated binaries must remain compatible +with the startup sequence, memory layout, and system-call behavior provided by +SO3. The success of the C++ integration therefore depends not only on enabling a +compiler flag, but on ensuring consistency between the compiler, the runtime +libraries, and the operating system environment. + +In embedded systems, the exact feature set exposed to C++ applications must be +chosen carefully. Some advanced runtime services can increase code size, memory +usage, and startup complexity. For that reason, the project follows a pragmatic +approach in which the baseline C++ environment remains compatible with embedded +constraints while still enabling application-level abstractions that are valuable +for maintainability and software structuring. For example, RTTI can be enabled +when needed but is not mandatory for all applications, and exception handling may +be restricted or disabled depending on the target profile. + +Expected benefits for applications +********************************** + +Adding C++ support is important because many embedded graphical and middleware +applications benefit from stronger abstraction mechanisms than plain C alone. +Classes, namespaces, templates, and stronger type modelling help organize +medium-size and large codebases, especially when multiple services, UI components, +and communication layers must coexist in the same application. + +Within MICOFE, C++ support is particularly relevant for user-space capsules that +package richer application logic on top of the MUSL runtime. It prepares the +ground for demonstrators and future products in which reusable software components, +object-oriented UI wrappers, hardware abstraction layers, and board-independent +service modules can be expressed in a more maintainable way than in plain C. + +Better language-level structuring also improves software quality by making +interfaces clearer, reducing duplication, and easing the separation between +platform-specific code and portable application logic. In a project aiming at +capsule portability across multiple boards, that separation is especially valuable. + +Current scope and limitations +***************************** + +The current work demonstrates that the SO3 user space can host a functional C++ +toolchain and execute applications that rely on the same runtime substrate as C +programs. However, this should not be interpreted as full desktop-class C++ +support. The intended scope remains embedded software, with a controlled subset of +runtime features chosen according to platform constraints. + +In particular, advanced features that depend on broader OS services, dynamic +loading, or very large standard-library subsystems may require additional work. +The project therefore positions C++ support as an incremental but important +milestone: enough to support real embedded applications and reusable software +components, while leaving room for future expansion if broader standard-library +coverage becomes necessary. + +Position within the project +*************************** + +From the perspective of the overall MICOFE architecture, C++ integration is a +direct consequence of the *libc* and *syscall* compatibility effort. Once a stable +runtime, startup sequence, and build chain are available, C++ becomes a natural +extension rather than a disconnected feature. This confirms that the project has +not only improved low-level compatibility, but has also moved SO3 closer to a +practical application platform for modern embedded development. + +More broadly, enabling higher-level language support on top of the validated MUSL +environment shows that the platform can host application development workflows that +are closer to current industrial practices — a key element for adoption, because +developers are more likely to use a platform that supports structured application +development rather than only low-level experimentation. diff --git a/doc/source/demonstrator.rst b/doc/source/demonstrator.rst new file mode 100644 index 0000000..ab2daff --- /dev/null +++ b/doc/source/demonstrator.rst @@ -0,0 +1,178 @@ +.. _demonstrator: + +Demonstrator and showcase +######################### + +This chapter presents a lightweight demonstrator designed to showcase the value of +MICOFE capsules for graphical applications (LVGL) running on SO3 alongside a +Linux-based "critical" environment. The goal is not to benchmark performance but to +illustrate isolation, composability (multiple capsules on the same target), and +portability (the same capsule across heterogeneous Arm platforms). + +Two complementary demonstration scenarios are implemented: + +* **Scenario 1 — Multi-capsule composition on a single target:** multiple SO3 + capsules, each running a distinct LVGL application, execute on the same hardware + while Linux continues to run the "critical" user interface and services. +* **Scenario 2 — Portability across heterogeneous platforms:** the same capsule + image runs unmodified on different Arm targets (e.g., Raspberry Pi 4, Toradex + Verdin iMX8MP) and on an emulated platform (QEMU/virt64), demonstrating a + consistent UI across boards. + +Demonstrator principles +*********************** + +The demonstrator is intentionally built on top of the core deliverables described +in the previous chapters: a SO3 user space able to run standard applications with +MUSL (without patching MUSL), and the kernel-side syscall compatibility required by +typical LVGL-based UIs. The showcase therefore focuses on the end-to-end +experience: building a capsule, launching it next to Linux, and validating that the +UI behaves consistently across targets. + +.. figure:: img/micofe-showcase-architecture.png + :name: _fig-showcase-architecture + :alt: Showcase architecture (Linux "critical UI" + multiple SO3 capsules) + :width: 620px + :align: center + + Showcase architecture (Linux "critical UI" + multiple SO3 capsules) + +Demonstrator setup and prerequisites +************************************ + +This section summarizes the environment used to run the showcase and the artifacts +required to reproduce it. + +* **Targets:** Raspberry Pi 4 (Arm64), Toradex Verdin iMX8MP (Arm64), and + QEMU/virt64 for emulation-based runs. +* **Host environment:** a Linux development machine with the SO3 build environment + and the capsule build tooling. +* **Software stack:** Linux used as the "critical" environment; SO3 as the capsule + OS; MUSL as the system libc inside capsules; LVGL applications as the showcased + workloads. +* **Artifacts:** one or more capsule images that embed (1) the SO3 user space, + (2) an LVGL application, and (3) its configuration assets (themes, fonts, input + mapping, etc.). + +Scenario 1 — Multi-capsule composition next to a Linux "critical UI" +******************************************************************** + +This scenario demonstrates how MICOFE can support the deployment of graphical +applications that interact with a Linux-based critical environment, while keeping +those applications isolated inside SO3 capsules. The key message is composability: +multiple independent UI capsules can coexist on the same target, with Linux +retaining control over the critical interface and any safety- or security-sensitive +services. + +#. **Prepare capsules:** build at least two capsules, each embedding a different + LVGL application (e.g., "Dashboard" and "Settings"). +#. **Boot the platform:** start Linux as the base environment and bring up the + critical UI (or a representative placeholder UI) on the main display. +#. **Launch capsules:** start the SO3 capsules from Linux using the MICOFE + runtime/launcher. +#. **Validate isolation:** intentionally stop or restart one capsule and verify + that the Linux critical UI and the other capsule keep running. +#. **Validate interaction contract:** verify that the capsules only access shared + resources through explicit, controlled interfaces (e.g., a device, a service + endpoint, or a pre-defined IPC mechanism), rather than ad-hoc shared state. + +**Success criteria.** The scenario is considered successful when: + +* Each capsule UI starts reliably and renders correctly using LVGL. +* A failure (crash/kill) of one capsule does not affect Linux or other capsules. +* The capsule's behavior matches expectations for a MUSL-based environment (no MUSL + patching required, and missing syscalls fail cleanly with ``ENOSYS`` where + applicable). +* Startup/shutdown cycles are repeatable without leaving the system in an + inconsistent state (e.g., resources released, no deadlocks in basic futex-based + synchronization). + +.. figure:: img/micofe-multicapsule-composition.png + :name: _fig-multicapsule-composition + :alt: Multi-capsule UI composition on one target + :width: 460px + :align: center + + Multi-capsule UI composition on one target + +Scenario 2 — Capsule portability across boards and emulation +************************************************************ + +This scenario demonstrates platform heterogeneity: the same capsule image can be +deployed across different Arm64 systems (and in QEMU) while providing a consistent +UI. The intent is to show that the capsule encapsulates its user space (MUSL + +application) and that the kernel interface exposed by SO3 remains sufficiently +stable across targets. + +#. **Select a reference capsule:** choose one LVGL capsule (e.g., "Dashboard") as + the portability baseline. +#. **Run on Raspberry Pi 4:** deploy the capsule and confirm correct rendering and + input handling. +#. **Run on Verdin iMX8MP:** deploy the exact same capsule image and confirm + identical functional behavior (layout, fonts, navigation). +#. **Run on QEMU/virt64:** boot an emulated target and run the capsule to validate + developer-friendly workflows (CI, regression tests, headless automation where + applicable). +#. **Compare outputs:** record a small set of checks (startup logs, a few + screenshots, and basic UI interactions) and verify equivalence across the three + environments. + +.. figure:: img/micofe-portability-matrix.png + :name: _fig-portability-matrix + :alt: Portability matrix (same capsule across targets) + :width: 560px + :align: center + + Portability matrix (same capsule across targets) + +Discussion, limitations, and next steps +*************************************** + +Together, the two scenarios provide an end-user-oriented validation of the +project's technical choices. Scenario 1 makes the isolation and composition +benefits tangible (multiple independent UIs running in parallel next to Linux), +while Scenario 2 demonstrates that capsules are a practical distribution format +across heterogeneous targets. + +Observed/expected limitations +============================= + +Based on the current SO3 syscall surface and MUSL alignment (see +:ref:`MUSL libc support `), the demonstrator intentionally stays within a +"baseline application" envelope: + +* Not all Linux flags/options are supported for every syscall (e.g., reduced + ``mmap`` flags; limited ``clone`` flag set; reduced ``futex`` operations). The + showcase therefore avoids advanced behaviors that rely on those options. +* Unimplemented syscalls return ``ENOSYS``; the demonstrator is designed so such + cases are either not triggered or are easy to diagnose in logs. +* The demonstrator focuses on functionality and integration rather than on + performance or real-time guarantees. + +Next steps +========== + +Building on the current demonstrator and the MUSL-based runtime, several extensions +are natural candidates for future work. The two most prominent are native Rust +support on top of SO3 and broader GPU coverage for graphical capsules. + +* **Rust support.** Completing Rust support so that capsules can host applications + written in both C++ and Rust on top of the same MUSL-aligned runtime. This will + require a dedicated Rust toolchain targeting SO3, including a stable mapping + between Rust's standard library expectations and the existing syscall surface, as + well as packaging guidelines for Rust-based capsules. In the medium term, Rust + support will make it easier to explore memory-safe system components and + higher-level services inside capsules. +* **Broader GPU coverage.** The current demonstrator focuses on a specific class of + GPUs and display pipelines. A natural evolution is to extend the GPU abstraction + layer so that LVGL-based capsules can be reused across a wider range of SoCs and + boards without reworking the application logic. This involves separating + board-specific display integration (framebuffer, composition, input routing) from + the capsule-visible interfaces, and validating the approach on additional GPU + families and display controllers. +* **Transversal improvements.** Hardening the Linux-capsule interaction contract by + documenting and implementing a small, well-defined set of services for + configuration, monitoring, and logging, usable consistently across capsules and + targets. Another is to industrialize the current demonstrator into a reusable + reference platform, with scripted deployment, regression tests, and example + capsules that can serve as templates for future industrial or academic projects. diff --git a/doc/source/dev_flow.rst b/doc/source/dev_flow.rst deleted file mode 100644 index 767ad05..0000000 --- a/doc/source/dev_flow.rst +++ /dev/null @@ -1,93 +0,0 @@ - -.. _dev_flow: - -Development flow -################# - -Here is an overview of the *development flow* used in the Infrabase project. - -* **Current**/**latest** version of the framework is available in the ``main`` - branch. -* The development activities are done in a specific branch. An issue is linked - with each development branches. -* Once the development of a new feature has completed, the developer create a ``merge - request (MR)``. The *changes* are reviewed and then merged into the ``main`` branch - by the *Infrabase maintainers*. - -The gitFlow_ figures shows this flow. - -Periodically, the *maintainers* publish a major release of the *Infrabase*. -For a new version, the following steps are performed: - -* The main new features has been re-tested -* The ``CHANGELOG`` file is updated with the new release information (release - number, description of the main add-on to the framework, ...) -* A ``tag`` with the version number is created - -.. _gitFlow: -.. uml:: - - master->>FeatureA: Create branch - master->>FeatureB: Create branch - FeatureA->>master: Merge new feature in master - FeatureB->>master: Merge new feature in master - - -Development -*********** - -For the development of new features or improvements, a new branch has to be created. -It should not be any development done directly in the ``main`` branch. Each new -*topic* has to have is own branch. Branches are not reused. - -An issue should be linked with each branch (an issue per branch). This issue should -provide: - -* A description of what is addressed -* (Optional) Information on the advancement of this topic, issues - found, explanation of the implementation, … - -The issue is automatically closed after -the development branch is merged of in the ``main`` branch. - -.. note:: - - Issue can be (should be) created to document problems, improvement found using - the framework without having to create a branch. - - The branch can be created when the *issue* is addressed - -Create new issue & branch -========================= - -To create a branch with an associated issue: - -1. Create a new issue. The doc from gitlab: `Create a new - issue `__ -2. Create the branch from the issue. The doc from gitlab: `Create a new - branch from an - issue `__ - - -Merge in the main branch -======================== - -Once the development of a specific topic has completed and been tested, it has to be -*integrated* in the ``main`` branch. It is done by creating a ``merge request (MR)``. - -By creating a ``merge request``, a developer asks *SOO maintainers* to: - -- Do a review of the modifications -- Performs the ``merge`` - -The creation of a ``merge request`` is simple: - -1. Form the issue page in gitlab, click ``Create merge request`` button -2. Validate the creation of the ``merge request`` in the new Windows - -`Merge request official doc `__. - -.. note:: - - Ideally, there is only one commit per changes. If, for some reasons, it is not - possible, please inform the *dev team* to lock this branch. diff --git a/doc/source/micofe/emiso.rst b/doc/source/emiso.rst similarity index 97% rename from doc/source/micofe/emiso.rst rename to doc/source/emiso.rst index ae30ec4..25de9f5 100644 --- a/doc/source/micofe/emiso.rst +++ b/doc/source/emiso.rst @@ -14,7 +14,7 @@ services in embedded systems, we propose to use a new model of container based o our SOO mobile entity concept which is based itself on the SO3 operating system. -.. figure:: pictures/micofe-overview.png +.. figure:: img/micofe-overview.png :name: _fig-Communication flow :alt: Communication flow :align: center @@ -68,7 +68,7 @@ Architecture The following picture depicts the architecture of the EMISO engine. -.. figure:: pictures/micofe-emiso-engine.png +.. figure:: img/micofe-emiso-engine.png :name: _fig-engine_architecture :alt: Engine Architecture :align: center @@ -162,7 +162,7 @@ file. The file path for these logs is as follows: The following image shows an overview of this log's mechanism. -.. figure:: pictures/micofe-logs.png +.. figure:: img/micofe-logs.png :name: _fig-emiso_engine_logs_flow :alt: EMISO engine logs flow :align: center diff --git a/doc/source/glossary.rst b/doc/source/glossary.rst index ebeae80..79b544f 100644 --- a/doc/source/glossary.rst +++ b/doc/source/glossary.rst @@ -3,11 +3,162 @@ Glossary ######## .. glossary:: + :sorted: MICOFE - Micro-Container for Edge Computing + Micro-Container for Edge Computing. The project that provides a lightweight, + strongly isolated micro-container environment for edge computing, built on + :term:`SO3` and Arm64 virtualization. - Standard script - A script which is out of the scope of bitbake. - - \ No newline at end of file + SO3 + A lightweight operating system supporting key Linux-like features such as + user/kernel separation, memory paging, and multithreading. It is the + operating system running inside the :term:`capsule`. + + SOO + The virtualization framework, developed at the :term:`REDS` Institute, that + introduced the :term:`mobile entity` concept on which the SO3 capsules are + based. + + AVZ + Agency Virtualizer — the hypervisor on top of which the :term:`agency domain` + (Linux) and the SO3 :term:`capsule` run. It manages the :term:`IPA`-to-:term:`PA` + address translation stage. + + Agency domain + The full Linux environment running next to the capsules. It hosts the + :term:`EMISO` engine and the "critical" user interface and services. + + Capsule + A strongly isolated :term:`SO3`-based container used to deploy a micro-service + or application alongside Linux. A capsule is derived from the :term:`SOO` + :term:`mobile entity` concept and is, in Docker terms, the equivalent of a + running container. + + Mobile Entity + Also abbreviated *ME*. The :term:`SOO` virtualization concept of a self-contained, + migratable execution unit on which SO3 capsules are based. + + EMISO + The engine, running in the :term:`agency domain` user space, that manages the + lifecycle of the SO3 capsules (creation, start/stop, pause/unpause, logs). It + exposes a subset of the Docker APIs. + + Portainer + *Portainer CE* (Community Edition), an open-source container management tool + used in the MICOFE framework as the :term:`COUI`. It runs on the host PC and + talks to the :term:`EMISO` engine through a RESTful API. + + COUI + Container Orchestration User Interface — the role played by :term:`Portainer` + in the MICOFE framework. + + Docker + The de-facto container platform whose APIs and concepts (image, container, + logs) are partially mirrored by :term:`EMISO` to manage SO3 capsules. + + MUSL + An implementation of the standard C/POSIX library designed for correctness, + static linking, and use in embedded systems. Used as the :term:`libc` for SO3 + user-space applications. + + libc + The standard C library providing the C/POSIX runtime to user-space + applications. In MICOFE, the libc is :term:`MUSL`. + + libgcc + The low-level GCC support library providing compiler helper routines (integer + arithmetic, stack unwinding metadata, object-layout support) required by + generated code, including :term:`C++ ` workloads. + + LVGL + *Light and Versatile Graphics Library* — a library for creating graphical user + interfaces on embedded devices, used as the graphical application class for + capsules. + + RTTI + Runtime Type Information — C++ services such as ``dynamic_cast`` and ``typeid``. + Optional in resource-constrained embedded systems. + + ABI + Application Binary Interface — the low-level convention (register usage, calling + convention, syscall numbering) that binaries must follow. SO3 uses the + Linux-style syscall ABI expected by :term:`MUSL`. + + syscall + System call — the interface through which a user-space application requests a + service from the kernel. SO3 implements a subset of the Linux syscalls expected + by :term:`MUSL`. + + ENOSYS + The error code returned by SO3 when an application invokes a syscall that is not + implemented, which makes missing functionality easy to diagnose in logs. + + futex + *Fast userspace mutex* — the Linux syscall used by :term:`MUSL` for thread + synchronization. SO3 implements the ``FUTEX_WAIT`` and ``FUTEX_WAKE`` operations. + + pthread + The POSIX threads API. Its :term:`MUSL` implementation relies on Linux syscalls + such as ``clone``, :term:`futex`, and ``exit``/``exit_group``. + + TLS + Thread-Local Storage — per-thread storage used to hold thread-specific data + (including the pthread context). On AArch64 it is held in ``tpidr_el0``. + + toolchain + The cross-compilation tool suite (compiler, linker, runtime libraries, and + :term:`sysroot`) built from source to produce binaries for ARM32 and ARM64 SO3 + targets. + + sysroot + The directory tree containing the target headers and libraries against which the + :term:`toolchain` compiles and links applications. + + binutils + The GNU binary utilities (assembler, linker, and related tools) that are part of + the :term:`toolchain`. + + Hypercall + A call from a guest (Linux or a capsule) to the :term:`AVZ` hypervisor, used for + example to share the :term:`framebuffer` address or to switch capsule focus. + + Framebuffer + The memory region representing the whole screen content. In MICOFE its + :term:`IPA` is remapped by :term:`AVZ` so that only the focused :term:`capsule` + is shown on the display. + + VA + Virtual Address — the address space seen by a user-space application, translated + to an :term:`IPA` by the first MMU stage. + + IPA + Intermediate Physical Address — the address space produced by the first MMU + translation stage, sitting between the virtual (:term:`VA`) and physical + (:term:`PA`) address spaces. Managed by Linux and the capsules. + + PA + Physical Address — the real hardware memory address, produced by the second MMU + translation stage managed by :term:`AVZ`. + + itb file + The *image tree blob* used as a SO3 :term:`capsule` image. EMISO stores these + images in the ``/root/capsule/`` folder. + + Snapshot + A saved state of an injected :term:`capsule`. Creating a capsule snapshots the + injected capsule; pausing a capsule snapshots its current state before shutting + it down. + + VLOGS + The backend/frontend driver mechanism used to forward log messages from a SO3 + :term:`capsule` to the Linux kernel, where they are stored per capsule under + ``/var/log/soo/``. + + TrustZone + The ARM hardware security technology leveraged, together with virtualization, to + provide a highly secure execution environment for the capsules. + + REDS + The *Reconfigurable & Embedded Digital Systems* institute of HEIG-VD, where the + :term:`SOO` framework and this project were developed. diff --git a/doc/source/img/EDGEMTech.png b/doc/source/img/EDGEMTech.png deleted file mode 100644 index 6da455c..0000000 Binary files a/doc/source/img/EDGEMTech.png and /dev/null differ diff --git a/doc/source/img/Infrabase-Build_System.drawio.png b/doc/source/img/Infrabase-Build_System.drawio.png deleted file mode 100644 index e0794f8..0000000 Binary files a/doc/source/img/Infrabase-Build_System.drawio.png and /dev/null differ diff --git a/doc/source/img/Infrabase-Folders_tmp.drawio.png b/doc/source/img/Infrabase-Folders_tmp.drawio.png deleted file mode 100644 index 47447a2..0000000 Binary files a/doc/source/img/Infrabase-Folders_tmp.drawio.png and /dev/null differ diff --git a/doc/source/img/Infrabase-IB_Architecture.drawio.png b/doc/source/img/Infrabase-IB_Architecture.drawio.png deleted file mode 100644 index ee81a1a..0000000 Binary files a/doc/source/img/Infrabase-IB_Architecture.drawio.png and /dev/null differ diff --git a/doc/source/img/Infrabase.drawio b/doc/source/img/Infrabase.drawio deleted file mode 100644 index 29d8196..0000000 --- a/doc/source/img/Infrabase.drawio +++ /dev/null @@ -1,344 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/source/img/REDS_HEIG-VD_logotype_rouge-rvb.png b/doc/source/img/REDS_HEIG-VD_logotype_rouge-rvb.png new file mode 100644 index 0000000..2242094 Binary files /dev/null and b/doc/source/img/REDS_HEIG-VD_logotype_rouge-rvb.png differ diff --git a/doc/source/img/micofe-architecture.png b/doc/source/img/micofe-architecture.png new file mode 100644 index 0000000..b0856d3 Binary files /dev/null and b/doc/source/img/micofe-architecture.png differ diff --git a/doc/source/micofe/pictures/micofe-emiso-engine.png b/doc/source/img/micofe-emiso-engine.png similarity index 100% rename from doc/source/micofe/pictures/micofe-emiso-engine.png rename to doc/source/img/micofe-emiso-engine.png diff --git a/doc/source/img/micofe-framebuffer-flow.png b/doc/source/img/micofe-framebuffer-flow.png new file mode 100644 index 0000000..18f025c Binary files /dev/null and b/doc/source/img/micofe-framebuffer-flow.png differ diff --git a/doc/source/img/micofe-framebuffer-map.png b/doc/source/img/micofe-framebuffer-map.png new file mode 100644 index 0000000..3566d8a Binary files /dev/null and b/doc/source/img/micofe-framebuffer-map.png differ diff --git a/doc/source/micofe/pictures/micofe-logs.png b/doc/source/img/micofe-logs.png similarity index 100% rename from doc/source/micofe/pictures/micofe-logs.png rename to doc/source/img/micofe-logs.png diff --git a/doc/source/img/micofe-multicapsule-composition.png b/doc/source/img/micofe-multicapsule-composition.png new file mode 100644 index 0000000..8067bbd Binary files /dev/null and b/doc/source/img/micofe-multicapsule-composition.png differ diff --git a/doc/source/micofe/pictures/micofe-overview.png b/doc/source/img/micofe-overview.png similarity index 100% rename from doc/source/micofe/pictures/micofe-overview.png rename to doc/source/img/micofe-overview.png diff --git a/doc/source/img/micofe-portability-matrix.png b/doc/source/img/micofe-portability-matrix.png new file mode 100644 index 0000000..78f548e Binary files /dev/null and b/doc/source/img/micofe-portability-matrix.png differ diff --git a/doc/source/img/micofe-showcase-architecture.png b/doc/source/img/micofe-showcase-architecture.png new file mode 100644 index 0000000..61c6678 Binary files /dev/null and b/doc/source/img/micofe-showcase-architecture.png differ diff --git a/doc/source/micofe/pictures/micofe.drawio b/doc/source/img/micofe.drawio similarity index 100% rename from doc/source/micofe/pictures/micofe.drawio rename to doc/source/img/micofe.drawio diff --git a/doc/source/index.rst b/doc/source/index.rst index f8230d7..4302080 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -1,52 +1,38 @@ .. doc Documentation master file. -.. image:: img/EDGEMTech.png +.. image:: img/REDS_HEIG-VD_logotype_rouge-rvb.png :align: center - :scale: 30% - :target: https://edgemtech.com - -.. toctree:: - :maxdepth: 5 - :numbered: - :hidden: - - introduction - rootfs/rootfs - User guide - build_system/build_system - dev_flow - base_extension/base_extension - micofe/micofe - Coding conventions - glossary + :width: 320px + :alt: REDS Institute - HEIG-VD + :target: https://reds.heig-vd.ch | - .. rst-class:: center -EDGEMTech Infrabase Devtools & Environment -########################################## +MICOFE - Micro-Container for Edge Computing +########################################### .. rst-class:: left -Setup and environment -********************* - -- :ref:`User Guide ` - -.. rst-class:: left +MICOFE provides a highly secure, virtualized approach to deploy and manage +micro-services in embedded systems, combining the SOO mobile entity concept and +the SO3 operating system with Arm64 virtualization. -Coding conventions and development flow -*************************************** +.. toctree:: + :maxdepth: 2 + :numbered: -- :ref:`Our coding conventions ` -- :ref:`Our development flow ` + introduction + architecture + emiso + portainer + syscalls_alignment + cpp + lvgl + demonstrator + glossary +| To edit the documentation and to use the correct underlying policy, you can read `this documentation style guide `_. - - - - - diff --git a/doc/source/introduction.rst b/doc/source/introduction.rst index 94505d1..b2f255c 100644 --- a/doc/source/introduction.rst +++ b/doc/source/introduction.rst @@ -1,19 +1,31 @@ .. _introduction: Introduction -============ +############ -``Infrabase`` provides the developer with a base environment to deal with embedded software to be deployed on -different hardware and emulated boards. +``MICOFE`` (*Micro-Container for Edge Computing*) aims to provide a lightweight +micro-container environment based on Arm64 virtualization and the *SO3* operating +system. SO3 is a lightweight OS that supports key Linux-like features such as +user/kernel separation, memory paging, and multithreading. -``Infrabase`` harnesses the power of BitBake's highly modular, recipe-driven architecture while seamlessly integrating prebuilt packages into the BitBake ecosystem. This approach is grounded in years of hands-on experience with R&D projects and embedded Linux development, where the typical software stack includes: +This environment is well suited to provide developers with a strongly isolated +execution environment where full-featured applications can run alongside Linux. -- A bootloader like U-Boot -- The Linux kernel -- The root filesystem -- A set of user-space applications +MICOFE targeted several objectives, including: +* Full support for the :ref:`MUSL libc library ` +* :ref:`C++ ` and Rust support +* Support for :ref:`LVGL-based graphical applications ` +All objectives were achieved except Rust support, which could not be completed +due to time constraints. +Acknowledgements +**************** +We sincerely appreciate the *Hasler Foundation* for making this ambitious project +possible and for helping us secure new projects with industrial partners. +We also extend our heartfelt thanks to Clément Dieperink, Jean-Pierre Miceli, and +Prof. Daniel Rossier from the *REDS Institute* of *HEIG-VD* for their invaluable +contributions to this project. diff --git a/doc/source/lvgl.rst b/doc/source/lvgl.rst new file mode 100644 index 0000000..4ed6701 --- /dev/null +++ b/doc/source/lvgl.rst @@ -0,0 +1,99 @@ +.. _lvgl: + +Capsules and LVGL integration +############################# + +*LVGL* is a library that enables the creation of graphical applications for +embedded devices and is already compatible with a standalone SO3 environment. +From the perspective of MICOFE, LVGL is important because it offers a realistic +application class for capsules: graphical workloads that are richer than +command-line examples and that make the benefits of isolation, portability, and +composition immediately visible. + +Sharing the framebuffer +*********************** + +To support LVGL on capsules, the goal is to use Linux to drive the screen and add +a link between the capsule and Linux to seamlessly give access to the display, +like it is already done with UART for the terminal. + +However, as the framebuffer represents the whole screen, it is much larger, +meaning that the current mechanism to share data between Linux and capsules is not +efficient as it only allows a small amount of memory pages to be shared. For +example, a screen of 1024x600 pixels with 16 bits per pixel uses 1'228'800 bytes, +or 300 memory pages, but AVZ only allows up to 32 pages to be shared. + +Also, the application running on the capsule uses ``mmap`` at initialization to +get an address to the framebuffer and then does not interact with the kernel when +a new frame is available, meaning that the transmission should occur without the +kernel. + +Finally, multiple capsules can run in parallel with their own graphical +application, but only one should be shown on screen. + +Two-stage MMU address mapping +***************************** + +To achieve this, the implementation takes benefit of the two stages of MMU, which +gives the physical (PA), intermediate physical (IPA) and virtual (VA) address +spaces. The address translation goes from VA to IPA, managed by Linux and the +capsules, and then from IPA to PA, managed by the hypervisor AVZ. + +To avoid allocating multiple framebuffers and making copies between them, only two +buffers are allocated: the one used by the screen driver in Linux and a *fake* one. +A fixed IPA is used for the framebuffer seen by the capsules. Depending on the +focused capsule, their respective IPA are either mapped to the actual framebuffer +or the fake one. + +.. figure:: img/micofe-framebuffer-map.png + :name: _fig-framebuffer-map + :alt: Framebuffer IPA and PA address map + :width: 680px + :align: center + + Framebuffer IPA and PA address map + +Only the page tables of IPA to PA need to be changed to switch the shown capsules. +At any time, the framebuffer must only be mapped to one capsule to avoid glitches +on the screen. However, the fake buffer is shared between all hidden capsules, but +this is not considered a problem as it is only used to write data and never read. + +Backend / frontend drivers +************************** + +Like UART, a backend (on Linux) and frontend (on capsules) driver are implemented +to share the required information, like the screen size. + +A user-space application on Linux is used to get the framebuffer address using +``mmap``, which is then given to the backend driver via a *sysfs* file and +transmitted to AVZ with a hypercall. The application then refreshes the screen to +ensure that images are shown correctly at 30 frames per second. A hypercall is also +added to switch focus to another capsule, which is called when switching the +terminal focus with two ``CTRL+A``, ensuring the same capsule is focused on +terminal and screen at the same time. + +The frontend driver exposes the virtual framebuffer device to the LVGL application, +so it can use the standard API. The framebuffer IPA is retrieved with a hypercall. + +.. figure:: img/micofe-framebuffer-flow.png + :name: _fig-framebuffer-flow + :alt: Flow and interaction for framebuffer on capsules + :width: 720px + :align: center + + Flow and interaction for framebuffer on capsules + +The first point is referencing mapping the HDMI port, GPU, and other addresses +required to access the display. + +Input forwarding +**************** + +To allow user interaction with the LVGL application, the input of the keyboard, +mouse, and touchscreen must also be forwarded to the application. This is achieved +with a backend and frontend driver using the existing sharing process, as the +transmitted data sizes are small enough. + +A user-space application is used to get events from all ``/dev/input`` files, +which are forwarded to the backend driver, then to the frontend and finally to the +LVGL application via device files. diff --git a/doc/source/micofe/micofe.rst b/doc/source/micofe/micofe.rst deleted file mode 100644 index e568ac0..0000000 --- a/doc/source/micofe/micofe.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. _micofe: - -MICOFE -###### - -.. toctree:: - :maxdepth: 5 - :hidden: - - emiso - portainer - syscalls_alignment - -MICOFE project will reuse :ref:`EMISO ` to exploit manage micro-services. -:ref:`Portainer ` is used as *Container Orchestration User Interface* -(COUI). diff --git a/doc/source/micofe/portainer.rst b/doc/source/portainer.rst similarity index 100% rename from doc/source/micofe/portainer.rst rename to doc/source/portainer.rst diff --git a/doc/source/rootfs/linux_usr.rst b/doc/source/rootfs/linux_usr.rst deleted file mode 100644 index 9f92e19..0000000 --- a/doc/source/rootfs/linux_usr.rst +++ /dev/null @@ -1,37 +0,0 @@ - -.. _linux_usr: - - -Linux user applications (usr) -***************************** - -In addition to the contents defined in the *rootfs*, additional applications can be built and deployed in the -``linux/usr/`` directory. Such applications are specific to the agency and do not belong to any external packages. - -Deployment in the rootfs -======================== - -All applications and files which need to be deployed in the rootfs must be first installed -in the ``usr/build/deploy`` directory. To do so, the current approach is to edit -the ``usr-linux`` recipe adding the *install* command, for example: - -.. code:: bash - - usr_do_install_file_root "${IB_TARGET}/build/lib/lv_port_linux/lvglsim" - -This command will copy the file ``lvglsim`` to the ``usr/build/deploy`` directory. - - -Development of modules and deployment -===================================== - -Kernel modules can also be compiled in the ``usr/module/`` directory according to the platform as defined -in ``build/conf/local.conf`` file. - -The modules are automatically deployed in the ``root/`` home directory of the target ``rootfs``. -The ``insmod`` application can then be used from the *shell* in order to load the module -into the kernel. - -A module can be helpful for testing purposes, for example to test kernel functionalities. - - diff --git a/doc/source/rootfs/rootfs.rst b/doc/source/rootfs/rootfs.rst deleted file mode 100644 index aa2d5c2..0000000 --- a/doc/source/rootfs/rootfs.rst +++ /dev/null @@ -1,28 +0,0 @@ - -.. _rootfs: - -User applications and rootfs -############################ - -.. toctree:: - :maxdepth: 5 - :hidden: - - linux_usr - -In the Linux environment, there are actually two ``rootfs`` (*root filesystem*). - -The first one is known as ``initrd`` and contains a minimal *rootfs* which is stored in *RAM*. It is -basically used to load firmware, basic drivers and to prepare switching to the secondary *rootfs* -generally stored in a separate partition of the SD-card. - -The second one is the main (secondary) *rootfs* which contains everything required at the user space level. - -The *rootfs* is built by means of ``buildroot`` which can be easily customised according to needs. - -In addtion, user space applications can also be compiled and deployed separately. -These :ref:`applications ` are stored in the ``linux/usr/`` directory. - - - - diff --git a/doc/source/micofe/syscalls_alignment.rst b/doc/source/syscalls_alignment.rst similarity index 77% rename from doc/source/micofe/syscalls_alignment.rst rename to doc/source/syscalls_alignment.rst index 1d8230e..dceb03d 100644 --- a/doc/source/micofe/syscalls_alignment.rst +++ b/doc/source/syscalls_alignment.rst @@ -226,3 +226,65 @@ In fine, all syscall available in SO3 are now listed in ``syscall.tbl``. Here is * Time, ``nanosleep, gettimeofday[_time32], clock_gettime[32]`` * Network, ``socket, connect, bind, ...`` + +Toolchain +********* + +To make the MUSL-based environment usable in practice, the project also required a +complete cross-compilation toolchain able to produce binaries for both ARM32 and +ARM64 SO3 targets. The toolchain is therefore not a secondary convenience component +but a core project deliverable, because it turns the kernel and *libc* compatibility +work described in the previous sections into a reproducible application development +workflow. + +From a project perspective, the role of the toolchain is twofold. First, it provides +developers with a stable way to build applications that match the exact ABI, startup +conventions, and library behavior expected by SO3. Second, it ensures that validation +results are meaningful, because the binaries used during development, testing, and +demonstration are all produced by the same controlled environment. + +Build from source +================= + +The toolchain is built fully from source. This choice improves reproducibility, +avoids dependence on host-distribution packaging choices, and ensures that the exact +versions of *binutils*, compiler runtime components, headers, and MUSL integration +logic are controlled by the project. It also makes it possible to regenerate +identical environments for development machines, CI runners, and future maintenance +activities. + +Building the full toolchain from source is particularly important in an embedded +context. Small differences in compiler version, linker behavior, or runtime support +libraries can lead to subtle differences in binary layout, relocation handling, stack +initialization, or generated code patterns. By controlling the complete chain, the +project reduces the risk of hard-to-diagnose mismatches between the generated binaries +and the SO3 runtime environment. + +A dedicated automated build script was developed to orchestrate the complete +generation process. The script downloads or references the required sources, +configures the build for the selected target architecture, applies the expected +project configuration, and produces the final compiler, linker, runtime support +libraries, and associated *sysroot* in a deterministic way. This automation +significantly reduces setup time for developers and removes a large class of manual +integration errors. + +The generated toolchain does more than compile plain C programs. It also provides the +basis required to build :ref:`C++ applications `, package capsule workloads, and +assemble the demonstrator applications. In that sense, it is the practical bridge +between low-level kernel/libc compatibility and high-level application delivery. + +CI integration and maintainability +================================== + +The toolchain work also required integration into the continuous integration +pipeline. The repository CI/CD workflow was extended so that toolchain builds can be +generated, validated, and versioned automatically. This makes regressions easier to +detect when changes are introduced in the kernel *syscall* layer, in the build +scripts, or in the runtime libraries, because the impact can be observed immediately +at build time rather than much later during manual testing. + +In summary, the toolchain deliverable provides the operational foundation required to +exploit the MUSL integration work. It standardizes builds, improves reproducibility, +enables CI-based validation, reduces platform drift, and makes application development +for SO3 capsules practical for both internal developers and future adopters of the +platform. diff --git a/doc/source/user_guide.rst b/doc/source/user_guide.rst deleted file mode 100644 index e4aa9b2..0000000 --- a/doc/source/user_guide.rst +++ /dev/null @@ -1,275 +0,0 @@ -.. _user_guide: - -User Guide -########## - -The installation should work in any Ubuntu/Kubuntu installation superior -to ``20.04``. It is assumed that you are running an x86_64 version. - -The following description is used to build the different target boards -including the emulated environment based upon QEMU. - -According to the board and requirements of your configuration, all components -are not necessary such as OPTEE-OS or even U-boot if you use x86 boards. - -Pre-requisites -************** - -Shell -===== - -The build system requires the **bash** shell. - -.. warning:: - - With Ubuntu 22.04, the default shell is now ``dash`` which does not - have the same syntax as *bash*. Please have a look at - `this procedure `_ - to replace *dash* by *bash* - -Packages -======== - -The following packages need to be installed: - -.. code:: bash - - sudo apt install make cmake gcc-arm-none-eabi libc-dev \ - bison flex bash patch mount device-tree-compiler \ - dosfstools u-boot-tools net-tools \ - bridge-utils iptables dnsmasq libssl-dev \ - util-linux e2fsprogs - -Since the documentation relies on `Sphinx `_, -the python environment is required as well as some additional extensions: - -.. code:: bash - - sudo apt install python3 - pip install sphinxcontrib-openapi sphinxcontrib-plantuml - -If OPTEE-OS is required, the following python packages are required: - -.. code:: bash - - pip3 install pycryptodome - sudo apt install python3-pyelftools - - -Toolchain -========= - -The AArch-32 (ARM 32-bit) toolchain can be installed with the following commands: - -.. code-block:: shell - - $ sudo mkdir -p /opt/toolchains && cd /opt/toolchains - # Download and extract arm-none-linux-gnueabihf toolchain (gcc v9.2.1). - $ sudo wget https://developer.arm.com/-/media/Files/downloads/gnu-a/9.2-2019.12/binrel/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz - $ sudo tar xf gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz - $ sudo rm gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz - $ sudo mv gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf arm-none-linux-gnueabihf_9.2.1 - $ sudo echo 'export PATH="${PATH}:/opt/toolchains/arm-none-linux-gnueabihf_9.2.1/bin"' | sudo tee -a /etc/profile.d/02-toolchains.sh - -For the 64-bit version (virt64 & RPi4), we are using the `aarch64-none-linux-gnu toolchain version 12.1.rel1 `_, -which is the official ARM toolchain. - -The AARCH-64 (ARM 64-bit) used with SO3/avz is ``aarch64-none-elf-gcc``. It can be -installed with the following commands: - -.. code-block:: shell - - $ sudo mkdir -p /opt/toolchains && cd /opt/toolchains - # Download and extract arm-none-linux-gnueabihf toolchain (gcc v12.3.1). - $ sudo wget https://developer.arm.com/-/media/Files/downloads/gnu/12.3.rel1/binrel/arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-elf.tar.xz - $ sudo tar xf arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-elf.tar.xz - $ sudo rm arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-elf.tar.xz - $ sudo mv arm-gnu-toolchain-12.3.rel1-x86_64-aarch64-none-elf/ aarch64-none-elf_12.3 - $ sudo echo 'export PATH="${PATH}:/opt/toolchains/aarch64-none-elf_12.3/bin"' | sudo tee -a /etc/profile.d/02-toolchains.sh - - -Configuration options -********************* - -The main configuration of the project resides in the ``build/conf/local.conf`` file. - -There is pre-defined values for all variables. - -Platforms -========= - -The ``IB_PLATFORM`` variable defines the target platform (also known as "machine"). - -The following values are possible target platforms: - -+----------------+-------------------------------+ -| Name | Platform | -+================+===============================+ -| *virt32* | QEMU 32-bit emulated platform | -+----------------+-------------------------------+ -| *virt64* | QEMU 64-bit emulated platform | -+----------------+-------------------------------+ -| *rpi4* | Raspberry Pi 4 in 32-bit mode | -+----------------+-------------------------------+ -| *rpi4_64* | Raspberry Pi 4 in 64-bit mode | -+----------------+-------------------------------+ -| *bbb* | BeagleBone Black platform | -+----------------+-------------------------------+ -| *x86* | x86 PC platform | -+----------------+-------------------------------+ -| *x86_qemu* | x86 PC emulated platform | -+----------------+-------------------------------+ -| *imx8_colibri* | x86 PC emulated platform | -+----------------+-------------------------------+ - -Execution of *bitbake* task -*************************** - -Tasks can be executed manually or automatically depending of the dependency scheme as -defined for a specific recipe. - -For manual execution, the task can be executed with the following command, -from the ``build/`` directory: - -.. code-block:: bash - - bitbake ** -c ** - -where ** is the name **without** the ``do_`` prefix. For example, the *do_patch* task is -executed as follows: - -.. code-block:: bash - - bitbake linux -c patch - -Complete building -***************** - -The build system relies on *bitbake* and requires to set some environment variables. -It can be achieved with the following script: - -.. code-block:: bash - - $ source env.sh - -However, the :term:`standard script` executes this command before invoking *bitbake* commands. - -The building of all components is achieved with: - -.. code-block:: bash - - $ ./build.sh -a - -The script ``build.sh`` has different options to build component individually. - -Options are: - -* ``-a`` Build all from scratch -* ``-f`` Create and prepare the filesystem -* ``-l`` Build Linux from scratch -* ``-r`` Build rootfs from scratch -* ``-b`` Build U-boot from scratch -* ``-u`` Build usr apps -* ``-q`` Build QEMU with custom patches (framebuffer enabled) - -QEMU -**** - -The installation of *QEMU* depends on the necessity to have the emulated framebuffer or not. -Currently, the QEMU machine is ``virt`` and is referred as **virt32** for 32-bit and **virt64** -for 64-bit versions in *Infrabase*. - -For the standard installation, QEMU can be installed via the standard ``apt-get`` command. -There are two possible versions of QEMU according to the architecture (32-/64-bit) - -.. code-block:: shell - - $ sudo apt-get install qemu-system-arm (for 32-bit version) - $ sudo apt-get install qemu-system-aarch64 (for 64-bit version) - -In the case of the patched version (with framebuffer enabled), QEMU can be built using the build system with -the following command: - -.. code-block:: bash - - $ ./build.sh -q - -The script will invoke the build task of the QEMU recipe. - - -The following configurations are available: - -+-----------------------+-------------------------------------+ -| Name | Platform | -+=======================+=====================================+ -| *vexpress_defconfig* | Basic QEMU/vExpress 32-bit platform | -+-----------------------+-------------------------------------+ -| *virt64_defconfig* | QEMU/virt 64-bit platform | -+-----------------------+-------------------------------------+ -| *rpi_4_32b_defconfig* | Raspberry Pi 4 in 32-bit mode | -+-----------------------+-------------------------------------+ -| *rpi4_64_defconfig* | Raspberry Pi 4 in 64-bit mode | -+-----------------------+-------------------------------------+ - -(The last one is a custom configuration and is to be used as replacemenent -of rpi_4_defconfig) - - -Root filesystem (*rootfs*) -************************** - -Main root filesystem (**rootfs**) -================================= - -The main root filesystem (*rootfs*) contains all application and configuration files -required by the distribution. It actually refers to user space activities. - -To mount the rootfs, the following command can be executed: - -.. code-block:: bash - - $ ./mount.sh rootfs - -The mounting point is the directory ``fs/``. - -And to unmount: - -.. code-block:: bash - - $ ./umount.sh rootfs - -Initial ramfs (initrd) filesystem -================================= - - -The initial rootfs filesystem, aka *ramfs* (or *initrd*) is loaded in RAM during the kernel -boot. It aims at starting user space applications dedicated to initialization; firmware loading -and mounting specific storage can be achieved at this moment. - -To mount the ramfs, the following command can be executed: - -.. code-block:: bash - - $ ./mount.sh ramfs - -The mounting point is the directory ``fs/``. - -And to unmount: - -.. code-block:: bash - - $ ./umount.sh ramfs - -User space applications -*********************** - -Custom user applications as well as kernel modules are located in -``linux/usr``. - -The build system for user applications relies on *Cmake*. - - - -.. _ARM_toolchain: https://developer.arm.com/-/media/Files/downloads/gnu/12.2.rel1/binrel/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-linux-gnu.tar.xz?rev=6750d007ffbf4134b30ea58ea5bf5223&hash=6C7D2A7C9BD409C42077F203DF120385AEEBB3F5 - - diff --git a/env.sh b/env.sh new file mode 100755 index 0000000..2b2e5b7 --- /dev/null +++ b/env.sh @@ -0,0 +1,40 @@ +#!/bin/sh +export IB_ROOT_DIR=$PWD +export BUILDDIR="$PWD/build" +export BBPATH=$BUILDDIR +PATH=$PATH:$PWD/scripts:$BUILDDIR/bitbake/bin + +# Specify auxiliary layers for the -x component opt +export IB_AUX_LAYERS="meta-usr meta-torizon meta-so3 meta-qemu meta-atf" + +# TODO: It would be nice to test for the presence of such and +# such compiler in meta-bsp +if ! test -z $IB_TOOLCHAIN_PATH +then + PATH="$PATH:$IB_TOOLCHAIN_PATH" +fi + +# Avoid setting uid/gid of the regular user +# when sourced again by the root user in deploy.sh +if test -z "$IB_UNPRIVILEDGED_USER_ID" +then + IB_UNPRIVILEDGED_USER_ID=`id -u` +fi + +if test -z "$IB_UNPRIVILEDGED_GROUP_ID" +then + IB_UNPRIVILEDGED_GROUP_ID=`id -g` +fi + +# If not set - set default list of preserved variables +# that are passed to bitbake +if test -z "$BB_ENV_PASSTHROUGH_ADDITIONS" +then + BB_ENV_PASSTHROUGH_ADDITIONS='IB_TOOLCHAIN_PATH IB_UNPRIVILEDGED_USER_ID IB_UNPRIVILEDGED_GROUP_ID IB_ROOT_DIR' + export BB_ENV_PASSTHROUGH_ADDITIONS +fi + +export PATH +export IB_UNPRIVILEDGED_USER_ID +export IB_UNPRIVILEDGED_GROUP_ID +