Bao: a static partitioning hypervisor for mixed-criticality embedded systems
Bao, a Lightweight Static Partitioning Hypervisor
At a glance
- What is it?
- Bao is a from-scratch embedded hypervisor that statically partitions resources between VMs at instantiation time, with 2-stage memory translation, pass-through IO and a 1-1 mapping of virtual to physical CPUs with no scheduler. It runs on Arm, RISC-V, TriCore and RH850, and the project states plainly that it is work in progress.
- Who is it for?
- Bao fits an embedded engineer who has a mixed-criticality system to partition, wants isolation and real-time guarantees without running a general purpose operating system underneath, and is prepared to work at the level of ISA virtualization extensions. It does not fit a team that needs a general purpose hypervisor with device emulation, dynamic scheduling or a rich guest driver story, because IO is pass-through only and there is no scheduler.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Bao is and the partitioning model it commits to
Bao, from the Mandarin Chinese bǎohù, meaning to protect, is a lightweight, open-source embedded hypervisor which aims at providing strong isolation and real-time guarantees. The project describes it as a minimal, from-scratch implementation of the partitioning hypervisor architecture.
The design is aimed mainly at mixed-criticality systems, and the focus is isolation for fault containment and real-time behaviour. The implementation is described as only a minimal, thin layer of privileged software that uses ISA virtualization support.
Four properties define the model, and they are worth reading as one design decision rather than four. Resources are statically partitioned and assigned at VM instantiation time, so nothing moves at runtime. Memory is statically assigned using 2-stage translation. IO is pass-through only, meaning a device is owned by one guest rather than emulated and multiplexed. Virtual interrupts are directly mapped to physical ones. And there is a 1-1 mapping of virtual to physical CPUs, with no need for a scheduler.
That last point is the one that separates Bao from most hypervisors. Without a scheduler, a guest cannot be preempted, and the CPU allocation is fixed at instantiation. The payoff is deterministic behaviour and a very small trusted computing base, since Bao has no external dependencies such as privileged VMs running untrustable, large monolithic general-purpose operating systems like Linux, and as such encompasses a much smaller TCB.
The audience is embedded systems engineers working on safety or security critical mixed-criticality hardware, where a full virtualisation stack would be more machinery than the problem allows.
The platform list is the honest measure of coverage
The supported platforms are listed with checkboxes for what works and empty boxes for what is in progress, which is unusually candid and makes the list a coverage map rather than a marketing claim.
Armv8-A AArch64 is the broadest set. Checked are the Xilinx Zynq UltraScale+ MPSoC ZCU102 and ZCU104, the Ultra96 Zynq UltraScale+ ZU3EG, the NXP MCIMX8QM-CPU, the NVIDIA Jetson TX2, the 96Boards HiKey 960, the Raspberry Pi 4, QEMU virt, the Arm Fixed Virtual Platforms, the Toradex Verdin iMX8M Plus with the Dahlia Carrier Board, the NXP S32G3, the NXP iMX8M Nano EVK and the Altera Agilex 5 SoC FPGA.
The other architectures are narrower. Armv7-A and Armv8-A AArch32 has the Arm Fixed Virtual Platforms checked and QEMU virt unchecked. Armv8-R AArch64 has the Arm Fixed Virtual Platforms. Armv8-R AArch32 has the Fixed Virtual Platforms, the Arm MPS3-AN536, the Semidrive E3650 and the NXP S32Z270 checked, with the Renesas RZT2M unchecked.
RISC-V RV64 has QEMU virt and the SpacemiT K3 CoM260 Kit, which is the Banana Pi BPI-SM10, with the SiFive HiFive Premier P550 unchecked. RISC-V RV32 has QEMU virt. Infineon TriCore 1.8 has the TC4x Communication Board. Renesas RH850 has the RH850 U2A16.
The two TriCore and RH850 entries are what set Bao apart from the academic Arm and RISC-V work that most hypervisor projects in this space are. Those are automotive and industrial architectures, and a static partitioning model with a small TCB is exactly what that domain asks for.
Building the hypervisor and the cross toolchain variables
The build is driven by a Makefile at the repository root, and the variables that matter are passed in rather than baked in. The default values in the Makefile are:
DEBUG:=n
OPTIMIZATIONS:=2
CONFIG=
PLATFORM=DEBUG defaults to off, OPTIMIZATIONS to 2, and CONFIG and PLATFORM are empty, so a build has to be told which configuration and which board it is targeting. The PLATFORM value selects the platform directory, since the Makefile computes platforms_dir as src/platform, and the CONFIG_REPO variable defaults to the configs directory in the tree.
The toolchain handling is the part that matters for a cross compile. The Makefile checks whether the CROSS_COMPILE value contains clang, and if so it derives a clang toolchain with lld, llvm-as, llvm-objcopy, llvm-objdump, llvm-readelf and llvm-size, using clang-cpp and llvm-strip as well. Otherwise it falls back to the GNU equivalents, cpp, strip, gcc, ld, as, objcopy, objdump, readelf and size, each prefixed with the CROSS_COMPILE value.
The project name is bao, and the version is derived from git describe with a v semver match, turned into a symbol prefixed with baoversion_. So a build stamps itself with the tag it was made from, which matters for a system where identifying the exact hypervisor build on a device is part of the record.
The directory layout is conventional: src/ holds the code, split into arch, lib, core and platform subdirectories, configs/ holds the configuration repository, scripts/ holds the build and packaging scripts, and ci/ holds the continuous integration definitions, which the Makefile includes with the ci.mk file.
The demo guide is where the real documentation lives
The README is short, and it points elsewhere for everything operational. The project website is at bao-project.org, the documentation is on readthedocs, and the step-by-step guide for running different demo configurations of the Bao hypervisor, featuring multiple guest operating systems and targeting several platforms, is in the separate bao-demos repository.
That separation is worth understanding before you start. The bao-hypervisor repository is the hypervisor itself, the configs/ directory holds the configuration, and the demos repository holds the worked examples. A newcomer following the demo guide will be pulling in a second repository, and the configuration for those demos is where the partition layout is actually spelled out.
The workflow badges in the README are per-architecture, with separate build workflows for arm, riscv, rh850 and tricore, plus a code quality workflow, so each architecture is built in its own pipeline. The workflow badges themselves are per-architecture, with separate build workflows for arm, riscv, rh850 and tricore, plus a code quality workflow, so each architecture is built in its own pipeline.
Two other things in the tree are worth knowing about. There is a.gitmodules file, so some parts of the build are pulled in as submodules. And there is a CONTRIBUTORS file and a ci/ directory, alongside the usual src/, configs/ and scripts/ directories.
If you are evaluating Bao, the order that works is: read the README for the model, pick your platform from the checklist, then read the demo guide for a configuration close to your board. Reading the source before you have a working configuration is a slower path.
What the published research says about the design
Bao is an academic project with a substantial publication record, and the references in the README are worth skimming because they explain why the design takes the shape it does.
The original paper, Bao: A Lightweight Static Partitioning Hypervisor for Modern Multi-Core Embedded Systems, appeared at the Workshop on Next Generation Real-Time Embedded Systems in 2020, with a companion piece at the Embedded World Conference the same year. A paper on static partitioning virtualization on RISC-V was presented at RISC-V Summit Virtual in 2020, and a first look at RISC-V virtualization from an embedded perspective appeared in IEEE Transactions on Computers in 2021.
The 2023 and 2024 papers cover the parts that matter most for automotive and mixed-criticality work. Shedding Light on Static Partitioning Hypervisors for Arm-based Mixed-Criticality Systems was published at RTAS 2023 in San Antonio, and a paper on porting the design to Arm's Cortex-R52 was presented at Embedded Open Source Summit 2023 in Prague.
Two later items extend the work beyond the core hypervisor. Bao-Enclave is a paper on virtualization-based enclaves for Arm, which is about using the same partitioning mechanism for trusted execution rather than for mixing criticalities. And BiRtIO is VirtIO for real-time network interface sharing on the Bao hypervisor, published in IEEE Access in 2024, which is the clearest sign that pass-through IO has a use case worth generalising.
There is also a tutorial called Hello 'Bao' World from a virtual workshop, and a 2024 gem5 blog post on running the hypervisor on gem5, which matters if you want to simulate a board you do not own.
Where Bao is the wrong choice
The first limit is stated by the project itself: this is work in progress, don't expect things to be complete, use it at your own risk. That is on a 2.0.0 tag while the documentation still says it, so it is a statement about the current state rather than a disclaimer from the beginning of the project.
The second is the absence of a scheduler. The 1-1 mapping of virtual to physical CPUs is a deliberate simplification, and it means a guest cannot be time-sliced, cannot be paused, and cannot share a core with another guest. If your workload needs to oversubscribe a small number of cores, or needs priority preemption between VMs, the model does not offer it.
The third is pass-through IO. Devices are owned by a guest rather than emulated, so there is no virtual device model to program against, and there is no way to share a device between two guests without extra work such as the BiRtIO sharing mechanism.
The fourth is the guest software requirement. Bao is designed so that a general purpose operating system is not underneath, and the TCB argument depends on that. The cost is that you are running bare-metal or real-time guest software on the far side, and a Linux guest that expects a full virtualised machine will not get one.
Compare that with a general purpose hypervisor on a server CPU. The difference in approach is that a server hypervisor emulates devices, schedules vCPUs and runs unmodified operating systems, so it can host a Linux guest with no porting, at the cost of a large TCB and no real-time guarantees. Bao inverts every one of those choices for the opposite priorities, which is exactly why it does not fit a cloud or virtualisation use case, and why the platform list stops at embedded boards and QEMU.
Licence, maintenance and the upgrade question
Bao is released under the Apache-2.0 licence, and the Makefile carries the SPDX identifier and a copyright line for the Bao Project and Contributors. Apache 2.0 is a permissive licence with a patent grant, which for a hypervisor intended to be adopted by automotive and industrial suppliers is a sensible choice, since it avoids the copyleft obligations that would complicate a proprietary safety stack. Read the LICENSE file yourself for the exact terms.
There is a third party component to be aware of, because the tree includes a.gitmodules file. A hypervisor that pulls in submodules should have its dependency versions reviewed as part of any safety case, and that review is on you rather than on the project.
On maintenance, the repository is not archived and the last push was on 2026-10-22, so the tree is current. The release history is short: v0.1.0 on 2021-04-04, v1.0.0 on 2023-11-21 and v2.0.0 on 2026-03-04. A 1.0 to 2.0 gap that ran for more than two years is a signal about the rate of interface change, and it means an upgrade is a migration rather than a patch.
The continuous integration badges tell you what is checked on every push. There is a code quality workflow, and separate build workflows for arm, riscv, rh850 and tricore, so a change that compiles on Arm can still break the TriCore build, and the reverse. That is a real cost for a multi-architecture project, and it is the thing to check before you fork and diverge.
What to verify first is concrete. Take a demo configuration for your platform, build it, and confirm the partition layout matches what you need. Then check whether your platform is in the checked or the unchecked column of the support list, because the unchecked entries are the ones the project itself is still working on.
Editorial conclusion
Bao fits an embedded engineer who has a mixed-criticality system to partition, wants isolation and real-time guarantees without running a general purpose operating system underneath, and is prepared to work at the level of ISA virtualization extensions. It does not fit a team that needs a general purpose hypervisor with device emulation, dynamic scheduling or a rich guest driver story, because IO is pass-through only and there is no scheduler. Before adopting it, read the demo guide in bao-demos for a configuration close to your board, confirm your platform is in the supported list rather than the work in progress list, and treat the version 2.0.0 tag and the project's own warning that this is work in progress as the two facts that should shape your plan.
Frequently asked questions
What kind of hypervisor is Bao?
Bao is a lightweight, open-source embedded hypervisor providing a minimal, from-scratch implementation of the static partitioning architecture. Resources are statically partitioned at VM instantiation time, memory uses 2-stage translation, IO is pass-through only, and virtual CPUs map 1-1 to physical CPUs with no scheduler.
Which platforms does Bao support?
The checked entries include the Xilinx Zynq UltraScale+ boards, Ultra96, NXP MCIMX8QM-CPU, NVIDIA Jetson TX2, HiKey 960, Raspberry Pi 4, QEMU virt, Arm Fixed Virtual Platforms, Toradex Verdin iMX8M Plus, NXP S32G3, NXP iMX8M Nano EVK, Altera Agilex 5, Arm MPS3-AN536, Semidrive E3650, NXP S32Z270, SpacemiT K3 CoM260, the Infineon TC4x Communication Board and the Renesas RH850 U2A16. QEMU virt for AArch32, the Renesas RZT2M and the SiFive HiFive Premier P550 are listed as work in progress.
How do I build the Bao hypervisor?
The build is driven by the root Makefile, which takes the configuration, the platform, a debug flag and an optimisation level, defaulting to DEBUG:=n and OPTIMIZATIONS:=2 with CONFIG and PLATFORM empty. The toolchain is selected by the CROSS_COMPILE value, using a clang and lld set when it contains clang and the GNU binutils otherwise.
Where can I find working Bao configurations and demos?
The step-by-step demo configurations with multiple guest operating systems live in the separate bao-demos repository, linked as the Bao Hypervisor Demo Guide. The project documentation is on readthedocs and the project website is at bao-project.org.
What licence is Bao released under?
Bao is released under the Apache-2.0 licence, with the SPDX identifier and copyright line for the Bao Project and Contributors carried in the Makefile and the full text in the LICENSE file at the repository root.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bao-project-bao-hypervisor)Was this useful?