From 51b654d5e354f4784925e232f88e02b4dc0168c9 Mon Sep 17 00:00:00 2001 From: "Pierre-Emmanuel Gob." Date: Mon, 5 Oct 2026 18:11:57 +0200 Subject: [PATCH] entry: copy staged E820 map into .bss memmap_* --- include/e820.h | 34 ++++++++++++++++++++++++++++++++++ kernel/arch/x86_64/entry.asm | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 include/e820.h diff --git a/include/e820.h b/include/e820.h new file mode 100644 index 0000000..9f87c08 --- /dev/null +++ b/include/e820.h @@ -0,0 +1,34 @@ +/* Nadir BIOS E820 memory-map entry (int 0x15, eax=0xE820). + * + * Staged by the stage-1 boot sector in 16-bit real mode at Ring 0 (CPL 0) + * into low memory (0x5000 count, 0x5020 entries) while BIOS calls still + * work, then copied by the stage-2 entry into the .bss globals + * memmap_count / memmap_entries owned by the PMM. Runs under the + * identity-mapped first 1GB, so physical == virtual addresses here. + * Fault behavior: no IDT exists during staging/copy, so a bad pointer + * triple-faults; the entry count is clamped to E820_MAX on both ends. + */ + +#ifndef NADIR_E820_H +#define NADIR_E820_H + +#include + +/* Max entries the boot sector stages and the kernel keeps. */ +#define E820_MAX 64 + +/* Usable-RAM type in the E820 type field. */ +#define E820_USABLE 1 + +/* One 24-byte BIOS E820 entry: byte-based [base, base+length) range. + * Preconditions: filled by BIOS int 0x15 or by the boot-sector fallback + * (single type-1 region at 1MB); length may be 0 (ignored by the PMM). + * Failure modes: none in C — a corrupt table only mis-marks frames. */ +struct e820_entry { + uint64_t base; + uint64_t length; + uint32_t type; + uint32_t acpi_attr; +} __attribute__((packed)); + +#endif /* NADIR_E820_H */ diff --git a/kernel/arch/x86_64/entry.asm b/kernel/arch/x86_64/entry.asm index 34e73db..47a87b0 100644 --- a/kernel/arch/x86_64/entry.asm +++ b/kernel/arch/x86_64/entry.asm @@ -9,8 +9,14 @@ ; ; Steps: verify long mode exists, identity-map the first 1GB with 2MB ; pages, enable PAE + LME + paging, reload a GDT with a 64-bit code -; segment, zero BSS, then call the C entry point kmain (System V ABI). +; segment, zero BSS, copy the BIOS memory map staged by stage 1 into +; kernel .bss, then call the C entry point kmain (System V ABI). ; Interrupts stay disabled for the whole sequence. +; +; WHY copy after zeroing: the map globals live in .bss, so zeroing first +; then copying keeps the staged entries. Zeroing after would wipe them; +; copying before is impossible (BSS addresses are only valid once paging +; and the zeroed state the C code expects are both in place). bits 32 section .boot32 @@ -18,11 +24,17 @@ global boot32_entry extern kmain extern __bss_start extern __bss_end +extern memmap_count +extern memmap_entries PML4 equ 0x70000 PDPT equ 0x71000 PD equ 0x72000 STACK64_TOP equ 0x90000 +MEMMAP_COUNT_PHYS equ 0x5000 ; dword staged by stage 1 +MEMMAP_BUF_PHYS equ 0x5020 ; 24-byte E820 entries staged by stage 1 +E820_MAX equ 64 +E820_ENTRY_SIZE equ 24 boot32_entry: ; --- CPUID: does this CPU do 64-bit long mode? --- @@ -121,6 +133,25 @@ long_entry: xor eax, eax rep stosb + ; --- copy staged E820 map into .bss globals (identity map covers + ; both 0x5000 and .bss, and paging is already on) --- + ; WHY byte + clamp: stage 1 stages a single count byte (64 max fits); + ; the clamp is belt-and-braces against a corrupt staging byte. + movzx eax, byte [abs MEMMAP_COUNT_PHYS] + cmp eax, E820_MAX + jbe .map_count_ok + mov eax, E820_MAX +.map_count_ok: + mov [rel memmap_count], eax + test eax, eax + jz .map_done + mov rsi, MEMMAP_BUF_PHYS + lea rdi, [rel memmap_entries] + mov ecx, eax + imul ecx, ecx, E820_ENTRY_SIZE ; bytes = count * 24 + rep movsb +.map_done: + call kmain ; first C code — does not return cli .hang: