Loads the kernel from the ESP, places its ELF segments, records the framebuffer, translates the UEFI memory map into E820 entries, exits boot services, builds the page tables the kernel expects and jumps. Verified under OVMF: the kernel starts, brings up PCI, VGA, e1000 and the RTC, and reaches "cpu0: starting". UEFI structures are written from the specification rather than importing gnu-efi or EDK II -- a large dependency for two hundred lines of use, and a licensing question the project does not need to answer. clang emits PE/COFF directly, so this needs no new toolchain. The kernel gained a second entry point. The multiboot entry is 32-bit code that climbs into long mode itself, and firmware that already put us there would have to drop back down only to climb out again -- a mode switch whose failure mode is a triple fault with no console. So entry.S publishes its 64-bit entry the same way it publishes the multiboot header: a magic to scan for, SCH64BOO, with include/schboot.h owning the constants so the two cannot disagree. That header goes *after* the multiboot header, never before: header_addr says the multiboot header lives at mboot_load_addr, and the BIOS loader computes the kernel's file offset from it. The kernel loads its own GDT at that entry rather than the loader doing it. Arriving in long mode means arriving on the firmware's descriptors, and the first thing depending on the kernel's own selectors faulted -- "unexpected trap 13 ... cs=38", a long way from the cause. KNOWN LIMITATION, diagnosed and not yet fixed: e820_init takes the usable run *containing the kernel*, which under OVMF ends at 8 MB -- the firmware places an ACPI NVS region at 0x800000, so the run is genuinely fragmented. The map is truthful and untruncated (21 entries); the assumption of one contiguous run is BIOS-shaped. The fix is for the kernel to free each usable region rather than one range, which touches kalloc and deserves its own change rather than the tail of this one. BIOS boot is unaffected: 27 checks, no failures.
36 lines
1.3 KiB
C
36 lines
1.3 KiB
C
// SPDX-License-Identifier: Apache-2.0
|
|
#pragma once
|
|
#ifndef SCHBOOT_H
|
|
#define SCHBOOT_H
|
|
|
|
// The loader/kernel hand-off, in one place.
|
|
//
|
|
// Included by kernel/arch/x86_64/entry.S and by boot/uefi/main.c, so the two
|
|
// cannot disagree about the magic or the layout. Defining it twice is exactly
|
|
// how a loader ends up scanning for bytes the kernel never wrote — the first
|
|
// attempt here searched for "SCH6" while the assembler had stored 0x53434836,
|
|
// which lands in the file as "6HCS".
|
|
//
|
|
// Keep this header assembler-safe: no typedefs, no structs outside the C
|
|
// guard, nothing entry.S cannot preprocess.
|
|
|
|
// Scanned for in the first 16 KB of the kernel image, 8-byte aligned, exactly
|
|
// as the BIOS loader scans for the multiboot magic. Followed by a little-endian
|
|
// 64-bit physical address: the kernel's 64-bit entry point.
|
|
//
|
|
// The values spell "SCH6" "4BOO" when stored little-endian, which is what
|
|
// makes them findable by eye in a hex dump of the image.
|
|
#define SCH64_MAGIC0 0x36484353 /* "SCH6" */
|
|
#define SCH64_MAGIC1 0x4f4f4234 /* "4BOO" */
|
|
|
|
#ifndef __ASSEMBLER__
|
|
|
|
struct sch64_header {
|
|
unsigned int magic0; // SCH64_MAGIC0
|
|
unsigned int magic1; // SCH64_MAGIC1
|
|
unsigned long long entry; // physical address, entered in long mode
|
|
};
|
|
|
|
#endif /* !__ASSEMBLER__ */
|
|
|
|
#endif /* SCHBOOT_H */
|