Getting Started
This document provides an overview of the Kyronix’s kernel and instructions for building and running it.
What is Kyronix’s kernel
Kyronix’s kernel(aka k9) is a POSIX-like operating system kernel for the x86_64 architecture. It implements a hybrid design with a custom jail-based sandboxing subsystem, lwIP-based networking, and an ext2 root filesystem.
Key Features
- Limine v3 boot protocol support (BIOS and UEFI)
- Lock-free physical memory allocator (LL-Free)
- Virtual memory with 4-level page tables and demand paging
- Process management with round-robin scheduling
- SMP support (up to
MAX_CPUScores) - POSIX signals, file descriptors, and process management
- Jail-based sandboxing with filesystem, PID, IPC, and privilege isolation
- lwIP TCP/IP stack over virtio-net
- ext2, FAT32, and CPIO filesystems
- ChaCha20-based CSPRNG
- Kernel memory leak detector (
kmemleak)
Quick Start
- Build the kernel and bootable ISO:
make iso
- Run in QEMU with KVM acceleration:
make run
- For serial-only output:
make run-serial
Architecture
The kernel targets x86_64 and uses the following design:
- Boot: Limine v3 protocol provides memory map, framebuffer, HHDM, RSDP, and kernel address information.
- Memory: LL-Free lock-free allocator for physical frames; 4-level page tables for virtual memory; first-fit heap allocator.
- Scheduling: Per-CPU round-robin with lock-free bitmap scanning via
g_ready_mask. - Syscalls: Linux x86_64 ABI-compatible syscall interface via
SYSCALL/SYSRET. - Networking: lwIP stack connected to virtio-net with static QEMU user-mode IP (10.0.2.15/24).
Directory Structure
| Path | Description |
|---|---|
kernel/ | Kernel source (arch, mm, fs, drivers, syscall, proc, net) |
user/ | Userspace programs (shell, utilities) |
rootfs/ | Root filesystem template |
scripts/ | Build scripts and Kconfig tools |
limine/ | Limine bootloader files |
dist/ | Build output directory |
Testing
Run the full test suite:
make test-iso && make test-run-log
This boots the kernel with a testrunner init program, executes test binaries, and reports pass/fail status via serial output. Memory leak detection is performed via the kmemleak subsystem.
Last reviewed: 2026-07-22
Building
This document describes the build process for the Kyronix’s kernel (codename k9). It is the root of the Building section, linking to containerized and native build methods.
Prerequisites
The kernel targets the x86_64 architecture and requires the following toolchain:
- C11 compiler (
gccorx86_64-elf-gcc) - GNU
ld(orx86_64-elf-ld) makexorriso(for ISO generation)mkfs.ext2(for disk image creation)cpio(for initrd packaging)
The build system uses Kconfig for kernel configuration. The generated header kernel/config.h is auto-created from kernel/Kconfig via scripts/kconfig/conf.
Build Targets
| Target | Description |
|---|---|
make all | Builds kernel ELF, initrd, and disk image (default) |
make iso | Builds persistent bootable ISO |
make live-iso | Builds live ISO (no persistent disk) |
make test-iso | Builds test ISO with testrunner initrd |
make test-disk | Creates a 16 MiB ext2 test disk image |
make test-initrd | Builds test initrd with userspace test suite |
make kallsyms | Regenerates the kernel symbol table from kernel.elf |
make nconfig | Opens interactive ncurses-based kernel configuration |
Build Output
| Artifact | Path |
|---|---|
| Kernel ELF | dist/kernel.elf |
| Persistent ISO | dist/kkyronix-<VERSION>-INDEV-amd64.iso |
| Live ISO | dist/kkyronix-<VERSION>-INDEV-amd64-live.iso |
| Test ISO | dist/kkyronix-<VERSION>-INDEV-amd64-test.iso |
| Initrd | dist/initrd.cpio |
| Disk image | dist/disk.img |
Compiler Flags
The kernel is compiled with the following critical flags:
-std=c11 -O2 -ffreestanding -fno-stack-protector-m64 -march=x86-64 -mno-sse -mno-sse2 -mno-mmx -mno-80387-mno-red-zone -mcmodel=kernel-fno-pic -fno-pie -fno-omit-frame-pointer
IMPORTANT: SSE and MMX are disabled in C flags but enabled at runtime via cpu_enable_sse() for FPU context switching. The linker script is linker.ld.
Container Builds
The Makefile supports building inside a container (Podman or Docker) by setting the CRUNTIME variable. See with-cbuildrt, with Docker, or without containers for details.
make all CRUNTIME=podman
make iso CRUNTIME=docker
QEMU Run Targets
| Target | Description |
|---|---|
make run | Graphical QEMU with KVM, virtio-net, AHCI disk |
make run-serial | Serial-only QEMU (no display) |
make run-disk | Direct disk boot (no ISO) |
make run-uefi | UEFI boot with OVMF |
make live-run | Live session from live ISO |
make test-run | Test runner in QEMU |
NOTE: Run targets do NOT rebuild. Execute make iso (or equivalent) first.
Testing
The test framework uses a custom testrunner init that boots the kernel, runs test binaries from the test initrd, and reports results via serial output. Memory leak detection is performed via kmemleak during test runs.
make test-iso && make test-run-log
The test-run-log target captures serial output to test.log and checks for ALL TESTS PASSED and zero KMEMLEAK reports.
Last reviewed: 2026-07-22
Building with cbuildrt
This document describes how to build the Kyronix kernel using cbuildrt. It is the child of Building.
Overview
cbuildrt is a container-based build runtime that provides reproducible build environments. The Kyronix kernel build system supports cbuildrt as an alternative to Docker or Podman for containerized builds.
Status
This document is a placeholder. The cbuildrt integration is not yet present in the kernel source tree. See with Docker/Podman for the current containerized build method, or without containers for native builds.
Last reviewed: 2026-07-22
Building with Docker or Podman
This document describes how to build the Kyronix kernel inside a Docker or Podman container. This is the recommended method for reproducible builds.
Overview
The containerized build uses the Containerfile at the repository root, based on Alpine Linux 3.20. The container image includes all required build dependencies: gcc, make, binutils, nasm, bison, flex, cpio, e2fsprogs, xorriso, and others.
Usage
- Build any target with the
CRUNTIMEvariable set:
make iso CRUNTIME=podman
make all CRUNTIME=docker
-
The Makefile automatically builds the container image from
Containerfileif it does not exist or if theContainerfilehas been modified since the image was last built. -
The source tree is mounted at
/srcinside the container. All build artifacts are written to the host filesystem.
Supported Runtimes
| Runtime | Variable | Default |
|---|---|---|
| Podman | CRUNTIME=podman | Yes (default in Makefile) |
| Docker | CRUNTIME=docker | No |
Container Image
The image is tagged kyronix-build:latest by default. Override via CONTAINER_IMAGE and CONTAINER_IMAGE_TAG variables.
make iso CRUNTIME=docker CONTAINER_IMAGE=custom-build CONTAINER_IMAGE_TAG=v1
Cleanup
make clean CRUNTIME=podman
This removes the dist/, build/, and iso_root/ directories on the host, plus rebuilds the container image on the next build.
NOTE: The container image is cached between builds. Only rebuilds when Containerfile changes.
Last reviewed: 2026-07-22
Building Without Containers
This document describes how to build the Kyronix kernel natively on the host system without containers.
Required Packages
Install the following packages for your distribution:
- Alpine:
gcc g++ make binutils musl-dev linux-headers nasm bison flex ncurses-dev cpio e2fsprogs xorriso - Debian/Ubuntu:
gcc g++ make binutils nasm bison flex libncurses-dev cpio e2fsprogs xorriso - Arch:
gcc make binutils nasm bison flex ncurses cpio e2fsprogs xorriso
Build Steps
- Ensure
gcc(orx86_64-elf-gcc) andld(orx86_64-elf-ld) are inPATH. - Run the desired target without
CRUNTIME:
make all
make iso
- The Kconfig toolchain (
scripts/kconfig/conf) is built automatically from source on first run.
Cross-Compilation
If x86_64-elf-gcc and x86_64-elf-ld are found in PATH, the build system uses them automatically. Otherwise, it falls back to the system gcc and ld.
Kernel Configuration
Edit kernel options interactively:
make nconfig
This opens an ncurses interface. Configuration is stored in .config and generates kernel/config.h via Kconfig autoheader.
Formatting
Format all kernel C source files:
make fmt
Check formatting without modifying files:
make fmt-check
Formatting uses clang-format with the project’s .clang-format style file.
Last reviewed: 2026-07-22
Contributing
This document provides guidelines for contributing to the Kyronix kernel. It is the root of the Contributing section.
Subsections
Last reviewed: 2026-07-22
Contributing Overview
This document provides an overview of the contribution workflow for the Kyronix kernel. It is the child of Contributing.
Workflow
- The project uses a standard fork-and-pull workflow.
- All code must pass
make fmt-check(clang-format) before submission. - The kernel is written in C11 with the project’s
.clang-formatstyle. - Assembly files use AT&T syntax with Intel intrinsics.
- The project uses Kconfig for kernel configuration.
Last reviewed: 2026-07-22
Commit Messages
This document describes the commit message conventions for the Kyronix kernel. It is the child of Contributing.
Format
- Commit messages must follow the conventional format.
- The first line is a short summary (50-72 characters).
- A blank line separates the summary from the body.
- The body explains what and why, not how.
- Reference issues with
#NNN.
Last reviewed: 2026-07-22
Coding Style
This document describes the coding style conventions for the Kyronix kernel. It is the child of Contributing.
Conventions
- Formatting: enforced by
clang-formatwith the project’s.clang-formatfile. - Run
make fmtto format all kernel source files. - Run
make fmt-checkto verify formatting without changes. - Naming: snake_case for functions and variables, UPPER_CASE for macros and constants.
- Headers: include what you use, prefer forward declarations.
- Error handling: check return values, use goto-based cleanup.
- Memory: always check allocation results, free on error paths.
- Assembly: AT&T syntax for
.Sfiles, Intel intrinsics via<stdint.h>.
Last reviewed: 2026-07-22
AI Policy
This document describes the AI usage policy for the Kyronix kernel project. It is the child of Contributing.
Rules
- AI-generated code must be clearly attributed in commit messages.
- Contributors must understand and be able to explain all code they submit, regardless of how it was generated.
- AI tools may be used for code review, documentation, and research.
- All submissions must be reviewed by a human maintainer before merging.
Last reviewed: 2026-07-22
System Architecture
This document describes the high-level architecture of the Kyronix operating system. It is the root of the System Architecture section.
System Layers
The Kyronix system consists of the following layers, from lowest to highest:
- Kernel – Hardware abstraction, memory management, process scheduling, syscalls
- Drivers – PCI, ACPI, AHCI, VirtIO, input, framebuffer, TTY, serial
- Filesystems – VFS, ext2, procfs, devfs
- Networking – lwIP TCP/IP stack, virtio-net interface
Design Principles
- The kernel is hybrid: all basic subsystems run in kernel space with direct hardware access but selected drivers can run in userspace.
- Syscalls follow the Linux x86_64 ABI for compatibility with Linux user-space programs.
- Jail-based sandboxing provides process isolation without requiring separate address spaces.
- The physical memory allocator is lock-free (LL-Free) for scalability on SMP systems.
Last reviewed: 2026-07-22
Components
This document lists the major components of the Kyronix kernel and their source locations.
Kernel Subsystems
| Component | Source Path | Description |
|---|---|---|
| Architecture (x86_64) | kernel/arch/x86_64/ | CPU primitives, GDT, IDT, LAPIC, PIT, syscall entry |
| Memory Management | kernel/mm/ | PMM (LL-Free), VMM, VMA, heap, shared memory |
| Process Management | kernel/proc/ | Process table, scheduler, SMP, signals, jails |
| Filesystems | kernel/fs/ | VFS, ext2, FAT32, procfs, devfs, pipes, sockets |
| Drivers | kernel/drivers/ | PCI, ACPI, AHCI, VirtIO, input, framebuffer, TTY, serial |
| Syscalls | kernel/syscall/ | Linux ABI-compatible syscall dispatcher and handlers |
| Networking | kernel/net/ | lwIP integration, virtio-net interface |
| Cryptography | kernel/crypto/ | ChaCha20 CSPRNG |
| Executable Loading | kernel/exec/ | ELF loader, process exec, stack setup |
| Boot | kernel/boot/ | Limine protocol definitions |
Libraries
| Library | Source Path | Description |
|---|---|---|
| String | kernel/lib/string.c | libc-style string functions |
| Printf | kernel/lib/printf.c | Kernel printf implementation |
| Log | kernel/lib/log.c | Kernel logging (log_info, log_warn) |
| Kallsyms | kernel/lib/kallsyms.c | Kernel symbol lookup |
Last reviewed: 2026-07-22
Kernel
This document describes the Kyronix kernel subsystem. It is the child of System Architecture and parent of all kernel-specific architecture documents.
Kernel Overview
The Kyronix kernel (codename k9) is a monolithic kernel for x86_64, version 0.2. It boots via the Limine v3 protocol and initializes the following subsystems in order:
- Serial output and printf setup
- GDT and IDT
- Physical Memory Manager (PMM) with LL-Free lock-free allocator
- Virtual Memory Manager (VMM) with 4-level page tables
- Local APIC and SMP
- Kernel heap allocator
- Syscall entry (SYSCALL/SYSRET)
- Process scheduler
- Jail sandboxing
- Virtual Filesystem (VFS) with
/proc,/sys,/dev/ptsmounts - PCI enumeration, ACPI, AHCI, VirtIO-net
- Network stack (lwIP)
- PIT timer and LAPIC timer calibration
- Application Processor (AP) boot
- ChaCha20 CSPRNG
- Root filesystem mount and init exec
Kernel Entry Point
The kernel entry point is kmain() in kernel/kernel.c:255. It receives no arguments from the bootloader; all boot information is obtained via Limine protocol requests.
Sections
- Boot – Limine protocol and boot sequence
- Architecture – x86_64 hardware abstractions
- Memory Management – PMM, VMM, heap, VMA
- Process Management – Scheduler, SMP, signals, jails
- Filesystems – VFS, ext2, procfs, devfs
- Drivers – PCI, ACPI, AHCI, VirtIO, input, TTY
- Networking – lwIP, network interface
- Syscalls – Linux ABI-compatible syscall interface
Last reviewed: 2026-07-22
Boot
This document describes the Kyronix kernel boot process. It is the child of Kernel and parent of the Limine protocol reference.
Boot Sequence
The Kyronix kernel boots via the Limine v3 boot protocol. The bootloader loads the kernel ELF and provides the following information through Limine requests:
- Memory map (
LIMINE_MEMMAP_REQUEST) – Physical memory regions (usable, reserved, ACPI, framebuffer) - HHDM offset (
LIMINE_HHDM_REQUEST) – Higher Half Direct Map base address - Framebuffer (
LIMINE_FRAMEBUFFER_REQUEST) – Linear framebuffer for early display - Kernel address (
LIMINE_KERNEL_ADDRESS_REQUEST) – Physical and virtual base addresses - RSDP (
LIMINE_RSDP_REQUEST) – ACPI Root System Description Pointer - Modules (
LIMINE_MODULE_REQUEST) – Bootloader modules (initrd)
All requests use LIMINE_BASE_REVISION(3).
Boot Phases
Phase 1: Early Hardware (BSP)
serial_init(COM1)– Initialize serial port for debug outputgdt_init()– Set up Global Descriptor Table and Task State Segmentidt_init()– Set up Interrupt Descriptor Table, remap PIC to vectors 32-47kbd_init()– Initialize keyboard driver
Phase 2: Memory Setup
pmm_init()– Initialize physical memory manager from Limine memory mapvmm_init()– Enable NX bit, initialize kernel page tablesheap_init()– Initialize kernel heap allocator (64 KiB initial)
Phase 3: Per-CPU and SMP
- Write
MSR_GS_BASEandMSR_KERNEL_GS_BASEfor BSP per-CPU data smp_init()– Enumerate CPUs from Limine SMP response- SMEP detection and enable via CPUID leaf 7
syscall_init()– Configure SYSCALL/SYSRET MSRs, enable SSE
Phase 4: Device Drivers
pci_enumerate()– Scan PCI busacpi_init()– Parse ACPI tables from RSDPahci_init()– Initialize SATA/AHCI controllersvirtnet_init()– Initialize VirtIO network devicenet_init()– Initialize lwIP network stack
Phase 5: Timer and Scheduling
pit_init()– Program PIT channel 0 at ~250 Hzlapic_calibrate_timer()– Calibrate LAPIC timer against PIT- Create BSP idle process
smp_boot_aps()– Wake Application Processors
Phase 6: Filesystem and Init
ext2_init()– Register ext2 filesystem driver- Mount root filesystem from disk or load initrd via CPIO
process_exec("/init")– Load and execute init process
AP Boot Sequence
Application Processors are woken via the Limine SMP goto_address trampoline (ap_trampoline in kernel/proc/ap_trampoline.S). Each AP:
- Loads its
cpu_local_tfromlimine_smp_info.extra_argument - Loads the idle process kernel stack
- Calls
ap_init_cpu()which initializes GDT, IDT, MSRs, SSE, SYSCALL, LAPIC - Spins on
g_kernel_readyuntil BSP signals completion - Starts 250 Hz LAPIC periodic timer
- Enters
ap_sched_loop()(idle/scheduling loop)
Status Output
During boot, each initialization step prints a status line:
* Initialising PMM ... [ ok ]
* Initialising VMM ... [ ok ]
The [ ok ] / [ !! ] indicator is right-aligned at column 72 using ANSI escape codes.
Last reviewed: 2026-07-22
Limine Protocol
This document describes the Limine v3 boot protocol interface used by the Kyronix kernel. It is the child of Boot.
Overview
The Kyronix kernel uses the Limine v3 boot protocol to obtain boot-time information from the bootloader. The protocol uses a request/response mechanism where the kernel declares requests in a special ELF section (.limine_requests), and the bootloader populates the response fields before jumping to the kernel entry point.
Request Types
| Request | Structure | Purpose |
|---|---|---|
LIMINE_FRAMEBUFFER_REQUEST | limine_framebuffer_response | Linear framebuffer information |
LIMINE_MEMMAP_REQUEST | limine_memmap_response | Physical memory map |
LIMINE_HHDM_REQUEST | limine_hhdm_response | Higher Half Direct Map offset |
LIMINE_MODULE_REQUEST | limine_module_response | Bootloader modules (initrd) |
LIMINE_KERNEL_ADDRESS_REQUEST | limine_kernel_address_response | Kernel physical/virtual addresses |
LIMINE_RSDP_REQUEST | limine_rsdp_response | ACPI RSDP physical address |
LIMINE_SMP_REQUEST | limine_smp_response | SMP CPU information |
Memory Map Types
| Type | Value | Description |
|---|---|---|
LIMINE_MEMMAP_USABLE | 0 | Available for kernel use |
LIMINE_MEMMAP_RESERVED | 1 | Reserved by hardware/firmware |
LIMINE_MEMMAP_ACPI_RECLAIMABLE | 2 | Usable after ACPI parsing |
LIMINE_MEMMAP_ACPI_NVS | 3 | ACPI NVS memory (must not reclaim) |
LIMINE_MEMMAP_BAD_MEMORY | 4 | Defective memory region |
LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE | 5 | Usable after bootloader exits |
LIMINE_MEMMAP_KERNEL_AND_MODULES | 6 | Kernel and module images |
LIMINE_MEMMAP_FRAMEBUFFER | 7 | Linear framebuffer memory |
HHDM Response
The limine_hhdm_response provides the offset field, which is the base address of the Higher Half Direct Map. All physical addresses can be converted to virtual via phys_to_virt(phys) = phys + g_hhdm_offset.
Kernel Address Response
The limine_kernel_address_response provides physical_base and virtual_base, used to compute the physical end of the kernel image for PMM initialization.
Module Response
The limine_module_response provides an array of limine_file structures. Kyronix uses the first module as the initrd (CPIO archive).
SMP Response
The limine_smp_response provides cpu_count and an array of limine_smp_info structures. Each entry contains processor_id, lapic_id, and goto_address (trampoline entry point for APs).
Request Declaration
Requests are declared as static volatile structures bracketed by LIMINE_REQUESTS_START_MARKER and LIMINE_REQUESTS_END_MARKER. The base revision is set via LIMINE_BASE_REVISION(3).
LIMINE_REQUESTS_START_MARKER;
LIMINE_BASE_REVISION(3);
static volatile struct limine_memmap_request mmap_req = {
.id = LIMINE_MEMMAP_REQUEST,
.revision = 0,
.response = NULL,
};
LIMINE_REQUESTS_END_MARKER;
IMPORTANT: The response field must be initialized to NULL. The bootloader sets it to a valid pointer if the request is fulfilled.
Last reviewed: 2026-07-22
Architecture
This document describes the hardware abstraction layer for the Kyronix kernel. It is the child of Kernel and parent of architecture-specific documents.
Supported Architectures
The Kyronix kernel currently supports x86_64 (AMD64) only. The architecture-specific code lives in kernel/arch/x86_64/.
Architecture Components
| Component | Source | Description |
|---|---|---|
| CPU Primitives | arch/x86_64/cpu.h | I/O ports, MSRs, control registers, compiler attributes |
| GDT | arch/x86_64/gdt.c | Global Descriptor Table and Task State Segment |
| IDT | arch/x86_64/idt.c | Interrupt Descriptor Table and ISR dispatch |
| LAPIC | arch/x86_64/lapic.c | Local APIC MMIO, IPI, timer calibration |
| PIT | arch/x86_64/pit.c | Programmable Interval Timer and RTC |
| Syscall Setup | arch/x86_64/syscall_setup.c | SYSCALL/SYSRET MSRs, SSE, per-CPU data |
| Syscall Entry | arch/x86_64/syscall_entry.S | SYSCALL entry and userspace trampolines |
| IDT Stubs | arch/x86_64/idt_stubs.S | Assembly ISR entry/exit stubs |
Last reviewed: 2026-07-22
x86-64 Architecture
This document describes the x86-64 architecture support in the Kyronix kernel. It is the child of Architecture and parent of x86-64-specific documents.
Files
| File | Purpose |
|---|---|
cpu.h | CPU primitives, I/O ports, MSRs, control registers, data structures |
gdt.c | GDT creation, TSS initialization, per-CPU segments |
idt.c | IDT setup, PIC remapping, ISR dispatch |
idt_stubs.S | Assembly ISR entry/exit stubs, isr_stub_table |
lapic.c | Local APIC initialization, IPI, timer calibration |
pit.c | PIT channel 0 programming, RTC epoch reading |
syscall_setup.c | SYSCALL/SYSRET configuration, SSE enable, per-CPU local data |
syscall_entry.S | SYSCALL entry point, enter_userspace trampolines |
GDT Layout
| Selector | Entry | Description |
|---|---|---|
0x00 | Null | Null descriptor |
0x08 | Kernel code | 64-bit ring 0 executable |
0x10 | Kernel data | 64-bit ring 0 writable |
0x18 | User data | 64-bit ring 3 writable |
0x20 | User code | 64-bit ring 3 executable |
0x28 + n*0x10 | TSS for CPU n | Task State Segment |
IDT Vector Layout
| Vectors | Source | Gate Type | Description |
|---|---|---|---|
| 0-31 | CPU exceptions | INT_GATE | #DE through #SX |
| 32-47 | PIC IRQ 0-15 | INT_GATE | Legacy PIC interrupts |
| 0x80 (128) | SYSCALL | USER_GATE (DPL=3) | System call entry |
| 224 (0xE0) | LAPIC timer | INT_GATE | Per-CPU timer tick |
| 255 (0xFF) | LAPIC spurious | INT_GATE | Spurious interrupt |
IST Usage
| IST Index | Stack | Assigned To |
|---|---|---|
| 1 | 16 KiB dedicated | Double Fault (#8) |
| 2 | 16 KiB dedicated | NMI (vector 2) |
Per-CPU Data
Per-CPU data is accessed via the GS segment register. MSR_GS_BASE points to cpu_local_t for the current CPU. Key offsets:
| Offset | Field | Description |
|---|---|---|
| 0 | kernel_rsp | Kernel stack pointer (for SYSCALL entry) |
| 8 | user_rsp | User stack pointer (saved on SYSCALL) |
| 16 | cpu_id | CPU identifier |
| 32 | current | Current proc_t pointer |
| 40 | idle | Idle process pointer |
The swapgs instruction swaps between user and kernel GS bases on privilege transitions.
Last reviewed: 2026-07-22
CPU Primitives
This document describes the x86-64 CPU primitives used by the Kyronix kernel. It is the child of x86-64 Architecture.
Source
kernel/arch/x86_64/cpu.h
Compiler Attributes
| Attribute | Definition | Purpose |
|---|---|---|
NORETURN | __attribute__((noreturn)) | Function never returns |
PACKED | __attribute__((packed)) | No struct padding |
ALIGNED(n) | __attribute__((aligned(n))) | Alignment requirement |
INLINE | static inline __attribute__((always_inline)) | Force inlining |
UNUSED | __attribute__((unused)) | Suppress unused warnings |
I/O Port Functions
| Function | Description |
|---|---|
outb(port, val) | Write byte to I/O port |
outw(port, val) | Write 16-bit word to I/O port |
outl(port, val) | Write 32-bit dword to I/O port |
inb(port) | Read byte from I/O port |
inw(port) | Read 16-bit word from I/O port |
inl(port) | Read 32-bit dword from I/O port |
io_wait() | Write 0 to port 0x80 (delay) |
Interrupt Control
| Function | Description |
|---|---|
cli() | Disable interrupts |
sti() | Enable interrupts |
hlt() | Halt CPU until next interrupt |
cpu_relax() | pause instruction (spin-loop hint) |
cpu_halt() | Disable interrupts, halt forever (NORETURN) |
MSR Access
| Function | Description |
|---|---|
rdmsr(msr) | Read 64-bit MSR |
wrmsr(msr, val) | Write 64-bit MSR |
Control Register Access
| Function | Description |
|---|---|
read_cr0() / write_cr0(val) | CR0 (cache control, write protect) |
read_cr2() | CR2 (page fault linear address) |
read_cr3() / write_cr3(val) | CR3 (page table base) |
read_cr4() / write_cr4(val) | CR4 (SMEP, PGE, etc.) |
IRQ Save/Restore
| Function | Description |
|---|---|
irq_save() | Save RFLAGS, disable interrupts, return saved flags |
irq_restore(flags) | Restore RFLAGS to saved value |
Data Structures
cpu_state_t (Interrupt/Syscall Frame)
184-byte packed structure pushed by ISR stubs:
| Offset | Field | Description |
|---|---|---|
| 0x00-0x38 | r15-r8 | General purpose registers |
| 0x40-0x78 | rbp, rdi, rsi, rdx, rcx, rbx, rax | More GPRs |
| 0x80 | int_no | Interrupt vector number |
| 0x88 | error_code | CPU error code (or 0) |
| 0x90 | rip | Return instruction pointer |
| 0x98 | cs | Code segment |
| 0xA0 | rflags | Flags register |
| 0xA8 | rsp | Stack pointer |
| 0xB0 | ss | Stack segment |
gdt_entry_t (8 bytes, packed)
| Field | Size | Description |
|---|---|---|
| limit_low | u16 | Segment limit bits 0-15 |
| base_low | u16 | Base address bits 0-15 |
| base_mid | u8 | Base address bits 16-23 |
| access | u8 | Access byte |
| granularity | u8 | Granularity + flags + limit bits 16-19 |
| base_high | u8 | Base address bits 24-31 |
idt_entry_t (16 bytes, packed)
| Field | Size | Description |
|---|---|---|
| offset_low | u16 | Handler offset bits 0-15 |
| selector | u16 | Code segment selector |
| ist | u8 | Interrupt Stack Table index |
| type_attr | u8 | Gate type + DPL + present bit |
| offset_mid | u16 | Handler offset bits 16-31 |
| offset_high | u32 | Handler offset bits 32-63 |
| zero | u32 | Reserved (must be zero) |
Last reviewed: 2026-07-22
GDT
This document describes the Global Descriptor Table (GDT) implementation in the Kyronix kernel. It is the child of x86-64 Architecture.
Source
kernel/arch/x86_64/gdt.c
Overview
The GDT provides segment descriptors for kernel and user code/data, plus per-CPU Task State Segment (TSS) descriptors. In long mode, segments are mostly flat (base=0, limit=4 GiB), but the TSS is essential for interrupt stack switching and I/O permission bitmap.
GDT Structure
typedef struct {
gdt_entry_t entries[5]; // null, kcode, kdata, udata, ucode
tss_desc_t tss[MAX_CPUS]; // one TSS descriptor per CPU
} gdt_t; // aligned(16)
Segment Values
| Entry | Selector | Encoded Value | Meaning |
|---|---|---|---|
| Kernel code | 0x08 | 0x00AF9A000000FFFF | 64-bit, ring 0, executable, readable |
| Kernel data | 0x10 | 0x00CF92000000FFFF | 64-bit, ring 0, writable |
| User data | 0x18 | 0x00CFF2000000FFFF | 64-bit, ring 3, writable |
| User code | 0x20 | 0x00AFFA000000FFFF | 64-bit, ring 3, executable, readable |
TSS Structure
The TSS (104 bytes on x86-64) provides:
- rsp0: Ring 0 stack pointer, used on privilege level transitions (interrupts from ring 3)
- ist[7]: Interrupt Stack Table entries for critical handlers (Double Fault, NMI)
- iopb_offset: Offset to I/O permission bitmap
typedef struct {
uint32_t reserved0;
uint64_t rsp0, rsp1, rsp2;
uint64_t reserved1;
uint64_t ist[7];
uint64_t reserved2;
uint16_t reserved3;
uint16_t iopb_offset; // = sizeof(tss_t)
} tss_t; // 104 bytes, packed
Key Functions
| Function | Description |
|---|---|
gdt_init() | Initialize GDT, BSP TSS, load GDT and TSS on BSP |
gdt_ap_load(cpu_id) | Load GDT and TSS on an Application Processor |
gdt_set_kernel_stack(rsp0) | Update TSS rsp0 for the current CPU |
tss_init(tss) | Initialize TSS fields (IST stacks, IOPB offset) |
IST Stacks
| IST Index | Stack | Size | Assigned To |
|---|---|---|---|
| 1 | g_ist_df | 16 KiB | Double Fault (#8) |
| 2 | g_ist_nmi | 16 KiB | NMI (vector 2) |
NOTE: IST stacks provide dedicated, non-overflowable stacks for the most critical exceptions, preventing kernel stack corruption during Double Faults.
Last reviewed: 2026-07-22
IDT
This document describes the Interrupt Descriptor Table (IDT) implementation in the Kyronix kernel. It is the child of x86-64 Architecture.
Source
kernel/arch/x86_64/idt.c, kernel/arch/x86_64/idt_stubs.S
Overview
The IDT provides 256 interrupt vector entries. The Kyronix kernel maps CPU exceptions (vectors 0-31), legacy PIC IRQs (vectors 32-47), the SYSCALL vector (0x80), LAPIC timer (224), and LAPIC spurious (255) through a table of 51 assembly stubs (isr_stub_table).
Vector Allocation
| Vectors | Source | Gate Type | IST | Handler |
|---|---|---|---|---|
| 0-31 | CPU exceptions | INT_GATE | – | isr_dispatch() |
| 3 (#BP) | Breakpoint | TRAP_GATE | – | Allows debugger resume |
| 8 (#DF) | Double Fault | INT_GATE | IST 1 | Dedicated DF stack |
| 2 (NMI) | NMI | INT_GATE | IST 2 | Dedicated NMI stack |
| 32-47 | PIC IRQ 0-15 | INT_GATE | – | isr_dispatch() |
| 128 (0x80) | SYSCALL | USER_GATE (DPL=3) | – | isr_dispatch() |
| 224 (0xE0) | LAPIC timer | INT_GATE | – | isr_dispatch() |
| 255 (0xFF) | LAPIC spurious | INT_GATE | – | Silently returns |
Gate Types
| Constant | Value | Description |
|---|---|---|
IDT_INT_GATE | 0x8E | Interrupt gate: present, DPL=0, clears IF on entry |
IDT_TRAP_GATE | 0x8F | Trap gate: present, DPL=0, does NOT clear IF |
IDT_USER_GATE | 0xEE | Interrupt gate: present, DPL=3 (user-accessible) |
ISR Dispatch (isr_dispatch)
The central C function called from isr_common assembly after register save. It handles:
CPU Exceptions (vectors 0-31)
- User-mode exceptions: Deliver signal to process via
exception_signal(n)(SIGFPE, SIGILL, SIGTRAP, SIGSEGV, SIGBUS, etc.) - Page fault (vector 14):
handle_user_page_fault()implements demand paging for stack growth and VMA-based anonymous pages - Breakpoint/Debug (vectors 1, 3): Check
tracer_pidfor ptrace support; #BP decrements RIP by 1 pastint3 - Kernel-mode exceptions: Full panic with register dump, exception name, CR2 (for #PF), and kernel backtrace
PIC IRQs (vectors 32-47)
- IRQ 0 (timer tick): Increments
g_ticks, cursor blink, zombie reaping, network polling, timer mask processing (wakeup, alarm, itimer), preemption check - IRQs 1-15: Dispatch to registered
g_irq_handlers[irq]handlers
Special Vectors
- LAPIC timer (224): Same preemption logic as PIC IRQ 0
- LAPIC spurious (255): Silently returns
ISR Stub Assembly
The isr_common routine in idt_stubs.S performs:
swapgsif entering from ring 3 (privilege transition)- Push all 15 GPRs (forming
cpu_state_tframe) - Call
isr_dispatch(state)in C - Pop all GPRs
swapgsif returning to ring 3iretq
IRQ Registration
void request_irq(uint8_t irq, irq_handler_fn fn, void *arg);
Registers a handler for PIC IRQ 0-15 and unmasks it via pic_unmask_irq().
Kernel Backtrace
The kernel_backtrace() function scans the kernel stack for return addresses in the range [0xffffffff80000000, 0xffffffff80040000) and prints up to 48 candidates. It is called only during kernel panics.
Last reviewed: 2026-07-22
LAPIC
This document describes the Local APIC implementation in the Kyronix kernel. It is the child of x86-64 Architecture.
Source
kernel/arch/x86_64/lapic.c
Overview
The Local APIC (Advanced Programmable Interrupt Controller) provides per-CPU interrupt handling, Inter-Processor Interrupts (IPIs), and the LAPIC timer. The MMIO registers are mapped at virtual address 0xfffffe0000000000.
Initialization
- Read
IA32_APIC_BASEMSR to get physical MMIO address - Enable LAPIC if disabled (set
IA32_APIC_BASE_ENABLE) - Map physical LAPIC to
LAPIC_VIRTwithVMM_KDATA | VMM_PCD(page-cache disabled for MMIO) - Enable Spurious Vector Register (SVR) with spurious vector
- Mask error, thermal, performance, and timer LVT entries
- Clear Task Priority Register (TPR)
- Read LAPIC ID and version
Key Functions
| Function | Description |
|---|---|
lapic_init() | Full LAPIC initialization and MMIO mapping |
lapic_eoi() | Write 0 to EOI register (end-of-interrupt) |
lapic_send_ipi(lapic_id, icr_lo) | Send IPI to specific LAPIC |
lapic_send_ipi_self(icr_lo) | Send self-IPI |
lapic_calibrate_timer() | Calibrate LAPIC timer against PIT |
lapic_timer_start_periodic(hz) | Start periodic timer at given frequency |
lapic_timer_freq() | Return calibrated timer frequency (ticks/ms) |
Timer Calibration
The calibration algorithm:
- Set LAPIC timer to one-shot mode with divisor
0x0Band initial count0xFFFFFFFF - Count 5 PIT counter wraps (each wrap = one PIT period)
- Compute
remaining = 0xFFFFFFFF - current_count - Derive
g_lapic_timer_freq = remaining / 5(ticks per millisecond)
The LAPIC timer is then started in periodic mode at 250 Hz for scheduling ticks.
IPI Mechanism
Inter-Processor Interrupts are sent via the Interrupt Command Register (ICR):
- Wait for send-pending bit to clear
- Write target LAPIC ID to ICR_HI
- Write delivery info to ICR_LO
- Wait for send-pending to clear again
Register Layout
| Offset | Register | Description |
|---|---|---|
| 0x20 | TPR | Task Priority Register |
| 0x80 | EOI | End of Interrupt |
| 0xB0 | ICR_LO | Interrupt Command (low) |
| 0xC0 | ICR_HI | Interrupt Command (high) |
| 0xD0 | SVR | Spurious Vector Register |
| 0x320 | LVT Timer | Timer LVT entry |
| 0x350 | LVT LINT0 | LINT0 LVT entry |
| 0x360 | LVT LINT1 | LINT1 LVT entry |
| 0x370 | LVT Error | Error LVT entry |
Last reviewed: 2026-07-22
PIT
This document describes the Programmable Interval Timer (PIT) implementation in the Kyronix kernel. It is the child of x86-64 Architecture.
Source
kernel/arch/x86_64/pit.c
Overview
The PIT provides the system tick source via channel 0. The CMOS Real-Time Clock (RTC) is read at boot to establish a Unix epoch base time.
PIT Configuration
| Setting | Value |
|---|---|
| Channel | 0 |
| Mode | Square wave (mode 3) |
| Reload value | 4772 |
| Frequency | 1193182 / 4772 = ~250.06 Hz |
| Tick interval | ~4 ms |
Key Functions
| Function | Description |
|---|---|
pit_init() | Program PIT channel 0, read RTC epoch, unmask PIC IRQ 0 |
pit_read_counter() | Latch and read PIT channel 0 counter (used during LAPIC calibration) |
RTC Reading
The CMOS RTC is read at boot to obtain the current date/time:
- Wait for UIP (Update In Progress) flag to clear (CMOS register 0x0A, bit 7)
- Read seconds, minutes, hours, day, month, year, century from CMOS registers
- Convert BCD to binary if needed (Status Register B, bit 2)
- Handle 12/24 hour mode (Status Register B, bit 1)
- Compute Unix timestamp: total seconds since 1970-01-01
The resulting g_epoch_base is used by sys_gettimeofday(), sys_clock_gettime(), and sys_time() to provide wall-clock time.
Global State
| Variable | Type | Description |
|---|---|---|
g_ticks | volatile uint64_t | System tick counter (incremented on each IRQ 0) |
g_epoch_base | uint64_t | Unix timestamp at boot |
NOTE: The PIT is the legacy timer source. The LAPIC timer is calibrated against it and provides the per-CPU scheduling tick at 250 Hz.
Last reviewed: 2026-07-22
Syscall Entry
This document describes the syscall entry mechanism in the Kyronix kernel. It is the child of x86-64 Architecture.
Sources
kernel/arch/x86_64/syscall_setup.c, kernel/arch/x86_64/syscall_entry.S
Overview
The Kyronix kernel uses the AMD64 SYSCALL/SYSRET mechanism for system calls. This provides a fast, non-interrupt-based transition between user mode (ring 3) and kernel mode (ring 0).
MSR Configuration
| MSR | Value | Purpose |
|---|---|---|
MSR_EFER (0xC0000080) | SCE bit set | Enable SYSCALL support |
MSR_STAR (0xC0000081) | Segments encoded | User CS/SS = 0x20/0x28, Kernel CS/SS = 0x08/0x18 |
MSR_LSTAR (0xC0000082) | syscall_entry | SYSCALL entry point address |
MSR_SFMASK (0xC0000084) | IF, TF, DF, AC | RFLAGS bits cleared on SYSCALL |
SYSCALL Entry Sequence
The syscall_entry label in syscall_entry.S:
swapgs– switch GS to kernel per-CPU data- Save user RSP to
gs:CPU_USER_RSP - Load kernel RSP from
gs:CPU_KERNEL_RSP - Push all 15 GPRs (forming a
cpu_state_t-compatible frame) - Move RSP to RDI (first argument = pointer to register frame)
call syscall_dispatch(C function)- Pop all GPRs in reverse
- Restore user RSP from
gs:CPU_USER_RSP swapgs– switch GS back to user per-CPU datasysretq– return to ring 3
Userspace Trampolines
| Function | Description |
|---|---|
enter_userspace(rip, rsp, rflags) | First entry to ring 3 (no swapgs) |
enter_userspace_exec(rip, rsp, rflags) | Entry after exec (includes swapgs) |
Both functions zero all GPRs except RIP, RSP, and RFLAGS, then execute sysretq.
SSE/FPU Setup
SSE is enabled before SYSCALL configuration:
- Clear CR0.EM (bit 2) – disable emulation
- Set CR0.MP (bit 1) – monitor coprocessor
- Set CR4.OSFXSR (bit 9) – enable FXSAVE/FXRSTOR
- Set CR4.OSXMMEXCPT (bit 10) – enable unmasked SSE exceptions
fninit+ldmxcsr 0x1F80– initialize x87 and SSE defaults
Per-CPU Local Data
cpu_local_t is a 64-byte aligned structure accessed via GS:
typedef struct {
uint64_t kernel_rsp; // offset 0
uint64_t user_rsp; // offset 8
uint32_t cpu_id; // offset 16
uint32_t lapic_id; // offset 20
uint32_t online; // offset 24
proc_t *current; // offset 32
proc_t *idle; // offset 40
} cpu_local_t;
Last reviewed: 2026-07-22
Memory Management
This document describes the memory management subsystem of the Kyronix kernel. It is the child of Kernel and parent of memory management component documents.
Architecture
The memory management subsystem consists of four layers:
- LL-Free (
llfree.c) – Lock-free physical frame allocator - PMM (
pmm.c) – Physical page allocation - VMM / VMA (
vmm.c,vma.c) – Virtual memory and area tracking - Heap / SHM (
heap.c,shm.c) – Kernel heap and shared memory
Components
| Component | Source | Description |
|---|---|---|
| PMM | mm/pmm.c | Physical page allocation via LL-Free |
| VMM | mm/vmm.c | 4-level page table management |
| VMA | mm/vma.c | Virtual Memory Area tracking |
| Heap | mm/heap.c | Kernel heap (first-fit linked list) |
| SHM | mm/shm.c | SysV shared memory (up to 64 segments) |
| LL-Free | mm/llfree.c | Lock-free physical frame allocator |
| KmemLeak | mm/kmemleak.c | Kernel memory leak detector |
Key Constants
| Constant | Value | Description |
|---|---|---|
PAGE_SIZE | 4096 | Page frame size |
PAGE_SHIFT | 12 | Bit shift for page-to-byte conversion |
HEAP_START | 0xffff910000000000 | Heap virtual address base |
HEAP_MAX | 0xffff920000000000 | Maximum heap address (4 GiB) |
USER_LIMIT | 0x800000000000 | Top of user half (128 TiB) |
VMM_MAX_SPACES | 256 | Maximum concurrent address spaces |
VMM_VMA_MAX | 2048 | Maximum VMAs per address space |
Last reviewed: 2026-07-22
PMM
This document describes the Physical Memory Manager (PMM) in the Kyronix kernel. It is the child of Memory Management.
Source
kernel/mm/pmm.c, kernel/mm/pmm.h
Overview
The PMM manages physical page frames using the LL-Free lock-free allocator. It provides allocation and deallocation of 4 KiB page frames, with support for contiguous multi-page allocations.
Key Constants
| Constant | Value | Description |
|---|---|---|
PAGE_SIZE | 4096 | Size of one page frame |
PAGE_SHIFT | 12 | Bits to shift for page count |
ZPOOL_SIZE | 32 | Pre-allocated zeroed page pool size |
Macros
| Macro | Description |
|---|---|
PAGE_ALIGN_UP(x) | Round up to next page boundary |
PAGE_ALIGN_DOWN(x) | Round down to page boundary |
phys_to_virt(phys) | Physical to virtual via HHDM offset |
virt_to_phys(virt) | Virtual to physical via HHDM offset |
Functions
| Function | Description |
|---|---|
pmm_init(memmap, hhdm_offset, kernel_end) | Initialize from Limine memory map |
pmm_alloc() | Allocate one frame (order 0) |
pmm_alloc_zeroed() | Allocate one zeroed frame (pool or alloc+memset) |
pmm_alloc_contiguous(n) | Allocate n physically contiguous pages |
pmm_free(phys) | Return a frame to the allocator |
pmm_free_pages() | Return count of free frames |
pmm_total_pages() | Return total managed frames |
pmm_usable_pages() | Return frames marked usable by Limine |
Initialization
- Parse Limine memory map to find highest usable address
- Compute total frames from usable regions
- Allocate LL-Free metadata from the largest usable region (after
kernel_end_phys) - Initialize LL-Free with
LLFREE_INIT_FREE(all frames free) - Fill the zero-page pool (32 pre-allocated zeroed pages)
Requires at least 512 managed frames.
Zero-Page Pool
The PMM maintains a stack of 32 pre-allocated zeroed pages (g_zpool). pmm_alloc_zeroed() first checks this pool; if empty, falls back to pmm_alloc() + memset(0). This avoids repeated zeroing for common allocations.
LL-Free Integration
The PMM delegates to the LL-Free allocator for all frame management. LL-Free is a three-tier lock-free buddy-like allocator with CPU-local reservations for scalability:
- Frame: 4 KiB base unit
- Child: 512 frames = 2 MiB (huge page boundary)
- Tree: 8 children = 4096 frames = 16 MiB
- Local: Per-CPU reservation of one tree
Maximum allocatable order is 12 (4096 frames = 16 MiB contiguous).
Last reviewed: 2026-07-22
VMM
This document describes the Virtual Memory Manager (VMM) in the Kyronix kernel. It is the child of Memory Management.
Source
kernel/mm/vmm.c, kernel/mm/vmm.h
Overview
The VMM manages 4-level x86-64 page tables (PML4 -> PDPT -> PD -> PT) for both kernel and user address spaces. It provides page mapping, unmapping, protection changes, and demand paging support.
Address Space Layout
- User half:
0x000000000000to0x800000000000(128 TiB) - Kernel half:
0x800000000000to0xFFFFFFFFFFFF(128 TiB)
Kernel page table entries (PML4 indices 256-511) are shared across all address spaces.
Composite Flags
| Name | Value | Meaning |
|---|---|---|
VMM_KCODE | PRESENT | Kernel code: present, NX off |
VMM_KDATA | PRESENT | WRITE | NX | Kernel data: present, writable, NX |
VMM_UCODE | PRESENT | USER | User code: present, user, NX off |
VMM_UDATA | PRESENT | WRITE | USER | NX | User data: present, writable, user, NX |
Functions
| Function | Description |
|---|---|
vmm_init() | Enable NX bit via EFER, read kernel PML4 from CR3 |
vmm_map(sp, virt, phys, flags) | Map a single page (allocates intermediate tables as needed) |
vmm_unmap(sp, virt) | Unmap a single page (zeroes leaf PTE) |
vmm_protect(sp, virt, flags) | Change flags on existing mapping |
vmm_virt_to_phys(sp, virt) | Walk page tables for virtual-to-physical translation |
vmm_user_range_ok(sp, virt, len, write) | Validate user range accessibility |
vmm_user_range_fault_in(sp, virt, len, write) | Demand page user range (allocates on fault) |
vmm_space_new() | Create new address space (copies kernel half) |
vmm_space_free(sp) | Free all user-half page tables and frames |
vmm_switch(sp) | Switch address space (write CR3) |
vmm_fork_user(dst, src) | Deep-copy entire user-half address space |
Page Table Indexing
| Level | Index Macro | Bits |
|---|---|---|
| PML4 | (va >> 39) & 0x1FF | Bits 39-47 |
| PDPT | (va >> 30) & 0x1FF | Bits 30-38 |
| PD | (va >> 21) & 0x1FF | Bits 21-29 |
| PT | (va >> 12) & 0x1FF | Bits 12-20 |
Demand Paging
vmm_user_range_fault_in() implements demand paging:
- Check if the VMA subsystem permits the fault (
vma_page_fault_allowed) - Allocate a zeroed physical page via
pmm_alloc_zeroed() - Map it into the address space with appropriate flags
- This allows lazy allocation of user memory on first access
Address Space Management
- Maximum 256 concurrent address spaces (
VMM_MAX_SPACES) - Each space stores its PML4 physical address and a flat array of up to 2048 VMAs
vmm_space_new()copies kernel half entries fromg_kernel_spacevmm_space_free()recursively frees all user-half page table levels
Last reviewed: 2026-07-22
Heap
This document describes the kernel heap allocator in the Kyronix kernel. It is the child of Memory Management.
Source
kernel/mm/heap.c, kernel/mm/heap.h
Overview
The kernel heap provides dynamic memory allocation via kmalloc() and kfree(). It uses a first-fit linked-list allocator with block coalescing, backed by physically contiguous pages from the PMM.
Address Range
| Constant | Value | Description |
|---|---|---|
HEAP_START | 0xffff910000000000 | Heap virtual base |
HEAP_MAX | 0xffff920000000000 | Maximum heap (4 GiB) |
Data Structure
typedef struct block_hdr {
uint64_t size; // Payload size (excluding header)
uint64_t free; // 1 = free, 0 = allocated
struct block_hdr *prev;
struct block_hdr *next;
} block_hdr_t; // 32 bytes
Allocation Algorithm
kmalloc(size)
- Align requested size to 16 bytes
- Disable IRQs, acquire spinlock
- Walk linked list for first-fit free block
- If no block found, call
heap_grow()(16 pages = 64 KiB minimum) - If block is large enough to split (remaining >= 48 bytes), split it
- Mark block as allocated, update stats
kfree(ptr)
- Disable IRQs, acquire spinlock
- Mark block free
- Forward coalesce: merge with next block if free
- Backward coalesce: merge with previous block if free
heap_grow(min_payload)
- Compute pages needed:
ceil(min_payload / PAGE_SIZE)(minimum 16 pages) - Allocate contiguous pages via
pmm_alloc_contiguous() - Map each page into heap range with
VMM_KDATAflags - Append new free block to linked list
Functions
| Function | Description |
|---|---|
heap_init() | Initial heap growth (64 KiB) |
kmalloc(size) | First-fit allocation with 16-byte alignment |
kcalloc(nmemb, size) | Allocation + zero-fill |
krealloc(ptr, new_size) | Resize (copy if needed) |
kfree(ptr) | Free with coalescing |
heap_stats() | Print block count, used/free in KiB |
heap_alloc_delta() | Net allocated bytes (alloc - free) |
heap_walk_used(callback, user) | Walk all allocated blocks (for kmemleak) |
Thread Safety
The heap uses a spinlock with IRQ save/restore for all operations. This ensures safe concurrent access from multiple CPUs and interrupt handlers.
Last reviewed: 2026-07-22
VMA
This document describes the Virtual Memory Area (VMA) subsystem in the Kyronix kernel. It is the child of Memory Management.
Source
kernel/mm/vma.c, kernel/mm/vma.h
Overview
VMAs track which virtual address ranges are mapped in each address space. They are used for demand paging, mmap/munmap tracking, and page fault handling.
Protection Constants
| Constant | Value | Description |
|---|---|---|
PROT_READ | 0x1 | Read permission |
PROT_WRITE | 0x2 | Write permission |
PROT_EXEC | 0x4 | Execute permission |
Data Structure
typedef struct {
uint64_t start; // Start virtual address
uint64_t end; // End virtual address
uint32_t prot; // Protection flags (PROT_READ/WRITE/EXEC)
uint32_t map_flags; // VMM mapping flags
uint8_t used; // Slot in use
uint8_t free_on_unmap; // Free physical pages on unmap
} vmm_vma_t;
VMAs are stored in a flat array of 2048 entries (VMM_VMA_MAX) inside each vmm_space_t. All lookups are linear scans.
Functions
| Function | Description |
|---|---|
vma_reset(sp) | Zero all VMA slots |
vma_copy(dst, src) | Copy VMA array between address spaces |
vma_conflicts(sp, start, len) | Check for overlapping VMAs |
vma_add(sp, start, len, prot, flags, free_on_unmap) | Register a new VMA |
vma_remove(sp, start, len) | Remove a VMA range (with splitting) |
vma_remove_overlaps(sp, start, len) | Remove all overlapping VMAs |
vma_protect(sp, start, len, prot) | Change protection on a range |
vma_page_fault_allowed(sp, addr, write, exec) | Check if a page fault can be handled |
vma_page_flags(sp, addr) | Convert VMA protection to PTE flags |
vma_range_ok(sp, start, len) | Validate range is fully covered by VMAs |
VMA Splitting
When removing a sub-range from a VMA, four cases apply:
- No leftovers: Clear the VMA entirely
- Left only: Shrink
v->end = start - Right only: Shrink
v->start = end - Split: Create two VMAs (left and right of the hole)
Case 4 requires an empty VMA slot and may fail with -ENOMEM.
Page Fault Integration
vma_page_fault_allowed() is called by the VMM’s demand paging path. It returns true only if:
- A VMA covers the faulting address
- The VMA has
free_on_unmapset - The VMA has sufficient permissions (PROT_READ minimum, PROT_WRITE for writes, PROT_EXEC for instruction fetches)
This enables lazy allocation: pages are allocated on first access rather than at mmap time.
Last reviewed: 2026-07-22
Process Management
This document describes the process management subsystem of the Kyronix kernel. It is the child of Kernel and parent of process management component documents.
Components
| Component | Source | Description |
|---|---|---|
| Process Table | proc/proc.c | Process allocation, lifecycle, scheduling |
| Scheduler | proc/sched.S | Context switch (assembly) |
| SMP | proc/smp.c | CPU enumeration, AP boot |
| Signals | proc/signal.c | POSIX signal delivery |
| Jails | proc/jail.c | Sandbox/container isolation |
| ELF Loader | exec/elf.c | 64-bit ELF parsing and loading |
| Process Exec | exec/process.c | Exec, stack setup, userspace entry |
Process States
| State | Value | Description |
|---|---|---|
PROC_UNUSED | 0 | Slot is free |
PROC_RUNNING | 1 | Currently executing on a CPU |
PROC_READY | 2 | Eligible to run, waiting for time slice |
PROC_WAITING | 3 | Blocked (I/O, signal, etc.) |
PROC_ZOMBIE | 4 | Exited, not yet reaped |
PROC_DYING | 5 | In the process of exiting |
PROC_STOPPED | 6 | Job-control stopped |
Process Table
- Fixed array of 64 slots (
PROC_MAX) - Spinlock-protected allocation
- PID = slot index + 1 (PID 0 reserved for idle)
Global Bitmasks
| Bitmask | Description |
|---|---|
g_ready_mask | Processes in READY state (eligible for scheduling) |
g_used_mask | All allocated process slots |
g_timer_mask | Processes with active timers |
Last reviewed: 2026-07-22
Scheduler
This document describes the scheduler in the Kyronix kernel. It is the child of Process Management.
Source
kernel/proc/proc.c, kernel/proc/sched.S
Algorithm
The scheduler implements per-CPU round-robin with lock-free bitmap scanning. The g_ready_mask 64-bit bitmask enables O(1) next-process selection via __builtin_ctzll (count trailing zeros).
Key Functions
| Function | Description |
|---|---|
proc_next_ready(skip) | Find next ready process via bitmap scan |
sched_claim_next(skip) | CAS-based claim (READY -> RUNNING) |
sched_yield_blocking() | Voluntary yield on block |
sched_switch(next) | Context switch (assembly) |
proc_idle_until_ready(skip) | Busy-wait for ready process |
proc_create_idle(cpu_id, entry) | Create idle process for a CPU |
Context Switch (sched_switch)
The context switch in sched.S performs:
- Save callee-saved registers (RBX, RBP, R12-R15)
- Save FPU/SSE state via
fxsave64 - Save FS base via
rdmsr(IA32_FS_BASE) - Save kernel stack pointer (
kstack_rsp) and user RSP - Load next process’s kernel stack, FS base, user RSP
- Switch address space via
vmm_switch(next->space)(CR3) - Restore FPU/SSE state via
fxrstor64 - Pop callee-saved registers and return
SMP Scheduling
Each CPU runs its own scheduling loop (ap_sched_loop):
- Try
sched_claim_next(idle)– CAS from READY to RUNNING - If found: switch from idle to the claimed process
- If not found:
sti; hlt(halt until next interrupt)
Preemption occurs on both PIC IRQ 0 and LAPIC timer tick (vector 224). If a higher-priority process is found via sched_claim_next, the current process is preempted.
Kernel Stack Layout
Each process gets 16 pages (64 KiB) of kernel stack plus 1 guard page:
- Guard page: unmapped (detects overflow)
- Usable stack: 16 pages mapped with
VMM_KDATA - Virtual base:
0xffff920000000000(bump-allocated)
FPU State
Each process has 512 bytes of FPU/SSE state (fpu_state) at offset 3328, saved/restored on every context switch via fxsave64/fxrstor64. Initialized with FCW=0x037F and MXCSR=0x1F80 (all exceptions masked).
Last reviewed: 2026-07-22
SMP
This document describes the Symmetric Multi-Processing (SMP) support in the Kyronix kernel. It is the child of Process Management.
Source
kernel/proc/smp.c, kernel/proc/smp.h, kernel/proc/ap_trampoline.S
Overview
SMP support enables the kernel to run on multiple CPU cores. The BSP (Bootstrap Processor) discovers CPUs via the Limine SMP protocol and wakes APs (Application Processors) via a trampoline mechanism.
CPU Discovery (smp_init)
- Read
limine_smp_responsefrom bootloader - Set
g_cpu_countto reported CPU count - Identify BSP by its LAPIC ID, assign CPU ID 0
- Assign sequential IDs to APs (starting at 1)
- Store
&g_cpu_local[cid]in each CPU’sextra_argument
AP Boot Sequence (smp_boot_aps)
- Create idle process for each non-BSP CPU
- Write
ap_trampolineto each CPU’sgoto_address(Limine wake-up mechanism) - Wait until
g_aps_ready == g_cpu_count - 1
AP Trampoline (ap_trampoline)
The AP entry point in assembly:
cli– disable interrupts- Load
limine_smp_info.extra_argument(points tocpu_local_t) - Load
cpu_local_t.current(idle process) - Load
proc_t.kstack_topas RSP - Call
ap_init_cpu(cpu_local_t *)in C
AP Initialization (ap_init_cpu)
Each AP performs full initialization (in order):
- GDT:
gdt_ap_load(cpu_id)– per-CPU GDT + TSS - IDT:
idt_load_ap()– reload IDT - MSR setup: Write
IA32_GS_BASEandIA32_KERNEL_GS_BASE - SSE:
cpu_enable_sse() - SYSCALL MSRs: Configure SYSCALL/SYSRET (same as BSP)
- LAPIC: Enable spurious vector, mask LVT entries
- Signal readiness: Atomically increment
g_aps_ready - Wait for BSP: Spin on
g_kernel_ready - Start timer:
lapic_timer_start_periodic(250) - Enter
ap_sched_loop()
Per-CPU Data
Each CPU has a cpu_local_t structure accessed via GS:
| Offset | Field | Description |
|---|---|---|
| 0 | kernel_rsp | Kernel stack pointer |
| 8 | user_rsp | User stack pointer |
| 16 | cpu_id | CPU identifier |
| 32 | current | Current process |
| 40 | idle | Idle process |
Maximum supported CPUs is defined by MAX_CPUS.
Last reviewed: 2026-07-22
Signals
This document describes the signal handling implementation in the Kyronix kernel. It is the child of Process Management.
Source
kernel/proc/signal.c, kernel/proc/signal.h
Overview
The Kyronix kernel implements POSIX-compatible signal handling with Linux ABI compatibility. Signals are delivered by constructing an rt_sigframe on the user stack and redirecting execution to the signal handler.
Supported Signals
| Signal | Value | Default Action |
|---|---|---|
SIGHUP | 1 | Fatal |
SIGINT | 2 | Fatal |
SIGQUIT | 3 | Fatal |
SIGILL | 4 | Fatal |
SIGTRAP | 5 | Fatal |
SIGABRT | 6 | Fatal |
SIGBUS | 7 | Fatal |
SIGFPE | 8 | Fatal |
SIGKILL | 9 | Fatal (uncatchable) |
SIGUSR1 | 10 | Fatal |
SIGSEGV | 11 | Fatal |
SIGUSR2 | 12 | Fatal |
SIGPIPE | 13 | Fatal |
SIGALRM | 14 | Fatal |
SIGTERM | 15 | Fatal |
SIGCHLD | 17 | Non-fatal (ignore) |
SIGCONT | 18 | Non-fatal (continue) |
SIGSTOP | 19 | Stop (uncatchable) |
SIGTSTP | 20 | Stop |
SIGTTIN | 21 | Stop |
SIGTTOU | 22 | Stop |
SIGWINCH | 28 | Non-fatal (ignore) |
Signal Delivery
signal_check(f)
Called on every syscall entry/exit and timer interrupt:
- Check terminal-driven signals via
tty_check_signals() - Load pending signals masked by complement of
sig_mask - Find lowest-numbered unmasked signal via
__builtin_ctzll - Clear from
pending_sigs - If ptrace-traced, call
proc_ptrace_stop() - Otherwise call
deliver_signal()
deliver_signal(p, sig, frame)
- SIGSTOP/SIGTSTP (default): Enter job-control stop
- SIG_IGN: No action
- SIG_DFL: If fatal, call
proc_do_exit(-sig) - Custom handler: Build signal frame and redirect execution
setup_sigframe(p, sig, frame)
- Check for alternate signal stack (
SA_ONSTACK) - Allocate
rt_sigframe_t(440 bytes) below user RSP - Populate with register snapshot, signal info, ucontext
- Update signal mask (add signal bit +
sa_mask) - Redirect:
rcx= handler,rdi= signal number,rsi= siginfo,rdx= ucontext
Signal Action Flags
| Flag | Value | Effect |
|---|---|---|
SA_NOCLDSTOP | 0x0001 | Don’t send SIGCHLD on stops |
SA_NOCLDWAIT | 0x0002 | Don’t create zombies |
SA_SIGINFO | 0x0004 | Extended handler (3-arg) |
SA_ONSTACK | 0x08000000 | Execute on alternate stack |
SA_RESETHAND | 0x80000000 | Reset to SIG_DFL after delivery |
SA_NODEFER | 0x40000000 | Don’t block signal during handler |
Alternate Signal Stack
Each process can have an alternate stack configured via sigaltstack(). The frame is placed at the top of the alternate stack when SA_ONSTACK is set.
Last reviewed: 2026-07-22
Jail
This document describes the jail (sandbox) subsystem in the Kyronix kernel. It is the child of Process Management.
Source
kernel/proc/jail.c, kernel/proc/jail.h
Overview
Jails provide process isolation through hierarchical containment with four independent isolation axes: filesystem, PID namespace, IPC, and privilege restriction. Up to 32 jails can exist simultaneously.
Jail Flags
| Flag | Value | Effect |
|---|---|---|
JAILF_FS | 0x01 | Filesystem isolation (chroot-like root) |
JAILF_PID | 0x02 | PID namespace isolation |
JAILF_IPC | 0x04 | IPC isolation |
JAILF_PRIV | 0x08 | Privilege restriction (root inside jail is restricted) |
Jail States
| State | Value | Description |
|---|---|---|
JAIL_UNUSED | 0 | Slot is free |
JAIL_ACTIVE | 1 | Jail is operational |
JAIL_DYING | 2 | Pending destruction (waiting for processes to exit) |
Data Structures
typedef struct {
int state;
uint32_t id;
uint32_t parent_id;
uint32_t flags;
char name[32];
char root[256];
int nprocs;
int max_procs;
uint32_t creator_uid;
} jail_t;
Syscalls
| Syscall | Number | Description |
|---|---|---|
jail_create | 500 | Create a new jail |
jail_attach | 501 | Move process into a jail |
jail_get | 502 | Get jail info by ID |
jail_list | 503 | List all visible jails |
jail_remove | 504 | Remove/destroy a jail |
jail_self | 505 | Get current process’s jail ID |
jail_set_auto | 506 | Toggle auto-isolation mode |
Key Functions
| Function | Description |
|---|---|
jail_init() | Zero all jail slots |
jail_create(parent_id, cfg, uid) | Create jail with parent relationship |
jail_enter(p, jid) | Move process into jail |
jail_remove(jid, requester) | Remove jail (permission checked) |
jail_can_see(observer, target) | PID namespace visibility check |
jail_host_priv(p) | Check host-level privilege |
jail_can_fork(jid) | Check fork permission and capacity |
jail_root_current() | Get current process’s jail root |
jail_canon_clamp(path, sz, root) | Clamp path within jail root |
Path Canonicalization
The jail system canonicalizes paths to prevent directory traversal escapes:
path_canon()resolves.and.., collapses multiple slashesjail_canon_clamp()ensures the result stays within the jail’s rootjail_strip_root()removes the jail root prefix forgetcwd()display
Hierarchy
Jails form a tree rooted at JAIL_HOST (0). A process can only enter a jail that is a descendant of its current jail. This prevents privilege escalation by entering an ancestor jail.
Auto-Isolation
When g_jail_auto_isolate is enabled (via jail_set_auto), every execve() call creates a fresh jail for the process. The init process and its direct descendants are exempt (marked with JAILF_EXEMPT).
Last reviewed: 2026-07-22
Filesystems
This document describes the filesystem subsystem of the Kyronix kernel. It is the child of Kernel and parent of filesystem component documents.
Components
| Component | Source | Description |
|---|---|---|
| VFS | fs/vfs.c | Virtual Filesystem Switch layer |
| ext2 | fs/ext2.c | ext2/3 filesystem driver |
| FAT32 | fs/fat32.c | FAT32 filesystem driver |
| procfs | fs/procfs.c | Process information filesystem (/proc) |
| devfs | fs/devfs.c | Device filesystem (/dev) |
| eventfd | fs/eventfd.c | Event file descriptor |
| pipe | fs/pipe.c | Anonymous pipes |
| CPIO | fs/cpio.c | CPIO archive loader (initrd) |
| fstab | fs/fstab.c | /etc/fstab parser |
| Unix socket | fs/unix_socket.c | Unix domain sockets |
| Inet socket | fs/inet_socket.c | Internet domain sockets (lwIP) |
Mount Points
The kernel mounts the following filesystems at boot:
| Mount | Source | Description |
|---|---|---|
/proc | procfs | Process information |
/sys | devfs | System/device nodes |
/dev/pts | devfs | Pseudo-terminal devices |
/ | ext2 or initrd | Root filesystem |
File Descriptor Operations
The VFS layer provides the following operations on file descriptors:
| Operation | Function |
|---|---|
| Read | fd_read() |
| Write | fd_write() |
| Seek | fd_lseek() |
| Close | fd_close() |
| Stat | fd_stat() / fd_fstat() |
| Dup | fd_dup() / fd_dup2() / fd_dup3() |
| Poll | fd_pollin() / fd_pollout() / fd_pollhup() |
| Ioctl | fd_ioctl() |
| Getdents | fd_getdents64() |
Last reviewed: 2026-07-22
VFS
This document describes the Virtual Filesystem Switch (VFS) in the Kyronix kernel. It is the child of Filesystems.
Source
kernel/fs/vfs.c, kernel/fs/vfs_internal.h
Overview
The VFS provides a unified interface for all filesystem operations. It manages mount points, file descriptor tables, node reference counting, and filesystem registration.
Data Structures
vfs_node_t
Represents a file, directory, device, or special node:
| Field | Description |
|---|---|
type | Node type (VFS_TYPE_REG, VFS_TYPE_DIR, VFS_TYPE_DEV, etc.) |
name | Node name |
size | File size in bytes |
mode | Permission bits |
uid, gid | Owner and group |
data | Filesystem-specific data |
fs_ops | Filesystem operations (read, write, create, etc.) |
refcount | Reference count |
vfs_file_t
Represents an open file descriptor:
| Field | Description |
|---|---|
node | Associated VFS node |
offset | Current file position |
flags | Open flags (O_RDONLY, O_WRONLY, etc.) |
pipe | Pipe data (for pipe FDs) |
inet | Inet socket data |
Mount System
| Function | Description |
|---|---|
vfs_init() | Initialize VFS, mount /proc, /sys, /dev/pts |
vfs_mount(path, fs, dev) | Mount a filesystem at a path |
vfs_lookup(path) | Look up a node by path |
vfs_register_fs(fs) | Register a filesystem driver |
Path Resolution
Paths are resolved relative to the process’s current working directory (cwd) and jail root. The resolution process:
- If path is absolute and jail root exists, prepend jail root
- Walk components, resolving
.and.. - Return refcounted node pointer
Filesystem Operations
Each registered filesystem provides:
| Operation | Description |
|---|---|
check_root(bd) | Check if a block device contains this filesystem |
mount(bd, path) | Mount the filesystem |
read(node, buf, off, len) | Read data |
write(node, buf, off, len) | Write data |
create(node, name, type) | Create a file or directory |
unlink(node, name) | Remove a file |
readdir(node, entries) | List directory contents |
Reference Counting
VFS nodes use reference counting to prevent use-after-free. vfs_lookup() increments the refcount; vfs_node_unref_internal() decrements it. When the refcount reaches zero, the node is freed.
Last reviewed: 2026-07-22
ext2
This document describes the ext2 filesystem driver in the Kyronix kernel. It is the child of Filesystems.
Source
kernel/fs/ext2.c
Overview
The ext2 driver provides read/write access to ext2/3 filesystems. It is the primary disk-based filesystem used for the root partition.
Features
- Block size: 4096 bytes
- Inode-based file storage
- Directory entries with inode references
- Symbolic link support
- File creation, deletion, renaming
- Permission bits (mode, uid, gid)
Mount Process
- Read superblock from block device
- Validate magic number and block size
- Initialize block and inode bitmaps
- Mount at specified path
Block Allocation
The driver maintains block and inode bitmaps. Free blocks are found via linear scan of the bitmap. Block groups are used to distribute metadata across the disk.
Registration
ext2_init(); // Register ext2 filesystem driver
After registration, the kernel attempts to mount ext2 on block devices during boot.
Last reviewed: 2026-07-22
FAT32
This document describes the FAT32 filesystem driver in the Kyronix kernel. It is the child of Filesystems.
Source
kernel/fs/fat32.c
kernel/fs/fat32.h
Overview
The FAT32 driver provides read/write access to FAT32-formatted disk partitions. The driver supports directory traversal, file read/write, and file creation.
Features
- Directory traversal
- File read/write
- File creation
VFS Integration
The FAT32 driver integrates with the VFS layer through standard filesystem operations.
Last reviewed: 2026-07-22
CPIO
This document describes the CPIO archive loader in the Kyronix kernel. It is the child of Filesystems.
Source
kernel/fs/cpio.c
kernel/fs/cpio.h
Overview
The CPIO loader provides read-only access to CPIO archives used as initial ramdisks (initrds). The loader extracts files from the CPIO archive passed by the Limine bootloader as a module.
VFS Integration
The CPIO loader integrates with the VFS layer to present archive contents as a filesystem.
Last reviewed: 2026-07-22
procfs
This document describes the procfs filesystem in the Kyronix kernel. It is the child of Filesystems.
Source
kernel/fs/procfs.c
Overview
procfs is an in-memory filesystem mounted at /proc that exposes process and kernel information. It provides a read-only view of system state.
Mount Point
/proc
Entries
| Entry | Description |
|---|---|
/proc/<pid>/ | Per-process information directories |
/proc/self/ | Symlink to current process |
/proc/meminfo | Memory usage statistics |
/proc/version | Kernel version string |
/proc/uptime | System uptime |
Implementation
procfs nodes are dynamically generated on lookup. The filesystem does not persist data to disk; all information is gathered from kernel state at access time.
Last reviewed: 2026-07-22
devfs
This document describes the devfs filesystem in the Kyronix kernel. It is the child of Filesystems.
Source
kernel/fs/devfs.c
Overview
devfs is an in-memory filesystem mounted at /dev that provides device nodes. It dynamically creates entries for registered character and block devices.
Mount Points
| Mount | Description |
|---|---|
/dev | Device nodes |
/sys | System information |
/dev/pts | Pseudo-terminal devices |
Device Registration
Drivers register device nodes via devfs_register():
| Device | Path | Description |
|---|---|---|
| Framebuffer | /dev/fb0 | Linear framebuffer device |
| Input event 0 | /dev/input/event0 | Keyboard input |
| Input event 1 | /dev/input/event1 | Mouse input |
| AHCI disk | /dev/ahci0 | SATA/AHCI block device |
Device Types
| Type | Description |
|---|---|
VFS_TYPE_DEV | Character device |
VFS_TYPE_BLK | Block device |
Last reviewed: 2026-07-22
eventfd
This document describes the event file descriptor in the Kyronix kernel. It is the child of Filesystems.
Source
kernel/fs/eventfd.c
Overview
eventfd provides a lightweight signaling mechanism between processes or threads. It implements a 64-bit counter that can be read and written atomically.
Syscalls
| Syscall | Number | Description |
|---|---|---|
eventfd | 284 | Create eventfd with flags |
eventfd2 | 290 | Create eventfd with flags (O_CLOEXEC, O_NONBLOCK) |
Operations
| Operation | Behavior |
|---|---|
read() | Blocks if counter is 0; otherwise returns counter and resets to 0 |
write() | Adds to the counter atomically |
poll() | Returns readable when counter > 0, writable when counter < MAX |
Implementation
eventfd instances are backed by a 64-bit atomic counter stored in the VFS node’s data field. Reads and writes are performed atomically using spinlocks.
Last reviewed: 2026-07-22
Pipe
This document describes the pipe implementation in the Kyronix kernel. It is the child of Filesystems.
Source
kernel/fs/pipe.c, kernel/fs/fdpipe.c
Overview
Pipes provide unidirectional inter-process communication. The Kyronix kernel implements both anonymous pipes (pipe/pipe2) and named pipes (FIFOs).
Syscalls
| Syscall | Number | Description |
|---|---|---|
pipe | 22 | Create anonymous pipe |
pipe2 | 293 | Create pipe with flags (O_CLOEXEC, O_NONBLOCK) |
Data Structure
typedef struct {
uint8_t *buf; // Ring buffer
size_t size; // Buffer capacity
size_t read_pos; // Read position
size_t write_pos; // Write position
size_t count; // Bytes available
// Synchronization primitives for blocking read/write
} pipe_t;
Operations
| Operation | Behavior |
|---|---|
read() | Blocks if empty; reads up to requested bytes |
write() | Blocks if full; writes up to requested bytes |
close() | Signals EOF to readers/writers |
Ancillary Data (SCM_RIGHTS)
Pipes support file descriptor passing via SCM_RIGHTS ancillary data on Unix domain sockets. This enables processes to share file descriptors across address spaces.
Blocking
Read and write operations block the calling process when the pipe is empty (read) or full (write). Blocked processes are moved to PROC_WAITING state and woken when data becomes available.
Last reviewed: 2026-07-22
Drivers
This document describes the device driver subsystem of the Kyronix kernel. It is the child of Kernel and parent of driver component documents.
Components
| Component | Source | Description |
|---|---|---|
| PCI | drivers/pci.c | PCI bus enumeration |
| ACPI | drivers/acpi.c | ACPI table parsing |
| AHCI | drivers/ahci.c | SATA/AHCI block device driver |
| VirtIO | drivers/virtio_net.c | VirtIO network device driver |
| Input | drivers/input.c | Event-based input subsystem |
| Keyboard | drivers/kbd.c | PS/2 keyboard driver |
| PS/2 Mouse | drivers/ps2mouse.c | PS/2 mouse driver |
| Framebuffer | drivers/fb.c | Linear framebuffer driver |
| fbdev | drivers/fbdev.c | Framebuffer device (/dev/fb0) |
| TTY | drivers/tty.c | Teletype terminal |
| Virtual TTY | drivers/vt.c | Virtual terminal switching |
| Serial | drivers/serial.c | Serial port (COM1) |
| Block | drivers/block.c | Block device abstraction |
| UIO | drivers/uio.c | Userspace I/O device |
Initialization Order
Drivers are initialized in kmain() after PCI enumeration and ACPI setup:
block_init()– Block device abstractionahci_init()– SATA/AHCI controllersvirtnet_init()– VirtIO networknet_init()– Network stack (lwIP)uio_init()– Userspace I/Ofbdev_init()– Framebuffer deviceinput_init()– Input event subsystemvt_init()– Virtual terminalpit_init()– Timerps2mouse_init()– PS/2 mouse
Last reviewed: 2026-07-22
PCI
This document describes the PCI bus enumeration in the Kyronix kernel. It is the child of Drivers.
Source
kernel/drivers/pci.c
Overview
PCI (Peripheral Component Interconnect) enumeration discovers and configures all PCI devices on the bus. The kernel scans the standard I/O configuration space to identify devices.
Configuration Space Access
PCI configuration is accessed via I/O ports:
| Port | Description |
|---|---|
0xCF8 | Configuration Address Register |
0xCFC | Configuration Data Register |
Device Structure
struct pci_device {
uint8_t bus, dev, func;
uint16_t vendor_id, device_id;
uint8_t class, subclass;
uint8_t prog_if;
uint8_t header_type;
uint32_t bar[6];
uint16_t command;
};
Enumeration
pci_enumerate() scans all 256 buses, 32 devices, and 8 functions:
- For each device/function, read vendor ID
- If vendor ID is
0xFFFF, device does not exist – skip - Read class, subclass, BAR registers, and header type
- Store in global device table
BAR (Base Address Register) Types
| Type | Description |
|---|---|
| I/O | Memory-mapped I/O port |
| Memory | Memory-mapped device registers |
BARs are used by drivers (AHCI, VirtIO) to access device registers.
Last reviewed: 2026-07-22
ACPI
This document describes the ACPI implementation in the Kyronix kernel. It is the child of Drivers.
Source
kernel/drivers/acpi.c
Overview
ACPI (Advanced Configuration and Power Interface) provides hardware configuration information. The kernel parses the RSDP (Root System Description Pointer) to locate the ACPI tables.
Initialization
acpi_init(rsdp_address);
- Read RSDP from the address provided by Limine
- Validate RSDP signature (“RSD PTR “)
- Locate RSDT/XSDT (Root/Extended System Description Table)
- Parse SDT entries for MADT (APIC), FADT (Fixed ACPI), and others
Key Tables
| Table | Purpose |
|---|---|
| RSDP | Root pointer to all ACPI tables |
| RSDT/XSDT | Root/Extended System Description Table |
| MADT | Multiple APIC Description Table (CPU topology) |
| FADT | Fixed ACPI Description Table (PM timer, reset port) |
Functions
| Function | Description |
|---|---|
acpi_init(addr) | Parse ACPI tables from RSDP address |
acpi_available() | Check if ACPI was successfully initialized |
Last reviewed: 2026-07-22
AHCI
This document describes the AHCI (Advanced Host Controller Interface) driver in the Kyronix kernel. It is the child of Drivers.
Source
kernel/drivers/ahci.c
Overview
AHCI provides access to SATA storage devices. The driver initializes AHCI controllers discovered via PCI enumeration and registers block devices for each attached drive.
Initialization
- Scan PCI devices for AHCI class (class=0x01, subclass=0x06)
- Read ABAR (AHCI Base Address Register) from PCI BAR5
- Map AHCI HBA registers into kernel virtual space
- Reset the HBA and detect attached ports
- For each active port, initialize command list and FIS structures
- Register as block device via
block_register()
Block Device Interface
AHCI block devices are accessed through the generic block device layer:
struct block_device {
void (*read)(uint64_t lba, uint32_t count, void *buf);
void (*write)(uint64_t lba, uint32_t count, const void *buf);
uint64_t total_sectors;
// ...
};
Functions
| Function | Description |
|---|---|
ahci_init() | Initialize AHCI controller(s) |
ahci_ready() | Check if AHCI is operational |
NOTE: AHCI devices appear as /dev/ahci0 via devfs.
Last reviewed: 2026-07-22
VirtIO
This document describes the VirtIO network driver in the Kyronix kernel. It is the child of Drivers.
Source
kernel/drivers/virtio_net.c
Overview
VirtIO provides paravirtualized network access for QEMU virtual machines. The driver implements the VirtIO 1.0 network device specification.
Initialization
- Scan PCI devices for VirtIO vendor ID (
0x1AF4) - Negotiate feature bits with the device
- Initialize virtqueues (TX and RX)
- Register MAC address (6 bytes)
- Set link status to up
Virtqueue Layout
| Queue | Purpose |
|---|---|
| TX queue | Transmit Ethernet frames |
| RX queue | Receive Ethernet frames |
Functions
| Function | Description |
|---|---|
virtnet_init() | Initialize VirtIO-net device |
virtnet_ready() | Check if device is operational |
virtnet_send(buf, len) | Transmit an Ethernet frame |
virtnet_recv(buf, len) | Receive an Ethernet frame |
virtnet_mac() | Get MAC address |
Network Integration
The VirtIO-net driver is connected to the lwIP network stack via the kyronix netif layer. Raw Ethernet frames are passed between the driver and lwIP without additional encapsulation.
Last reviewed: 2026-07-22
Input
This document describes the input subsystem in the Kyronix kernel. It is the child of Drivers.
Source
kernel/drivers/input.c, kernel/drivers/kbd.c, kernel/drivers/ps2mouse.c
Overview
The input subsystem provides an event-based interface for keyboard and mouse input. Events are delivered to user-space via character devices at /dev/input/event0 (keyboard) and /dev/input/event1 (mouse).
Event Structure
struct input_event {
uint32_t type; // Event type
uint32_t code; // Key/button code
int32_t value; // Value (press/release/movement)
};
Event Types
| Type | Description |
|---|---|
| Keyboard event | Key press/release with scancode |
| Mouse event | Relative X/Y movement and button state |
Devices
| Device | Path | Source |
|---|---|---|
| Keyboard | /dev/input/event0 | PS/2 keyboard |
| Mouse | /dev/input/event1 | PS/2 mouse |
Functions
| Function | Description |
|---|---|
input_init() | Initialize input subsystem |
kbd_init() | Initialize PS/2 keyboard |
ps2mouse_init() | Initialize PS/2 mouse |
Terminal Integration
The input subsystem is connected to the TTY layer. Keyboard events drive the virtual terminal, and mouse events are forwarded to user-space via the event devices.
Last reviewed: 2026-07-22
Framebuffer
This document describes the framebuffer driver in the Kyronix kernel. It is the child of Drivers.
Source
kernel/drivers/fb.c, kernel/drivers/fbdev.c
Overview
The framebuffer driver provides access to the linear framebuffer provided by the Limine bootloader. It supports text rendering via a built-in PSF font and exposes a character device at /dev/fb0.
Initialization
- Read framebuffer info from Limine (
LIMINE_FRAMEBUFFER_REQUEST) - Map framebuffer into kernel virtual space
- Clear screen with background color
- Register
/dev/fb0character device via fbdev
Framebuffer Properties
| Field | Description |
|---|---|
address | Linear framebuffer physical address |
width, height | Resolution in pixels |
pitch | Bytes per scanline |
bpp | Bits per pixel |
Text Rendering
The kernel includes a built-in PSF (PC Screen Font) for text rendering. Each character is 8x16 pixels. The framebuffer supports ANSI color codes for colored text output.
Functions
| Function | Description |
|---|---|
fb_init(lfb) | Initialize framebuffer from Limine response |
fb_clear(color) | Clear screen with solid color |
fb_putchar(c) | Render a character at the current cursor position |
fb_set_color(fg, bg) | Set foreground and background colors |
fb_cursor_blink_tick(ticks) | Update cursor blink state |
Last reviewed: 2026-07-22
TTY
This document describes the TTY (teletype) subsystem in the Kyronix kernel. It is the child of Drivers.
Source
kernel/drivers/tty.c, kernel/drivers/vt.c
Overview
The TTY subsystem provides terminal I/O with support for multiple virtual terminals. It handles character buffering, line editing, and ANSI escape sequence processing.
Components
| Component | Source | Description |
|---|---|---|
| TTY | tty.c | Terminal I/O and line discipline |
| Virtual TTY | vt.c | Virtual terminal switching |
Features
- Line buffering with echo
- ANSI escape sequence parsing (colors, cursor movement)
- Multiple virtual terminals (switched via keyboard)
- SIGINT (Ctrl+C), SIGQUIT (Ctrl+) generation
- Cursor blink timer
Functions
| Function | Description |
|---|---|
tty_putchar(c) | Output a character to the current terminal |
tty_check_signals() | Check for terminal-driven signals |
Signal Generation
| Key | Signal | Description |
|---|---|---|
| Ctrl+C | SIGINT | Interrupt |
| Ctrl+\ | SIGQUIT | Quit |
| Ctrl+Z | SIGTSTP | Terminal stop |
Last reviewed: 2026-07-22
Serial
This document describes the serial port driver in the Kyronix kernel. It is the child of Drivers.
Source
kernel/drivers/serial.c
Overview
The serial driver provides early kernel output via the COM1 serial port (I/O address 0x3F8). It is the first driver initialized during boot and remains available for debug output throughout kernel execution.
COM1 Port Layout
| Port | Offset | Description |
|---|---|---|
0x3F8 | +0 | Data register (read/write) |
0x3F9 | +1 | Interrupt Enable Register |
0x3FA | +2 | FIFO Control Register |
0x3FB | +3 | Line Control Register |
0x3FC | +4 | Modem Control Register |
0x3FD | +5 | Line Status Register |
Initialization
serial_init(COM1);
- Disable interrupts (write 0 to IER)
- Enable DLAB (set LCR bit 7)
- Set baud rate divisor to 1 (115200 baud)
- 8 data bits, 1 stop bit, no parity (LCR = 0x03)
- Enable FIFO, clear, 14-byte threshold (FCR = 0xC7)
- IRQs enabled, RTS/DSR set (MCR = 0x0B)
Output
Serial output is used for:
- Kernel debug messages (
log_info,log_warn) - Boot status messages
- Test framework output (
test-run-log) - QEMU serial console (
-serial stdio)
NOTE: The serial port is initialized before any other driver, making it the most reliable output path for early boot debugging.
Last reviewed: 2026-07-22
Networking
This document describes the networking subsystem of the Kyronix kernel. It is the child of Kernel and parent of networking component documents.
Components
| Component | Source | Description |
|---|---|---|
| Network Stack | net/net.c | lwIP initialization and polling |
| lwIP Glue | net/lwip_glue.c | Kernel memory allocator bridge |
| Kyronix Netif | net/netif/kyronix_netif.c | lwIP network interface driver |
| VirtIO-Net | drivers/virtio_net.c | Hardware NIC driver |
Architecture
User-space (sockets)
|
v
Syscall layer (socket.c)
|
v
lwIP TCP/IP stack
|
v
kyronix_netif (lwIP netif)
|
v
virtio-net driver
|
v
QEMU virtio-net device
Network Configuration
| Setting | Value |
|---|---|
| IP Address | 10.0.2.15 |
| Subnet Mask | 255.255.255.0 (/24) |
| Gateway | 10.0.2.2 |
| DNS Server | 10.0.2.3 |
These are static addresses matching QEMU’s default user-mode networking (SLIRP) configuration.
Socket Types
| Type | Source | Description |
|---|---|---|
| Unix domain | fs/unix_socket.c | Local IPC sockets |
| Internet | fs/inet_socket.c | TCP/UDP over lwIP |
Functions
| Function | Description |
|---|---|
net_init() | Initialize lwIP and register network interface |
net_poll() | Drain virtio-net RX queue, process lwIP timeouts |
net_receive(frame, len) | Feed raw Ethernet frame to lwIP |
Last reviewed: 2026-07-22
lwIP
This document describes the lwIP integration in the Kyronix kernel. It is the child of Networking.
Source
kernel/net/lwip/ (lwIP library), kernel/net/lwip_glue.c
Overview
lwIP (Lightweight IP) is an open-source TCP/IP stack designed for embedded systems. Kyronix integrates lwIP with a glue layer that bridges its memory allocation to the kernel heap.
Glue Layer
The lwip_glue.c file maps lwIP’s expected libc functions to kernel implementations:
| lwIP Expects | Kernel Provides |
|---|---|
malloc(s) | kmalloc(s) |
free(p) | kfree(p) |
calloc(n, s) | kcalloc(n, s) |
sys_now() | g_ticks * 10 (ticks to ms) |
strtol(s, end, base) | Custom decimal parser |
Protocols Supported
- TCP (connection-oriented)
- UDP (connectionless)
- ICMP (ping)
- ARP (Address Resolution Protocol)
- IPv4
Initialization
net_init();
- Check
virtnet_ready() - Call
lwip_init() - Configure static IP (10.0.2.15/24, gateway 10.0.2.2)
- Register kyronix netif with
ethernet_inputas input function - Set DNS server to 10.0.2.3
Timeout Processing
lwIP timeouts are processed periodically via sys_check_timeouts(). This is called every 256 polls from net_poll().
Last reviewed: 2026-07-22
Network Interface
This document describes the Kyronix network interface driver in the Kyronix kernel. It is the child of Networking.
Source
kernel/net/netif/kyronix_netif.c
Overview
The kyronix netif bridges lwIP to the virtio-net hardware. It implements the lwIP netif interface for sending and receiving raw Ethernet frames.
Netif Configuration
| Property | Value |
|---|---|
| Name | "e0" |
| MTU | 1500 |
| Output (ARP+IP) | etharp_output |
| Link output | kyronix_netif_output |
| Flags | NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP |
| MAC address | From virtnet_mac() |
Functions
| Function | Description |
|---|---|
kyronix_netif_init(nif) | Initialize netif (called by netif_add) |
kyronix_netif_input(nif, data, len) | Feed raw Ethernet frame into lwIP |
kyronix_netif_output(nif, p) | Send pbuf chain via virtio-net |
Receive Path
- virtio-net driver calls
net_receive(frame, len) net_receivecallskyronix_netif_input()kyronix_netif_inputallocates apbuffromPBUF_POOL- Copies frame data into pbuf chain
- Calls
nif->input()(which isethernet_input)
Transmit Path
- lwIP calls
kyronix_netif_output(nif, p) - Gathers pbuf chain into flat buffer (max 1514 bytes)
- Calls
virtnet_send(buf, total)
Last reviewed: 2026-07-22
Syscalls
This document describes the syscall interface of the Kyronix kernel. It is the child of Kernel and parent of syscall category documents.
Overview
The Kyronix kernel implements a Linux x86_64 ABI-compatible syscall interface. User programs invoke syscalls via the SYSCALL instruction with the syscall number in RAX and arguments in RDI, RSI, RDX, R10, R8, R9.
Syscall Entry
swapgs(switch to kernel GS base)- Save user RSP, load kernel RSP
- Push all GPRs into
cpu_state_tframe - Call
syscall_dispatch(frame)in C - Restore registers,
sysretqto user mode
Categories
| Category | Document | Syscalls |
|---|---|---|
| File Operations | file.md | read, write, open, close, stat, lseek, dup, ioctl, … |
| Process Control | process.md | fork, clone, execve, exit, wait4, … |
| Memory Management | memory.md | mmap, munmap, brk, mprotect, mremap, … |
| Socket Operations | socket.md | socket, connect, bind, listen, accept, sendto, recvfrom, … |
| Timers | timer.md | nanosleep, clock_gettime, alarm, setitimer, … |
| Epoll | epoll.md | epoll_create1, epoll_ctl, epoll_wait, … |
| Futex | futex.md | futex (WAIT, WAKE, REQUEUE) |
| Ptrace | ptrace.md | ptrace (TRACEME, PEEK, POKE, CONT, SINGLESTEP, …) |
Error Handling
Syscalls return errors via RAX. Negative values represent Linux errno constants (e.g., -ENOENT, -EINVAL).
Signal Delivery
After every syscall, signal_check() is called to deliver pending signals. If a signal is delivered, the syscall may be restarted or interrupted based on signal handler configuration.
Ptrace Integration
The syscall dispatcher checks ptrace_syscall_trace on every entry and exit. If set, the process is stopped with SIGTRAP|0x80 for debugger observation.
Last reviewed: 2026-07-22
File Operations
This document describes the file operation system calls (syscalls) in the Kyronix kernel. It is the child of Syscalls.
Syscall Table
-
0
read- Read data from a file descriptor (fd) -
1
write- Write data to a file descriptor -
2
open- Open a file by path -
3
close- Close a file descriptor -
4
stat- Get file status by path -
5
fstat- Get file status by fd -
6
lstat- Get file status by path (no symlink follow) -
7
poll- Wait for events on fds -
8
lseek- Set file offset for a fd -
16
ioctl- Control device parameters -
17
pread64- Read from fd at offset -
18
pwrite64- Write to fd at offset -
19
readv- Read multiple buffers from fd -
20
writev- Write multiple buffers to fd -
21
access- Check file accessibility by path -
22
pipe- Create a pipe -
23
select- Monitor multiple fds for events -
32
dup- Duplicate a fd -
33
dup2- Duplicate a fd to a specific number -
40
sendfile- Transfer data between fds -
72
fcntl- File descriptor control operations -
76
truncate- Truncate a file to a specified length -
77
ftruncate- Truncate a fd to a specified length -
78
getdents64- Read directory entries -
79
getcwd- Get current working directory -
80
chdir- Change current working directory -
81
fchdir- Change current working directory by fd -
82
rename- Rename a file or directory -
83
mkdir- Create a directory -
84
rmdir- Remove a directory -
85
creat- Create a file -
86
link- Create a hard link -
87
unlink- Remove a file -
88
symlink- Create a symbolic link -
89
readlink- Read a symbolic link -
90
chmod- Change file permissions by path -
91
fchmod- Change file permissions by fd -
92
chown- Change file owner by path -
93
fchown- Change file owner by fd -
94
lchown- Change file owner (no symlink follow) -
95
umask- Set file creation mask -
137
statfs- Get filesystem statistics by path -
138
fstatfs- Get filesystem statistics by fd -
257
openat- Open file relative to directory fd -
258
mkdirat- Create directory relative to directory fd -
260
mknodat- Create device node relative to directory fd -
261
fchownat- Change file owner relative to directory fd -
262
newfstatat- Get file status relative to directory fd -
263
unlinkat- Remove file relative to directory fd -
264
renameat- Rename file relative to directory fds -
265
linkat- Create hard link relative to directory fds -
266
symlinkat- Create symbolic link relative to directory fd -
267
readlinkat- Read symbolic link relative to directory fd -
268
fchmodat- Change file permissions relative to directory fd -
269
faccessat- Check file accessibility relative to directory fd -
292
dup3- Duplicate a fd with flags -
293
pipe2- Create a pipe with flags -
295
preadv- Read from fd at offset with scatter-gather -
296
pwritev- Write to fd at offset with scatter-gather -
326
copy_file_range- Copy data between two fds -
332
statx- Get extended file status -
334
close_range- Close a range of fds
Path Resolution
All path-based syscalls route through path_abs() to resolve user-provided paths to absolute paths. This function applies jail root confinement via jail_root_current() and prepends the current working directory (cwd) for relative paths.
The at-relative syscalls (openat, mkdirat, unlinkat, etc.) use at_resolve() for directory fd resolution. This function validates the directory fd and combines it with the relative path.
Internal Helpers
The kernel provides user pointer validation helpers:
uptr_ok(ptr, size)- Validates a user pointer for read access with automatic page faultinguptr_ok_w(ptr, size)- Validates a user pointer for write access with automatic page faulting
These helpers ensure user pointers are in valid user address space before dereferencing.
Last reviewed: 2026-07-22
Process Control
This document describes the process control system calls (syscalls) in the Kyronix kernel. It is the child of Syscalls.
Syscall Table
-
56
clone- Create a new process/thread -
57
fork- Create a child process -
58
vfork- Create a child process (treated as fork) -
59
execve- Execute a program -
60
exit- Terminate a process -
61
wait4- Wait for a process to change state -
231
exit_group- Terminate all threads in a process -
247
waitid- Wait for a specific process state change -
39
getpid- Get process id (PID) -
110
getppid- Get parent PID -
186
gettid- Get thread id (TID) -
102
getuid- Get real user id (UID) -
104
getgid- Get real group id (GID) -
107
geteuid- Get effective UID -
108
getegid- Get effective GID -
105
setuid- Set real UID -
106
setgid- Set real GID -
109
setpgid- Set process group id (PGID) -
112
setsid- Create a session and set session id (SID) -
113
setreuid- Set real and effective UID -
114
setregid- Set real and effective GID -
115
getgroups- Get supplementary group list -
116
setgroups- Set supplementary group list -
117
setresuid- Set real, effective, and saved UID -
118
getresuid- Get real, effective, and saved UID -
119
setresgid- Set real, effective, and saved GID -
120
getresgid- Get real, effective, and saved GID -
121
getpgid- Get PGID -
122
setfsuid- Set filesystem UID -
123
setfsgid- Set filesystem GID -
124
getsid- Get session ID -
158
arch_prctl- Architecture-specific process register (ARCH_SET_FS, ARCH_SET_GS, ARCH_GET_FS, ARCH_GET_GS)
clone Flags
The clone syscall accepts flags to control process/thread creation behavior:
CLONE_VM- Share memory with parent processCLONE_FILES- Share file descriptor table with parentCLONE_THREAD- Create a thread (shared address space)CLONE_SETTLS- Set thread-local storage (TLS)CLONE_PARENT_SETTID- Store child TID at parent-provided addressCLONE_CHILD_CLEARTID- Clear child TID at exit and wake waitersCLONE_CHILD_SETTID- Store child TID at child-provided address
execve Details
The execve syscall performs the following operations:
- Reads the shebang line (#!) if present and interprets the interpreter path
- Loads the executable binary (Executable and Linkable Format (ELF))
- For dynamically linked executables, sets up the dynamic linker via
PT_INTERPsegment at virtual address 0x7f0000000000 - Sets Position Independent Executable (PIE) base address at 0x400000
- Sets up the user stack with
argc,argv,envp, and auxiliary vector (auxv) - Initializes Address Space Layout Randomization (ASLR) for the memory map bump allocator (
mmap_bump)
fork Details
The fork syscall performs the following operations:
- Deep-copies the address space via
vmm_fork_user() - Copies the file descriptor table
- Creates a new kernel stack for the child process
- The child process returns with
raxset to 0
clone Thread Support
The clone syscall with CLONE_THREAD flag creates a thread that shares:
- The address space (via
CLONE_VM) - The file descriptor table (via
CLONE_FILES)
wait4 Details
The wait4 syscall supports the following features:
- Zombie reaping of terminated children
- Handling of
ptrace-stopped tracees - Job-stopped children
- Non-blocking operation via
WNOHANGflag
proc_do_exit
The proc_do_exit function performs the following cleanup operations:
- Cleans up System V Shared Memory (SHM)
- Unreferences the jail
- Releases the file descriptor table
- Reparents children to PID 1 (init process)
- Delivers
SIGCHLDsignal to the parent process
Last reviewed: 2026-07-22
Memory Management Syscalls
This document describes the memory management system calls (syscalls) in the Kyronix kernel. It is the child of Syscalls.
Syscall Table
-
9
mmap- Map memory or files into address space -
10
mprotect- Set memory protection on a region -
11
munmap- Unmap memory from address space -
12
brk- Change data segment size -
25
mremap- Remap a virtual memory area (VMA) -
26
msync- Synchronize memory with storage (noop for ramfs) -
27
mincore- Determine page residency in memory -
28
madvise- Provide advice about memory usage (noop) -
29
shmget- Get System V shared memory segment -
30
shmat- Attach shared memory to address space -
31
shmctl- Control shared memory operations -
67
shmdt- Detach shared memory from address space
mmap Flags
The mmap syscall accepts the following flags:
MAP_ANON- Create an anonymous mapping (not backed by a file)MAP_FIXED- Place the mapping at the exact address specifiedMAP_PRIVATE- Create a private copy-on-write (COW) mappingMAP_SHARED- Create a shared mapping visible to other processes
mmap Details
The mmap syscall uses mmap_pick_addr() to select a virtual address for anonymous mappings. The address selection uses a bump allocator that starts at:
p->mmap_bump = 0x0000500000000000 + random_offset
The mmap implementation supports:
- Anonymous mappings (file descriptor is -1)
- File-backed mappings (valid file descriptor)
- Character device custom mappings (User I/O (UIO))
brk Details
The brk syscall implements the classic break mechanism for heap management:
- Operates with page-granularity (minimum allocation is one page)
- Allocates zeroed pages via
pmm_alloc_zeroed() - Tracks
pages_allocandpages_freedcounters - Expands the data segment by mapping new pages
- Contracts the data segment by unmapping pages
mprotect Details
The mprotect syscall changes both:
- Virtual Memory Area (VMA) metadata (protection flags)
- Page table entries (hardware-level permissions)
Shared Memory (SHM)
The SHM syscalls implement System V shared memory with the following characteristics:
- Requires
JAILF_IPCflag for jail isolation - Maximum of 64 shared memory segments per process
- Maximum of 4096 pages (16 MiB at 4 KiB pages) per segment
- Supports attach, detach, and control operations
Last reviewed: 2026-07-22
Socket Operations
This document describes the socket operation syscalls in the Kyronix kernel. It is the child of Syscalls.
Syscall Table
- 41
socket- Create a socket endpoint - 42
connect- Initiate a connection on a socket - 43
accept- Accept a connection on a socket - 44
sendto- Send a message on a socket - 45
recvfrom- Receive a message from a socket - 46
sendmsg- Send a message with ancillary data - 47
recvmsg- Receive a message with ancillary data - 48
shutdown- Shut down part of a full-duplex connection - 49
bind- Bind a socket to an address - 50
listen- Listen for connections on a socket - 51
getsockname- Get local address of a socket - 52
getpeername- Get remote address of a socket - 53
socketpair- Create a pair of connected sockets - 54
setsockopt- Set a socket option - 55
getsockopt- Get a socket option - 288
accept4- Accept a connection with flags
Socket Types
The socket syscall routes to one of two backends based on the domain argument.
AF_UNIX (Unix Domain Sockets)
Unix domain sockets are implemented in unix_socket.c. The domain value is 1. Only SOCK_STREAM is supported. Unix domain sockets provide local inter-process communication (IPC) using pipe-backed data transfer.
The socket lifecycle follows these states:
SOCK_UNBOUND- Socket created but not yet bound to a pathSOCK_BOUND- Socket bound to a filesystem path or abstract nameSOCK_LISTENING- Socket in listening state, accepting connections
Abstract sockets use names prefixed with a null byte. The kernel maintains a table of MAX_ABSTRACT_SOCKS (16) entries for abstract socket names. Abstract sockets are invisible across jails when the JAILF_IPC flag is set on the originating jail.
AF_INET (Internet Sockets)
Internet sockets are implemented in inet_socket.c using the lwIP (Lightweight IP) stack. The domain value is 2. Three socket types are supported:
SOCK_STREAM(1) - Transmission Control Protocol (TCP) connections backed bytcp_pcbSOCK_DGRAM(2) - User Datagram Protocol (UDP) connections backed byupcbSOCK_RAW(3) - Raw IP connections backed byraw_pcb
Each internet socket contains a net_conn_t structure with protocol control blocks, a 16 KiB receive ring buffer for TCP, and an 8-slot datagram queue for UDP/raw sockets.
SCM_RIGHTS (File Descriptor Passing)
The SCM_RIGHTS ancillary data type enables file descriptor passing between processes over Unix domain sockets. The constant value is 1.
- The sender calls
sendmsgwith a control message containingSOL_SOCKET,SCM_RIGHTS, and an array of file descriptors - The kernel extracts VFS (Virtual File System) node pointers from the sender’s file descriptors via
fd_get_node() - Nodes are queued into the pipe’s ancillary data ring via
pipe_anc_send() - The receiver calls
recvmsgand the kernel reconstructs file descriptors from the queued VFS nodes viafd_open_node() - A maximum of
PIPE_ANC_MAXFDSfile descriptors are transferred per message
SCM_CREDENTIALS (Peer Credential Passing)
The SCM_CREDENTIALS ancillary data type enables peer credential passing. The constant value is 2. The SO_PASSCRED socket option (value 16) must be enabled on the receiving socket to receive credentials.
- The receiver enables credential passing via
setsockopt(SOL_SOCKET, SO_PASSCRED, &on) - The receiver calls
recvmsgwith a control buffer large enough to hold aucred_sstructure - The kernel fills the control message with the sender’s process ID (PID), user ID (UID), and group ID (GID)
- The
ucred_sstructure containspid(int32),uid(uint32), andgid(uint32)
Socket Options
Socket options are managed via setsockopt (syscall 54) and getsockopt (syscall 55) at the SOL_SOCKET (level 1) layer.
Supported Options
| Option | Value | Direction | Description |
|---|---|---|---|
SO_TYPE | 3 | Get | Returns socket type (1=stream, 2=dgram, 3=raw) |
SO_ERROR | 4 | Get | Returns last error code (always 0) |
SO_PASSCRED | 16 | Set | Enables SCM_CREDENTIALS delivery |
SO_PEERCRED | 17 | Get | Returns peer PID/UID/GID in ucred_s |
SO_DOMAIN | 39 | Get | Returns address family (1=AF_UNIX, 2=AF_INET) |
sendmsg / recvmsg (Vectored I/O)
The sendmsg (syscall 46) and recvmsg (syscall 47) syscalls support vectored I/O through scatter-gather lists of iovec structures.
The msghdr layout in memory:
| Offset | Field | Type |
|---|---|---|
| 0 | msg_name | void pointer |
| 8 | msg_namelen | uint32 |
| 12 | msg_iov | iovec pointer |
| 16 | msg_iovlen | int |
| 24 | msg_control | void pointer |
| 32 | msg_controllen | uint64 |
| 40 | msg_flags | uint32 |
sendmsg
- Validate the
msghdrpointer andiovecarray - For each iovec entry, call
fd_write()with the iovec base and length - If a control buffer is present, parse
cmsg_len,cmsg_level, andcmsg_type - For
SCM_RIGHTSmessages, extract file descriptors and pass their VFS nodes through the pipe’s ancillary ring
recvmsg
- For internet sockets, delegate to
inet_recvfrom()for the first iovec entry and fillmsg_namewith the source address - For Unix domain sockets, read data from iovec entries via
fd_read()orfd_peek()(whenMSG_PEEKis set) - If ancillary data is available in the pipe’s receive ring, construct an
SCM_RIGHTScontrol message with reconstructed file descriptors - If
SO_PASSCREDis enabled and credentials are available, construct anSCM_CREDENTIALScontrol message with peer PID/UID/GID
Last reviewed: 2026-07-22
Timers
This document describes the timer syscalls in the Kyronix kernel. It is the child of Syscalls.
Syscall Table
- 35
nanosleep- Pause execution for a relative time interval - 36
getitimer- Get current value of an interval timer - 37
alarm- Set a real-time signal alarm - 38
setitimer- Set an interval timer - 96
gettimeofday- Get current wall-clock time - 97
getrlimit- Get resource limits - 98
getrusage- Get resource usage (stub, returns zeroed struct) - 99
sysinfo- Get system information - 100
times- Get process times - 201
time- Get time in seconds - 228
clock_gettime- Get clock time - 229
clock_getres- Get clock resolution - 230
clock_nanosleep- Sleep until an absolute or relative clock time - 302
prlimit64- Get or set resource limits
Time Model
The Kyronix kernel derives time from two global counters maintained by the Programmable Interval Timer (PIT) and the Real-Time Clock (RTC):
g_ticks(volatile uint64) - Milliseconds since boot, incremented on each PIT tick at approximately 250 Hzg_epoch_base(uint64) - Unix timestamp in seconds at boot time, read from the RTC during initialization
Wall time in milliseconds is computed as:
wall_ms = g_epoch_base * 1000 + g_ticks
The time (syscall 201) and gettimeofday (syscall 96) syscalls both return wall time derived from this formula. The clock_gettime (syscall 228) syscall also uses this computation and returns the result as a timespec structure with seconds and nanoseconds.
Clock Resolution
The clock_getres (syscall 229) syscall reports a resolution of {0, 1000000} nanoseconds (1 millisecond). This reflects the PIT tick rate of approximately 250 Hz, yielding a 4-millisecond tick period. The kernel floors sub-millisecond precision to 1 millisecond in all time calculations.
nanosleep
The nanosleep (syscall 35) syscall pauses the calling process for a specified duration:
- Read the requested time from the user-provided
timespecstructure (seconds and nanoseconds) - Convert the duration to milliseconds:
ms = sec * 1000 + nsec / 1000000 - Set
p->wakeup_tick = g_ticks + ms - Call
proc_set_timer(p)to register the timer - Yield the processor in a blocking loop until
g_ticks >= deadlineor the process is woken by a signal - Clear
p->wakeup_tickand return 0
clock_nanosleep
The clock_nanosleep (syscall 230) syscall extends nanosleep with clock ID and flags support:
- Read the requested time from the user-provided
timespecstructure - If the
TIMER_ABSTIMEflag (bit 0) is set, compute the relative sleep duration astarget_ms - current_wall_ms - Otherwise, treat the request as a relative sleep duration
- Follow the same blocking loop as
nanosleep
alarm
The alarm (syscall 37) syscall sets a real-time signal alarm:
- Compute the previous alarm’s remaining seconds from
p->alarm_tick - If
seconds > 0, setp->alarm_tick = g_ticks + seconds * 1000and register the timer - If
seconds == 0, clearp->alarm_tick - Return the number of seconds remaining on the previous alarm
The alarm delivers SIGALRM to the process when the deadline expires. The kernel checks p->alarm_tick in the PIT interrupt handler (IDT vector 32).
itimer (Interval Timer)
The setitimer (syscall 38) and getitimer (syscall 36) syscalls manage interval timers that deliver SIGALRM at periodic intervals:
setitimerreads the new interval from aitimervalstructure containing interval (seconds, microseconds) and value (seconds, microseconds)- The interval is stored in
p->itimer_interval_msand the next trigger inp->itimer_next_tick getitimerreturns the current interval and remaining time until the next trigger- The kernel checks
p->itimer_next_tickin the PIT interrupt handler and deliversSIGALRMwhen the deadline expires
getrlimit / prlimit64
The getrlimit (syscall 97) and prlimit64 (syscall 302) syscalls report resource limits:
| Resource | Hard Limit | Soft Limit |
|---|---|---|
RLIMIT_NOFILE (7) | VFS_FD_MAX (1024) | VFS_FD_MAX (1024) |
| All others | 1 GiB (1073741824) | 1 GiB (1073741824) |
The prlimit64 syscall accepts a PID argument but ignores it, always operating on the current process. The new limits argument (nl) is accepted but not applied.
sysinfo
The sysinfo (syscall 99) syscall returns system information in a fixed structure:
| Field | Value |
|---|---|
| uptime | g_ticks / 1000 (seconds since boot) |
| totalram | 256 MiB (268435456 bytes) |
| freeram | 128 MiB (134217728 bytes) |
| mem_unit | 1 (byte) |
| procs | 1 |
All other fields are zeroed.
times
The times (syscall 100) syscall returns a monotonic tick count (g_ticks + 1). The user-provided tms structure is zeroed. The return value is always positive.
Last reviewed: 2026-07-22
Epoll
This document describes the epoll event polling interface in the Kyronix kernel. It is the child of Syscalls.
Syscall Table
- 213
epoll_create- Create an epoll instance (delegates toepoll_create1(0)) - 232
epoll_wait- Wait for events on an epoll instance - 233
epoll_ctl- Control an epoll instance - 281
epoll_pwait- Wait for events with signal mask (delegates toepoll_wait) - 291
epoll_create1- Create an epoll instance with flags
Operations
The epoll_ctl (syscall 233) syscall modifies the set of file descriptors monitored by an epoll instance:
EPOLL_CTL_ADD(1) - Add a file descriptor to the epoll interest list. ReturnsEEXISTif the file descriptor is already monitored. ReturnsENOMEMif the watch limit is reached.EPOLL_CTL_DEL(2) - Remove a file descriptor from the epoll interest list. ReturnsENOENTif the file descriptor is not found.EPOLL_CTL_MOD(3) - Modify the events and data associated with an existing file descriptor. ReturnsENOENTif the file descriptor is not found.
Events
| Event | Value | Description |
|---|---|---|
EPOLLIN | 0x001 | Data is available for read |
EPOLLOUT | 0x004 | Ready for write |
EPOLLERR | 0x008 | Error condition |
EPOLLHUP | 0x010 | Hang up |
EPOLLONESHOT | 0x40000000 | One-shot: disarmed after first event delivery |
Events EPOLLERR and EPOLLHUP are reported regardless of whether they are in the interest set. The EPOLLONESHOT flag disables the watch after a single event; the watch must be re-armed via EPOLL_CTL_MOD.
Implementation
Epoll state is managed by the g_epolls array with EPOLL_SLOTS (64) entries. Each epoll instance contains:
epfd- The file descriptor handle (backed by an internal/dev/nullfile descriptor)owner_space- The VMM (Virtual Memory Manager) address space that owns the instancew[EPOLL_MAXW]- Array ofEPOLL_MAXW(256) watch entries, each containing a file descriptor, events mask, and user datanw- Current number of active watches
Epoll instances are associated with the creating process’s address space. An instance is only findable by processes sharing the same address space. Stale instances (where the backing file descriptor has been closed) are cleaned up during epoll_create1.
Polling
The epoll_wait (syscall 232) and epoll_pwait (syscall 281) syscalls poll all watches in the epoll interest list:
- For each watch, check
fd_valid()to determine if the file descriptor is still open. If not, reportEPOLLERR | EPOLLHUP. - If the watch requests
EPOLLIN, checkfd_pollin()for available read data. - If the watch requests
EPOLLOUT, checkfd_pollout()for write readiness. - Check
fd_pollhup()unconditionally for hang-up conditions. - If
EPOLLONESHOTis set on a triggered watch, disarm theEPOLLINandEPOLLOUTbits.
The polling loop runs at 5-millisecond intervals (p->wakeup_tick = g_ticks + 5). If events are found or the timeout expires, the syscall returns immediately. If a signal is pending, the syscall returns EINTR.
The timeout parameter controls the maximum wait duration:
timeout == 0- Non-blocking poll, return immediatelytimeout > 0- Block for up totimeoutmillisecondstimeout < 0- Block indefinitely until events are found or a signal arrives
The epoll_create (syscall 213) syscall delegates to epoll_create1(0). The epoll_pwait (syscall 281) syscall delegates to epoll_wait without applying a signal mask.
Last reviewed: 2026-07-22
Futex
This document describes the futex (Fast Userspace Mutex) implementation in the Kyronix kernel. It is the child of Syscalls.
Syscall Table
- 202
futex- Fast Userspace Mutex operations
Operations
The futex syscall supports four operation commands, selected by the op argument. The FUTEX_PRIVATE_FLAG (128) and FUTEX_CLOCK_REALTIME (256) flags may be OR’d with the operation but are currently ignored.
FUTEX_WAIT (0)
Atomically checks that the value at uaddr equals val, then blocks the calling process until woken:
- Verify
*uaddr == val. If not, returnEAGAIN. - Find a free slot in
g_futex_tab. If no slot is available, returnENOMEM. - Register the current process and
uaddrin the slot. - If a timeout is provided (a
timespecpointer), compute the deadline in milliseconds:deadline = g_ticks + (sec * 1000 + nsec / 1000000). - Block in a loop until the process is woken, the deadline expires, or a signal is delivered.
- On timeout, return
ETIMEDOUT. Otherwise, return 0.
FUTEX_WAKE (1)
Wakes up to val processes waiting on uaddr:
- Scan
g_futex_tabfor entries matchinguaddr. - For each matching entry, verify the waiting process is in the same jail as the caller (
g_futex_tab[i].proc->jail_id == self->jail_id). - Transition the waiting process from
PROC_WAITINGtoPROC_READYviaproc_set_ready(). - Return the count of processes woken.
FUTEX_REQUEUE (3)
Moves waiters from uaddr to uaddr2:
- Wake up to
valwaiters onuaddr. - Requeue up to the second argument (passed in the timeout slot) waiters from
uaddrtouaddr2by updating theiruaddrfield. - Cross-jail checks apply: only processes in the same jail as the caller are affected.
FUTEX_CMP_REQUEUE (4)
Same as FUTEX_REQUEUE, but first verifies that *uaddr == val3. Returns EAGAIN if the comparison fails.
Data Structure
Futex state is stored in the global g_futex_tab array with FUTEX_MAX_WAITERS (PROC_MAX) entries. Each entry contains:
uaddr- The userspace address being waited onproc- Pointer to the waiting process (NULL if the slot is free)
The table is protected by g_futex_lock, a spinlock acquired on all read and write operations. Waiter registration and wakeup use __sync_bool_compare_and_swap for atomic state transitions.
CLONE_CHILD_CLEARTID Integration
When a thread created with CLONE_CHILD_CLEARTID (flag 0x00200000) exits:
- The kernel writes zero to the
cleartid_addrstored in the thread’s process structure. - The kernel calls
cleartid_wake(cleartid_addr). cleartid_wakescansg_futex_tabfor all entries whoseuaddrmatchescleartid_addr.- Each matching process is transitioned from
PROC_WAITINGtoPROC_READY.
This mechanism enables pthread library implementations to use CLONE_CHILD_CLEARTID with a futex address, ensuring that joiners blocked on futex(CLEARTID) are woken when the thread exits.
Last reviewed: 2026-07-22
Ptrace
This document describes the process tracing (ptrace) interface in the Kyronix kernel. It is the child of Syscalls.
Syscall Table
- 101
ptrace- Process tracing and debugging
Operations
The ptrace syscall supports the following request codes:
PTRACE_TRACEME (0)
Sets the calling process’s tracer_pid to its parent PID. The process becomes traceable by its parent. No arguments are used.
PTRACE_ATTACH (16)
Attaches the calling process as a tracer to a target process:
- Look up the target process by PID via
proc_find(). - Verify the target is not already being traced (
tracer_pid == 0). If already traced, returnEPERM. - Set
t->tracer_pid = self->pid. - Send
SIGSTOPto the target process. - Return 0.
PTRACE_PEEKTEXT / PTRACE_PEEKDATA (1, 2)
Reads 8 bytes from the target process’s address space at address addr:
- Switch to the target’s address space via
vmm_switch(). - Validate the user pointer with
uptr_ok(). - Copy 8 bytes from the target address to a kernel buffer.
- Switch back to the caller’s address space.
- Write the result to the
datapointer in the caller’s address space.
Both request codes behave identically.
PTRACE_POKETEXT / PTRACE_POKEDATA (4, 5)
Writes 8 bytes to the target process’s address space at address addr:
- Switch to the target’s address space via
vmm_switch(). - Validate the user pointer with
uptr_ok_w(). - Copy 8 bytes from the
dataargument to the target address. - Switch back to the caller’s address space.
Both request codes behave identically.
PTRACE_GETREGS (12)
Reads the full register state of the target process into a ptrace_user_regs structure:
- Call
ptrace_fill_regs()to populate the structure from the target’s current frame. - Copy the structure to the caller’s
datapointer.
PTRACE_SETREGS (13)
Writes a ptrace_user_regs structure to the target process’s register state:
- Copy the
ptrace_user_regsstructure from the caller’sdatapointer. - Call
ptrace_store_regs()to apply the register values to the target’s current frame.
PTRACE_CONT (7)
Resumes the target process’s execution without syscall tracing or single-stepping:
- Verify the target is in a stopped state (
ptrace_stopped != 0). Otherwise, returnESRCH. - If a signal number is provided in
data, inject it as a pending signal. - Clear
ptrace_stoppedandptrace_reported. - Transition the target from
PROC_WAITINGtoPROC_READY.
PTRACE_SYSCALL (24)
Resumes the target process’s execution with syscall tracing enabled:
- Same as
PTRACE_CONT, but setsptrace_syscall_trace = 1. - The syscall dispatcher checks
ptrace_syscall_traceon entry and exit, stopping the process withSIGTRAP|0x80at each syscall boundary.
PTRACE_SINGLESTEP (9)
Resumes the target process’s execution with single-stepping enabled:
- Same as
PTRACE_CONT, but setsptrace_step = 1. - The target executes one instruction before being stopped again.
PTRACE_KILL (8)
Injects SIGKILL into the target process:
- Set the
SIGKILLbit in the target’spending_sigs. - Clear
ptrace_stoppedandptrace_reported. - Transition the target from
PROC_WAITINGtoPROC_READY.
PTRACE_DETACH (17)
Detaches the tracer from the target process:
- Clear
tracer_pidandptrace_syscall_trace. - If the target is stopped, clear
ptrace_stoppedand transition it toPROC_READY.
PTRACE_SETOPTIONS (0x4200)
Accepted as a no-op. Returns 0.
Register State
The ptrace_user_regs structure contains the full x86_64 general-purpose register state:
r15, r14, r13, r12, rbp, rbx, r11, r10, r9, r8,
rax, rcx, rdx, rsi, rdi, orig_rax, rip, cs, eflags,
rsp, ss, fs_base, gs_base, ds, es, fs, gs
Segment registers are set to kernel constants: cs = GDT_USER_CODE_SEL, ss/ds/es/fs/gs = GDT_USER_DATA_SEL. The fs_base is read from the target process’s fs_base field.
Frame Kinds
The ptrace_frame_kind field determines how register values are extracted and stored:
- Frame kind 1 (
syscall_frame_t) - Syscall entry frame.RIPis derived fromrcx(the syscall return address).RFLAGSis derived fromr11. This frame is used when the process is stopped at a syscall entry/exit viaSIGTRAP|0x80. - Frame kind 2 (
cpu_state_t) - Full interrupt frame.RIPandRFLAGSare read directly from the interrupt frame. This frame is used when the process is stopped via#BP(breakpoint) or#DB(debug) exceptions.
Permission Model
Only the tracer process (identified by t->tracer_pid == self->pid) may operate on a tracee. All operations except PTRACE_TRACEME and PTRACE_ATTACH verify the caller is the tracer. If the caller is not the tracer, the syscall returns ESRCH.
Exception Integration
The kernel’s Interrupt Descriptor Table (IDT) checks tracer_pid on #BP (vector 3) and #DB (vector 1) exceptions:
- On
#BP, the instruction pointer is decremented by 1 (past theint3opcode). - The process’s
ptrace_orig_raxis saved. proc_ptrace_stop()is called with frame kind 2, deliveringSIGTRAPto stop the process.
Syscall Dispatcher Integration
The syscall dispatcher checks ptrace_syscall_trace on every syscall entry and exit:
- On entry, if
ptrace_syscall_traceis set and the syscall number is not 101 (ptraceitself), the process is stopped withSIGTRAP|0x80and frame kind 1. - On exit, after storing the return value, the process is stopped again with
SIGTRAP|0x80and frame kind 1. - The
ptrace_in_syscallflag is set on entry and cleared on exit to distinguish entry stops from exit stops.
Last reviewed: 2026-07-22
Implementation Notes
This document provides implementation notes for the Kyronix kernel subsystems. It is the root of the Implementation Notes section.
The Implementation Notes section covers detailed internal implementation details for the kernel and drivers, including initialization sequences, scheduling internals, Interrupt Request (IRQ) handling, memory management algorithms, and Peripheral Component Interconnect (PCI) enumeration.
Sections
Last reviewed: 2026-07-22
Kernel Implementation Notes
This document provides implementation notes for the Kyronix kernel core subsystems. It is the child of Implementation Notes.
The kernel implementation notes detail the internal design and algorithmic choices for initialization, scheduling, interrupt handling, and memory management within the Kyronix kernel core.
Subsections
- Initialization — Kernel boot and initialization sequence
- Scheduling — Process and thread scheduling internals
- IRQ Handling — Interrupt request dispatch and handling
- Memory Management — Physical and virtual memory allocation algorithms
Last reviewed: 2026-07-22
Kernel Initialization
This document describes the detailed kernel initialization sequence in the Kyronix kernel. It is the child of Kernel Implementation Notes.
The kmain() function executes a nine-phase initialization sequence that brings up all kernel subsystems from early hardware detection through to the first userspace process execution.
Initialization Phases
-
Phase 1 — Early console and core tables:
serial_init,printfsetup, Global Descriptor Table (GDT) initialization (gdt_init), Interrupt Descriptor Table (IDT) initialization (idt_init), and keyboard initialization (kbd_init). -
Phase 2 — Boot protocol validation: Validate Limine boot protocol responses, compute
kernel_end_phys, and configure the bootstrap processor (BSP) Model-Specific Registers (MSRs) viag_cpu_local[0]. -
Phase 3 — Core memory and processor setup: Physical Memory Manager initialization (
pmm_init), framebuffer initialization (fb_init), Virtual Memory Manager initialization (vmm_init), Local APIC (Advanced Programmable Interrupt Controller) initialization (lapic_init), Symmetric Multi-Processing initialization (smp_init), and Supervisor Mode Execution Prevention (SMEP) enable. -
Phase 4 — Kernel services: Kernel heap initialization (
heap_init), system call initialization (syscall_init), process subsystem initialization (proc_init), jail initialization (jail_init), Virtual File System initialization (vfs_init), and root mount verification. -
Phase 5 — Hardware enumeration: PCI enumeration (
pci_enumerate), Advanced Configuration and Power Interface (ACPI) initialization (acpi_init), block device initialization (block_init), AHCI (Advanced Host Controller Interface) initialization (ahci_init), VirtIO network initialization (virtnet_init), and network stack initialization (net_init). -
Phase 6 — User interface devices: User Interface (UI) initialization (
uio_init), framebuffer device initialization (fbdev_init), input subsystem initialization (input_init), virtual terminal initialization (vt_init), Programmable Interval Timer (PIT) initialization (pit_init), and LAPIC timer calibration (lapic_calibrate_timer). -
Phase 7 — Application processor boot and entropy: BSP idle process creation, Application Processor (AP) boot (
smp_boot_aps), and Cryptographically Secure Pseudo-Random Number Generator (CSPRNG) initialization with RDRAND instruction and Timestamp Counter (TSC) fallback. -
Phase 8 — Interrupts and self-tests:
sti(Set Interrupt Flag), PS/2 mouse initialization (ps2mouse_init), and self-tests for the PMM, VMM, and heap subsystems. -
Phase 9 — Filesystem and init: ext2 filesystem initialization (
ext2_init), root mount, initial ramdisk (initrd) load, Filesystem Table (fstab) mount, and execution of/init.
Self-Tests
The following self-tests execute during Phase 8 to verify core subsystem integrity.
PMM Self-Test
- Allocate four physical pages.
- Map each page to a virtual address via
phys_to_virt. - Write the constant
0xDEADBEEFCAFEBABEto each page. - Verify that each page contains a unique allocation (distinct physical addresses).
VMM Self-Test
- Map a single page at virtual address
0xffff900000001000. - Write the constant
0xC0FFEE00DEADC0DEto the mapped page. - Read back and verify the written value.
- Unmap the page.
Heap Self-Test
- Allocate buffers of 64, 128, and 256 bytes.
- Fill the 64-byte buffer with
0xAA, the 128-byte buffer with0xBB, and the 256-byte buffer with0xCC. - Verify each buffer contains the expected fill pattern.
- Test
kreallocby reallocating each buffer and verifying content preservation.
Last reviewed: 2026-07-22
Scheduling
This document describes the scheduling implementation in the Kyronix kernel. It is the child of Kernel Implementation Notes.
The Kyronix kernel uses a per-CPU round-robin scheduler with lock-free bitmap-based ready-queue selection and hardware-assisted FPU context switching.
Scheduling Algorithm
Ready Queue and Bitmap
- Each CPU maintains a 64-bit ready bitmask (
g_ready_mask) representing the priority levels with at least one runnable thread. - Next-thread selection uses
__builtin_ctzll(Count Trailing Zeros, Long Long) ong_ready_maskto locate the lowest-numbered set bit in O(1) time. - Each priority level maps to a linked list of threads in the READY state.
Lock-Free Claim
sched_claim_nexttransitions a thread from READY to RUNNING using a Compare-And-Swap (CAS) operation, eliminating lock contention on the common path.- The CAS atomically marks the thread as RUNNING before any scheduler state is visible to other processors.
Round-Robin Fairness
- Per-CPU arrays (
g_last_scheduled) track the last scheduled thread per priority level to enforce round-robin fairness across threads of equal priority.
Context Switch
The context switch performs the following operations in sequence:
- Save callee-saved general-purpose registers from the outgoing thread.
- Execute
fxsave64to save the floating-point / SIMD state of the outgoing thread. - Restore callee-saved general-purpose registers for the incoming thread.
- Execute
fxrstor64to restore the floating-point / SIMD state of the incoming thread. - Write the FS base MSR (Model-Specific Register) for the incoming thread’s Thread-Local Storage (TLS).
- Load CR3 (Control Register 3) to switch to the incoming thread’s address space.
Preemption
- Preemption is triggered on Programmable Interval Timer (PIT) IRQ 0 and Local APIC timer interrupt (vector 224).
- The timer interrupt handler invokes the scheduler to perform a context switch if a higher-priority or equal-priority thread is runnable.
Application Processor Idle Loop
Application Processors (APs) execute the following idle loop:
- Call
sched_claim_nextto attempt to acquire a runnable thread. - If a thread is claimed, call
sched_switchto context-switch into it. - If no thread is available, execute
hlt(Halt) until the next interrupt.
Process States and Transitions
Threads transition through the following states:
UNUSED -> READY -> RUNNING -> READY
|-> WAITING
|-> ZOMBIE -> DYING
|-> STOPPED
UNUSED— Thread slot is unallocated.READY— Thread is runnable and waiting for CPU time.RUNNING— Thread is executing on a CPU.WAITING— Thread is blocked on an event (e.g., I/O, sleep).ZOMBIE— Thread has exited but its resources have not yet been reclaimed.DYING— Thread is in the final stage of resource teardown.STOPPED— Thread has been stopped (e.g., via signal).
Deferred Reaping
proc_defer_thread_reapstores a zombie thread in a pending list for deferred cleanup.- The next call to
proc_reap_pendingprocesses the deferred list and reclaims thread resources. - Deferred reaping avoids performing memory deallocation in the interrupt context where the thread transitions to ZOMBIE.
Last reviewed: 2026-07-22
IRQ Handling
This document describes the interrupt handling implementation in the Kyronix kernel. It is the child of Kernel Implementation Notes.
The Kyronix kernel dispatches interrupts through a common assembly entry point (isr_common) that supports PIC IRQs, CPU exceptions, LAPIC interrupts, and system calls.
PIC Remapping
The Programmable Interrupt Controller (PIC) is remapped to interrupt vectors 32–47 to avoid collision with CPU exception vectors 0–31.
ISR Common Entry Point
The isr_common assembly stub performs the following steps:
- If the interrupt originated from ring 3 (user mode), execute
swapgsto switch to the kernel GS base. - Push all General-Purpose Registers (GPRs) onto the kernel stack.
- Call the C dispatch function
isr_dispatch. - Pop all GPRs from the kernel stack.
- If returning to ring 3, execute
swapgsto restore the user GS base. - Execute
iretqto return from the interrupt.
Interrupt Dispatch
isr_dispatch handles the following interrupt sources:
CPU Exceptions (Vectors 0–31)
- User-mode exception: The exception is delivered as a signal to the faulting process.
- Kernel-mode exception: The kernel invokes a panic handler with a stack backtrace.
Page Fault (Vector 14)
Page faults are handled with demand paging for the following cases:
- User stack growth: Faults within
USER_STACK_GROW_BASEtoUSER_STACK_TOPtrigger automatic stack expansion. - VMA (Virtual Memory Area) regions: Faults within a mapped VMA region trigger demand paging via
vmm_user_range_fault_in.
PIC IRQs (Vectors 32–47)
PIC IRQs are forwarded from the PIC to the corresponding vector offset.
System Call (Vector 0x80)
System calls are dispatched via the syscall instruction (vector 128).
LAPIC Timer (Vector 224)
The LAPIC (Local Advanced Programmable Interrupt Controller) timer interrupt is handled with the same preemption logic as PIC IRQ 0.
LAPIC Spurious (Vector 255)
Spurious LAPIC interrupts are acknowledged without further processing.
Timer Tick (PIC IRQ 0)
Each PIC IRQ 0 tick performs the following operations:
- Increment the global tick counter (
g_ticks). - Update the cursor blink state.
- Reap zombie threads.
- Poll the network stack.
- Process the timer mask for sleep/wake operations.
- Invoke the scheduler for preemption.
Double Fault
Double faults (vector 8) use Interrupt Stack Table (IST) stack 1, backed by a dedicated 16 KiB stack, to ensure a usable stack is available when the primary stack is corrupted.
Non-Maskable Interrupt (NMI)
Non-Maskable Interrupts (NMIs, vector 2) use IST stack 2, backed by a dedicated 16 KiB stack, to handle hardware-critical conditions independently of normal interrupt processing.
Kernel Backtrace
The kernel backtrace routine scans the kernel stack for return addresses within the kernel text region defined by the bounds:
[0xffffffff80000000, 0xffffffff80040000)
Any pointer found within this range is reported as a valid kernel return address.
Last reviewed: 2026-07-22
Memory Management
This document describes the memory management implementation details in the Kyronix kernel. It is the child of Kernel Implementation Notes.
The Kyronix kernel implements a layered memory management architecture comprising a Physical Memory Manager (PMM), Virtual Memory Manager (VMM), kernel heap, Shared Memory (SHM) subsystem, and a runtime memory leak detector.
Physical Memory Manager (PMM)
Initialization
- Parse the Limine boot protocol memory map to identify usable physical memory regions.
- Find the highest usable physical address across all regions.
- Compute the total number of physical frames from the highest usable address.
- Allocate LL-Free metadata from the largest contiguous usable region.
LL-Free Three-Tier Architecture
The LL-Free allocator organizes physical frames into a three-tier hierarchy:
- Frame: A single 4 KiB physical page.
- Child: A group of 512 frames, totaling 2 MiB.
- Tree: A group of 8 children, totaling 4096 frames (16 MiB).
CPU-Local Reservations
Each CPU reserves one tree from the LL-Free allocator for lock-free allocation, eliminating cross-CPU contention on the fast path.
Zero-Page Pool
A pool of 32 pre-allocated zeroed physical pages provides fast allocation for pmm_alloc_zeroed without requiring a memset on each allocation.
Virtual Memory Manager (VMM)
Page Table Management
The VMM performs a 4-level page table walk (PML4 → PDPT → PD → PT) to resolve and manipulate virtual-to-physical address mappings.
Demand Paging
Unmapped pages within valid Virtual Memory Area (VMA) regions trigger demand paging via vmm_user_range_fault_in, which allocates physical frames and installs page table entries on demand.
Virtual Memory Areas (VMA)
- VMAs are stored in a flat array of 2048 entries per process.
- Lookups use a linear scan of the array.
split_for_holesplits an existing VMA into two smaller VMAs when a region must be removed from the middle of a mapping.
Kernel Heap
- The heap uses a first-fit allocator with a doubly-linked free list.
- Coalescing is performed in both the forward and backward directions on free.
- All allocations are aligned to 16-byte boundaries.
- The heap grows in 64 KiB increments from the initial allocation.
Shared Memory (SHM)
- Shared Memory follows the System V Inter-Process Communication (IPC) model.
- A maximum of 64 SHM segments are supported.
- Jail isolation is enforced via the
JAILF_IPCflag, which prevents processes within a jail from accessing SHM segments outside the jail.
Memory Leak Detector (kmemleak)
The kmemleak subsystem implements a mark-and-sweep leak detector that scans the following memory regions for allocated pointers:
.datasection — Initialized global and static variables..bsssection — Uninitialized global and static variables.- Process table — All live process structures.
- Heap — All live heap allocations.
- Page tables — All mapped page table entries.
Last reviewed: 2026-07-22
Driver Implementation Notes
This document provides implementation notes for the Kyronix kernel drivers. It is the child of Implementation Notes.
The driver implementation notes cover internal details for hardware discovery and device initialization, including bus enumeration and device driver probe sequences.
Subsections
- PCI Enumeration — Peripheral Component Interconnect (PCI) bus enumeration
Last reviewed: 2026-07-22
PCI Enumeration
This document describes the PCI bus enumeration implementation in the Kyronix kernel. It is the child of Driver Implementation Notes.
The Kyronix kernel enumerates the PCI bus using Port I/O-based configuration space access to discover and catalog all connected hardware devices.
Configuration Space Access
PCI configuration space is accessed through two standard I/O ports:
- 0xCF8 (Address register): Receives the configuration address, which encodes the bus number, device number, function number, and register offset.
- 0xCFC (Data register): Provides read/write access to the configuration data at the specified address.
Enumeration Procedure
- Iterate over all 256 buses.
- For each bus, iterate over all 32 devices.
- For each device, iterate over all 8 functions.
- Read the Vendor ID register at offset 0x00.
- If the Vendor ID returns
0xFFFF, the device or function is absent; skip to the next function. - Read the Class Code, Subclass, Programming Interface (prog_if), Base Address Register (BAR) registers, and Header Type from the configuration space.
- Store the device information in the global device table.
Usage
The global device table populated by PCI enumeration is consumed by the following drivers to discover and initialize their respective hardware:
- AHCI (Advanced Host Controller Interface) driver
- VirtIO driver
- Other PCI device drivers that query the device table during their probe sequences
Last reviewed: 2026-07-22
Reference
This document provides reference material for the Kyronix kernel. It is the root of the Reference section.
Subsections
Last reviewed: 2026-07-22
Syscalls Reference
This document provides a complete reference of all syscalls implemented in the Kyronix kernel. It is the child of Reference.
Overview
The kernel implements approximately 140 Linux x86_64 ABI-compatible syscalls plus custom jail syscalls.
Syscall Table
| # | Name | # | Name |
|---|---|---|---|
| 0 | read | 1 | write |
| 2 | open | 3 | close |
| 4 | stat | 5 | fstat |
| 6 | lstat | 7 | poll |
| 8 | lseek | 9 | mmap |
| 10 | mprotect | 11 | munmap |
| 12 | brk | 13 | rt_sigaction |
| 14 | rt_sigprocmask | 15 | rt_sigreturn |
| 16 | ioctl | 17 | pread64 |
| 18 | pwrite64 | 19 | readv |
| 20 | writev | 21 | access |
| 22 | pipe | 23 | select |
| 25 | mremap | 29 | shmget |
| 30 | shmat | 31 | shmctl |
| 32 | dup | 33 | dup2 |
| 34 | pause | 35 | nanosleep |
| 36 | getitimer | 37 | alarm |
| 38 | setitimer | 39 | getpid |
| 40 | sendfile | 41 | socket |
| 42 | connect | 43 | accept |
| 44 | sendto | 45 | recvfrom |
| 46 | sendmsg | 47 | recvmsg |
| 48 | shutdown | 49 | bind |
| 50 | listen | 51 | getsockname |
| 52 | getpeername | 53 | socketpair |
| 54 | setsockopt | 55 | getsockopt |
| 56 | clone | 57 | fork |
| 58 | vfork | 59 | execve |
| 60 | exit | 61 | wait4 |
| 62 | kill | 63 | uname |
| 67 | shmdt | 72 | fcntl |
| 76 | truncate | 77 | ftruncate |
| 78 | getdents64 | 79 | getcwd |
| 80 | chdir | 82 | rename |
| 83 | mkdir | 84 | rmdir |
| 86 | link | 87 | unlink |
| 88 | symlink | 89 | readlink |
| 90 | chmod | 95 | umask |
| 96 | gettimeofday | 97 | getrlimit |
| 101 | ptrace | 102 | getuid |
| 104 | getgid | 105 | setuid |
| 106 | setgid | 107 | geteuid |
| 108 | getegid | 109 | setpgid |
| 112 | setsid | 117 | setresuid |
| 119 | setresgid | 137 | statfs |
| 158 | arch_prctl | 169 | reboot |
| 186 | gettid | 201 | time |
| 202 | futex | 213 | epoll_create |
| 218 | set_tid_address | 228 | clock_gettime |
| 229 | clock_getres | 230 | clock_nanosleep |
| 231 | exit_group | 232 | epoll_wait |
| 233 | epoll_ctl | 234 | tgkill |
| 257 | openat | 262 | newfstatat |
| 263 | unlinkat | 270 | pselect6 |
| 271 | ppoll | 280 | openat2 |
| 283 | timerfd_create | 284 | eventfd |
| 288 | accept4 | 290 | eventfd2 |
| 291 | epoll_create1 | 292 | dup3 |
| 293 | pipe2 | 295 | preadv |
| 296 | pwritev | 302 | prlimit64 |
| 318 | getrandom | 319 | memfd_create |
| 326 | copy_file_range | 332 | statx |
| 334 | close_range |
Custom Jail Syscalls
| # | Name |
|---|---|
| 500 | jail_create |
| 501 | jail_attach |
| 502 | jail_get |
| 503 | jail_list |
| 504 | jail_remove |
| 505 | jail_self |
| 506 | jail_set_auto |
Last reviewed: 2026-07-22
Protocols
This document describes the protocols supported by the Kyronix kernel. It is the child of Reference.
Supported Protocols
- Limine v3 boot protocol: memory map, HHDM (Higher Half Direct Map), framebuffer, modules, RSDP (Root System Description Pointer), SMP (Symmetric Multi-Processing), kernel address.
- PCI configuration: standard I/O configuration space (ports 0xCF8/0xCFC).
- ACPI (Advanced Configuration and Power Interface): RSDP, RSDT/XSDT, MADT (Multiple APIC Description Table), FADT (Fixed ACPI Description Table).
- AHCI (Advanced Host Controller Interface): SATA (Serial ATA) host controller interface.
- VirtIO 1.0: paravirtualized network device.
- lwIP TCP/IP (lightweight IP): IPv4 (Internet Protocol version 4), TCP (Transmission Control Protocol), UDP (User Datagram Protocol), ICMP (Internet Control Message Protocol), ARP (Address Resolution Protocol).
- PS/2: keyboard and mouse input.
- Syscall: AMD64 SYSCALL/SYSRET mechanism.
Last reviewed: 2026-07-22
API
This document describes the internal kernel API surface of the Kyronix kernel. It is the child of Reference.
Memory
pmm_alloc- allocate a physical pagepmm_alloc_zeroed- allocate a zeroed physical pagepmm_alloc_contiguous- allocate contiguous physical pagespmm_free- free a physical pagevmm_map- map a virtual addressvmm_unmap- unmap a virtual addressvmm_protect- set protection flags on a mappingvmm_space_new- create a new virtual address spacevmm_space_free- free a virtual address spacevmm_switch- switch to a virtual address spacevmm_fork_user- fork user address spacekmalloc- kernel memory allocatekcalloc- kernel memory callockrealloc- kernel memory reallocatekfree- kernel memory free
Process
proc_alloc- allocate a processproc_ref- increment process reference countproc_unref- decrement process reference countproc_find- find a process by PID (Process ID)proc_do_exit- terminate a processsched_switch- context switch to another processsched_claim_next- claim the next runnable process
Filesystem
vfs_init- initialize the Virtual File System (VFS)vfs_lookup- look up a path in the VFSvfs_mount- mount a filesystemvfs_node_unref_internal- unreference an internal VFS nodevfs_sync_all- synchronize all mounted filesystems
Signals
proc_send_signal- send a signal to a processsignal_check- check for pending signals
Jail
jail_init- initialize the jail subsystemjail_create- create a new jailjail_enter- enter a jailjail_remove- remove a jailjail_can_see- check if a process can see another processjail_host_priv- check if a process has host privileges
Crypto
chacha20_rng_init- initialize the ChaCha20 random number generatorchacha20_rng_bytes- generate random bytes
Last reviewed: 2026-07-22