GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - uLipe/ulmk_microkernel: A very small microkernel with memory isolation support, predictable WCET, and IPC primitives.The soul's sucessor of the KalangoRTOS.

BranchesTags
Open more actions menu

Latest commit

 

History

305 Commits
305 Commits

Folders and files

NameName
Last commit message
Last commit date
.github/workflows
.github/workflows
 
 
arch
arch
 
 
boards
boards
 
 
cmake
cmake
 
 
components
components
 
 
docs
docs
 
 
include/ulmk
include/ulmk
 
 
kernel
kernel
 
 
linker
linker
 
 
stub
stub
 
 
tests
tests
 
 
tools
tools
 
 
.gitignore
.gitignore
 
 
CMakeLists.txt
CMakeLists.txt
 
 
README.md
README.md
 
 
empty.txt
empty.txt
 
 

Repository files navigation

ulmk

A small, seL4-inspired microkernel for automotive-grade embedded systems. Primary targets: AURIX TriCore TC2xx/TC3xx (QEMU CI), RISC-V RV32IMAC (QEMU virt CI), and ARM Cortex-M — ARMv7-M (Cortex-M7, mps2-an500) and ARMv8-M (Cortex-M33, mps2-an505) on QEMU CI. Isolation is enforced by the hardware MPU/PMP at thread granularity; policy lives entirely in userspace. Single ELF output, O(1) bitmap scheduler, synchronous IPC with priority inheritance.


Architecture overview

ulmk architecture: userspace, syscall gateway, kernel, hardware

Key properties:

  • One ELF, MPU isolation. All components link into a single binary. The hardware MPU enforces data domain boundaries between threads.
  • Synchronous IPC. Caller blocks until server replies. Priority inheritance prevents priority inversion.
  • Component model. Each feature is a component: a directory with a CMakeLists.txt calling ulmk_component_register(). Components default to OFF; enable them with python3 tools/dev.py components enable.
  • No weak symbols. Board and component sources provide strong definitions. A missing symbol is a link error, not a silent no-op.

Microkernel philosophy

ulmk follows the classic microkernel split: the kernel is mechanism, userspace is policy. Threads never call each other directly — they exchange messages through kernel-managed IPC endpoints and notifications. Every privileged operation (create a thread, map memory, bind an IRQ) crosses a single syscall gateway; the kernel validates the request, enforces MPU boundaries, and returns. Driver logic, service topology, and startup order all live in userspace (ulmk_root_thread, board services, components).

Microkernel philosophy: protection domains in userspace talk through kernel IPC endpoints and notifications

The request/reply between the application and the UART driver is only the logical view: the message travels through endpoint E1 in the kernel, and the UART interrupt reaches the driver as a bit on notification N1. Applications hold only the capabilities they were granted; the MPU keeps each thread inside its own areas even though everything links into one ELF.


Application model

ulmk_root_thread()                 ← provided by the ROOT_THREAD component
    board_services_init(info)    ← provided by the board (console, etc.)
    my_component_init()          ← provided by each enabled component
    ulmk_thread_exit()

See docs/application_development_guide.md for a complete walkthrough.


Getting started

Requirements

  • Linux host (Ubuntu 22.04 or newer recommended)
  • Docker (for the dev container — cross-toolchains + QEMU)
  • Python 3.8+

Toolchains and QEMU are only available inside the dev container. Do not try to compile or run target tests on the host.

Enter the dev container

# First run builds the Docker image (~20–30 min)
python3 tools/dev.py

# Force rebuild if the image is stale
python3 tools/dev.py --rebuild

The workspace is mounted at /workspace inside the container.

Build the hello world demo (inside the container)

All components are OFF by default. Enable a demo, build, and run. hello_world is the only builtin component; ping_pong lives in the sibling ulmk_apps/ repo (auto-discovered when present). Each has its own ROOT_THREAD — enable only one at a time.

# 1. See what is available
python3 tools/dev.py components list

# 2. Enable hello_world (builtin)
python3 tools/dev.py components enable hello_world

# 3. Build
python3 tools/dev.py build --board boards/qemu_riscv_virt

# TriCore QEMU (default board)
python3 tools/dev.py build

# ARM Cortex-M7 (ARMv7-M)
python3 tools/dev.py build --board boards/qemu_mps2_an500

# ARM Cortex-M33 (ARMv8-M)
python3 tools/dev.py build --board boards/qemu_mps2_an505

# Clean rebuild
python3 tools/dev.py build --clean

# One-shot enable without saving .ulmk/components.conf
python3 tools/dev.py build --no-components --component hello_world

# IPC demo from ulmk_apps (requires sibling checkout)
python3 tools/dev.py build --no-components --component ping_pong

# Kernel-only image (no components)
python3 tools/dev.py build --no-components

Local component selection is stored in .ulmk/components.conf (gitignored).

Run on QEMU (inside the container)

python3 tools/dev.py build qemu --board boards/qemu_riscv_virt
python3 tools/dev.py build qemu
python3 tools/dev.py build qemu --board boards/qemu_mps2_an500
python3 tools/dev.py build qemu --board boards/qemu_mps2_an505

Expected output with hello_world:

ulmk: kernel entry
...
ulmk: switching to root thread
ulmk: hello from userspace — hello world!

