5.1 KiB
Simple UEFI Operating System
A minimal bootable UEFI operating system written in C that demonstrates basic UEFI functionality.
Features
- UEFI Boot: Boots directly on UEFI firmware
- 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
Requirements
- GCC compiler
- GNU-EFI library
- QEMU with OVMF firmware
- Make
Installation
On Debian/Ubuntu:
make install-deps
Or manually:
sudo apt-get install gnu-efi qemu-system-x86 ovmf gcc binutils make
On Arch Linux:
sudo pacman -S gnu-efi qemu-system-x86 edk2-ovmf gcc binutils make
On Fedora/RHEL:
sudo dnf install gnu-efi qemu-system-x86 edk2-ovmf gcc binutils make
Building
Build the UEFI application and kernel:
make
This will create build/EFI/BOOT/BOOTX64.EFI and build/kernel.elf.
Running
Test with QEMU (no graphics mode):
make run
The loader expects kernel.elf at the root of the EFI partition (next to the EFI/ directory).
QEMU Controls:
- Exit QEMU: Press
Ctrl+A, thenX - Shutdown OS: Type
shutdownin the OS
Commands in the OS
Once the OS boots, you can use these commands:
help- Display all available commandsman <command>- Display detailed help for a commandshutdown- Shutdown the systemclear- Clear the screenabout- Display system information
Example usage:
-> help
-> man shutdown
-> clear
-> about
-> shutdown
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
How It Works
- UEFI Entry Point: The
efi_mainfunction is the entry point called by UEFI firmware - Initialization: GNU-EFI library is initialized with the system table
- Console Setup: Output is configured and screen is cleared
- Kernel Load: The loader reads
kernel.elfand maps its loadable segments - Main Loop: The kernel enters a loop waiting for keyboard input
- Command Processing: User commands are parsed and dispatched to registered handlers
- Command Execution: Each command is executed via its handler function
- Shutdown: UEFI runtime services are used to shutdown the system
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
mancommand provides detailed help by looking up command metadata - New commands can be easily added by implementing a handler and registering it
Building for Real Hardware
To create a bootable USB drive:
- Build the project:
make - Format a USB drive with GPT and create an EFI partition (FAT32)
- Mount the EFI partition
- Copy
build/EFI/BOOT/BOOTX64.EFIto/EFI/BOOT/on the USB drive - Copy
build/kernel.elfto the root of the EFI partition - Boot from the USB drive in UEFI mode
Warning: Always backup your data before creating bootable media!
Cleaning
Remove build artifacts:
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
- Executable Format: PE32+ (Portable Executable for EFI)
- Boot Protocol: UEFI Boot Services
License
This is a minimal educational example. Feel free to use and modify as needed.
Further Development
The codebase is now modular and easy to extend:
Adding New Commands:
- Open
commands.c - Create a new handler function:
static void cmd_yourcommand(BootInfo *Boot, CHAR16 *Args) - Add your command to the
commands[]array with name, description, usage, and handler - Rebuild with
make
Other Ideas for expansion:
- File system support
- Memory management
- Graphics output
- Network stack
- Device drivers
- Multi-tasking