Find a file
2025-12-12 20:51:39 +00:00
.github/workflows Only test on linux 2025-12-10 16:39:17 +00:00
apps Renaming and documentating header 2025-12-12 20:42:26 +00:00
common Split includes. 2025-12-12 15:56:47 +00:00
doc Renaming and documentating header 2025-12-12 20:42:26 +00:00
hosts Make extram uint8_t 2025-12-12 20:51:39 +00:00
precompiled Renaming and documentating header 2025-12-12 20:42:26 +00:00
test Make extram uint8_t 2025-12-12 20:51:39 +00:00
uvm32 Make extram uint8_t 2025-12-12 20:51:39 +00:00
Dockerfile SDL based host with extram mapped to framebuffer and simple gfx app to accompany it 2025-12-11 23:31:10 +00:00
LICENSE uvm32 initial version 2025-12-06 16:44:23 +00:00
Makefile Move all host examples under host/ 2025-12-11 12:57:59 +00:00
README.md Markdown fix 2025-12-12 16:54:28 +00:00

🌱 uvm32

uvm32 is a minimalist, dependency-free virtual machine sandbox designed for microcontrollers and other resource-constrained devices. Single C file, no dynamic memory allocations, asynchronous design, pure C99.

On an STM32L0 (ARM Cortex-M0+) the required footprint is under 4KB flash/1KB RAM.

What is it for?

  • As a no-frills alternative to embedded script engines (Lua, Duktape, MicroPython, etc)
  • As a sandbox to isolate untrusted or unreliable elements of a system
  • As a way to allow development in modern systems programming languages where a compiler for the target may not be available (rust-hello)
  • As a way to write once, run anywhere and avoid maintaining multiple software variants

Features

  • Bytecode example apps written in C, Zig, Rust and assembly
  • Non-blocking design, preventing misbehaving bytecode from stalling the host
  • No assumptions about host IO capabilities (no stdio)
  • Simple, opinionated execution model
  • Safe minimally typed FFI
  • Small enough for "if this then that" scripts/plugins, capable enough for much more
  • Aims for safety over speed, bad code running in the VM should never be able to crash the host

Although based on a fully fledged CPU emulator, uvm32 is intended for executing custom script like logic, not for simulating hardware.

Understanding this repo

uvm32 is a tiny virtual machine, all of the code is in uvm32.

A minimal example of a host to run code in is at host-mini.

Everything else is a more advanced host, or a sample application which could be run.

Example

A simple VM host from host-mini

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uvm32.h"
#include "uvm32_common_custom.h"

uint8_t rom[] = { // mandel.bin
  0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0xc0, 0x00, 0xb7, 0x08, 0x00, 0x01,
  ...
  ...
};

int main(int argc, char *argv[]) {
    uvm32_state_t vmst;
    uvm32_evt_t evt;
    bool isrunning = true;

    uvm32_init(&vmst);
    uvm32_load(&vmst, rom, sizeof(rom));

    while(isrunning) {
        uvm32_run(&vmst, &evt, 100);   // num instructions before vm considered hung

        switch(evt.typ) {
            case UVM32_EVT_END:
                isrunning = false;
            break;
            case UVM32_EVT_SYSCALL:    // vm has paused to handle UVM32_SYSCALL
                switch(evt.data.syscall.code) {
                    case UVM32_SYSCALL_PUTC:
                        printf("%c", uvm32_getval(&vmst, &evt, ARG0));
                    break;
                    case UVM32_SYSCALL_PRINTLN: {
                        const char *str = uvm32_getcstr(&vmst, &evt, ARG0);
                        printf("%s\n", str);
                    } break;
                    case UVM32_SYSCALL_YIELD:
                    break;
                    default:
                        printf("Unhandled syscall 0x%08x\n", evt.data.syscall.code);
                    break;
                }
            break;
            case UVM32_EVT_ERR:
                printf("UVM32_EVT_ERR '%s' (%d)\n", evt.data.err.errstr, (int)evt.data.err.errcode);
            break;
            default:
            break;
        }
    }

    return 0;
}

Samples

Quickstart (docker)

make dockerbuild
make dockershell

Then, from inside the docker shell

make

./hosts/host/host apps/helloworld/helloworld.bin

host is the command line test VM for running samples. Run host -h for a full list of options.

More information

Start at doc/README.md

License

This project is licensed under the MIT License. Feel free to use in research, products and embedded devices.