This guide covers architecture, build process, and how to extend PromptOS.
PromptOS is a monolithic x86-64 kernel with the following components:
- UEFI Bootloader (
bootloader/) – Loads kernel and initramfs, sets up framebuffer, passes boot info - Kernel Entry (
kernel/arch/x86_64/boot/) – Assembly bootstrap, GDT, IDT - Kernel Main (
kernel/main.c) – Phased initialization:- Phase 1: CPU (GDT, TSS, IDT)
- Phase 2: Boot info parsing
- Phase 3: Memory (PMM, heap, slab)
- Phase 4: ACPI
- Phase 5: Interrupts (APIC, HPET)
- Phase 6: Scheduler and threads
- Phase 7: VFS, drivers, network
- Phase 8: Syscalls, userspace prep
| Subsystem | Location | Description |
|---|---|---|
| Memory | kernel/mm/ |
PMM, VMM, heap, slab, uaccess |
| Process | kernel/proc/ |
Processes, ELF, signals |
| Scheduler | kernel/sched/ |
Threads, context switch |
| Filesystem | kernel/fs/ |
VFS, ramfs, betterfs, procfs |
| Network | kernel/net/ |
TCP/UDP, sockets, routing |
| Drivers | kernel/drivers/ |
Block, input, net, PCI |
| Debug | kernel/debug/ |
ksyms, profiler |
- Cross-compiler:
x86_64-elf-gcc,x86_64-elf-ld - NASM assembler
- For bootloader: MinGW (gcc-mingw-w64-x86-64)
- For disk image: sgdisk, mkfs.fat, mtools, mkfs.betterfs
make toolchainThis builds a cross-compiler into toolchain/.
make # Full build (kernel, bootloader, userland, tests, image)
make kernel # Kernel only
make bootloader # UEFI bootloader
make userland # init, hello
make tests # Stress tests
make image # Create bootable disk imagemake runOr with GDB:
make debug
# In another terminal: gdb -ex 'target remote :1234' build/kernel/kernel.elfPromptOS/
├── bootloader/ # UEFI bootloader (MinGW)
├── kernel/ # Kernel source
│ ├── arch/x86_64/ # Architecture-specific (boot, SMP, syscall)
│ ├── acpi/ # ACPI parsing, power
│ ├── drivers/ # PCI, block, net, input, etc.
│ ├── fs/ # VFS and filesystems
│ ├── ipc/ # Pipes, FIFOs, futex, poll
│ ├── mm/ # Memory management
│ ├── net/ # TCP/IP stack
│ ├── proc/ # Process management
│ ├── sched/ # Scheduler
│ ├── sync/ # Spinlocks, mutexes
│ ├── syscall/ # GUI syscalls
│ └── debug/ # ksyms, profiler
├── userland/ # Userspace programs
│ ├── init/ # Init process
│ ├── libc/ # Minimal libc (syscall wrappers)
│ └── apps/ # Desktop applications
├── tests/ # Stress tests
├── tools/ # mkfs.betterfs, fsck
├── scripts/ # Build and run scripts
└── docs/ # Documentation
-
Choose a syscall number – See
docs/SYSCALL.mdfor the number table. Use the next free slot in the appropriate range. -
Implement in kernel – In
kernel/arch/x86_64/syscall.c:- Add
#define SYS_MYNEW XX - Implement
static i64 sys_mynew(...)with proper argument handling - Add a
case SYS_MYNEW:insyscall_handler_c()
- Add
-
Expose to userspace – In
userland/libc/syscall.h:- Add
#define SYS_MYNEW XX - Add wrapper:
static inline int64_t mynew(...) { return syscallN(SYS_MYNEW, ...); }
- Add
-
Copy from user – For pointer arguments, use
copy_from_user()/copy_to_user()frommm/uaccess.h. Validate withis_user_address(). -
Error handling – Return negative errno on failure (e.g.
-EINVAL,-ENOMEM).
-
Identify the bus – PCI drivers use
kernel/drivers/pci/. Create a subdirectory underdrivers/(e.g.drivers/mydev/). -
Register with PCI – Use
pci_register_driver()or scan the PCI bus in your init. Seekernel/drivers/net/e1000.cfor an example. -
Implement ops – For block devices: implement
BlockDeviceOps. For character devices: register with devfs. -
Interrupt handling – Register IRQ via
irq_register_handler(). In the handler, acknowledge the interrupt (device-specific) and signal completion. -
Add to kernel Makefile – Ensure your
.cfiles are covered by$(wildcard drivers/mydev/*.c)or add explicit entries.
- Serial output – Kernel logs to COM1 (0x3F8). Use
-serial stdioin QEMU. - Profiler – Call
profiler_start("name")/profiler_stop("name")in kernel code, thenprofiler_dump()to print statistics. - Stack traces –
ksyms_print_stack_trace(rbp, max_frames)after a fault. - QEMU monitor – Use
Ctrl+A Cto enter the monitor,info memfor mappings.