Task scheduler
This commit is contained in:
201
README.md
201
README.md
@@ -1,14 +1,16 @@
|
||||
# Simple UEFI Operating System
|
||||
|
||||
A minimal bootable UEFI operating system written in C that demonstrates basic UEFI functionality.
|
||||
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
|
||||
- **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
|
||||
- **System Information**: Displays firmware details
|
||||
- **Kernel Loader**: Loads an ELF64 kernel from the EFI partition
|
||||
- **Simple Commands**: Minimal interactive command interface
|
||||
- **Interrupt Handling**: IDT setup with CPU exception handlers (vectors 0–31) 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
|
||||
|
||||
@@ -28,30 +30,30 @@ make install-deps
|
||||
Or manually:
|
||||
|
||||
```bash
|
||||
sudo apt-get install gnu-efi qemu-system-x86 ovmf gcc binutils make
|
||||
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
|
||||
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
|
||||
sudo dnf install gnu-efi qemu-system-x86 edk2-ovmf gcc binutils make xorriso mtools
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
Build the UEFI application and kernel:
|
||||
Build the UEFI loader and kernel:
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
This will create `build/EFI/BOOT/BOOTX64.EFI` and `build/kernel.elf`.
|
||||
This creates `build/EFI/BOOT/BOOTX64.EFI` (UEFI loader) and `build/kernel.elf` (kernel binary).
|
||||
|
||||
## Running
|
||||
|
||||
@@ -61,63 +63,151 @@ Test with QEMU (no graphics mode):
|
||||
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 in the OS
|
||||
## Commands
|
||||
|
||||
Once the OS boots, you can use these commands:
|
||||
|
||||
- `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
|
||||
| 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
|
||||
|
||||
Example usage:
|
||||
```
|
||||
-> help
|
||||
-> man shutdown
|
||||
-> clear
|
||||
-> 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 main loop
|
||||
├── commands.c # Command registry and handlers
|
||||
├── commands.h # Command interface definitions
|
||||
├── string_utils.c # String utility functions
|
||||
├── string_utils.h # String utility declarations
|
||||
├── kernel.ld # Kernel linker script
|
||||
├── boot_info.h # Shared boot interface
|
||||
├── Makefile # Build configuration
|
||||
└── README.md # This file
|
||||
├── 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 0–255) 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
|
||||
```
|
||||
|
||||
## How It Works
|
||||
## Architecture
|
||||
|
||||
1. **UEFI Entry Point**: The `efi_main` function is the entry point called by UEFI firmware
|
||||
2. **Initialization**: GNU-EFI library is initialized with the system table
|
||||
3. **Console Setup**: Output is configured and screen is cleared
|
||||
4. **Kernel Load**: The loader reads `kernel.elf` and maps its loadable segments
|
||||
5. **Main Loop**: The kernel enters a loop waiting for keyboard input
|
||||
6. **Command Processing**: User commands are parsed and dispatched to registered handlers
|
||||
7. **Command Execution**: Each command is executed via its handler function
|
||||
8. **Shutdown**: UEFI runtime services are used to shutdown the system
|
||||
### Boot Flow
|
||||
|
||||
**Command System Architecture:**
|
||||
- Commands are registered in a static array with metadata (name, description, usage, handler)
|
||||
- The `execute_command()` function parses input, splits command and arguments, and dispatches to handlers
|
||||
- The `man` command provides detailed help by looking up command metadata
|
||||
- New commands can be easily added by implementing a handler and registering it
|
||||
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 (0–31) 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
|
||||
|
||||
@@ -166,30 +256,23 @@ Ensure you have QEMU with x86_64 support and OVMF firmware installed.
|
||||
- **Architecture**: x86_64
|
||||
- **Firmware Interface**: UEFI 2.x
|
||||
- **Development Library**: GNU-EFI
|
||||
- **Executable Format**: PE32+ (Portable Executable for 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.
|
||||
|
||||
## Further Development
|
||||
## Adding New Commands
|
||||
|
||||
The codebase is now modular and easy to extend:
|
||||
|
||||
**Adding New Commands:**
|
||||
1. Open `commands.c`
|
||||
2. Create a new handler function: `static void cmd_yourcommand(BootInfo *Boot, CHAR16 *Args)`
|
||||
3. Add your command to the `commands[]` array with name, description, usage, and handler
|
||||
4. Rebuild with `make`
|
||||
|
||||
**Other Ideas for expansion:**
|
||||
- File system support
|
||||
- Memory management
|
||||
- Graphics output
|
||||
- Network stack
|
||||
- Device drivers
|
||||
- Multi-tasking
|
||||
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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user