Files
Operator-system/README.md
2026-02-26 21:08:06 +00:00

282 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Simple UEFI Operating System
A minimal bootable UEFI operating system written in C that demonstrates UEFI boot loading, memory management, interrupt handling, and cooperative multitasking.
## Features
- **UEFI Boot**: Boots directly on UEFI firmware via a PE32+ loader
- **ELF64 Kernel Loader**: Reads and maps a standalone kernel from the EFI partition
- **Console I/O**: Interactive keyboard input and screen output
- **Interrupt Handling**: IDT setup with CPU exception handlers (vectors 031) and hardware IRQ dispatch
- **Memory Management**: Bitmap-based physical memory manager (PMM), 4-level x86-64 paging, and a first-fit heap allocator with block coalescing
- **Cooperative Multitasking**: Process control blocks, assembly context switching, and a round-robin task scheduler
- **Interactive Shell**: Command registry with `help`, `man`, built-in commands, and test utilities
## Requirements
- GCC compiler
- GNU-EFI library
- QEMU with OVMF firmware
- Make
## Installation
### On Debian/Ubuntu:
```bash
make install-deps
```
Or manually:
```bash
sudo apt-get install gnu-efi qemu-system-x86 ovmf gcc binutils make xorriso mtools
```
### On Arch Linux:
```bash
sudo pacman -S gnu-efi qemu-system-x86 edk2-ovmf gcc binutils make xorriso mtools
```
### On Fedora/RHEL:
```bash
sudo dnf install gnu-efi qemu-system-x86 edk2-ovmf gcc binutils make xorriso mtools
```
## Building
Build the UEFI loader and kernel:
```bash
make
```
This creates `build/EFI/BOOT/BOOTX64.EFI` (UEFI loader) and `build/kernel.elf` (kernel binary).
## Running
Test with QEMU (no graphics mode):
```bash
make run
```
To build and run from an ISO image:
```bash
make runiso
```
The loader expects `kernel.elf` at the root of the EFI partition (next to the `EFI/` directory).
### QEMU Controls:
- **Exit QEMU**: Press `Ctrl+A`, then `X`
- **Shutdown OS**: Type `shutdown` in the OS
## Commands
Once the OS boots, you can use these commands:
| Command | Description |
|---------|-------------|
| `help` | Display all available commands |
| `man <command>` | Display detailed help for a command |
| `shutdown` | Shutdown the system |
| `clear` | Clear the screen |
| `about` | Display system information |
| `mem` | Display memory statistics (PMM, heap, paging) |
| `ps` | List all active tasks with PID, state, and name |
| `spawn [name]` | Create a demo background task |
| `memtest` | Run memory allocation/deallocation tests |
| `tasktest` | Spawn multiple concurrent tasks to test the scheduler |
### Example Session
```
-> help
-> about
-> mem
-> memtest
-> spawn worker1
-> spawn worker2
-> ps
-> tasktest
-> shutdown
```
### Testing Memory Management
The `memtest` command runs through four test phases:
1. **Heap allocation** — allocates 8 blocks of increasing size (16 to 4096 bytes) via `kmalloc()`
2. **Heap free** — frees all allocated blocks via `kfree()` and verifies coalescing
3. **PMM single page** — allocates and frees a single 4 KB page
4. **PMM multi-page** — allocates and frees 4 contiguous pages
Each phase reports addresses, success/failure, and usage statistics.
### Testing Task Scheduling
The `tasktest` command:
1. Spawns 3 worker tasks (`worker-A`, `worker-B`, `worker-C`)
2. Each worker prints 3 progress steps, yielding between each
3. The shell yields to let workers run in round-robin order
4. Displays the task list after completion
You can also manually test with `spawn` and `ps`:
```
-> spawn myTask
Created task 'myTask' (PID 1)
-> ps
PID STATE SWITCHES NAME
--- ---------- -------- ----
0 RUNNING 5 kernel
1 READY 0 myTask
Active tasks: 2 / 32
```
Background tasks run whenever the shell yields (which happens automatically while waiting for keyboard input).
## Project Structure
```
.
├── main.c # UEFI loader (reads and loads kernel ELF)
├── kernel.c # Kernel entry point and interactive shell loop
├── kernel.ld # Kernel linker script (base address 0x100000)
├── boot_info.h # Shared boot interface (BootInfo struct)
├── commands.c # Command registry and handler implementations
├── commands.h # Command interface definitions
├── string_utils.c # String utility functions (trim, compare, etc.)
├── string_utils.h # String utility declarations
├── idt.c # IDT setup, exception handlers, PIC EOI
├── idt.h # IDT types (ISRFrame) and init declaration
├── isr.S # ISR stub table (vectors 0255) with common handler
├── memory.c # PMM (bitmap), paging (4-level), heap (first-fit)
├── memory.h # Memory subsystem declarations and constants
├── task.c # Task manager: PCB pool, scheduler, yield/exit
├── task.h # Task types (Task, TaskState) and API
├── context_switch.S # Assembly cooperative context switch (x86-64)
├── Makefile # Build configuration
└── README.md # This file
```
## Architecture
### Boot Flow
1. **UEFI Entry**`efi_main()` in `main.c` is called by firmware
2. **GNU-EFI Init** — library initialized with the system table
3. **Kernel Load**`kernel.elf` is read from the EFI partition, ELF64 PT_LOAD segments are mapped into memory
4. **BootInfo Setup** — function pointers for console I/O, shutdown, and page allocation are packaged into a `BootInfo` struct
5. **Kernel Entry**`kmain()` is called with the `BootInfo` pointer
### Kernel Initialization
1. **IDT** — CPU exception vectors (031) are installed; firmware IRQ handlers are preserved
2. **Memory** — PMM allocates a 16 MB page pool via UEFI, bitmap tracks free/used pages; paging reads CR3; heap carves 256 KB from the PMM
3. **Tasks** — scheduler initializes; the running kernel becomes task 0
4. **Shell** — interactive loop with non-blocking input and cooperative yielding
### Memory Management
| Component | Description |
|-----------|-------------|
| **PMM** | Bitmap-based page-frame allocator managing a 16 MB pool (4096 pages); supports single and contiguous multi-page allocation |
| **Paging** | Walks/creates 4-level x86-64 page tables (PML4 → PDPT → PD → PT); supports map, unmap, and virtual-to-physical translation |
| **Heap** | First-fit free-list allocator with block splitting and bidirectional coalescing; 16-byte alignment; magic number corruption detection |
### Task System
| Component | Description |
|-----------|-------------|
| **PCB** | `Task` struct with PID, state, name, saved RSP, stack, entry function, and scheduling metadata |
| **States** | `FREE``READY``RUNNING``TERMINATED``FREE` |
| **Scheduler** | Round-robin selection among `READY` tasks via `task_yield()` |
| **Context Switch** | Assembly routine saves/restores callee-saved registers (`rbp`, `rbx`, `r12``r15`) and `RFLAGS`, swaps RSP |
| **Stack** | Each task gets 32 KB (8 pages) allocated from PMM; freed on `task_exit()` |
| **Limits** | Up to 32 concurrent tasks; cooperative (voluntary yield) only |
### Command System
- Commands are registered in a static array with metadata (name, description, usage, handler function)
- `execute_command()` parses input, splits command and arguments, and dispatches to the matching handler
- `man` provides detailed help by looking up command metadata
- New commands are added by writing a handler and appending to the `commands[]` array
## Building for Real Hardware
To create a bootable USB drive:
1. Build the project: `make`
2. Format a USB drive with GPT and create an EFI partition (FAT32)
3. Mount the EFI partition
4. Copy `build/EFI/BOOT/BOOTX64.EFI` to `/EFI/BOOT/` on the USB drive
5. Copy `build/kernel.elf` to the root of the EFI partition
6. Boot from the USB drive in UEFI mode
**Warning**: Always backup your data before creating bootable media!
## Cleaning
Remove build artifacts:
```bash
make clean
```
## Troubleshooting
### GNU-EFI headers not found
Make sure GNU-EFI is installed. The headers are typically in `/usr/include/efi`.
If installed in a different location, update the `EFI_INC` variable in the Makefile.
### OVMF firmware not found
OVMF files might be in different locations depending on your distribution:
- `/usr/share/OVMF/`
- `/usr/share/qemu/`
- `/usr/share/edk2-ovmf/`
Update the paths in the Makefile if needed.
### QEMU crashes or fails to start
Ensure you have QEMU with x86_64 support and OVMF firmware installed.
## Technical Details
- **Architecture**: x86_64
- **Firmware Interface**: UEFI 2.x
- **Development Library**: GNU-EFI
- **Loader Format**: PE32+ (Portable Executable for EFI)
- **Kernel Format**: ELF64
- **Boot Protocol**: UEFI Boot Services
- **Memory Model**: Identity-mapped (UEFI), 4-level paging (kernel)
- **Scheduling**: Cooperative round-robin multitasking
## License
This is a minimal educational example. Feel free to use and modify as needed.
## Adding New Commands
1. Open `commands.c`
2. Add a forward declaration: `static void cmd_yourcommand(BootInfo *Boot, CHAR16 *Args);`
3. Add an entry to the `commands[]` array (before the sentinel)
4. Implement the handler function
5. Rebuild with `make`
## Resources
- [UEFI Specification](https://uefi.org/specifications)
- [GNU-EFI Documentation](https://sourceforge.net/projects/gnu-efi/)
- [OSDev Wiki](https://wiki.osdev.org/)