--- /dev/null
+# Rump Kernel Integration Roadmap
+
+## Overview
+
+[Rump Kernels](https://github.com/rumpkernel/wiki) allow AdrOS to reuse production-quality
+NetBSD drivers (USB, audio, ZFS, TCP/IP, etc.) without writing them from scratch. The
+integration requires implementing a **hypercall layer** (`librumpuser_adros`) that maps
+NetBSD kernel abstractions to AdrOS primitives.
+
+## Prerequisites Status
+
+| Requirement | Status | AdrOS Implementation |
+|---|---|---|
+| Dynamic memory (malloc/free) | ✅ Ready | `kmalloc`/`kfree` (buddy allocator, 16-byte aligned) |
+| Kernel threads | ✅ Ready | `process_create_kernel`, `PROCESS_FLAG_THREAD` |
+| Mutexes | ✅ Ready | `kmutex_t` in `sync.c` |
+| Semaphores | ✅ Ready | `ksem_t` with timeout in `sync.c` |
+| Condition variables | ✅ Ready | `kcond_t` (wait/signal/broadcast) in `sync.c` |
+| FPU/SSE context switch | ✅ Ready | FXSAVE/FXRSTOR per process |
+| Nanosecond timekeeping | ✅ Ready | TSC-calibrated `clock_gettime_ns()` |
+| Shared IRQ handling | ✅ Ready | IRQ chaining (32-node pool) in `idt.c` |
+| Block I/O | ✅ Ready | ATA multi-drive, VFS callbacks |
+| PCI enumeration | ✅ Ready | PCI scanner + HAL driver registry |
+
+## Rumpuser Hypercall API → AdrOS Mapping
+
+The `rumpuser(3)` interface requires ~35 functions grouped into 8 categories:
+
+### Phase 1: Core (Memory + Console + Init)
+```
+rumpuser_init() → validate version, store upcalls
+rumpuser_malloc() → kmalloc() with alignment
+rumpuser_free() → kfree()
+rumpuser_putchar() → kprintf("%c", ch)
+rumpuser_dprintf() → kprintf()
+rumpuser_exit() → kprintf + halt/panic
+rumpuser_getparam() → return NCPU, hostname from cmdline
+rumpuser_getrandom() → /dev/urandom or RDRAND
+```
+
+### Phase 2: Threads + Synchronization
+```
+rumpuser_thread_create() → process_create_kernel() wrapper
+rumpuser_thread_exit() → process_exit_notify() + schedule()
+rumpuser_thread_join() → waitpid() equivalent
+rumpuser_curlwpop() → per-thread TLS via GS segment
+rumpuser_curlwp() → read from TLS
+rumpuser_mutex_init() → kmutex_init() or spinlock_init()
+rumpuser_mutex_enter() → kmutex_lock() (unschedule rump ctx first)
+rumpuser_mutex_exit() → kmutex_unlock()
+rumpuser_mutex_owner() → track owner in wrapper struct
+rumpuser_rw_init() → custom reader-writer lock
+rumpuser_rw_enter() → kcond_t based rwlock
+rumpuser_cv_init() → kcond_init()
+rumpuser_cv_wait() → kcond_wait()
+rumpuser_cv_timedwait() → kcond_wait() with timeout
+rumpuser_cv_signal() → kcond_signal()
+rumpuser_cv_broadcast() → kcond_broadcast()
+```
+
+### Phase 3: Clocks + Signals
+```
+rumpuser_clock_gettime() → clock_gettime_ns() (MONO) or rtc (WALL)
+rumpuser_clock_sleep() → process_sleep() with ns precision
+rumpuser_kill() → process_kill() signal delivery
+rumpuser_seterrno() → per-thread errno via TLS
+```
+
+### Phase 4: File/Block I/O
+```
+rumpuser_open() → vfs_open() or raw device access
+rumpuser_close() → vfs_close()
+rumpuser_getfileinfo() → vfs_stat()
+rumpuser_bio() → async ATA I/O + callback
+rumpuser_iovread() → vfs_read() scatter-gather
+rumpuser_iovwrite() → vfs_write() scatter-gather
+rumpuser_syncfd() → flush + barrier
+```
+
+## Implementation Plan
+
+### Stage 1: Filesystem (ext2 via Rump) — weeks 1-2
+**Goal**: Mount an ext2 image using NetBSD's ext2fs driver via Rump instead of AdrOS native.
+- Implement Phase 1 + 2 + 3 hypercalls
+- Build `librumpuser_adros.a` statically linked into kernel
+- Cross-compile `librump.a` + `librumpvfs.a` + `librumpfs_ext2fs.a`
+- Test: mount ext2 disk image, read files, compare with native driver
+
+**Why first**: Exercises memory, threads, and synchronization without hardware IRQs.
+
+### Stage 2: Network (E1000 via Rump) — weeks 3-4
+**Goal**: Replace lwIP+custom E1000 driver with NetBSD's full TCP/IP stack.
+- Implement Phase 4 (block I/O) hypercalls
+- Cross-compile `librumpnet.a` + `librumpdev_pci.a` + `librumpdev_wm.a`
+- Wire PCI device passthrough via rumpuser_open/bio
+- Test: ping, TCP connect through Rump network stack
+
+**Why second**: Adds IRQ sharing and async I/O, leveraging existing IOAPIC routing.
+
+### Stage 3: USB (xHCI/EHCI via Rump) — weeks 5-8
+**Goal**: USB mass storage support.
+- Cross-compile USB host controller + mass storage components
+- Map PCI MMIO regions for USB controller
+- DMA buffer management via rumpuser_malloc with alignment
+- Test: enumerate USB devices, mount USB mass storage
+
+### Stage 4: Audio (HDA via Rump) — optional
+**Goal**: Intel HDA audio playback.
+- Leverages same PCI/IRQ infrastructure as Stage 2-3
+
+## Build Integration
+
+```
+src/rump/
+ rumpuser_adros.c # All hypercall implementations
+ rumpuser_adros.h # Internal helpers
+ rump_integration.c # Boot-time init, component loading
+third_party/rump/
+ include/ # NetBSD rump headers
+ lib/ # Pre-built librump*.a archives
+```
+
+## Missing Kernel Primitives (to implement as needed)
+
+| Primitive | Needed For | Complexity |
+|---|---|---|
+| Reader-writer lock (`krwlock_t`) | `rumpuser_rw_*` | Small |
+| Per-thread TLS storage | `rumpuser_curlwp` | Small (GS segment) |
+| Aligned kmalloc | `rumpuser_malloc` with alignment | Small (round up) |
+| Async block I/O callback | `rumpuser_bio` | Medium |
+
+## References
+
+- [rumpuser(3) manpage](https://man.netbsd.org/rumpuser.3)
+- [buildrump.sh](https://github.com/rumpkernel/buildrump.sh)
+- [Rump Kernel wiki](https://github.com/rumpkernel/wiki/wiki)
+- Antti Kantee, "The Design and Implementation of the Anykernel and Rump Kernels", 2012
--- /dev/null
+/*
+ * AdrOS Rump Kernel Hypercall Implementation
+ *
+ * This file implements the rumpuser(3) hypercall interface, mapping
+ * NetBSD Rump Kernel abstractions to AdrOS kernel primitives.
+ *
+ * Reference: https://man.netbsd.org/rumpuser.3
+ *
+ * Phase 1: Core (memory, console, init, params, random)
+ * Phase 2: Threads + synchronization (TODO)
+ * Phase 3: Clocks + signals (TODO)
+ * Phase 4: File/Block I/O (TODO)
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdarg.h>
+
+#include "heap.h"
+#include "console.h"
+#include "timer.h"
+#include "process.h"
+#include "sync.h"
+#include "hal/cpu.h"
+
+#include <string.h>
+
+/* ------------------------------------------------------------------ */
+/* Rump hypercall version */
+/* ------------------------------------------------------------------ */
+
+#define RUMPUSER_VERSION 17
+
+/* ------------------------------------------------------------------ */
+/* Upcall pointers (set by rumpuser_init) */
+/* ------------------------------------------------------------------ */
+
+typedef void (*rump_schedule_fn)(void);
+typedef void (*rump_unschedule_fn)(void);
+
+static rump_schedule_fn g_hyp_schedule = NULL;
+static rump_unschedule_fn g_hyp_unschedule = NULL;
+
+/* ------------------------------------------------------------------ */
+/* Phase 1: Initialization */
+/* ------------------------------------------------------------------ */
+
+struct rump_hyperup {
+ rump_schedule_fn hyp_schedule;
+ rump_unschedule_fn hyp_unschedule;
+ /* additional upcalls omitted for now */
+};
+
+int rumpuser_init(int version, const struct rump_hyperup *hyp) {
+ if (version != RUMPUSER_VERSION) {
+ kprintf("[RUMP] Version mismatch: kernel=%d, expected=%d\n",
+ version, RUMPUSER_VERSION);
+ return 1;
+ }
+
+ if (hyp) {
+ g_hyp_schedule = hyp->hyp_schedule;
+ g_hyp_unschedule = hyp->hyp_unschedule;
+ }
+
+ kprintf("[RUMP] Hypercall layer initialized (v%d).\n", version);
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* Phase 1: Memory allocation */
+/* ------------------------------------------------------------------ */
+
+int rumpuser_malloc(size_t len, int alignment, void **memp) {
+ if (!memp) return 22; /* EINVAL */
+ if (len == 0) { *memp = NULL; return 0; }
+
+ /* kmalloc returns 16-byte aligned; for larger alignment, over-allocate */
+ if (alignment <= 16) {
+ *memp = kmalloc(len);
+ } else {
+ /* Over-allocate and manually align */
+ size_t total = len + (size_t)alignment + sizeof(void*);
+ void *raw = kmalloc(total);
+ if (!raw) { *memp = NULL; return 12; } /* ENOMEM */
+ uintptr_t addr = ((uintptr_t)raw + sizeof(void*) + (size_t)alignment - 1)
+ & ~((uintptr_t)alignment - 1);
+ ((void**)addr)[-1] = raw;
+ *memp = (void*)addr;
+ return 0;
+ }
+
+ return *memp ? 0 : 12; /* ENOMEM */
+}
+
+void rumpuser_free(void *mem, size_t len) {
+ (void)len;
+ if (mem) kfree(mem);
+}
+
+/* ------------------------------------------------------------------ */
+/* Phase 1: Console output */
+/* ------------------------------------------------------------------ */
+
+void rumpuser_putchar(int ch) {
+ char c = (char)ch;
+ (void)c;
+ kprintf("%c", ch);
+}
+
+void rumpuser_dprintf(const char *fmt, ...) {
+ char buf[256];
+ va_list ap;
+ va_start(ap, fmt);
+ kvsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ kprintf("%s", buf);
+}
+
+/* ------------------------------------------------------------------ */
+/* Phase 1: Termination */
+/* ------------------------------------------------------------------ */
+
+#define RUMPUSER_PANIC 0xFF
+
+void rumpuser_exit(int value) {
+ if (value == RUMPUSER_PANIC) {
+ kprintf("[RUMP] PANIC — halting.\n");
+ } else {
+ kprintf("[RUMP] Exit with code %d.\n", value);
+ }
+ for (;;) hal_cpu_idle();
+}
+
+/* ------------------------------------------------------------------ */
+/* Phase 1: Parameter retrieval */
+/* ------------------------------------------------------------------ */
+
+int rumpuser_getparam(const char *name, void *buf, size_t buflen) {
+ if (!name || !buf || buflen == 0) return 22; /* EINVAL */
+
+ if (strcmp(name, "_RUMPUSER_NCPU") == 0) {
+ /* Report 1 CPU for now — SMP rump requires more work */
+ strncpy((char*)buf, "1", buflen);
+ return 0;
+ }
+ if (strcmp(name, "_RUMPUSER_HOSTNAME") == 0) {
+ strncpy((char*)buf, "adros-rump", buflen);
+ return 0;
+ }
+ if (strcmp(name, "RUMP_VERBOSE") == 0) {
+ strncpy((char*)buf, "1", buflen);
+ return 0;
+ }
+
+ /* Unknown parameter */
+ ((char*)buf)[0] = '\0';
+ return 2; /* ENOENT */
+}
+
+/* ------------------------------------------------------------------ */
+/* Phase 1: Random */
+/* ------------------------------------------------------------------ */
+
+#define RUMPUSER_RANDOM_HARD 0x01
+#define RUMPUSER_RANDOM_NOWAIT 0x02
+
+int rumpuser_getrandom(void *buf, size_t buflen, int flags, size_t *retp) {
+ (void)flags;
+ if (!buf || !retp) return 22;
+
+ /* Simple PRNG seeded from TSC — adequate for early bring-up */
+ uint8_t *p = (uint8_t*)buf;
+ uint32_t seed = (uint32_t)clock_gettime_ns();
+ for (size_t i = 0; i < buflen; i++) {
+ seed = seed * 1103515245 + 12345;
+ p[i] = (uint8_t)(seed >> 16);
+ }
+ *retp = buflen;
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* Phase 3: Clocks */
+/* ------------------------------------------------------------------ */
+
+#define RUMPUSER_CLOCK_RELWALL 0
+#define RUMPUSER_CLOCK_ABSMONO 1
+
+extern uint32_t rtc_unix_timestamp(void);
+
+int rumpuser_clock_gettime(int clk, int64_t *sec, long *nsec) {
+ if (!sec || !nsec) return 22;
+
+ if (clk == RUMPUSER_CLOCK_RELWALL) {
+ *sec = (int64_t)rtc_unix_timestamp();
+ *nsec = 0;
+ } else {
+ uint64_t ns = clock_gettime_ns();
+ *sec = (int64_t)(ns / 1000000000ULL);
+ *nsec = (long)(ns % 1000000000ULL);
+ }
+ return 0;
+}
+
+int rumpuser_clock_sleep(int clk, int64_t sec, long nsec) {
+ if (clk == RUMPUSER_CLOCK_RELWALL) {
+ uint32_t ms = (uint32_t)(sec * 1000 + nsec / 1000000);
+ uint32_t ticks = (ms + TIMER_MS_PER_TICK - 1) / TIMER_MS_PER_TICK;
+ if (ticks > 0) process_sleep(ticks);
+ } else {
+ /* ABSMONO: sleep until absolute monotonic time */
+ uint64_t target_ns = (uint64_t)sec * 1000000000ULL + (uint64_t)nsec;
+ uint64_t now = clock_gettime_ns();
+ if (target_ns > now) {
+ uint64_t delta_ms = (target_ns - now) / 1000000ULL;
+ uint32_t ticks = (uint32_t)((delta_ms + TIMER_MS_PER_TICK - 1) / TIMER_MS_PER_TICK);
+ if (ticks > 0) process_sleep(ticks);
+ }
+ }
+ return 0;
+}