hello_world then stops the simulator, so QEMU exits 0 by itself.

Expected output with ping_pong:

ping_pong: round 1

Alternative: consume ulmk as a prebuilt SDK

The demo above builds a single ELF from the kernel sources. If instead you want to drop ulmk into an existing firmware tree or a third-party IDE (Eclipse, STM32Cube, the Infineon toolchain — e.g. to replace FreeRTOS), build it once as a distributable SDK: two static archives + a fully-processed linker script + the public headers.

# --board is mandatory with --kernel; it may point anywhere (out-of-tree board)
python3 tools/dev.py build --kernel --board boards/qemu_tc3xx

This emits a self-contained tree under build/ulipe-<arch>-sdk/dist/ulmk/:

ulmk/
  lib/libulmk_kernel_<tag>.a  kernel + arch (supervisor)
  lib/libulmk_board_<tag>.a   startup + vectors + board services (driver)
  linker/linker_<tag>.ld      processed linker script
  include/                    public microkernel + board headers

Your firmware then provides ulmk_root_thread(), includes <ulmk/microkernel.h>, and links both archives. See the SDK integration guide for the full recipe, and tests/sdk_e2e/ for a working consumer.

Build options reference

# Custom board chip dir
python3 tools/dev.py build --board /path/to/my_board

CMake configure variables of interest:

-DULMK_CHIP_DIR=boards/qemu_tc3xx           # TriCore QEMU (default)
-DULMK_CHIP_DIR=boards/qemu_riscv_virt      # RISC-V QEMU virt
-DULMK_CHIP_DIR=boards/qemu_mps2_an500      # ARMv7-M Cortex-M7 QEMU
-DULMK_CHIP_DIR=boards/qemu_mps2_an505      # ARMv8-M Cortex-M33 QEMU
-DULMK_COMP_hello_world_ENABLED=ON          # component override (dev.py sets these)
-DULMK_CONFIG_MAX_IRQ_BINDINGS=16          # SRPN → notif binding table
-DULMK_CONFIG_DEBUG_PRINTK=1               # kernel debug prints

Run tests (inside the container)

# Unit tests (host, no QEMU)
python3 tools/dev.py tests unit

# Integration tests — TriCore (default)
python3 tools/dev.py tests integ

# Integration tests — RISC-V
python3 tools/dev.py tests integ --board boards/qemu_riscv_virt

# Integration tests — ARM Cortex-M
python3 tools/dev.py tests integ --board boards/qemu_mps2_an500
python3 tools/dev.py tests integ --board boards/qemu_mps2_an505

Individual integration tests also support ARCH=tricore, ARCH=riscv, or ARCH=arm via tests/integ_common.mk (see any tests/*/Makefile). For ARM, pass ARM_BOARD=qemu_mps2_an500 or ARM_BOARD=qemu_mps2_an505 when invoking make directly.


Repository layout

CMakeLists.txt               top-level build orchestrator
cmake/
  arch.cmake                   ULMK_ARCH selection from board.cmake
  toolchain-tricore-gcc.cmake
  toolchain-riscv-gcc.cmake
  toolchain-arm-gcc.cmake
  component_api.cmake          ulmk_component_register, ulmk_components_finalize
  config.cmake                 kernel configuration symbols
  linker_api.cmake             ulmk_generate_linker_script
  generate_ld.py               assembles the generated linker script
kernel/                      platform-independent kernel
arch/tricore/                TriCore TC1.6.x port
arch/riscv/                  RISC-V RV32 port
arch/arm/                    ARM Cortex-M port (ARMv7-M / ARMv8-M)
boards/qemu_tc3xx/           TriCore QEMU CI board
boards/qemu_riscv_virt/      RISC-V QEMU virt CI board
boards/qemu_mps2_an500/      ARMv7-M Cortex-M7 QEMU CI board
boards/qemu_mps2_an505/      ARMv8-M Cortex-M33 QEMU CI board
components/hello_world/      reference ROOT_THREAD component (default OFF)
components/ulmk_device_manager/  QNX-style userspace device manager (mechanism)
                             # class contracts + demos in sibling ../ulmk_apps/
                             # ping_pong lives in sibling ../ulmk_apps/ping_pong/
include/ulmk/microkernel.h     public API (all syscall wrappers)
linker/                      arch-independent linker fragments
stub/                        documentation-only stub templates
tests/                       unit + sdk_suite (standalone Makefiles)
tools/dev.py                 container frontend
docs/                        specifications and guides

Documentation

Document What it covers
api_spec Complete public API reference
arch_api_spec Architecture abstraction layer contract
build_system_spec CMake build model and component discovery
component_spec Component system design
device_manager_spec Userspace device manager (mechanism vs policy)
linker_spec Three-layer linker script model
application_development_guide How to build an application for custom hardware
arch_porting_guide How to add a new architecture
riscv_implementation RISC-V RV32 port details

License

MIT — see SPDX-License-Identifier: MIT in each source file.

About

A very small microkernel with memory isolation support, predictable WCET, and IPC primitives.The soul's sucessor of the KalangoRTOS.

Resources

Readme
Activity

Stars

16 stars

Watchers

5 watching

Forks

2 forks
Report repository

Releases

Packages

Contributors

Languages

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.