From 89936300810d3b4609f53cbc83e45169ecfac16d Mon Sep 17 00:00:00 2001 From: JimmyBinoculars Date: Thu, 26 Feb 2026 17:37:57 +0000 Subject: [PATCH] Initial commit, working --- .gitignore | 19 +++++++ Makefile | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 93 +++++++++++++++++++++++++++++++ 4 files changed, 425 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de6cfc0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Build directory +build/ + +# Object files +*.o +*.so +*.efi +*.EFI + +# Editor files +*.swp +*.swo +*~ +.vscode/ +.idea/ + +# OS files +.DS_Store +Thumbs.db diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..762fbc5 --- /dev/null +++ b/Makefile @@ -0,0 +1,152 @@ +# Makefile for UEFI Operating System + +# Architecture +ARCH = x86_64 + +# Compiler and tools +CC = gcc +LD = ld +OBJCOPY = objcopy + +# Directories +SRC_DIR = . +BUILD_DIR = build +EFI_DIR = $(BUILD_DIR)/EFI/BOOT +IMAGE_DIR = $(BUILD_DIR)/image + +# GNU-EFI paths (common locations) +EFI_INC = /usr/include/efi +EFI_INCLUDES = -I$(EFI_INC) -I$(EFI_INC)/$(ARCH) -I$(EFI_INC)/protocol +EFI_LDS = /usr/lib/elf_$(ARCH)_efi.lds +EFI_CRT_OBJS = /usr/lib/crt0-efi-$(ARCH).o +EFI_LIB_PATHS = -L/usr/lib + +# Compiler flags +CFLAGS = -ffreestanding -fno-stack-protector -fpic \ + -fshort-wchar -mno-red-zone -Wall -Wextra \ + $(EFI_INCLUDES) -DEFI_FUNCTION_WRAPPER + +# Linker flags +LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared \ + -Bsymbolic $(EFI_LIB_PATHS) $(EFI_CRT_OBJS) + +# Libraries +LIBS = -lefi -lgnuefi + +# Target +TARGET = BOOTX64.EFI +TARGET_SO = bootx64.so +OBJ = $(BUILD_DIR)/main.o + +# QEMU settings +QEMU = qemu-system-x86_64 + +# Try to find OVMF firmware (different locations on different distros) +OVMF_CODE := $(shell \ + if [ -f /usr/share/OVMF/OVMF_CODE_4M.fd ]; then \ + echo /usr/share/OVMF/OVMF_CODE_4M.fd; \ + elif [ -f /usr/share/OVMF/OVMF_CODE.fd ]; then \ + echo /usr/share/OVMF/OVMF_CODE.fd; \ + elif [ -f /usr/share/qemu/OVMF_CODE.fd ]; then \ + echo /usr/share/qemu/OVMF_CODE.fd; \ + elif [ -f /usr/share/edk2-ovmf/x64/OVMF_CODE.fd ]; then \ + echo /usr/share/edk2-ovmf/x64/OVMF_CODE.fd; \ + else \ + echo /usr/share/OVMF/OVMF_CODE.fd; \ + fi) + +OVMF_VARS_TEMPLATE := $(shell \ + if [ -f /usr/share/OVMF/OVMF_VARS_4M.fd ]; then \ + echo /usr/share/OVMF/OVMF_VARS_4M.fd; \ + elif [ -f /usr/share/OVMF/OVMF_VARS.fd ]; then \ + echo /usr/share/OVMF/OVMF_VARS.fd; \ + elif [ -f /usr/share/qemu/OVMF_VARS.fd ]; then \ + echo /usr/share/qemu/OVMF_VARS.fd; \ + elif [ -f /usr/share/edk2-ovmf/x64/OVMF_VARS.fd ]; then \ + echo /usr/share/edk2-ovmf/x64/OVMF_VARS.fd; \ + else \ + echo /usr/share/OVMF/OVMF_VARS.fd; \ + fi) + +QEMU_FLAGS = -machine q35 \ + -drive if=pflash,format=raw,readonly=on,file=$(OVMF_CODE) \ + -drive if=pflash,format=raw,file=$(BUILD_DIR)/OVMF_VARS.fd \ + -drive format=raw,file=fat:rw:$(BUILD_DIR) \ + -net none \ + -nographic + +# Phony targets +.PHONY: all clean run setup install-deps + +# Default target +all: setup $(EFI_DIR)/$(TARGET) + +# Create necessary directories +setup: + @mkdir -p $(BUILD_DIR) + @mkdir -p $(EFI_DIR) + @mkdir -p $(IMAGE_DIR) + +# Compile source files +$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c + @echo "Compiling $<..." + $(CC) $(CFLAGS) -c $< -o $@ + +# Link to create shared object +$(BUILD_DIR)/$(TARGET_SO): $(OBJ) + @echo "Linking $@..." + $(LD) $(LDFLAGS) $(OBJ) -o $@ $(LIBS) + +# Convert to EFI application +$(EFI_DIR)/$(TARGET): $(BUILD_DIR)/$(TARGET_SO) + @echo "Creating EFI application..." + $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic \ + -j .dynsym -j .rel -j .rela -j .reloc \ + --target=efi-app-$(ARCH) $< $@ + @echo "Build complete: $@" + +# Run with QEMU +run: all + @echo "Starting QEMU..." + @echo "Using OVMF firmware: $(OVMF_CODE)" + @if [ ! -f $(BUILD_DIR)/OVMF_VARS.fd ]; then \ + echo "Creating OVMF_VARS.fd from template..."; \ + cp $(OVMF_VARS_TEMPLATE) $(BUILD_DIR)/OVMF_VARS.fd 2>/dev/null || \ + dd if=/dev/zero of=$(BUILD_DIR)/OVMF_VARS.fd bs=1M count=64 2>/dev/null; \ + fi + @echo "================================================" + @echo "QEMU is starting in nographic mode" + @echo "To exit QEMU: Press Ctrl+A, then X" + @echo "In the OS: Press 'q' to shutdown" + @echo "================================================" + $(QEMU) $(QEMU_FLAGS) + +# Clean build artifacts +clean: + @echo "Cleaning build directory..." + rm -rf $(BUILD_DIR) + @echo "Clean complete." + +# Install dependencies (for Debian/Ubuntu) +install-deps: + @echo "Installing dependencies..." + sudo apt-get update + sudo apt-get install -y gnu-efi qemu-system-x86 ovmf gcc binutils make + @echo "Dependencies installed." + +# Help target +help: + @echo "UEFI Operating System Makefile" + @echo "" + @echo "Targets:" + @echo " all - Build the UEFI application (default)" + @echo " run - Build and run with QEMU" + @echo " clean - Remove build artifacts" + @echo " install-deps - Install required dependencies (Debian/Ubuntu)" + @echo " help - Display this help message" + @echo "" + @echo "Usage:" + @echo " make # Build the OS" + @echo " make run # Build and run in QEMU" + @echo " make clean # Clean build files" + @echo " make install-deps # Install dependencies" diff --git a/README.md b/README.md new file mode 100644 index 0000000..d09c003 --- /dev/null +++ b/README.md @@ -0,0 +1,161 @@ +# 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 +- **Simple Commands**: Interactive command interface + +## 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 +``` + +### On Arch Linux: + +```bash +sudo pacman -S gnu-efi qemu-system-x86 edk2-ovmf gcc binutils make +``` + +### On Fedora/RHEL: + +```bash +sudo dnf install gnu-efi qemu-system-x86 edk2-ovmf gcc binutils make +``` + +## Building + +Build the UEFI application: + +```bash +make +``` + +This will create `build/EFI/BOOT/BOOTX64.EFI` + +## Running + +Test with QEMU (no graphics mode): + +```bash +make run +``` + +### QEMU Controls: +- **Exit QEMU**: Press `Ctrl+A`, then `X` +- **Shutdown OS**: Press `q` in the OS + +## Commands in the OS + +Once the OS boots, you can use these commands: + +- `h` - Display help +- `i` - Display system information +- `c` - Clear screen +- `q` - Shutdown the system + +## Project Structure + +``` +. +├── main.c # Main UEFI application source code +├── Makefile # Build configuration +└── README.md # This file +``` + +## How It Works + +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. **Main Loop**: The OS enters a loop waiting for keyboard input +5. **Command Processing**: User commands are processed and executed +6. **Shutdown**: UEFI runtime services are used to shutdown the system + +## 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. 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 +- **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 + +Ideas for expansion: +- File system support +- Memory management +- Graphics output +- Network stack +- Device drivers +- Multi-tasking + +## Resources + +- [UEFI Specification](https://uefi.org/specifications) +- [GNU-EFI Documentation](https://sourceforge.net/projects/gnu-efi/) +- [OSDev Wiki](https://wiki.osdev.org/) diff --git a/main.c b/main.c new file mode 100644 index 0000000..46e9d8c --- /dev/null +++ b/main.c @@ -0,0 +1,93 @@ +#include +#include + +EFI_STATUS +EFIAPI +efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + + // Initialize the GNU-EFI library + InitializeLib(ImageHandle, SystemTable); + + // Clear the screen + uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); + + // Set text color to light green + uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, + EFI_TEXT_ATTR(EFI_LIGHTGREEN, EFI_BLACK)); + + // Print welcome messages + Print(L"================================================\n\r"); + Print(L" Welcome to Simple UEFI Operating System!\n\r"); + Print(L"================================================\n\r"); + Print(L"\n\r"); + Print(L"System Information:\n\r"); + Print(L" UEFI Firmware Vendor: %s\n\r", ST->FirmwareVendor); + Print(L" UEFI Firmware Revision: %d.%d\n\r", + ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xFFFF); + Print(L"\n\r"); + + // Display some runtime services info + Print(L"Available Services:\n\r"); + Print(L" - Console Input/Output: Active\n\r"); + Print(L" - Runtime Services: Active\n\r"); + Print(L" - Boot Services: Active\n\r"); + Print(L"\n\r"); + + // Simple command loop + Print(L"Commands:\n\r"); + Print(L" 'h' - Display help\n\r"); + Print(L" 'i' - Display system info\n\r"); + Print(L" 'c' - Clear screen\n\r"); + Print(L" 'q' - Shutdown\n\r"); + Print(L"\n\r"); + Print(L"Press a key to start...\n\r"); + + while (TRUE) { + // Wait for key press + Status = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, + ST->ConIn, &Key); + + if (EFI_ERROR(Status)) { + continue; + } + + // Handle commands + if (Key.UnicodeChar == L'q' || Key.UnicodeChar == L'Q') { + Print(L"\n\rShutting down...\n\r"); + // Reset the system + uefi_call_wrapper(RT->ResetSystem, 4, EfiResetShutdown, + EFI_SUCCESS, 0, NULL); + } + else if (Key.UnicodeChar == L'h' || Key.UnicodeChar == L'H') { + Print(L"\n\r=== Help ===\n\r"); + Print(L"This is a minimal UEFI operating system.\n\r"); + Print(L"It demonstrates basic UEFI functionality.\n\r"); + Print(L"\n\r"); + } + else if (Key.UnicodeChar == L'i' || Key.UnicodeChar == L'I') { + Print(L"\n\r=== System Info ===\n\r"); + Print(L"Firmware Vendor: %s\n\r", ST->FirmwareVendor); + Print(L"Firmware Revision: %d.%d\n\r", + ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xFFFF); + Print(L"UEFI Specification: %d.%d\n\r", + ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xFFFF); + Print(L"\n\r"); + } + else if (Key.UnicodeChar == L'c' || Key.UnicodeChar == L'C') { + uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); + Print(L"Screen cleared. Press 'h' for help.\n\r"); + } + else if (Key.UnicodeChar >= 32 && Key.UnicodeChar < 127) { + // Echo printable characters + Print(L"%c", Key.UnicodeChar); + } + else if (Key.UnicodeChar == L'\r') { + Print(L"\n\r> "); + } + } + + return EFI_SUCCESS; +}