BasmOS: A Complete Protected-Mode Operating System in a Single 512-Byte Boot Sector
0xAA55 signature. The kernel is assembled
entirely with BASM and requires no second-stage loader: the kernel is the boot
record. Behavior is verified deterministically by reading VGA text memory back from
QEMU after boot, by a small x86 interpreter embedded in the project's web page that
executes the same shipped bytes, and through Linux KVM. This report documents the design, the
size-engineering techniques, and the verification methodology.
1 · Introduction
We use nanokernel for a kernel whose complete implementation fits inside one 512-byte disk sector — the smallest unit a PC BIOS will load and jump to. Under that constraint, "complete" must be earned rather than asserted: BasmOS enters 32-bit protected mode, enables paging, preempts two tasks on the timer interrupt, and passes bytes between them through a ring buffer — all inside the sector that is also its own boot record.
Contributions: (i) a full protected-mode OS in 401 payload bytes; (ii) a set of reusable size-engineering techniques (§4); (iii) a deterministic, externally observable verification method (§6.1); (iv) independently implemented QEMU, browser-interpreter and KVM execution paths with specified observable agreement (§6.2).
2 · Boot and mode transition
Execution starts in real mode at 0x7C00: cli, DS=0,
lgdt, then protected mode. Because CR0.PE is architecturally 0 at reset,
inc ax implements or eax,1 in a single byte with no carry
possible. A far jump into a flat 4 GB code segment completes the transition.
The entire real-mode prologue is 22 bytes.
3 · Memory
Paging is enabled with exactly one store: a single PSE page-directory entry
(mov dword [eax],0x83, EAX=0x1000) identity-maps the first 4 MB, and
the same register value is immediately reused as CR3. Everything the kernel touches —
image at 0x7C00, IDT at 0x500, IPC ring at 0x700, private task windows at
0x800/0x900, stack/page directory at 0x1000, and VGA at 0xB8000 — lies below 1 MB,
making the A20 line irrelevant by construction.
SS remains flat for interrupt frames. Task DS selectors are limited to 256 bytes;
handlers reach kernel state only through flat ES, and GS is limited to the VGA page.
Task CS selectors (0x30, 0x38) bound each task's instruction fetch to its own bytes:
a five-byte push/push/retf prologue enters task0 through its window, task1's
frame ships CS directly, and runaway execution beyond a window raises #GP13 at the fetch.
4 · Concurrency
The scheduler state is one cell, other_sp. The complete switch is
xchg esp,[es:other_sp] · popad · mov ds,bp · iretd: 11 bytes, no current-task
index and no branch. EBP carries the incoming task's bounded DS selector, and the
interrupted task's code selector returns through the iretd frame itself.
task1 is born from a 12-byte frame (EIP, CS, EFLAGS=0x202) assembled as data;
its stack has no allocation of its own, cycling within a 44-byte window of
initialization bytes that are never needed again. IRQ0 is remapped to vector 32,
outside the exception range; int 32 remains the voluntary yield ABI and
shares that handler.
5 · IPC
A single-producer/single-consumer byte ring at 0x700 occupies 256 bytes. Its head and
tail live in each endpoint's saved ECX; inc cl provides modulo 256 for free.
Comparing the opposite saved cursor distinguishes full and empty, yielding 255 usable
queued bytes without a count field. System calls: int 32 = yield,
int 33 = send(AL), int 34 = recv → AL (0 = empty).
At boot, ESP builds valid gates for exceptions 0–31 and the three services; vector 13 is patched to a distinct fail-stop gate for exact negative testing. The GDT remains assembled data, with its 6-byte descriptor hidden inside its own null slot.
6 · Verification
6.1 External. QEMU boots basmos.bin; a script then reads guest VGA
memory and asserts six bytes: '3',0x0F at 0xB8000 (task0 output),
'6',0x0F at 0xB8002 (task1 was preemptively scheduled),
'9',0x0A at 0xB8004 (task1 printed a received byte). The producer's loop
contains no hlt and no yield — it is CPU-bound — so the 6, the 9 and a
heartbeat byte at 0x6FC that must keep incrementing require asynchronous IRQ0
preemption of a task that was mid-computation. QEMU must remain running for a
further two-second dwell.
6.2 Browser. The project page embeds a deliberately limited x86 interpreter covering the kernel's required instruction and segmentation behavior and executes the same bytes the page displays and distributes. It does not model paging, the PIC or the PIT. Its virtual timer supplies only the deterministic scheduling behavior needed by this artifact. The bounded 2.0×10⁶-instruction run:
| metric | value |
|---|---|
| timer IRQs delivered | 44 |
| yields (int 32) | 0 |
| sends (int 33) | 126,144 |
| recvs (int 34) | 22 |
| heartbeat @0x6FC | 44 (= ticks) |
| final VGA bytes @0xB8000 | 33 0F 36 0F 39 0A |
Independent executors reaching the same observable state provide corroborating implementation evidence while retaining different modeling assumptions.
7 · Size accounting
| symbol | bytes | role |
|---|---|---|
| start | 22 | real-mode entry, PE enable, far jmp |
| pm | 155 | IDT construction, segments, paging, PIC/PIT, stack |
| t1frame | 12 | task1 bootstrap frame (data) |
| task0 | 34 | 5-byte retf prologue + private-domain producer: send loop, no hlt, no yield |
| task1 | 33 | private-domain consumer, including HLT loop |
| exception / #GP / timer | 18 | fail-stop entries; IRQ0 + EOI + heartbeat |
| do_switch | 11 | atomic stack and DS-context switch |
| sys_send | 23 | ES-scoped ring write plus full detection |
| sys_recv | 21 | ES-scoped ring read plus empty detection |
| idtr | 6 | IDTR image |
| gdt | 62 | flat kernel, task data domains, VGA and task code-window descriptors |
| other_sp | 4 | all persistent scheduler state |
| payload | 401 | 317 code + 84 data |
| padding + 0xAA55 | 111 | 109 headroom + 2-byte signature |
8 · Related magnitude
The broad predecessor is NanoOS 2.1 (2004), a 512-byte real-mode OS with
timer-preemptive multitasking and blocking copy IPC, but no PM32 or paging.
A close PM32 scheduler neighbor is pczero; its reproduced functional
image is 18,060 bytes and the reviewed code has no paging or IPC.
No prior artifact was found with the complete BasmOS feature intersection.
9 · Limitations
Scope decisions, not accidents: a single privilege level (ring 0); no interactive input; trusted CPL0 task code (windows contain runaway fetches, not deliberate far transfers); a static two-task set; a 4 MB identity map; PSE-capable IA-32 hardware; and no recovery policy beyond fail-stop for CPU exceptions. The PIC and PIT are initialized, every architectural exception has a valid gate, and 109 payload bytes remain available.
10 · Reproducibility
make toolchain diagnoses the local prerequisites and make toolchain-install
installs the reviewed Debian/Ubuntu package set. make lists the build and proof targets;
make verify performs the
QEMU readback of §6.1; make map prints the per-symbol byte budget behind §7.
The full binary is embedded in the project page — downloadable, copyable as hex, and
executable in place. BasmOS is released under the BSD 3-Clause license.
bemu-nano, this repo)
boots the sector on bare hardware virtualization with zero firmware, alongside QEMU
and this page's interpreter; (b) the same source assembles a second personality,
basmos-vm.bin (232 bytes), which the VMM enters directly in
protected mode with paging on — boot without boot; (c) an extended prior-art survey
(web, GitHub, academic literature, demoscene — RESEARCH.md) found no
prior one-sector x86 artifact combining protected mode, paging, preemptive multitasking
and IPC. This is a dated search result, not a certified world record. The 512-byte sector described by this
report includes bounded DS domains and exact data/code #GP denial probes; (d) the sibling artifact
basmos-sh.bin spends 498 payload bytes on TSS-backed CPL3, a serial monitor,
and loading/executing 256-byte user modules, independently verified by QEMU and KVM;
(e) JASH is a 255+1-byte native CPL3 shell with a 3,584-byte data Pack outside
module CS, 14 exact commands over 15 cells, a four-operation EVM1 manifest,
NK-SIGIL/1, PRF1 evidence and a direct C/KVM interactive Wire.
References
[1] Intel® 64 and IA-32 Architectures Software Developer's Manual, Vol. 3A: System Programming Guide — mode transitions, PSE paging, interrupt descriptors.
[2] calint/pczero — github.com/calint/pczero (magnitude reference).
[3] NanoOS 2.1 — board.flatassembler.net/topic.php?t=2164 (2004 predecessor).
[4] BasmOS artifact: basmos.basm / basmos.bin — this site.