Overview
Next step in our kernel — execution!
KFS_5 is all about processes. A process is the actual execution of the instructions
in a program. This means we’re also going to be dealing with threads, scheduling, and
multitasking — right now we only have one thread of execution with no concurrency at all.
In computing, a process is an instance of a computer program being executed. It contains the program code and its current activity. Several processes may be associated with the same program — opening multiple instances of the same application means multiple processes running simultaneously.
Multitasking is how multiple processes share a single CPU. The CPU can only execute one task at a time, but by switching between tasks rapidly — on I/O operations, voluntary yields, or hardware interrupts — it creates the illusion of parallelism.
Processes have relationships and metadata we need to track:
- PID — unique integer to identify the process
- Parent/Children — process family tree
- Owner — which user owns this process
- Dedicated memory — each process gets its own stack (KFS_3 paging finally earning its keep)
- Signals — pending signal queue plus per-process handler table
- Sockets — inter-process communication
This is gonna be a big one. And it was.
Connection to KFS_4
A lot of what we built in KFS_4 directly feeds into this — it wasn’t busywork:
InterruptFramebecomes the process context save/restore structure for context switching. Every process has a heap-allocated frame that the scheduler saves into on every timer tick.- The signal system gains per-process handler tables — separate from the global
SIGNAL_TABLE, individual processes can now register their own handlers for specific signals. - The
get_line()deadlock from KFS_4 is now architecturally resolved. It deadlocked because it was called from interrupt context — now the shell runs as its own execution context andget_line()works correctly. - The syscall stubs (
sys_write,sys_read,sys_exit) get real process-aware implementations when KFS_7 arrives. The groundwork is in place.
What We Built
The Process Structure
A Process struct that tracks everything the kernel needs to know — pid, status,
parent/child/sibling tree, stack pointer and size, heap region, signal queue,
per-process signal handlers, owner id, and the all-important state pointer to
the saved InterruptFrame. The child/sibling pointers form a proper Unix process
family tree without any extra heap allocation per relationship.
Key Functions
All the mandatory syscall helpers: fork (full process copy including stack contents
via memcpy), exit (frees stack, marks Zombie, sends SIGCHLD to parent), kill
(queues signal or calls exit for SIGKILL), getuid (returns owner id), signal
(registers per-process handler), and wait (spins until a child becomes Zombie).
exec_fn loads a function as a process — creates the process, allocates a stack via
vmalloc_user, builds a dummy_frame pointing to the function, and registers it
in the process table. Demonstrated with sys exec and sys proc in the shell.
Sockets
Inter-process communication via a socket table. socket_create, socket_write,
socket_read, socket_close — mirrors Unix socket semantics so the KFS_7 syscall
layer can plug straight in. Buffers backed by vmalloc, socket metadata by kmalloc.
The Scheduler
Timer-driven round-robin scheduler. On every tick: save current process state via
rust_timer_handler, pick the next valid process via get_next_frame, switch ESP
to its saved frame, popa and iretd into it. Process 0 (kernel idle) is excluded
from scheduling and runs directly in the main loop.
The scheduler infrastructure is complete. It is currently disabled because of a
fundamental ring 0 limitation — iretd at ring 0 cannot switch stacks, so processes
don’t run on their allocated stacks and corruption follows. The proper fix is ring 3
processes, which is KFS_7’s job.
The TSS
The Task State Segment is implemented and loaded. esp0 points to the kernel stack
top, ss0 = 0x10. The GDT entry at index 5 is properly filled and ltr 0x28 is
called at boot. When KFS_7 flips the switch to ring 3, the TSS is already doing its
job — telling the CPU which kernel stack to switch to on every ring 3 → ring 0
transition.
Ring 3 Groundwork
While true ring 3 execution is KFS_7, the foundations are all in place:
user GDT segments have been there since KFS_2, vmalloc_user maps pages with
PAGE_USER set, InterruptFrame has esp_user and ss_user fields for the
extended ring 3 frame layout, and dummy_frame knows how to configure a ring 3
entry. Nothing structural needs to change in KFS_7 — it’s a configuration flip.
Mandatory
Data
A full process structure containing:
- PID
- Status (Running, Zombie, Thread)
- Pointers to parent and children
- Stack and heap with size tracking
- Current signal queue
- Per-process signal handler table
- Owner ID
- Saved CPU state (
*mut InterruptFrame)
And functions:
create_process— allocate and register a process- Queue a signal to a process, delivered on the next CPU tick
- Socket communication helpers between processes
- Memory functions (
vmalloc_userfor process stacks) fork— copy an entire process
Plus syscall helpers: wait, exit, getuid, signal, kill
Memory
In KFS_3 we implemented paging — now we actually use it. Each process gets a
vmalloc_user’d stack on creation, mapped with PAGE_USER flags so it’s accessible
from ring 3 when that arrives. The stack and stack_size fields on the process
struct track the allocation so fork can copy it correctly.
Execution
The kernel handles multitasking via a round-robin timer-based scheduler. The
infrastructure is complete — timer saves state, get_next_frame picks the next
process, iretd jumps into it.
Testing
exec_fn loads a function as a process and registers it in the process table.
Demonstrated in the shell:
> sys exec
Creating test process...
test_process addr: 0x00105900
Process created!
> sys proc
=== Process Table ===
PID 0: state=0x00261060 stack=0x00000000
PID 1: state=0x00261110 stack=0x00900000
Process 0 is the kernel idle process. Process 1 is the test process with its own
vmalloc’d stack at 0x00900000. Shell remains fully responsive throughout.
Bonus
Once the mandatory is done, the fun stuff:
mmap— let a process query and manage its virtual memory- Link IDT and processes to follow future syscall signals
- Create
BSSanddatasectors in the process structure
These are deferred — the mandatory is solid and the bonus items depend on having ring 3 processes working first anyway.