259 lines
9.1 KiB
Makefile
259 lines
9.1 KiB
Makefile
# ==============================================================================
|
|
# Makefile for Simple UEFI Operating System
|
|
# ==============================================================================
|
|
|
|
# ---- Architecture -----------------------------------------------------------
|
|
ARCH = x86_64
|
|
|
|
# ---- 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 ---------------------------------------------------------
|
|
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 / linker flags ------------------------------------------------
|
|
|
|
# Flags shared by both the UEFI loader and the kernel
|
|
COMMON_CFLAGS = -ffreestanding -fno-stack-protector -fshort-wchar \
|
|
-mno-red-zone -Wall -Wextra $(EFI_INCLUDES)
|
|
|
|
# UEFI loader: position-independent (shared object → PE32+ conversion)
|
|
LOADER_CFLAGS = $(COMMON_CFLAGS) -fpic -DEFI_FUNCTION_WRAPPER
|
|
|
|
# Kernel: position-dependent static ELF
|
|
KERNEL_CFLAGS = $(COMMON_CFLAGS) -fno-pic
|
|
|
|
LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared \
|
|
-Bsymbolic $(EFI_LIB_PATHS) $(EFI_CRT_OBJS)
|
|
|
|
LIBS = -lefi -lgnuefi
|
|
|
|
# ---- Targets / objects ------------------------------------------------------
|
|
TARGET = BOOTX64.EFI
|
|
TARGET_SO = bootx64.so
|
|
LOADER_OBJ = $(BUILD_DIR)/main.o
|
|
|
|
KERNEL_TARGET = kernel.elf
|
|
KERNEL_LD = kernel.ld
|
|
KERNEL_C_SRCS = kernel.c string_utils.c commands.c idt.c memory.c task.c
|
|
KERNEL_S_SRCS = isr.S context_switch.S
|
|
KERNEL_OBJS = $(patsubst %.c,$(BUILD_DIR)/%.o,$(KERNEL_C_SRCS)) \
|
|
$(patsubst %.S,$(BUILD_DIR)/%.o,$(KERNEL_S_SRCS))
|
|
|
|
# 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 \
|
|
-no-reboot
|
|
|
|
# ==============================================================================
|
|
# Phony targets
|
|
# ==============================================================================
|
|
|
|
.PHONY: all clean run setup install-deps iso runiso help
|
|
|
|
# ---- Default ----------------------------------------------------------------
|
|
|
|
all: setup $(EFI_DIR)/$(TARGET) $(BUILD_DIR)/$(KERNEL_TARGET)
|
|
# ==============================================================================
|
|
# ISO image
|
|
# ==============================================================================
|
|
|
|
ISO_FILE = $(IMAGE_DIR)/os.iso
|
|
ESP_IMG = $(IMAGE_DIR)/staging/esp.img
|
|
|
|
iso: all
|
|
@echo "Creating FAT ESP image for UEFI boot..."
|
|
@mkdir -p $(IMAGE_DIR)/staging
|
|
@# Calculate size: EFI binary + kernel + overhead, rounded up to MiB
|
|
@SIZE_KB=$$(( ($$(stat -c%s $(EFI_DIR)/$(TARGET)) + $$(stat -c%s $(BUILD_DIR)/$(KERNEL_TARGET)) + 1048576) / 1024 )); \
|
|
dd if=/dev/zero of=$(ESP_IMG) bs=1K count=$$SIZE_KB 2>/dev/null
|
|
mkfs.fat -F 12 $(ESP_IMG) >/dev/null
|
|
mmd -i $(ESP_IMG) ::EFI
|
|
mmd -i $(ESP_IMG) ::EFI/BOOT
|
|
mcopy -i $(ESP_IMG) $(EFI_DIR)/$(TARGET) ::EFI/BOOT/BOOTX64.EFI
|
|
mcopy -i $(ESP_IMG) $(BUILD_DIR)/$(KERNEL_TARGET) ::kernel.elf
|
|
@echo "Creating ISO image..."
|
|
xorriso -as mkisofs \
|
|
-o $(ISO_FILE) \
|
|
-e esp.img \
|
|
-no-emul-boot \
|
|
$(IMAGE_DIR)/staging
|
|
@echo "ISO image created: $(ISO_FILE)"
|
|
|
|
# ==============================================================================
|
|
# Run targets
|
|
# ==============================================================================
|
|
|
|
# Run from ISO with QEMU
|
|
runiso: iso
|
|
@echo "Starting QEMU from ISO..."
|
|
@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
|
|
$(QEMU) -machine q35 \
|
|
-drive if=pflash,format=raw,readonly=on,file=$(OVMF_CODE) \
|
|
-drive if=pflash,format=raw,file=$(BUILD_DIR)/OVMF_VARS.fd \
|
|
-cdrom $(ISO_FILE) \
|
|
-net none \
|
|
-nographic \
|
|
-no-reboot
|
|
|
|
# ==============================================================================
|
|
# Directory setup
|
|
# ==============================================================================
|
|
|
|
setup:
|
|
@mkdir -p $(BUILD_DIR)
|
|
@mkdir -p $(EFI_DIR)
|
|
@mkdir -p $(IMAGE_DIR)
|
|
|
|
# ==============================================================================
|
|
# Compilation rules
|
|
# ==============================================================================
|
|
|
|
# ---- UEFI loader object (PIC, linked as shared object → PE32+) ----
|
|
|
|
$(BUILD_DIR)/main.o: $(SRC_DIR)/main.c
|
|
@echo " CC $<"
|
|
@$(CC) $(LOADER_CFLAGS) -c $< -o $@
|
|
|
|
# ---- Kernel objects (position-dependent, linked into static ELF) ----
|
|
# Pattern rules replace the per-file rules for every kernel source.
|
|
|
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
|
|
@echo " CC $<"
|
|
@$(CC) $(KERNEL_CFLAGS) -c $< -o $@
|
|
|
|
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.S
|
|
@echo " AS $<"
|
|
@$(CC) $(KERNEL_CFLAGS) -c $< -o $@
|
|
|
|
# ==============================================================================
|
|
# Linking
|
|
# ==============================================================================
|
|
|
|
# ---- Kernel ELF ----
|
|
|
|
$(BUILD_DIR)/$(KERNEL_TARGET): $(KERNEL_OBJS) $(KERNEL_LD)
|
|
@echo " LD $@"
|
|
@$(LD) -nostdlib -T $(KERNEL_LD) $(KERNEL_OBJS) -o $@
|
|
|
|
# ---- UEFI loader shared object ----
|
|
|
|
$(BUILD_DIR)/$(TARGET_SO): $(LOADER_OBJ)
|
|
@echo " LD $@"
|
|
@$(LD) $(LDFLAGS) $(LOADER_OBJ) -o $@ $(LIBS)
|
|
|
|
# ---- Convert to PE32+ EFI application ----
|
|
|
|
$(EFI_DIR)/$(TARGET): $(BUILD_DIR)/$(TARGET_SO)
|
|
@echo " OBJCOPY $@"
|
|
@$(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 (FAT directory)
|
|
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)
|
|
|
|
# ==============================================================================
|
|
# Maintenance
|
|
# ==============================================================================
|
|
|
|
# Clean build artifacts
|
|
clean:
|
|
@echo "Cleaning build directory..."
|
|
rm -rf $(BUILD_DIR)
|
|
@echo "Clean complete."
|
|
|
|
# Install dependencies (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 xorriso mtools
|
|
@echo "Dependencies installed."
|
|
|
|
# ==============================================================================
|
|
# Help
|
|
# ==============================================================================
|
|
|
|
help:
|
|
@echo "UEFI Operating System Makefile"
|
|
@echo ""
|
|
@echo "Targets:"
|
|
@echo " all - Build the UEFI application (default)"
|
|
@echo " run - Build and run with QEMU"
|
|
@echo " iso - Create a bootable ISO image"
|
|
@echo " runiso - Build, create ISO, and run in QEMU from ISO"
|
|
@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 iso # Create ISO image"
|
|
@echo " make runiso # Build, create ISO, and run in QEMU from ISO"
|
|
@echo " make clean # Clean build files"
|
|
@echo " make install-deps # Install dependencies"
|