Porting the Genode OS Framework to a new hardware platform

    Recently, more and more companies have shown interest in microkernel operating systems. These systems from the academic category begin to turn into the category of OS for use in real products. For example, the recently introduced Samsung Knox platform is built using the OKL4 Microvisor. It is very likely that there are many more such solutions, but not all manufacturers advertise the technologies used, since at the moment microkernel systems are mainly used in the field of information security.

    A brief history of microkernel OS and a description of the most famous projects were recently described by my colleague sartakov in the article " Microkernels and FOSDEM'13 ". I want to talk more about the Genode OS Frameworkand the process of porting it to a new hardware platform based on an ARM architecture processor. I used Fiasco.OC as a kernel for Genode .



    So what is the Genode OS Framework? This is a framework for building an operating system based on a microkernel. Genode provides a single API that allows you to use various microkernels to build the OS. The following microkernels are currently supported: Codezero, Fiasco, Fiasco.OC, Nova, OKL4, Pistachio. Linux kernel support is also supported. In addition, it is possible to run without the use of third-party cores (base-hw) on some platforms based on the ARM architecture.
    These cores support different processor architectures and may use some hardware features. For example, the Fiasco.OC kernel can work on a large number of architectures, such as: x86, amd64, ARM (other architectures are available, but their support is not used in Genode at the moment), and the Nova core is a micro hypervisor for the x86 architecture and allows you to use hardware virtualization. Thanks to the use of the Genode framework, we can compile the application for use on any of the supported kernels without changing the source code.
    More detailed information about Genode can be obtained from the documentation posted on the project website, as well as from materials read by Norman Feske for the " Ksys labs Summer School of System Programming "

    Currently, Genode + Fiasco.OC for ARM architecture supports the following platforms: Realview PBXA9, Versatile Express A9X4, Pandaboard (TI OMAP4), Freescale iMX53, Arndale (Samsung Exynos 5). All these debug boards are quite expensive, and some are generally very difficult to acquire. Now there are many single-board PCs with a price of less than $ 100, which are used by enthusiasts both as debug boards for studying the OS, and as a basis for prototyping and manufacturing their devices. Linux is usually ported to these devices and some even have open source documentation. A good article with an overview of available devices " Choosing a mini computer for home creativity (DIY) ". Some platforms of the described boards are already supported by the Fiasco.OC kernel and do not require porting.

    As you probably already guessed from the photo at the beginning of the post, I used the Cubieboard mini-PC based on the Allwinner A10 SoC as a porting platform .
    This platform is interesting for a number of reasons:
    - not too outdated Cortex-A8 architecture;
    - the presence of the source code of the U-Boot loader, the Linux kernel, and the presence of “leaked” documentation into the network in the form of a user manual;
    - A large set of peripherals (SATA, HDMI, etc.);
    - the presence of a large number of inexpensive "hackable" devices on this chip (Cubieboard, Mele A1000 / A2000, and others).

    Consider this SoC in more detail.

    CPU: ARM Cortex-A8 with a frequency of up to 1Ghz with support for NEON, VFPv3, Trustzone
    GPU: Mali 400 MP with support for Open GL ES 2.0
    VPU: CedarX with support for FullHD video.
    Peripherals: 4xUSB Host, USB OTG, 4xSD / MMC, 8xUART, 4xSPI, 3xI2C, GPIO, SATA, HDMI, LCD-interface and others.

    Fiasco.OC core supports Cortex-A8 processor architecture. This means that to port it to a new platform you only need to add platform support, the so-called Board Support Package (BSP). The source code for the BSP is located in the directory kernel / fiasco / src / kern / arm / bsp.
    The BSP for the ARM architecture in Fiasco.OC includes:
    - an interrupt controller driver;
    - timer driver;
    - UART driver;
    - implementation of the reset.
    In addition, the BSP includes a memory allocation configuration.
    The memory in A10, according to the user manual, is distributed as follows:

    In order for the OS to use memory, it must know the physical addresses. These parameters are set in the Mem_layout class, mem_layout-arm-sun4i.cpp file:
    EXTENSION class Mem_layout
    {
    public:
      enum Virt_layout_sun4i : Address {
        Timer_map_base       = Devices1_map_base + 0x020C00,
        Intc_map_base        = Devices1_map_base + 0x020400,
        Uart_base            = Devices1_map_base + 0x028000,
        Watchdog_map_base    = Timer_map_base    + 0x90,
      };
      enum Phys_layout_sun4i : Address {
        Devices1_phys_base   = 0x01c00000,
        Sdram_phys_base      = 0x40000000,
        Flush_area_phys_base = 0xe0000000,
      };
    };
    

    An interrupt controller is needed to handle events from various sources. The driver of the interrupt controller is used to control the controller, performing operations such as: controller configuration, masking interrupts, processing function. Driver code in pic-arm-sun4i.cpp file.

    A timer is needed to generate events, such as the end of a time slot or the IPC timeout. The A10 has 6 timers. The timer Timer0 is used as a timer for interruptions. In addition to general timers, SoC also includes Watchdog and RTC with an alarm clock. To use the timer in system mode, it must generate an interrupt every 1 ms. Timer initialization and necessary functions are implemented in the timer-arm-sun4i.cpp file.

    The UART driver is used by the kernel to output debugging messages and access the JDB kernel debugger. There is no initialization of the UART module in Fiasco.OC; it is believed that the bootloader has already configured it, in our case, U-Boot. The UART driver code is located in the files uart-arm-sun4i.cpp and kernel / fiasco / src / lib / uart / uart_sun4i.cc.

    To perform a complete reset of the processor, a Watchdog timer is used, the purpose of which is to reset the system when the code loops. The implementation is in the reset-arm-sun4i.cpp file.

    After performing these steps, we get the BSP for the selected processor. But the kernel still needs to be loaded. Consider the boot process of Genode + Fiasco.OC on the ARM architecture:

    1. At startup, ROM-boot looks for a bootloader on an SD card or boots from NAND if there is no SD card.
    2. U-Boot, executing the startup scripts, loads the Genode image as ELF or u-boot-image.
    3. The loaded module contains the Fiasco.OC kernel and all other executable files, such as: sigma0, root task (in Genode it is the core module) and user programs.
    4. Bootstrap is the first to start, which performs part of the operations necessary to start the kernel, such as:
    - scanning available memory (not for all architectures; on ARM, the available memory is set in the configuration on the platform);
    - moving modules in memory (sigma0 and root task must be located in certain regions so that the kernel can start them at startup);
    - and directly launch the kernel.
    7. The kernel performs the necessary initialization of the system, starts sigma0 and root task.
    8. The core module (which is the root task) starts, which initializes the Genode services and allows you to run the applications we need using the configuration file.

    Accordingly, to run bootstrap on Cubieboard, he must know about this platform, so we add the necessary configuration l4 / mk / platforms / cubieboard.conf and l4 / pkg / bootstrap / server / src / platform / sun4i.cc. In addition, you must implement the UART driver to display information about the download to the console.

    The final step in porting is to add the necessary configuration files to the Genode build system. The process is simple, I will not describe it, you can see the changes in the corresponding commit in the repository. A good description of the build system was discussed in the " Genode OS Framework Programming Environment " lecture .

    The source code is on Github https://github.com/Ksys-labs/genode in the tutorials branch. A modified version of Fiasco.OC in the https://github.com/Ksys-labs/foc repository in the r47-sun4i branch, these source codes already contain the necessary patches and are downloaded using the Genode build system.

    To build, you must clone the source code:
    git clone git://github.com/Ksys-labs/genode.git
    git checkout tutorials
    cd genode
    

    Build toolchain for ARM:
    ./tools/tool_chain arm
    

    And download the Fiasco.OC kernel:
    make prepare -C base-foc
    

    Now everything is ready to run.
    1. Create a directory for the assembly using the command:
    ./tools/create_builddir foc_cubieboard BUILD_DIR=_build.foc_cubieboard
    cd _build.foc_cubieboard
    

    2. Add the hello_tutorial repository to cope with the simplest scenario, which does not require drivers that are not yet available.
    echo 'REPOSITORIES += $(GENODE_DIR)/hello_tutorial' >> etc/build.conf
    

    3. Turn on u-boot-image file generation
    echo 'SPECS += uboot' >> etc/spec.conf
    

    4. Collect the image
    make run/hello
    

    After a short build, we get the image in the form: ELF (hello.elf) and u-boot-image (uImage) in the var / run / hello directory.
    After starting on the device, in the connected console, you can see the boot process and running applications from the hello tutorial:
    Log
    L4 Bootstrapper
    Build: # 4 Th. Apr 18 22:48:37 MSK 2013, 4.7.2
    Scanning up to 1024 MB RAM
    Memory size is 1024MB (40000000 - 80000000)
    RAM: 0000000040000000 - 000000007fffffff: 1048576kB
    Total RAM: 1024MB
    mod07: 4117e000-411b8e3c: genode / timer
    mod06: 41148000 -4117ddc0: genode / hello_server
    mod05: 4111c000-41147c28: genode / hello_client
    mod04: 410d6000-4111b738: genode / init
    mod03: 410d5000-410d51a4: genode / config
    mod02: 4106e000-410d431c: 4106e000-400400400400
    mod4
    core01 : 41015000-41063d20: /home/vanner/projects/genode/_build.foc_cubieboard/kernel/fiasco.oc/fiasco
    Moving up to 8 modules behind 41100000
    moving module 00 {41015000-41063d1f} -> {412a4000-412f2d1f} [322848]
    moving module 01 {41064000-4106d373} -> {412f3000-412fc373} [37748]
    moving module 02 {4106e000-410d431b} -> {412f1000-413633-413633-4000 } [418588]
    moving module 03 {410d5000-410d51a3} -> {411b9000-411b91a3} [420]
    moving module 04 {410d6000-4111b737} -> {411ba000-411ff737} [284472]
    moving module 05 {4111c000-41147c27} -> {41100000-4112bc27} [179240]
    moving module 06 {41148000-4117ddbf} -> {4112c000-41161dbf} [220608]
    moving module 07 {4117e000-411b8e3b} -> {41162000-4119ce3b} [241212]
    moving module 03 {411b9000- 411b91a3} -> {4119d000-4119d1a3} [420]
    moving module 04 {411ba000-411ff737} -> {4119e000-411e3737} [284472]
    Scanning /home/vanner/projects/genode/_build.foc_cubieboard/kernel/fiasco.oc/fiasco -serial_esc
    Scanning sigma0
    Scanning genode / core
    Relocated mbi to [0x4100e000-0x4100e19c]
    Loading cts / genode / _build.foc_cubieboard / kernel / fiasco.oc / fiasco
    Loading sigma0
    Loading genode / core
    find kernel info page ...
    found kernel info page at 0x40002000
    Regions of list 'regions'
    [40001000, 400019ff] { a00} Kern cts / genode / _build.foc_cubieboard / kernel / fiasco.oc / fiasco
    [40090000, 4009673b] {673c} Kern cts / genode / _build.foc_cubieboard / kernel / fiasco.oc / fiasco
    [4000f2000, 40060fff] {5f000} Sigma0 sigma0
    [40098000, 4009e17b] {617c} Sigma0 sigma0
    [40100000, 4024743f] {147440} Root genode / core
    [41000000, 410143f3] {143f4} Boot bootstrap
    [4100e000, 4100e299] {29a} Root Multiboot info
    [41137000], 41137000, 411 } Root Module
    API Version: (87) experimental
    Sigma0 config ip: 40090100 sp: 41013d24
    Roottask config ip: 4014af84 sp: 00000000
    Starting kernel cts / genode / _build.foc_cubieboard / kernel / fiasco.oc / fiasco at 40001198
    Hello from Startup :: stage2
    Boot_alloc: size = 0x180
    Boot_alloc: allocated extra memory block @ 0xf13e1000 (size = 400)
    Boot_alloc: @ 0xf13e1000
    Boot_alloc: remaining free block @ 0xf13e1180 (size = 280)
    Cache config: ON
    ID_PFR [01]: 00001131 00000011 ID_ [DA] FR0: 00000400 00000000
    ID_MMFR [04]: 01100003 20000000 01202000 00000211
    FPU0: Arch: VFPv3 (3), Part: VFPv3 (30), r: 3, v: c, i: 41, t: hard, p: dbl / sngl
    Startup :: stage2 finished
    SERIAL ESC: allocated IRQ 1 for serial uart
    Not using serial hack in slow timer handler.
    Welcome to Fiasco.OC (arm)!
    L4 / Fiasco.OC arm microkernel 1998-2013 TU Dresden
    Rev: 8991035 compiled with gcc 4.7.2 for sun4i []
    Build: # 3 Th. Apr 18 22:48:33 MSK 2013

    Calibrating timer loop ... done.
    SIGMA0: Hello!
    KIP @ 40002000
    allocated 4KB for maintenance structures
    SIGMA0: Dump of all resource maps
    RAM: ------------------------
    [0: 40000000; 40000fff]
    [0: 40061000; 4008ffff]
    [0: 40097000; 40097fff]
    [0: 4009f000; 400fffff]
    [4: 40100000; 40247fff]
    [0: 40248000; 4100dfff]
    [4: 4100e000; 4100efff]
    [ 0: 4100f000; 410fffff]
    [4: 41100000; 411e3fff]
    [0: 411e4000; 7effffff]
    IOMEM: ----------------------
    [0: 0; 3fffffff ]
    [0: 80000000; ffffffff]

    KIP @ 40002000
    magic: 4be6344c
    version: 87014444
    sigma0 esp: 41013d24 eip: 40090100
    sigma1 esp: 00000000 eip: 00000000
    root esp: 00000000 eip: 4014af84
    MBI @ 4100e000
    mod [3] [4111d000] config
    mod [4] [4119e000,411e3738) init
    mod [5] [41100000,4112bc28) hello_client
    mod [6] [4112c000,41161dc0) hello_server
    mod [7] [41162000,4119ce3c) timer
    : ram_alloc: Allocator 40230784 dump:
    Block: [50000000,5000001c) size = 0000001c avail = 0000001c avail = 0000 max_avail = 00000000
    Block: [5000001c, 50000038) size = 0000001c avail = 00000000 max_avail = 00000000
    Block: [50000038,50000054) size = 0000001c avail = 00000000 max_avail = 00000000
    Block: [50000054,50000070) size = 0000001c avail = 00000000 max_avail = 2effff58
    Block: [50000070,5000008c) size = 0000001c avail = 00000000 max_avail = 00000000
    Block: [5000008c, 500000a8) size = 0000001c avail = 00000000 max_avail = 2effff58
    Block: [500000a8,7f000000) size = 2effff58 avail = 2effff58 max_avail
    => mem_size = 788529152 (752 MB) / mem_avail = 788528984 (751 MB)
    : region_alloc: Allocator 402318f4 dump:
    Block: [00001000,40000000) size = 3ffff000 avail = 3ffff000 max_avail = 3ffff000
    Block: [7f000000, bfff0000) size = 40 avail = 40ff0000 max_avail = 40ff0000
    Block: [bfff1000, c0000000) size = 0000f000 avail = 0000f000 max_avail = 0000f000
    => mem_size = 2164252672 (2063 MB) / mem_avail = 2164252672 (2063 MB)
    : io_mem: Allocator 40230be0 dump:
    Block: [0000] , 40000000) size = 40,000,000 avail = 40,000,000 max_avail = 40,000,000
    Block: [40,000,000,4000,2000) size = 00001,000 avail = 00001,000 max_avail = 40,000,000
    Block: [4,0003,000,40061,000) size = 0005e000 avail = 0005e000 max_avail = 0005e000
    Block: [40090000,40097000) size = avail = 00007000 = 00007000 0005e000 max_avail
    Block: [40098000,4009f000) size = avail = 00007000 = 00007000 80ffffff max_avail
    Block: [7f000000, ffffffff) size = 80ffffff avail = 80ffffff max_avail 80ffffff =
    => mem_size = 3238449151 (3088 MB) / mem_avail = 3238449151 (3088 MB)
    : io_port: Allocator 4023103c dump::
    irq: Allocator 40231498 dump:
    Block: [00000000,00000100) size = 00000100 avail = 00000100 max_avail = 00000100
    => mem_size 256 (0 MB) / mem_avail = 256 (0 MB)
    : rom_fs: Rom_fs 402321a8 dump:
    Rom: [4119e000,411e3738) init
    Rom: [41100000,4112bc28) hello_client
    Rom: [4119d000,4119d1a4) config
    Rom: [4112c000,41161dc0 hello_server
    Rom: [40002000,40003000) l4v2_kip
    Rom: [40002000,40003000) kip
    Rom: [41162000,4119ce3c) timer
    : core ranges: Allocator 40233f08 dump:
    Block: [40100000,40248000) size = 00148000 avail = 00148000 max_avail = 00148000
    Block: [41100000,411e4000) size = 000e4000 avail = 000e4000 max_avail = 2f000000
    Block: [50000000,7f000000) size = 2f000000 avail = 2f000000 max_avail 2f000000 =
    => mem_size = 790 806 528 (754 MB) / mem_avail = 790 806 528 (754 MB)
    int main ( ): - create local services - int main (): - start init - int main (): transferred 751 MB to init
    int main (): - init created, waiting for exit condition - [init] Could not open file “ld. lib.so »
    [init -> hello_server] Hello :: Root_component :: Root_component (Genode :: Rpc_entrypoint *, Genode :: Allocator *): Creating root component.
    [init -> hello_server] virtual Hello :: Session_component * Hello :: Root_component :: _ create_session (const char *): creating hello session.
    [init -> hello_client] virtual void Hello :: Session_client :: say_hello (): Saying Hello.
    [init -> hello_server] virtual void Hello :: Session_component :: say_hello (): I am here ... Hello.
    [init -> hello_client] int main (): Added 2 + 5 = 7
    [init -> hello_client] virtual void Hello :: Session_client :: say_hello (): Saying Hello.
    [init -> hello_server] virtual void Hello :: Session_component :: say_hello (): I am here ... Hello.
    [init -> hello_client] int main (): Added 2 + 5 = 7
    ...

    As you can see, porting the microkernel to the new architecture is not at all difficult. Of course, as I wrote above, to use micronuclei in real projects, everything depends on the support of the platform hardware. For example, when making prototypes of devices based on Pandaboard and Gumstix Overo, we had to add a lot of drivers, such as: GPIO, UART, SPI, I2C. These interfaces were required to work with the LCD, touchscreen and smartcard reader. To use Cubieboard as a mini-PC with Genode, at least you need to write (or port) drivers: Framebuffer, USB, Ethernet.

    Genode Labs plans to build a modern OS based on its framework and they are confidently moving in this direction. This is a very interesting open source project related to alternative OSs. Genode is not very demanding on resources, and in my opinion, single-board PCs based on ARM architecture may well be used as one of the cheapest platforms for this OS.

    In addition, Genode is great for studying in the field of Computer Science, and if you are a student and you are interested, you can join us. To do this, you need to look at the first three lectures ( 1 , 2 , 3 ) and complete the tasks from them. You need to post the solution on Github and send a link to edu@ksyslabs.org.

    Also popular now: