commit 012b0454ed826c466d4ad6cd158c972db5e16a48 Author: zxq5 Date: Tue Feb 25 01:14:52 2025 +0000 wrote a basic bootloader diff --git a/boot/bios/stage1/stage1.ld b/boot/bios/stage1/stage1.ld new file mode 100644 index 0000000..fd01a20 --- /dev/null +++ b/boot/bios/stage1/stage1.ld @@ -0,0 +1,10 @@ +ENTRY(_start) +OUTPUT_FORMAT(binary) +SECTIONS +{ + . = 0x7C00; /* Where BIOS loads us */ + .text : { + *(.text) + . = 446; /* Pad to 510 bytes */ + } +} diff --git a/boot/bios/stage1/stage1.s b/boot/bios/stage1/stage1.s new file mode 100644 index 0000000..5d58504 --- /dev/null +++ b/boot/bios/stage1/stage1.s @@ -0,0 +1,92 @@ +section .text +global _start + +[BITS 16] +_start: + ; Set video mode (clear screen) + mov ah, 0x00 + mov al, 0x03 + int 0x10 + + ; Print loading message + mov ax, 0xb800 + mov ds, ax + + mov dword [ 0], "L O " + mov dword [ 4], "A D " + mov dword [ 8], "I N " + mov dword [ 12], "G . " + mov dword [ 16], ". . " + + ; setup a stack + cli + mov ax, 0x9000 + mov ss, ax + mov sp, 0x0000 + mov bp, sp + + mov bx, 0x0800 ; this is the first memory location we're interested in. + mov es, bx + xor bx, bx + + mov cl, 0x02 ; this is the first sector we're interested in. + + call load_sector + + mov ax, [es:6] ; load last two bytes (0x1FE = 510) + cmp ax, 0xAA55 ; check if it matches boot signature + jne error ; if not equal, not a valid boot sector + + ; jmp success + + mov ax, [es:4] ; load sector count + +next_sector: + dec ax ; decrement sectors left to write + inc cl + + cmp ax, 0 + je success + + add bx, 0x200 ; Add 512 to offset + + call load_sector + jmp next_sector + +load_sector: + pusha + + ; setup registers for disk read + mov ah, 0x02 ; read sectors function + mov dl, 0x80 ; first hard disk + mov ch, 0x00 ; cylinder 0 + mov dh, 0x00 ; head 0 + mov al, 1 ; read 1 sector + + ; do the read + int 0x13 + jc error ; if carry set, read failed + + popa + ret + +hang: + jmp hang + +error: + ; error getting the magic number + mov ah, 0x00 + mov al, 0x03 + int 0x10 + + mov ax, 0xb800 + mov ds, ax + + mov dword [ 0], "E R " + mov dword [ 4], "R O " + mov dword [ 8], "R . " + + jmp hang + +success: + jmp 0x0800:0x0016 ; jump to start of stage 2 diff --git a/boot/bios/stage2/boot.s b/boot/bios/stage2/boot.s new file mode 100644 index 0000000..8f5ba36 --- /dev/null +++ b/boot/bios/stage2/boot.s @@ -0,0 +1,118 @@ +section .text.boot +extern stage2_main +extern STAGE2_SIZE +extern STAGE2_SECTORS + +section .header +global _header_start +_header_start: + dd STAGE2_SIZE + dw STAGE2_SECTORS + db 0x55, 0xAA + +global _start +[BITS 16] +_start: + mov ah, 0x00 + mov al, 0x03 + int 0x10 + + mov ah, 0x06 + mov al, 0 + mov bh, 0x07 ; normal attribute (white on black) + mov cx, 0 ; upper left = (0,0) + mov dx, 0x184F ; lower right = (24,79) - full screen + int 0x10 + + ; print "loaded" + mov ax, 0xb800 + mov ds, ax + + mov byte [0], 'L' + mov byte [1], 0x07 + mov byte [2], 'O' + mov byte [3], 0x07 + mov byte [4], 'A' + mov byte [5], 0x07 + mov byte [6], 'D' + mov byte [7], 0x07 + mov byte [8], 'E' + mov byte [9], 0x07 + mov byte [10], 'D' + mov byte [11], 0x07 + + ; Set up stack + mov ax, 0x7000 + mov ss, ax + mov sp, 0xFFFF + + ; Enable A20 line + in al, 0x92 + or al, 2 + out 0x92, al + + ; Load GDT and switch to protected mode + cli + lgdt [GDT.pointer] + mov eax, cr0 + or eax, 1 + mov cr0, eax + + hlt + + ; Jump to 32-bit code + jmp GDT.code32:protected_mode + +[BITS 32] +protected_mode: + ; Set up segment registers + mov ax, GDT.data32 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + + ; Clear BSS section + mov edi, bss_start + mov ecx, bss_end + sub ecx, edi + xor eax, eax + rep stosb + + ; Call C code + call stage2_main + + ; Should never return + cli + hlt + +section .rodata +GDT: + ; Null descriptor + dq 0 + +.code32: equ $ - GDT + ; 32-bit code segment + dw 0xFFFF ; Limit 0:15 + dw 0x0000 ; Base 0:15 + db 0x00 ; Base 16:23 + db 0x9A ; Access byte - Code + db 0xCF ; Flags + Limit 16:19 + db 0x00 ; Base 24:31 + +.data32: equ $ - GDT + ; 32-bit data segment + dw 0xFFFF ; Limit 0:15 + dw 0x0000 ; Base 0:15 + db 0x00 ; Base 16:23 + db 0x92 ; Access byte - Data + db 0xCF ; Flags + Limit 16:19 + db 0x00 ; Base 24:31 + +.pointer: + dw $ - GDT - 1 ; Size + dd GDT ; Address + +extern bss_start +extern bss_end diff --git a/boot/bios/stage2/stage2.c b/boot/bios/stage2/stage2.c new file mode 100644 index 0000000..14c4b9d --- /dev/null +++ b/boot/bios/stage2/stage2.c @@ -0,0 +1,78 @@ +#include "stage2.h" + +// Constants for page tables +#define PRESENT (1 << 0) +#define WRITABLE (1 << 1) +#define HUGE_PAGE (1 << 7) + +// Page tables (must be aligned) +__attribute__((aligned(4096))) uint64_t pml4[512]; +__attribute__((aligned(4096))) uint64_t pdpt[512]; +__attribute__((aligned(4096))) uint64_t pd[512]; + +void enable_long_mode(void) { + // Zero out page tables + for (int i = 0; i < 512; i++) { + pml4[i] = 0; + pdpt[i] = 0; + pd[i] = 0; + } + + // Set up identity mapping for first 1GB + pml4[0] = ((uint64_t)pdpt) | PRESENT | WRITABLE; + pdpt[0] = ((uint64_t)pd) | PRESENT | WRITABLE; + + // Map 2MB pages for first 1GB + for (int i = 0; i < 512; i++) { + pd[i] = (i * 0x200000) | PRESENT | WRITABLE | HUGE_PAGE; + } + + // Load PML4 into CR3 + __asm__ volatile ( + "mov %0, %%cr3" + : + : "r"(pml4) + : "memory" + ); + + // Enable PAE + __asm__ volatile ( + "mov %%cr4, %%eax\n" + "or $0x20, %%eax\n" + "mov %%eax, %%cr4" + : + : + : "eax" + ); + + // Enable Long Mode in EFER + __asm__ volatile ( + "mov $0xC0000080, %%ecx\n" + "rdmsr\n" + "or $0x100, %%eax\n" + "wrmsr" + : + : + : "eax", "ecx", "edx" + ); + + // Enable paging + __asm__ volatile ( + "mov %%cr0, %%eax\n" + "or $0x80000000, %%eax\n" + "mov %%eax, %%cr0" + : + : + : "eax" + ); +} + +void stage2_main(void) { + // This is where we'll start in 32-bit mode + enable_long_mode(); + + // After long mode is enabled, we can load the kernel + // TODO: Add FAT32 code here + + while(1) { } +} diff --git a/boot/bios/stage2/stage2.h b/boot/bios/stage2/stage2.h new file mode 100644 index 0000000..7f1adbe --- /dev/null +++ b/boot/bios/stage2/stage2.h @@ -0,0 +1,18 @@ +#ifndef STAGE2_H +#define STAGE2_H + +// Type definitions +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +// Function declarations +void stage2_main(void); +void enable_long_mode(void); + +// Assembly interface functions (defined in boot.s) +void load_gdt(void* gdt_ptr); +void load_idt(void* idt_ptr); + +#endif /* STAGE2_H */ diff --git a/boot/bios/stage2/stage2.ld b/boot/bios/stage2/stage2.ld new file mode 100644 index 0000000..92789ed --- /dev/null +++ b/boot/bios/stage2/stage2.ld @@ -0,0 +1,37 @@ +ENTRY(_start) +OUTPUT_FORMAT(binary) + +SECTIONS +{ + . = 0x8000; /* Stage2 loads here */ + + .header : { + *(.header*) + } + + .text : { + *(.text.boot) /* Our assembly boot code first */ + *(.text*) /* Then other text sections */ + } + + .rodata : { + *(.rodata*) /* Read-only data */ + } + + .data : { + *(.data*) /* Writable data */ + } + + .bss : { + bss_start = .; + *(.bss*) /* Zero-initialized data */ + *(COMMON) + bss_end = .; + } + + ._end = .; /* Mark end of binary */ + + /* Calculate total size and sectors at the end */ + STAGE2_SIZE = ABSOLUTE(._end - 0x8000); + STAGE2_SECTORS = (STAGE2_SIZE + 511) / 512; +} \ No newline at end of file diff --git a/boot/bios/stage2/stage2.s b/boot/bios/stage2/stage2.s new file mode 100644 index 0000000..fe62e63 --- /dev/null +++ b/boot/bios/stage2/stage2.s @@ -0,0 +1,50 @@ +extern STAGE2_SIZE +extern STAGE2_SECTORS + +section .header +global _header_start +_header_start: + dd STAGE2_SIZE + dw STAGE2_SECTORS + db 0x55, 0xAA + +section .text +global _start +[BITS 16] +_start: + mov ah, 0x00 + mov al, 0x03 + int 0x10 + + mov ah, 0x06 + mov al, 0 + mov bh, 0x07 ; normal attribute (white on black) + mov cx, 0 ; upper left = (0,0) + mov dx, 0x184F ; lower right = (24,79) - full screen + int 0x10 + + jmp something + +times 500 db 0 + +something: + ; print "loaded" + mov ax, 0xb800 + mov ds, ax + + mov byte [0], 'L' + mov byte [1], 0x07 + mov byte [2], 'O' + mov byte [3], 0x07 + mov byte [4], 'A' + mov byte [5], 0x07 + mov byte [6], 'D' + mov byte [7], 0x07 + mov byte [8], 'E' + mov byte [9], 0x07 + mov byte [10], 'D' + mov byte [11], 0x07 + hlt + +hang: + hang \ No newline at end of file diff --git a/build/bios/boot.o b/build/bios/boot.o new file mode 100644 index 0000000..bea1bf1 Binary files /dev/null and b/build/bios/boot.o differ diff --git a/build/bios/stage1.bin b/build/bios/stage1.bin new file mode 100755 index 0000000..e327b4e Binary files /dev/null and b/build/bios/stage1.bin differ diff --git a/build/bios/stage1.o b/build/bios/stage1.o new file mode 100644 index 0000000..855242c Binary files /dev/null and b/build/bios/stage1.o differ diff --git a/build/bios/stage2.bin b/build/bios/stage2.bin new file mode 100755 index 0000000..24e9db6 Binary files /dev/null and b/build/bios/stage2.bin differ diff --git a/build/bios/stage2.o b/build/bios/stage2.o new file mode 100644 index 0000000..8d080f2 Binary files /dev/null and b/build/bios/stage2.o differ diff --git a/build/root/boot/EFI/BOOTX64.efi.placeholder b/build/root/boot/EFI/BOOTX64.efi.placeholder new file mode 100644 index 0000000..13d608f --- /dev/null +++ b/build/root/boot/EFI/BOOTX64.efi.placeholder @@ -0,0 +1 @@ +# THIS IS A PLACEHOLDER FILE. \ No newline at end of file diff --git a/build/root/boot/bios/stage1.bin.placeholder b/build/root/boot/bios/stage1.bin.placeholder new file mode 100644 index 0000000..9746735 --- /dev/null +++ b/build/root/boot/bios/stage1.bin.placeholder @@ -0,0 +1 @@ +# placeholder for bios boot stage 1 \ No newline at end of file diff --git a/build/root/boot/bios/stage2.bin.placeholder b/build/root/boot/bios/stage2.bin.placeholder new file mode 100644 index 0000000..b57c0c5 --- /dev/null +++ b/build/root/boot/bios/stage2.bin.placeholder @@ -0,0 +1 @@ +# stage 2 bios boot placeholder \ No newline at end of file diff --git a/disk.img b/disk.img new file mode 100644 index 0000000..7967c2c Binary files /dev/null and b/disk.img differ diff --git a/doc/bios_boot.md b/doc/bios_boot.md new file mode 100644 index 0000000..f048bc3 --- /dev/null +++ b/doc/bios_boot.md @@ -0,0 +1,95 @@ +# BIOS Boot Process and Disk Layout + +## Disk Layout + +``` +Sector 0 (MBR): ++-----------------------------------+ 0x000 +| | +| Bootstrap Code | +| (Stage 1 Bootloader) | +| | +| | ++-----------------------------------+ 0x1BE (446) +| Partition Entry 1 (16 bytes) | ++-----------------------------------+ 0x1CE (462) +| Partition Entry 2 (16 bytes) | ++-----------------------------------+ 0x1DE (478) +| Partition Entry 3 (16 bytes) | ++-----------------------------------+ 0x1EE (494) +| Partition Entry 4 (16 bytes) | ++-----------------------------------+ 0x1FE (510) +| Boot Signature (0x55AA) | ++-----------------------------------+ 0x200 (512) + +Sectors 1-2047: ++-----------------------------------+ 0x200 +| | +| Stage 2 Bootloader | +| (Up to 1023.5 KB) | +| | ++-----------------------------------+ 0x100000 (Sector 2048) + +Sector 2048 onwards: ++-----------------------------------+ 0x100000 +| | +| FAT32 Partition | +| (Rest of disk) | +| | ++-----------------------------------+ +``` + +## Partition Entry Format (16 bytes) +``` +Offset Size Description +0x00 1 Boot flag (0x80 = bootable, 0x00 = non-bootable) +0x01 3 Starting CHS address +0x04 1 Partition type +0x05 3 Ending CHS address +0x08 4 Starting sector (LBA) +0x0C 4 Number of sectors +``` + +## Boot Process + +1. **BIOS Power-On** + - BIOS performs POST (Power-On Self Test) + - Looks for bootable devices + +2. **MBR Load** + - BIOS loads Sector 0 (MBR) into memory at 0x7C00 + - Verifies 0x55AA signature + - Executes Stage 1 Bootloader + +3. **Stage 1 Bootloader** + - Runs in 16-bit real mode + - Limited to 446 bytes + - Main task: Load Stage 2 Bootloader + - Typically contains minimal disk I/O code + +4. **Stage 2 Bootloader** + - Located in sectors 1-2047 + - Has more space for complex operations + - Tasks: + - Switch to 32-bit protected mode + - Set up basic memory management + - Parse FAT32 filesystem + - Switch to long mode + - Load and execute kernel + +5. **Kernel Load** + - Stage 2 loads kernel from FAT32 partition + - Sets up necessary environment + - Transfers control to kernel + +## Memory Layout During Boot +``` +0x00000000 - 0x000003FF: Interrupt Vector Table +0x00000400 - 0x000004FF: BIOS Data Area +0x00000500 - 0x00007BFF: Free Memory +0x00007C00 - 0x00007DFF: Stage 1 Bootloader (MBR) +0x00007E00 - 0x0007FFFF: Free Memory (Stage 2 can be loaded here) +0x00080000 - 0x0009FFFF: Extended BIOS Data Area +0x000A0000 - 0x000FFFFF: BIOS ROM, Video Memory, etc. +0x00100000 onwards: Free Memory (Kernel typically loaded here) +``` diff --git a/doc/bios_interrupts.md b/doc/bios_interrupts.md new file mode 100644 index 0000000..0806820 --- /dev/null +++ b/doc/bios_interrupts.md @@ -0,0 +1,77 @@ +# BIOS Interrupt Vector Table (IVT) + +## Overview +The BIOS Interrupt Vector Table (IVT) is a crucial data structure in real mode that maps interrupt numbers to their handler routines. It is located at the very beginning of memory, starting at physical address 0x0000:0x0000. + +## Structure +- The IVT contains 256 entries (0x00 to 0xFF) +- Each entry is 4 bytes long: + - 2 bytes for the offset + - 2 bytes for the segment +- Total size: 256 * 4 = 1024 bytes (0x400) + +``` +Memory Layout: +0x0000:0x0000 - Int 0x00 vector (Divide by zero) +0x0000:0x0004 - Int 0x01 vector (Single step) +0x0000:0x0008 - Int 0x02 vector (NMI) +... +0x0000:0x0040 - Int 0x10 vector (Video services) +... +0x0000:0x03FC - Int 0xFF vector (Last vector) +``` + +## Common BIOS Interrupts +- **Int 0x10**: Video Services + - AH=0x00: Set video mode + - AH=0x0E: Write character in TTY mode + - AH=0x13: Write string + +- **Int 0x13**: Disk Services + - AH=0x00: Reset disk system + - AH=0x02: Read sectors + - AH=0x03: Write sectors + - AH=0x41: Check extensions present + - AH=0x42: Extended read sectors + - AH=0x43: Extended write sectors + +- **Int 0x16**: Keyboard Services + - AH=0x00: Read keystroke + - AH=0x01: Check for keystroke + +## How It Works +1. When an interrupt occurs (via hardware or `int` instruction): + - CPU pushes FLAGS, CS, and IP onto stack + - CPU disables further interrupts + - CPU looks up handler address in IVT + - CPU jumps to handler address + +2. Example of int 0x10 call: +```nasm +mov ah, 0x0E ; TTY output function +mov al, 'A' ; Character to print +int 0x10 ; Call BIOS video interrupt +``` + +3. The BIOS handler: + - Receives control + - Reads parameters from registers + - Performs requested operation + - Returns via IRET instruction + +## Important Notes +1. BIOS interrupts are only available in real mode +2. When transitioning to protected mode: + - BIOS interrupts become unavailable + - Must set up new Interrupt Descriptor Table (IDT) + - Must provide own interrupt handlers + +3. Some BIOS operations require interrupts to be enabled: + - Disk I/O (int 0x13) + - Keyboard input (int 0x16) + - Some video operations (int 0x10) + +4. Memory Map Considerations: + - IVT: 0x0000 - 0x03FF + - BIOS Data Area: 0x0400 - 0x04FF + - Your code should not overwrite these areas diff --git a/doc/boot_process.md b/doc/boot_process.md new file mode 100644 index 0000000..14f52dc --- /dev/null +++ b/doc/boot_process.md @@ -0,0 +1,164 @@ +# Boot Process and System Layout + +## Disk Layout +``` +FAT32 Partition +┌─────────────────────────┐ +│ / │ +├─────────────────────────┤ +│ ├── EFI/ │ +│ │ └── BOOT/ │ +│ │ └── BOOTX64.EFI│ <- UEFI bootloader +├─────────────────────────┤ +│ ├── boot/ │ +│ │ └── bootloader.bin │ <- BIOS bootloader +├─────────────────────────┤ +│ └── kernel │ <- Main kernel binary +└─────────────────────────┘ +``` + +## Kernel Binary Format +``` +Kernel Header Structure +┌─────────────────────────┐ +│ Magic Number (4 bytes) │ 0x00 +├─────────────────────────┤ +│ Entry Point (8 bytes) │ 0x04 +├─────────────────────────┤ +│ Stack Pointer (8 bytes) │ 0x0C +├─────────────────────────┤ +│ Flags (4 bytes) │ 0x14 +├─────────────────────────┤ +│ Text Offset (4 bytes) │ 0x18 +├─────────────────────────┤ +│ Text Size (4 bytes) │ 0x1C +├─────────────────────────┤ +│ Data Offset (4 bytes) │ 0x20 +├─────────────────────────┤ +│ Data Size (4 bytes) │ 0x24 +└─────────────────────────┘ +``` + +## Memory Layout (After Boot) +``` +Virtual Memory Layout +┌─────────────────────┐ 0xFFFFFFFF_FFFFFFFF +│ Higher Half │ +├─────────────────────┤ 0xFFFFFFFF_FF600000 +│ Recursive │ +│ Page Mapping │ +├─────────────────────┤ 0xFFFFFFFF_C0000000 +│ Kernel Stacks │ +├─────────────────────┤ +│ Kernel Heap │ +├─────────────────────┤ 0xFFFFFFFF_80000000 +│ Kernel Code │ +├─────────────────────┤ 0x00007FFF_FFFFFFFF +│ Guard │ +├─────────────────────┤ 0x00007FFF_00000000 +│ User Space │ +├─────────────────────┤ 0x0000000000400000 +│ Guard │ +└─────────────────────┘ 0x0000000000000000 + +Physical Memory Layout +┌─────────────────────┐ +│ Available RAM │ +├─────────────────────┤ +│ Kernel Binary │ <- Loaded at 1MB (0x100000) +├─────────────────────┤ +│ Reserved/BIOS │ +└─────────────────────┘ 0x00000000 +``` + +## Boot Process + +### BIOS Boot Flow +1. BIOS loads MBR (stage1.bin) +2. Stage 1 bootloader: + - Loads Stage 2 bootloader (stage2.bin) starting at sector 2048 +3. Stage 2 bootloader: + - Switches to protected mode + - Sets up initial page tables + - Finds and loads kernel from FAT32 + - Enables long mode + - Jumps to kernel entry point + +### UEFI Boot Flow +1. UEFI firmware loads BOOTX64.EFI +2. UEFI bootloader: + - Gets memory map + - Finds and loads kernel + - Exits boot services + - Sets up page tables + - Enables long mode + - Jumps to kernel entry point + +### Kernel Entry Point +```rust +extern "C" { + fn kmain(magic: u64, boot_info: *const BootInfo) -> !; +} +``` + +## Common Boot Environment +Both bootloaders must provide: + +### CPU State +``` +- Long mode enabled +- Paging enabled +- Interrupts disabled +- GDT set up for long mode +- IDT not required (kernel will set up) +``` + +### Register State +``` +RAX = Boot magic value (e.g., 0xCAFEBABE) +RBX = Pointer to boot info structure +RCX = 0 +RDX = 0 +RSI = 0 +RDI = 0 +RBP = 0 +RSP = Valid stack pointer (as specified in kernel header) +``` + +### Boot Info Structure +```c +struct BootInfo { + uint64_t magic; // Boot info magic number + uint64_t mem_map_addr; // Physical address of memory map + uint64_t mem_map_size; // Size of memory map + uint64_t fb_addr; // Framebuffer address (if available) + uint32_t fb_width; // Framebuffer width + uint32_t fb_height; // Framebuffer height + uint32_t fb_pitch; // Framebuffer pitch + uint8_t fb_bpp; // Bits per pixel + uint8_t boot_type; // 0 = BIOS, 1 = UEFI + uint8_t reserved[6]; // Padding to 64-bit align +}; +``` + +## Required Kernel Features +1. Position-independent code (PIC) +2. No assumptions about physical memory layout beyond boot info +3. Own interrupt handling +4. Own memory management after boot + +## Development Notes +1. Kernel must be compiled with: + - No red zone + - No MMX/SSE initially + - Position-independent code + - No standard library dependencies + +2. Testing can be done with: + ```bash + # BIOS boot + qemu-system-x86_64 disk.img + + # UEFI boot + qemu-system-x86_64 -bios /usr/share/OVMF/OVMF_CODE.fd disk.img + ``` diff --git a/doc/memory.md b/doc/memory.md new file mode 100644 index 0000000..df27ea4 --- /dev/null +++ b/doc/memory.md @@ -0,0 +1,55 @@ +# x86_64 Virtual Memory Layout + +┌─────────────────────┐ 0xFFFFFFFF_FFFFFFFF +│ Higher Half │ +├─────────────────────┤ 0xFFFFFFFF_FF600000 +│ Recursive │ (Optional: for page table manipulation) +│ Page Mapping │ +├─────────────────────┤ 0xFFFFFFFF_C0000000 +│ Kernel Stacks │ (Multiple 16KB or 32KB stacks, guard pages between) +├─────────────────────┤ +│ Kernel Heap │ (Dynamic allocation for kernel) +├─────────────────────┤ 0xFFFFFFFF_80000000 +│ Kernel Code │ (Loaded by bootloader) +├─────────────────────┤ 0x00007FFF_FFFFFFFF +│ Guard │ (Prevent user->kernel pointer errors) +├─────────────────────┤ 0x00007FFF_00000000 +│ User Stacks │ (Grows down) +├─────────────────────┤ +│ ... │ (Available for mmap, shared libraries, etc.) +├─────────────────────┤ +│ User Heap │ (Grows up) +├─────────────────────┤ +│ Program .bss │ (Uninitialized data) +│ Program .data │ (Initialized data) +│ Program .rodata │ (Read-only data) +│ Program .text │ (Code) +├─────────────────────┤ 0x0000000000400000 +│ Guard │ (Catch null pointer dereference) +└─────────────────────┘ 0x0000000000000000 + +## Memory Regions Explanation + +### Kernel Space (Higher Half) +- **Kernel Code**: Fixed location at -2GB +- **Kernel Heap**: Dynamic memory for kernel operations +- **Kernel Stacks**: Multiple stacks for different CPU modes/tasks +- **Recursive Mapping**: Optional region for page table manipulation + +### User Space (Lower Half) +- **Guard Pages**: Protect against null pointer dereference (0-4MB) +- **Program Sections**: Start at 0x400000 + - .text: Program code + - .rodata: Read-only data + - .data: Initialized data + - .bss: Uninitialized data +- **User Heap**: Grows upward from end of program sections +- **Dynamic Region**: Space for mmap allocations, shared libraries +- **User Stacks**: Grows downward from 0x00007FFF_00000000 + +### Key Features +- Full 48-bit addressing support (256TB virtual address space) +- Clear separation between user and kernel space +- Protected null pointer dereference +- Room for stack/heap growth +- Space for dynamic libraries and mappings \ No newline at end of file diff --git a/doc/uefi_boot.md b/doc/uefi_boot.md new file mode 100644 index 0000000..5a4fbdb --- /dev/null +++ b/doc/uefi_boot.md @@ -0,0 +1,141 @@ +# UEFI Boot Process and Disk Layout + +## Disk Layout with ESP (EFI System Partition) + +``` +Sector 0 (MBR/GPT): ++-----------------------------------+ 0x000 +| Protective MBR | +| (For BIOS compatibility) | ++-----------------------------------+ 0x200 + +EFI System Partition (FAT32): ++-----------------------------------+ Sector 2048 +| FAT32 Filesystem | +| /EFI/ | +| /BOOT/ | +| BOOTX64.EFI | ++-----------------------------------+ + +Main Partition (FAT32): ++-----------------------------------+ +| FAT32 Filesystem | +| (Kernel and other files) | ++-----------------------------------+ +``` + +## UEFI Boot Process + +1. **System Startup** + - Firmware initializes hardware + - Loads UEFI runtime services + - Sets up initial page tables and long mode + - CPU already in 64-bit mode + +2. **Boot Manager** + - Scans for bootable devices + - Looks for EFI System Partition (ESP) + - Searches for bootloader at `/EFI/BOOT/BOOTX64.EFI` + +3. **UEFI Bootloader** + - Already in long mode (64-bit) + - Has access to UEFI services: + - File operations + - Memory management + - Video output + - ACPI tables + - Tasks: + - Load kernel from main partition + - Set up memory map + - Exit boot services + - Jump to kernel + +4. **Kernel Load** + - Bootloader passes: + - Memory map + - Framebuffer info + - ACPI tables + - Kernel takes control + +## Key Differences from BIOS + +1. **Initial State** + - BIOS: 16-bit real mode + - UEFI: 64-bit long mode + +2. **Services** + - BIOS: Limited interrupt-based services + - UEFI: Rich API for system services + +3. **Memory Management** + - BIOS: Manual memory detection needed + - UEFI: Provides memory map and allocation services + +4. **File Access** + - BIOS: Manual disk I/O and filesystem parsing + - UEFI: Built-in filesystem support + +5. **Graphics** + - BIOS: VGA/VBE modes + - UEFI: GOP (Graphics Output Protocol) + +## UEFI Boot Services +``` +Available until ExitBootServices() is called: +- Memory allocation +- File system access +- Graphics output +- Timer services +- Environment variables + +Runtime Services (available after boot): +- Time services +- Variable services +- Reset system +- Virtual memory services +``` + +## Memory Map Example +``` +Type Physical Address Range +EfiLoaderCode 0x0000000000000000-0x0000000000100000 +EfiLoaderData 0x0000000000100000-0x0000000000200000 +EfiBootServicesCode 0x0000000000200000-0x0000000000300000 +EfiBootServicesData 0x0000000000300000-0x0000000000400000 +EfiConventionalMemory 0x0000000000400000-... +EfiACPIReclaimMemory ... +EfiACPIMemoryNVS ... +EfiReservedMemoryType ... +``` + +## Required UEFI Protocols +``` +- EFI_LOADED_IMAGE_PROTOCOL: Access to bootloader image info +- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL: File operations +- EFI_GRAPHICS_OUTPUT_PROTOCOL: Display output +- EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL: Text output +``` + +## Boot Flow Control +``` +UEFI Firmware + │ + ▼ +Boot Manager + │ + ▼ +BOOTX64.EFI + │ + ├── Get System Info + │ ├── Memory Map + │ ├── ACPI Tables + │ └── GOP Info + │ + ├── Load Kernel + │ └── Parse FAT32 + │ + ├── ExitBootServices() + │ + └── Jump to Kernel + └── Pass Boot Info +``` diff --git a/examples and stuff/.cargo/config.toml b/examples and stuff/.cargo/config.toml new file mode 100644 index 0000000..ba176d0 --- /dev/null +++ b/examples and stuff/.cargo/config.toml @@ -0,0 +1,16 @@ +[build] +target = "x86_64-custom.json" + +[unstable] +build-std = ["core", "compiler_builtins"] +build-std-features = ["compiler-builtins-mem"] + +[target.'cfg(target_os = "none")'] +runner = "bootimage runner" + +[target.x86_64-custom] +rustflags = [ + "-C", "link-arg=-Tlinker.ld", + "-C", "code-model=kernel", + "-C", "relocation-model=static" +] diff --git a/examples and stuff/boot b/examples and stuff/boot new file mode 100644 index 0000000..b71084a Binary files /dev/null and b/examples and stuff/boot differ diff --git a/examples and stuff/booting stuff/boot.S b/examples and stuff/booting stuff/boot.S new file mode 100644 index 0000000..ad6f73e --- /dev/null +++ b/examples and stuff/booting stuff/boot.S @@ -0,0 +1,55 @@ +[BITS 16] +[ORG 0x7c00] +start: + mov ah,0x00 ; set mode + mov al,0x03 ; set vga text buffer mode (80x25) + int 0x10 ; call bios + + cli + + in al, 0x92 + or al, 2 + out 0x92, al + + xor ax, ax + mov ds, ax + + lgdt [GDT_PTR] + + mov eax, 0x11 + mov cr0, eax + jmp GDT_BOOT_CS-GDT:protmode + +[BITS 32] +protmode: + mov ax, GDT_BOOT_DS-GDT + mov ds, ax + mov ss, ax + mov es, ax + mov esp, 0x90000 ; temporary stack + + mov edi, 0xb8000 + mov eax, "P R " + stosd + +hang: + pause + jmp hang + +GDT_PTR: + dw GDT_END-GDT-1 + dd GDT + + +align 16 +GDT: + + GDT_NULL: dq 0 ; segment zero cannot be used + GDT_BOOT_DS: dq 0X00CF92000000FFFF + GDT_BOOT_CS: dq 0X00CF9A000000FFFF + + GDT_END: + +times 510-$+start db 0; +db 0x55; +db 0xaa; \ No newline at end of file diff --git a/examples and stuff/booting stuff/mbr.asm b/examples and stuff/booting stuff/mbr.asm new file mode 100644 index 0000000..969991d --- /dev/null +++ b/examples and stuff/booting stuff/mbr.asm @@ -0,0 +1,118 @@ +[BITS 16] +[ORG 0x7C00] + + ; Initialize segment registers + xor ax, ax + mov ds, ax + mov es, ax + mov ss, ax + mov sp, 0x7C00 + + ; Reset disk system + mov ah, 0 + int 0x13 + + ; Load FAT32 BPB + mov si, bpb_oem_name + mov di, 0x7E00 + mov cx, bpb_size + rep movsb + + ; Read FAT32 root directory + mov ax, [bpb_reserved_sectors] + mov [dapack.lba_start], ax + + mov ah, 0x42 + mov si, dapack + int 0x13 + jc error + + ; Find kernel file + mov si, kernel_name + mov di, 0x8000 + mov cx, 11 ; FAT32 8.3 filename length + +find_kernel: + push cx + push si + push di + rep cmpsb + pop di + pop si + pop cx + je found_kernel + + add di, 32 ; Move to next directory entry + cmp di, 0x8200 ; Check if we've reached the end of the sector + jl find_kernel + + ; Kernel not found + mov si, err_no_kernel + call print + jmp $ + +found_kernel: + ; Get cluster number + mov ax, [di + 20] ; High word + shl eax, 16 + mov ax, [di + 26] ; Low word + + ; Load kernel + mov [cluster], eax + call load_cluster + + ; Jump to kernel + jmp 0x8000 + +error: + mov si, err_disk + call print + jmp $ + +print: + lodsb + or al, al + jz .done + mov ah, 0x0E + int 0x10 + jmp print +.done: + ret + +load_cluster: + ; Convert cluster to LBA + sub eax, 2 + mul dword [sectors_per_cluster] + add eax, [first_data_sector] + + mov [dapack.lba_start], eax + mov ah, 0x42 + mov si, dapack + int 0x13 + ret + +align 4 +dapack: + db 0x10 ; Size of packet + db 0 ; Reserved + dw 1 ; Number of sectors + dw 0x8000 ; Offset + dw 0 ; Segment + dq 0 ; LBA + +cluster: dd 0 +sectors_per_cluster: dd 8 +first_data_sector: dd 0 + +kernel_name: db "KERNEL BIN" +err_disk: db "Disk error", 0 +err_no_kernel: db "No kernel", 0 + +bpb_oem_name: times 8 db 0 +bpb_bytes_per_sector: dw 512 +bpb_sectors_per_cluster: db 8 +bpb_reserved_sectors: dw 32 +bpb_size: equ $ - bpb_oem_name + +times 510-($-$$) db 0 +dw 0xAA55 diff --git a/examples and stuff/booting stuff/uefi_boot.S b/examples and stuff/booting stuff/uefi_boot.S new file mode 100644 index 0000000..9c9e92c --- /dev/null +++ b/examples and stuff/booting stuff/uefi_boot.S @@ -0,0 +1,83 @@ +.section .efi.text, "ax" +.global _start +.code64 // UEFI is already in 64-bit protected mode + +_start: + // Save UEFI parameters + mov %rcx, uefi_image_handle + mov %rdx, uefi_system_table + + // Get memory map + call get_memory_map + + // Exit boot services + mov uefi_image_handle, %rcx + mov memory_map_key, %rdx + call exit_boot_services + + // Disable interrupts + cli + + // Load GDT for long mode + lgdt gdt64_pointer(%rip) + + // Setup page tables (identity map first 2MB + map kernel to higher half) + call setup_page_tables + + // Enable PAE + mov %cr4, %rax + or $(1 << 5), %rax + mov %rax, %cr4 + + // Set long mode bit + mov $0xC0000080, %ecx + rdmsr + or $(1 << 8), %eax + wrmsr + + // Enable paging + mov %cr0, %rax + or $0x80000000, %rax + mov %rax, %cr0 + + // Long jump to higher half kernel + lea higher_half(%rip), %rax + jmp *%rax + +.align 8 +higher_half: + // Now in long mode at higher half + // Setup stack and jump to Rust code + mov $kernel_stack_top, %rsp + call kmain + +// GDT for long mode +.align 16 +gdt64: + .quad 0 // Null descriptor + .quad 0x00AF9A000000FFFF // Code segment + .quad 0x00CF92000000FFFF // Data segment + +gdt64_pointer: + .word gdt64_pointer - gdt64 - 1 + .quad gdt64 + +.section .efi.data, "aw" +uefi_image_handle: .quad 0 +uefi_system_table: .quad 0 +memory_map_key: .quad 0 + +.section .bss +.align 4096 +kernel_stack_bottom: + .skip 16384 // 16 KB stack +kernel_stack_top: + +// Page tables +.align 4096 +pml4_table: + .skip 4096 +pdpt_table: + .skip 4096 +pd_table: + .skip 4096 diff --git a/examples and stuff/booting stuff/uefi_funcs.S b/examples and stuff/booting stuff/uefi_funcs.S new file mode 100644 index 0000000..89c6527 --- /dev/null +++ b/examples and stuff/booting stuff/uefi_funcs.S @@ -0,0 +1,94 @@ +.section .efi.text + +// Function to get UEFI memory map +get_memory_map: + push %rbp + mov %rsp, %rbp + + // Local variables for memory map + sub $48, %rsp + mov $0, -8(%rbp) // memory_map_size + mov $0, -16(%rbp) // memory_map_buffer + mov $0, -24(%rbp) // map_key + mov $0, -32(%rbp) // descriptor_size + mov $0, -40(%rbp) // descriptor_version + + // First call to get size + lea -8(%rbp), %rcx // memory_map_size + mov $0, %rdx // memory_map + lea -24(%rbp), %r8 // map_key + lea -32(%rbp), %r9 // descriptor_size + push $0 // descriptor_version + call boot_services_get_memory_map + + // Allocate buffer + mov -8(%rbp), %rcx // size + add $1000, %rcx // Add some extra space + mov $8, %rdx // alignment + lea -16(%rbp), %r8 // buffer pointer + call boot_services_allocate_pool + + // Get actual map + mov -8(%rbp), %rcx + mov -16(%rbp), %rdx + lea -24(%rbp), %r8 + lea -32(%rbp), %r9 + push -40(%rbp) + call boot_services_get_memory_map + + // Save map key + mov -24(%rbp), %rax + mov %rax, memory_map_key + + leave + ret + +// Function to exit boot services +exit_boot_services: + push %rbp + mov %rsp, %rbp + + // Parameters already in rcx (image_handle) and rdx (map_key) + call boot_services_exit + + leave + ret + +// Function to set up page tables +setup_page_tables: + push %rbp + mov %rsp, %rbp + + // Clear tables + mov $pml4_table, %rdi + mov $12288, %ecx // 3 pages (PML4, PDPT, PD) + xor %eax, %eax + rep stosb + + // Set up identity mapping for first 2MB + // PML4[0] -> PDPT + mov $pdpt_table, %eax + or $3, %eax // Present + Write + mov %eax, pml4_table + + // PDPT[0] -> PD + mov $pd_table, %eax + or $3, %eax + mov %eax, pdpt_table + + // PD[0] -> 2MB page + mov $0x83, %eax // Present + Write + Huge + mov %eax, pd_table + + // Map kernel to higher half + // PML4[511] -> PDPT + mov $pdpt_table, %eax + or $3, %eax + mov %eax, pml4_table + 4088 + + // Load CR3 + mov $pml4_table, %rax + mov %rax, %cr3 + + leave + ret diff --git a/examples and stuff/linker.ld b/examples and stuff/linker.ld new file mode 100644 index 0000000..ae15dc0 --- /dev/null +++ b/examples and stuff/linker.ld @@ -0,0 +1,140 @@ +/* Tell the linker that we want an x86_64 ELF64 output file */ +OUTPUT_FORMAT(elf64-x86-64) +OUTPUT_ARCH(i386:x86-64) + +/* Entry points */ +ENTRY(start) + +/* Define the program headers we want in our final kernel executable */ +PHDRS +{ + boot PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ + text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ + rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */ + data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ +} + +/* The kernel is linked to run at -2GB (KERNEL_BASE) */ +KERNEL_BASE = 0xFFFFFFFF80000000; + +SECTIONS +{ + /* For BIOS boot, start at 1MB physical */ + . = 1M; + + .boot : { + /* BIOS boot sections */ + KEEP(*(.multiboot)) /* Multiboot header */ + *(.boottext) /* BIOS boot code */ + *(.boottext.*) + + /* UEFI boot sections */ + KEEP(*(.pe_header)) /* PE/COFF header for UEFI */ + *(.efi.header) /* EFI header */ + . = ALIGN(4K); + *(.efi.text) /* UEFI boot code */ + *(.efi.text.*) + *(.efi.data) /* UEFI data */ + *(.efi.data.*) + } :boot + + /* Switch to higher half for kernel proper */ + . += KERNEL_BASE; + + /* Code section */ + .text : AT(ADDR(.text) - KERNEL_BASE) { + _text_start = .; + *(.text) + *(.text.*) + . = ALIGN(4K); + _text_end = .; + } :text + + /* Read-only data */ + .rodata : AT(ADDR(.rodata) - KERNEL_BASE) { + _rodata_start = .; + *(.rodata) + *(.rodata.*) + . = ALIGN(4K); + _rodata_end = .; + } :rodata + + /* Read-write data (initialized) */ + .data : AT(ADDR(.data) - KERNEL_BASE) { + _data_start = .; + *(.data) + *(.data.*) + *(.got) + *(.got.*) + . = ALIGN(4K); + _data_end = .; + } :data + + /* Read-write data (uninitialized) */ + .bss : AT(ADDR(.bss) - KERNEL_BASE) { + _bss_start = .; + *(COMMON) + *(.bss) + *(.bss.*) + . = ALIGN(4K); + _bss_end = .; + } :data + + /* Page-aligned data structures */ + .padata ALIGN(4K) : AT(ADDR(.padata) - KERNEL_BASE) { + *(.padata) + } :data + + /* Initial stack space */ + .stack ALIGN(4K) : AT(ADDR(.stack) - KERNEL_BASE) { + *(.stack) + } :data + + /* Thread-local storage */ + .tdata ALIGN(4K) : AT(ADDR(.tdata) - KERNEL_BASE) { + _tdata_start = .; + *(.tdata) + *(.tdata.*) + . = ALIGN(4K); + _tdata_end = .; + } :data + + .tbss ALIGN(4K) : AT(ADDR(.tbss) - KERNEL_BASE) { + _tbss_start = .; + *(.tbss) + *(.tbss.*) + . = ALIGN(4K); + _tbss_end = .; + } :data + + /* Debugging information */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_ranges 0 : { *(.debug_ranges) } + .debug_line 0 : { *(.debug_line) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + + /* Discard unused sections */ + /DISCARD/ : { + *(.eh_frame) + *(.note.*) + *(.comment) + } +} + +/* Symbols needed by both BIOS and UEFI boot code */ +PROVIDE(_kernel_start = ADDR(.boot)); +PROVIDE(_kernel_end = ADDR(.tbss) + SIZEOF(.tbss)); +PROVIDE(_kernel_physical_end = ADDR(.tbss) - KERNEL_BASE + SIZEOF(.tbss)); +PROVIDE(_kernel_virtual_base = KERNEL_BASE); + +/* UEFI-specific symbols */ +PROVIDE(_efi_start = ADDR(.boot)); +PROVIDE(_efi_text_start = ADDR(.efi.text)); +PROVIDE(_efi_text_end = ADDR(.efi.text) + SIZEOF(.efi.text)); + +/* BIOS-specific symbols */ +PROVIDE(_multiboot_start = ADDR(.multiboot)); +PROVIDE(_boottext_start = ADDR(.boottext)); diff --git a/examples and stuff/some scripts/build.sh b/examples and stuff/some scripts/build.sh new file mode 100755 index 0000000..a97bb02 --- /dev/null +++ b/examples and stuff/some scripts/build.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -e + +# Build the bootloader +nasm -f bin mbr.asm -o mbr.bin + +# Build the kernel +cargo build --release + +# Create disk image +./create_image.sh + +# Write MBR +dd if=mbr.bin of=disk.img conv=notrunc + +echo "Build complete! You can now boot disk.img" diff --git a/examples and stuff/some scripts/create_image.sh b/examples and stuff/some scripts/create_image.sh new file mode 100755 index 0000000..bd80399 --- /dev/null +++ b/examples and stuff/some scripts/create_image.sh @@ -0,0 +1,46 @@ +#!/bin/bash +set -e + +# Image configuration +IMAGE_NAME="disk.img" +IMAGE_SIZE_MB=64 +ESP_SIZE_MB=32 # EFI System Partition size + +# Create a new disk image +dd if=/dev/zero of=$IMAGE_NAME bs=1M count=$IMAGE_SIZE_MB + +# Create partition table and ESP partition +parted $IMAGE_NAME mklabel gpt +parted $IMAGE_NAME mkpart ESP fat32 1MiB ${ESP_SIZE_MB}MiB +parted $IMAGE_NAME set 1 esp on + +# Calculate offset for mounting +SECTOR_SIZE=512 +START_SECTOR=$(parted $IMAGE_NAME -ms unit s print | grep "^1:" | cut -d: -f2 | tr -d 's') +OFFSET=$((START_SECTOR * SECTOR_SIZE)) + +# Create FAT32 filesystem +LOOP_DEVICE=$(sudo losetup -f --show -o $OFFSET $IMAGE_NAME) +sudo mkfs.fat -F 32 $LOOP_DEVICE + +# Mount the image +MOUNT_POINT="/tmp/esp" +mkdir -p $MOUNT_POINT +sudo mount $LOOP_DEVICE $MOUNT_POINT + +# Create EFI directory structure +sudo mkdir -p $MOUNT_POINT/EFI/BOOT + +# Copy kernel to the ESP +# For UEFI boot, rename it to BOOTX64.EFI +sudo cp target/x86_64-custom/release/kernel $MOUNT_POINT/EFI/BOOT/BOOTX64.EFI + +# For BIOS boot, also copy it to the root +sudo cp target/x86_64-custom/release/kernel $MOUNT_POINT/ + +# Cleanup +sudo umount $MOUNT_POINT +sudo losetup -d $LOOP_DEVICE +rm -rf $MOUNT_POINT + +echo "Disk image created successfully!" diff --git a/examples and stuff/x86_64-custom.json b/examples and stuff/x86_64-custom.json new file mode 100644 index 0000000..a384dca --- /dev/null +++ b/examples and stuff/x86_64-custom.json @@ -0,0 +1,20 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float", + "pre-link-args": { + "ld.lld": [ + "--gc-sections" + ] + } +} diff --git a/scripts/build_stage1.sh b/scripts/build_stage1.sh new file mode 100755 index 0000000..11f2cb6 --- /dev/null +++ b/scripts/build_stage1.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +# Set root directory +cd "$(dirname "$0")/.." + +# Create build directory if it doesn't exist +mkdir -p build/bios + +# Assemble stage1 +nasm -f elf32 boot/bios/stage1/stage1.s -o build/bios/stage1.o + +# Link to binary +ld -m elf_i386 -T boot/bios/stage1/stage1.ld build/bios/stage1.o -o build/bios/stage1.bin + +# Verify size +size=$(wc -c < build/bios/stage1.bin) +if [ "$size" -gt 446 ]; then + echo "Error: stage1.bin is larger than 446 bytes ($size bytes)" + exit 1 +fi + +echo "Successfully built stage1.bin ($size bytes)" \ No newline at end of file diff --git a/scripts/build_stage2.sh b/scripts/build_stage2.sh new file mode 100755 index 0000000..b8471b8 --- /dev/null +++ b/scripts/build_stage2.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -e + +# Set root directory +cd "$(dirname "$0")/.." + +# Create build directory if it doesn't exist +mkdir -p build/bios + +# Compile C code +gcc -m32 -ffreestanding -fno-pie -fno-stack-protector -nostdlib -nodefaultlibs \ + -Wall -Wextra -O2 -c boot/bios/stage2/stage2.c -o build/bios/stage2.o + +# Assemble boot code +nasm -f elf32 boot/bios/stage2/boot.s -o build/bios/boot.o + +# Link to binary +ld -m elf_i386 -T boot/bios/stage2/stage2.ld \ + build/bios/boot.o \ + build/bios/stage2.o \ + -o build/bios/stage2.bin + +# Verify size (stage2 can be multiple sectors, but let's warn if it's too large) +size=$(wc -c < build/bios/stage2.bin) +if [ "$size" -gt 32768 ]; then # 64 sectors (32KB) should be plenty + echo "Warning: stage2.bin is larger than 32KB ($size bytes)" +fi + +echo "Successfully built stage2.bin ($size bytes)" \ No newline at end of file diff --git a/scripts/create_disk.sh b/scripts/create_disk.sh new file mode 100755 index 0000000..75343c2 --- /dev/null +++ b/scripts/create_disk.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +set -e + +# Size in MB +DISK_SIZE=64 +ESP_SIZE=100 # Size of EFI System Partition in sectors (100 sectors = ~50KB, enough for our bootloader) + +# Create build directory if it doesn't exist +mkdir -p build/bios + +# Build stage 1/2 bootloader +./scripts/build_stage1.sh +./scripts/build_stage2.sh + +# Create an empty disk image +dd if=/dev/zero of=disk.img bs=1M count=$DISK_SIZE + +# Create a partition table +( +echo o # Create a new empty DOS partition table +echo n # Add a new partition (EFI System Partition) +echo p # Primary partition +echo 1 # Partition number 1 +echo 2048 # First sector (leaving room for bootloader) +echo +${ESP_SIZE} # Size in sectors +echo t # Change partition type +echo ef # EFI System Partition type + +echo n # Add a new partition (Main partition) +echo p # Primary partition +echo 2 # Partition number 2 +echo # Default first sector (right after ESP) +echo # Use rest of disk +echo t # Change partition type +echo 2 # Select second partition +echo 0c # FAT32 LBA type +echo a # Make bootable +echo 2 # Select second partition +echo w # Write changes +) | fdisk disk.img > /dev/null 2>&1 + +# Copy bootloader to disk image +# First stage (MBR) +dd if=build/bios/stage1.bin of=disk.img conv=notrunc bs=446 count=1 + +# Second stage (right after MBR) +dd if=build/bios/stage2.bin of=disk.img conv=notrunc bs=512 seek=1 + +# Format ESP partition +ESP_OFFSET=$((2048 * 512)) # First partition starts at sector 2048 +mformat -i disk.img@@${ESP_OFFSET} -F -h 255 -t 1 -s 63 -c 1 :: + +# Format main partition +MAIN_OFFSET=$(( (2048 + ESP_SIZE) * 512 )) # Second partition starts after ESP +mformat -i disk.img@@${MAIN_OFFSET} -F -h 255 -t 1 -s 63 -c 1 :: + +# Create EFI directory structure in ESP +mmd -i disk.img@@${ESP_OFFSET} ::/EFI +mmd -i disk.img@@${ESP_OFFSET} ::/EFI/BOOT + +# When you have the UEFI bootloader ready, uncomment this: +# mcopy -i disk.img@@${ESP_OFFSET} boot/uefi/BOOTX64.EFI ::/EFI/BOOT/ diff --git a/scripts/run.sh b/scripts/run.sh new file mode 100755 index 0000000..d6f0579 --- /dev/null +++ b/scripts/run.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -e + +# set root directory of project +cd "$(dirname "$0")/.." + +# Build the bootloader +./scripts/create_disk.sh + +# Default to KVM if available +KVM_FLAGS="" +if [ -c /dev/kvm ]; then + KVM_FLAGS="-enable-kvm -cpu host" +fi + +# Run QEMU with appropriate flags +qemu-system-x86_64 \ + $KVM_FLAGS \ + -m 4G \ + -drive file=disk.img,format=raw \ + -monitor stdio \ + -no-reboot \ + -no-shutdown \ + -smp 4 \ + -serial file:serial.log diff --git a/serial.log b/serial.log new file mode 100644 index 0000000..e69de29