Multum In Parvo Operating System is a cooperative multitasking RTOS designed for single-chip microcontrollers with severely limited RAM and ROM. It provides tasks, mutual exclusion, signals, message queues, memory management, malloc, memory pools, timers, and optional console, file-system, and stdio support.
mipOS is written mainly in C and is intended to stay compact, portable, and easy to study. It can also run as a user-space simulator on Windows, Linux, and macOS.
The original design and source code were published in an article for the magazine Computer Programming, describing the internals of a portable and scalable kernel for resource-constrained microcontrollers. A modern, in-depth description of the kernel internals is available in docs/mipos-internals.md.
mipOS has been tested on Intel x86/x64 simulator targets, STM8, STM32, and ARM Cortex-M3 microcontroller families. The simulator also builds on ARM64 hosts; on macOS ARM64, the C/C++ unit tests run but the cooperative scheduler smoke test is disabled because the simulator context-switch backend is not currently supported on Apple Silicon.
See also: https://www.eantcal.eu/home/mipos. For release notes and recent project changes, see NEWS.md. Wiki-ready pages are maintained under docs/wiki for repositories where the GitHub wiki is not enabled yet.
CMake is the supported entry point for desktop simulator builds. The old checked-in Visual Studio solution and project files have been removed; generate Visual Studio solutions on demand from CMake instead.
cmake -S . -B build-vs-x64 -G "Visual Studio 18 2026" -A x64
cmake --build build-vs-x64 --config Release --parallelFor Visual Studio 2022, use:
cmake -S . -B build-vs-x64 -G "Visual Studio 17 2022" -A x64cmake -S . -B build-vs-win32 -G "Visual Studio 18 2026" -A Win32
cmake --build build-vs-win32 --config Release --parallelcmake -S . -B build
cmake --build build --parallelThe native build supports x86-64 and AArch64 hosts. On Apple Silicon, CMake builds the simulator natively and runs the non-scheduler unit tests; the cooperative scheduler smoke test is skipped because the simulator context switching backend is not supported on macOS ARM64.
cmake -S . -B build-linux-x64 -DMIPOS_ARCH=x64
cmake --build build-linux-x64 --parallelcmake -S . -B build-linux-x86 -DMIPOS_ARCH=x86
cmake --build build-linux-x86 --parallelLinux x86 builds require a 32-bit multilib toolchain and runtime. On Debian or
Ubuntu, install the equivalent of gcc-multilib and g++-multilib.
cmake -S . -B build-macos-x64 -DMIPOS_ARCH=x64
cmake --build build-macos-x64 --parallelMIPOS_ARCH=x64 sets CMAKE_OSX_ARCHITECTURES=x86_64 (on Apple Silicon the
binaries run under Rosetta; prefer the native build there). MIPOS_ARCH=x86
maps to i386, which requires a legacy macOS SDK/toolchain with 32-bit
executable support.
GoogleTest-based unit tests are available through CMake. They are enabled by
default when BUILD_TESTING is on, or explicitly with MIPOS_BUILD_TESTS=ON.
cmake -S . -B build-vs-x64 -G "Visual Studio 18 2026" -A x64 -DMIPOS_BUILD_TESTS=ON
cmake --build build-vs-x64 --config Release --target mipos_tests --parallel
ctest --test-dir build-vs-x64 -C Release --output-on-failureThe current test targets cover:
- queue FIFO and capacity behavior
- fixed-size memory pool allocation and reuse
- mipOS malloc/free/realloc basics
- cooperative multitasking: task creation, round-robin yielding, and task termination through the scheduler
- optional lwIP Ethernet/IPv4 integration: ARP, ICMP, UDP, TCP, DHCP, and DNS over a simulated link driver
The test suite also runs in CI (GitHub Actions) on Linux x64/x86, Windows
x64/Win32, and macOS ARM64. The macOS ARM64 job builds the project and runs
the GoogleTest unit tests; mipos_scheduler_smoke is intentionally not
registered on that host architecture.
- CMake is the canonical build system for desktop simulator builds and for the QEMU ARM port.
- Checked-in Visual Studio solutions/projects were removed; generate them with CMake when needed.
- GoogleTest covers queues, memory pools, and malloc behavior.
mipos_scheduler_smokeexercises cooperative scheduling on supported simulator hosts: Linux x64/x86 and Windows x64/Win32.- Optional STM8 firmware builds can be enabled with
-DMIPOS_TARGET_STM8_SDCC=ONwhen SDCC is installed. - Optional networking can be enabled with
-DMIPOS_NET_STACK=lwip. The current lwIP port isNO_SYS=1, IPv4/Ethernet only, and enables ARP, ICMP, UDP, TCP raw APIs, DHCP client, and DNS client. IPv6, sockets, and netconn are not enabled. - macOS ARM64 support is currently build/unit-test coverage only for the simulator. Scheduler context switching on Apple Silicon needs a dedicated backend before scheduler examples or smoke tests can be considered supported.
The default build does not include a TCP/IP stack. To enable the experimental
lwIP port, configure with MIPOS_NET_STACK=lwip:
cmake -S . -B build-vs-x64-lwip -G "Visual Studio 18 2026" -A x64 -DMIPOS_NET_STACK=lwip
cmake --build build-vs-x64-lwip --config Release --target mipos_lwip_tests
.\build-vs-x64-lwip\Release\mipos_lwip_tests.exeCMake downloads lwIP 2.2.1 from the official Savannah release archive and
builds only the subset needed by mipOS. The first driver model is an Ethernet
netif adapter with receive injection and link-output callbacks; the test
coverage verifies ARP, ICMP echo reply, UDP output, TCP connect/listen setup,
DHCP discover output, and DNS query output without requiring hardware.
For an end-to-end host test, use Npcap to capture and inject Ethernet frames
on a Layer-2 adapter such as TAP-Windows. This keeps ARP visible to mipOS, so
the first real service test can be the normal Windows ping command.
-
Install Npcap and a TAP adapter, for example the OpenVPN TAP-Windows driver.
-
In an Administrator PowerShell, create/configure the TAP adapter and start the mipOS side:
.\scripts\run-net-pcap.ps1 -EnsureTap
This looks for an existing
mipOS TAPadapter, otherwise tries to create one with OpenVPNtapctl.exe, configures the Windows side as10.77.0.1, and starts mipOS as10.77.0.2.To let mipOS reach hosts beyond the TAP subnet, also enable Windows NAT:
.\scripts\run-net-pcap.ps1 -EnsureTap -EnableNat
This enables IPv4 forwarding on the TAP interface and creates a Windows
NetNatnamedmipOSNatfor the10.77.0.0/24internal prefix. -
To inspect adapters manually instead:
.\scripts\run-net-pcap.ps1 -List
-
Or start the mipOS lwIP bridge on a specific TAP/Npcap adapter index:
.\scripts\run-net-pcap.ps1 -Adapter 3 -Ip 10.77.0.2 -Gateway 10.77.0.1
-
In another terminal, test ARP + ICMP:
ping 10.77.0.2
By default the TAP console keeps packet logs disabled. Type verbose to show
compact packet logs such as RX ARP who-has 10.77.0.2,
TX ARP is-at 10.77.0.2, RX ICMP echo request, and TX ICMP echo reply;
type quiet to hide them again. example-net-pcap.exe still supports
--quiet when run directly.
The TAP backend also exposes a small interactive console on the mipOS side:
mipOS-net> help
mipOS-net> route
mipOS-net> route 1.1.1.1
mipOS-net> arp 10.77.0.1
mipOS-net> ping 10.77.0.1
mipOS-net> ping 1.1.1.1
mipOS-net> udp 10.77.0.1 9000 hello
mipOS-net> tcp 1.1.1.1 80
mipOS-net> dhcp status
mipOS-net> dns server 1.1.1.1
mipOS-net> dns example.com
mipOS-net> stats
The console keeps an in-memory command history for the current session; use the Up/Down arrow keys to recall previous commands. On Linux the TAP and pcap consoles use a small raw-mode line editor that handles Backspace, Delete, Ctrl-C, and Ctrl-D while restoring the terminal state on exit.
route prints the current IPv4 routing view:
mipOS-net> route
destination gateway netmask iface type
10.77.0.0 0.0.0.0 255.255.255.0 mip0 connected
0.0.0.0 10.77.0.1 0.0.0.0 mip0 default
mipOS-net> route 1.1.1.1
destination next-hop iface type
1.1.1.1 10.77.0.1 mip0 default
arp should resolve the Windows-side TAP address. ping 10.77.0.1 sends an
ICMP echo request from mipOS to Windows; if the packet log shows the outgoing
request but no reply, allow inbound ICMP echo requests for that Windows network
profile/firewall rule and try again. With -EnableNat, ping 1.1.1.1 should
route via 10.77.0.1; ICMP through Windows NAT can still depend on local
firewall/NAT policy, so the packet log is the first thing to inspect.
The udp, tcp, dhcp, and dns commands exercise lwIP raw APIs from the
TAP console. udp emits one datagram, tcp starts a single connect attempt,
dhcp start|stop|status controls the DHCP client, and dns server <ip> plus
dns <name> configures and tests the DNS client. The host TAP setup does not
provide a DHCP server by itself; use static addressing unless a DHCP service is
running on that Layer-2 segment.
The example-net-pcap binary loads wpcap.dll dynamically on Windows, so the
project does not need the Npcap SDK to compile. On Linux, the normal end-to-end
path uses example-net-tap directly through /dev/net/tun; this makes the
kernel TAP behave like a connected Ethernet peer for ARP, ICMP, and routed
traffic:
sudo apt install cmake build-essential libpcap-dev iproute2
bash scripts/run-net-pcap.sh --ensure-tapThe Linux helper creates/configures mipos-tap as 10.77.0.1/24 and starts
mipOS as 10.77.0.2. In another terminal:
ping 10.77.0.2Opening /dev/net/tun normally requires elevated privileges; the helper runs
the TAP example with sudo when needed. If you run the binary manually, use
sudo ./build-linux-x64-net/example-net-tap --name mipos-tap or grant the
equivalent capability yourself. While the example is running, ip link show mipos-tap should show the TAP link as up with carrier; if the process stops,
Linux may show the interface as NO-CARRIER.
To allow mipOS traffic to leave the TAP subnet on Linux, enable forwarding and an iptables masquerade rule through the helper:
bash scripts/run-net-pcap.sh --ensure-tap --enable-natFor manual Linux adapter selection:
bash scripts/run-net-pcap.sh --list
bash scripts/run-net-pcap.sh --adapter mipos-tapManual --adapter mode uses libpcap and is mainly useful for adapter listing,
capture, and experiments. For the host kernel to answer mipOS ARP requests on a
Linux TAP device, prefer --ensure-tap, which uses the direct TAP backend.
Wintun is a useful future backend for Layer-3 IP packet tests, but it does not expose Ethernet/ARP frames, so TAP is the better first target for ARP and ping.
The QEMU port can also build cross-compiled lwIP firmware. The interactive
network console uses the same netif adapter with an in-memory Ethernet peer,
so it validates ARP and ICMP inside the ARM/QEMU environment while the real
Stellaris Ethernet driver is still pending:
.\scripts\run-qemu.ps1 net-consoleInside QEMU:
mipOS-net> ip
mipOS-net> peer
mipOS-net> route
mipOS-net> arp
mipOS-net> ping
mipOS-net> stats
The default mipOS address is 192.168.1.2; the in-memory peer and gateway are
192.168.1.10. This is a firmware-level lwIP exercise, not a host-routed QEMU
NIC path yet.
For the non-interactive self-test:
cmake -S . -B build-qemu-arm -G Ninja `
-DCMAKE_TOOLCHAIN_FILE=cmake/arm-none-eabi-toolchain.cmake `
-DMIPOS_TARGET_QEMU_ARM=ON `
-DMIPOS_QEMU_ARM_NET_SELFTEST=ON
cmake --build build-qemu-arm --target mipos-arm-qemu-net-selftest
.\scripts\run-qemu.ps1 net-selftestThe STM8 port has an optional build path for the Small Device C Compiler. This keeps the historical 8-bit BSP usable with a free toolchain instead of requiring older proprietary compilers.
Requirements:
sdccwith STM8 support;- optional
ucsim_stm8/sstm8fromsdcc-ucsimfor CPU-level simulation.
Build directly with CMake:
cmake -S . -B build-stm8-sdcc -DMIPOS_TARGET_STM8_SDCC=ON
cmake --build build-stm8-sdcc --target stm8-sdcc-helloworld --parallelThe output image is:
build-stm8-sdcc/stm8-sdcc/stm8s_example.ihx
Or use the helper scripts:
.\scripts\run-stm8-sdcc.ps1
.\scripts\run-stm8-sdcc.ps1 -Simsh scripts/run-stm8-sdcc.sh
sh scripts/run-stm8-sdcc.sh --example console --sim
sh scripts/run-stm8-sdcc.sh --test-console --rebuildThe console example exposes the emulated UART on localhost:7777 and the
uCsim monitor on localhost:7778. The automated mode drives help, ps, and
dump through the UART, verifies their output, and closes uCsim. The STM8S208
simulation uses a 16 MHz clock and polls TIM4 overflow from the scheduler to
advance the mipOS RTC without relying on an emulated interrupt vector table.
Simulator examples are built by default. Disable them with
-DMIPOS_BUILD_EXAMPLES=OFF.
Built example binaries use the example- prefix, for example:
./build/example-filesystemOn Visual Studio generators, binaries are emitted under the configuration directory, for example:
.\build-vs-x64\Release\example-filesystem.exeThe filesystem example loads mipOS inside a host process and mounts a disk image containing sample files.
Besides the host simulator, mipOS can be built as native bare-metal ARM
Cortex-M firmware and executed by QEMU. The port lives in
mipos/arch/qemu-arm/ and targets the QEMU lm3s6965evb machine
(TI Stellaris LM3S6965, Cortex-M3): UART0 console, SysTick-driven 1 ms RTC
quantum, cooperative context switch built on newlib setjmp/longjmp.
Requirements: the Arm GNU toolchain
(arm-none-eabi-gcc) and qemu-system-arm.
cmake -S . -B build-qemu-arm \
-DCMAKE_TOOLCHAIN_FILE=cmake/arm-none-eabi-toolchain.cmake \
-DMIPOS_TARGET_QEMU_ARM=ON
cmake --build build-qemu-arm --parallelThis produces the base firmwares (each with .elf, .bin, and .map):
mipos-arm-qemu.elf- hello-world demo: boots mipOS and prints a tick every secondmipos-arm-qemu-console.elf- interactive mipOS console (CLI) on the emulated UARTmipos-arm-qemu-filesystem.elf- interactive console with a RAM-backed mipOS tiny filesystem; trylsandcat test1mipos-arm-qemu-fatfs.elf- interactive console with FatFs over a host-backed block device through QEMU semihostingmipos-arm-qemu-net-console.elf- optional lwIP network console, enabled by the launch script when selectedmipos-arm-qemu-net-selftest.elf- optional lwIP ARP/ICMP self-test, enabled by the launch script when selected
The launch scripts build the firmware on first use and start QEMU:
.\scripts\run-qemu.ps1 # filesystem demo
.\scripts\run-qemu.ps1 console # mipOS console (CLI)
.\scripts\run-qemu.ps1 fatfs # FatFs host-backed block device
.\scripts\run-qemu.ps1 net-console # lwIP network console
.\scripts\run-qemu.ps1 net-selftest # lwIP ARP/ICMP self-test
.\scripts\run-qemu.ps1 helloworld # tick demo
.\scripts\run-qemu.ps1 vexpress-helloworld # vexpress-a9 UART/root-task demoGenerated Visual Studio solutions also include utility targets under
QEMU Examples: qemu-filesystem, qemu-console, qemu-fatfs,
qemu-net-console, qemu-helloworld, and qemu-vexpress-helloworld. Build
one of those targets to launch the corresponding firmware through
scripts/run-qemu.ps1.
From cmd.exe on Windows, use the wrapper:
scripts\run-qemu.cmd rem filesystem demo
scripts\run-qemu.cmd console rem mipOS console (CLI)
scripts\run-qemu.cmd fatfs rem FatFs host-backed block device
scripts\run-qemu.cmd net-console rem lwIP network console
scripts\run-qemu.cmd net-selftest rem lwIP ARP/ICMP self-test
scripts\run-qemu.cmd helloworld rem tick demo
scripts\run-qemu.cmd vexpress-helloworld rem vexpress-a9 UART/root-task demo./scripts/run-qemu.sh # filesystem demo
./scripts/run-qemu.sh console # mipOS console (CLI)
./scripts/run-qemu.sh fatfs # FatFs host-backed block device
./scripts/run-qemu.sh net-console # lwIP network console
./scripts/run-qemu.sh net-selftest # lwIP ARP/ICMP self-test
./scripts/run-qemu.sh helloworld # tick demo
./scripts/run-qemu.sh vexpress-helloworld # vexpress-a9 UART/root-task demoOn Linux or WSL, run-qemu.sh can launch an already-built firmware with only
qemu-system-arm installed. If the selected ELF is missing, or if you pass
--rebuild, install the ARM bare-metal toolchain too, for example
arm-none-eabi-gcc plus CMake.
or run QEMU directly:
qemu-system-arm -M lm3s6965evb \
-kernel build-qemu-arm/mipos-arm-qemu.elf \
-nographic -serial mon:stdiomipOS intentionally keeps three ARM QEMU profiles side by side:
lm3s6965evbis the current Cortex-M3 workhorse: console, filesystem, FatFs semihosting, and lwIP in-memory ARP/ICMP tests already run there.vexpress-a9is the didactic historical board. The first step is runnable today withvexpress-helloworld: startup, PL011 UART, ARM mode stacks, critical sections, and a mipOS root task. Timer/GIC, PL181 SD, and LAN9118 Ethernet are deliberately the next bring-up steps.virtis the future functional/CI board. The planned port lives undermipos/arch/qemu-virt/and should use PL011 first, then the ARM generic timer/GIC, followed by virtio-mmio block and network devices.
Build the current vexpress-a9 firmware directly with:
cmake -S . -B build-qemu-vexpress-a9 \
-DCMAKE_TOOLCHAIN_FILE=cmake/arm-none-eabi-toolchain.cmake \
-DMIPOS_TARGET_QEMU_VEXPRESS_A9=ON
cmake --build build-qemu-vexpress-a9 --parallel
qemu-system-arm -M vexpress-a9 \
-kernel build-qemu-vexpress-a9/mipos-arm-qemu-vexpress-a9.elf \
-nographic -serial mon:stdioThe hello-world firmware boots mipOS, starts a root task, and prints on the emulated UART:
mipOS ARM/QEMU port booting...
root task running
tick: 1
tick: 2
...
The filesystem firmware is the default launch-script demo. It presents the
mipOS> prompt and preloads two files in RAM:
mipOS tiny filesystem demo
Type 'ls' and 'cat test1'.
mipOS>ls
Volume label RAMDISK
test1 56 bytes
test2 55 bytes
mipOS>cat test1
test1 56 bytes
0123456789abcdefghijklmnopqrstuvwxyz0123ABCDEFGHIJKLMNO
The console firmware presents the same prompt without the filesystem commands;
type help for the list of built-in commands (ver, ps, dump, freeze,
signal, ...):
mipOS>ps
pid: 01 root@0x119 psig:00000000 wsig:00000001 status: 8 suspend ...
pid: 02 cnsltx@0x1579 psig:00000000 wsig:00000002 status: 8 suspend ...
pid: 03 cnslrx@0x1411 psig:00000000 wsig:00000000 status: 4 running ...
Exit QEMU with Ctrl-A x.
Start QEMU halted with a GDB server on port 1234 (or use the launch scripts
with -Gdb / --gdb):
qemu-system-arm -M lm3s6965evb \
-kernel build-qemu-arm/mipos-arm-qemu.elf \
-nographic -S -sThen, in another terminal:
arm-none-eabi-gdb build-qemu-arm/mipos-arm-qemu.elf
(gdb) target remote :1234
(gdb) break Reset_Handler
(gdb) continue- UART RX is polled (
mipos_bsp_rs232_recv_byteis non-blocking); no UART interrupts are used. - The SysTick ISR only accumulates ticks; the kernel RTC is updated from the scheduler epoch hook in thread context, so the RTC advances only while the scheduler is running (which is always the case in a cooperative system).
- Kernel, tasks, and ISRs all share the main stack (MSP); there is no PSP/privilege separation.
mipOS v.1.99 - (c) 2005-2017 antonino.calderone@gmail.com console
Compile date/time: Dec 27 2020 00:33:50 - opt. mods:
mipos_console
mipos_fs
mipos_stdio
mipos_mm
mipos_malloc
mipos_mpool
mipOS>help
help - shows this list
ver - shows mipOS version
dump [<a>,[<c>,[<b>]] - dump a memory area
patch <a> <b> - set a byte <b> at address <a>
ps - shows the list of tasks
freeze <tid> - freezes a task
unfreeze <tid> - unfreezes a task
delete <tid> - delete a task
signal <tid> <signum> - set a signal
ls - shows list of files
cat - shows list and content of files
mipOS>ls
Volume label RAMDISK
test1 60 bytes
test2 60 bytes
mipOS is provided in source form and licensed under the MIT License. See COPYING for details.



