Initial commit, working
This commit is contained in:
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@@ -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
|
||||||
152
Makefile
Normal file
152
Makefile
Normal file
@@ -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"
|
||||||
161
README.md
Normal file
161
README.md
Normal file
@@ -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/)
|
||||||
93
main.c
Normal file
93
main.c
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#include <efi.h>
|
||||||
|
#include <efilib.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user