acpi: take the RSDP from the loader when firmware gives it to us
find_rsdp() scanned the EBDA and 0xE0000-0x100000. That is a BIOS convention, and UEFI firmware is under no obligation to leave a copy there -- OVMF does not. So the kernel found no RSDP, no MADT and no IOAPIC, and nothing routed IRQ 4. Serial output is polled, so the machine booted all the way to a shell prompt and then ignored every key, which reads as a broken console rather than a missing table. The UEFI loader reads the RSDP out of the EFI configuration table, preferring ACPI 2.0 for its XSDT, and leaves it at SCHBOOT_RSDP_ADDR -- the same low-memory hand-off block the e820 map already uses, now described in include/schboot.h so the two sides cannot disagree. The kernel validates it rather than trusting it: the BIOS path never writes that slot, so there it holds whatever was in memory, and following a wild pointer faults before there is anything to report the fault with. Signature and checksum do that. It deliberately does not require 16-byte alignment -- that rule is about searching the BIOS area, and OVMF's RSDP sits at 0x3f77e014, so demanding it threw away the one address this code exists to use. UEFI now reports "acpi: 1 cpu, lapic at ..., ioapic id 0" and the ISO boots to an interactive shell: uname, ls /bin (241), writing and reading a file, ps, /proc/schfs -- all driven over serial. BIOS unchanged: bootcheck 108 [ok], same ACPI line as before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
61b35a1f71
commit
9735279970
4 changed files with 101 additions and 0 deletions
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "types.h"
|
||||
#include "defs.h"
|
||||
#include "schboot.h" // SCHBOOT_RSDP_ADDR: the loader/kernel hand-off
|
||||
#include "param.h"
|
||||
#include "memlayout.h"
|
||||
#include "mmu.h"
|
||||
|
|
@ -134,6 +135,28 @@ scan_rsdp(uint64 base, uint64 len)
|
|||
static struct acpi_rsdp *
|
||||
find_rsdp(void)
|
||||
{
|
||||
// A UEFI loader hands the address over directly, because the scan below is a
|
||||
// BIOS convention that UEFI firmware need not honour and OVMF does not: the
|
||||
// kernel found no RSDP, so no MADT, so no IOAPIC, and nothing routed IRQ 4 --
|
||||
// it reached a shell prompt on polled serial output and then ignored every
|
||||
// key.
|
||||
//
|
||||
// Validated, never trusted. The BIOS path does not write this slot, so there
|
||||
// it holds whatever happened to be in memory, and following a wild pointer
|
||||
// faults before there is anything to report the fault with. The bound is what
|
||||
// the direct map covers; the signature and checksum below do the rest.
|
||||
//
|
||||
// Deliberately *not* requiring 16-byte alignment. That rule applies to
|
||||
// searching the BIOS area, not to a pointer handed over by firmware -- OVMF's
|
||||
// sits at 0x3f77e014, and demanding alignment threw away the very address
|
||||
// this code was added to use.
|
||||
uint64 handed = *(uint64 *)P2V(SCHBOOT_RSDP_ADDR);
|
||||
if (handed && handed < 0x100000000ULL) {
|
||||
struct acpi_rsdp *r = (struct acpi_rsdp *)P2V(handed);
|
||||
if (memcmp(r->sig, "RSD PTR ", 8) == 0 && checksum_ok(r, 20))
|
||||
return r;
|
||||
}
|
||||
|
||||
// The EBDA, whose segment address the BIOS leaves at 0x40E.
|
||||
uint16 ebda_seg = *(uint16 *)P2V(0x40E);
|
||||
if (ebda_seg) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue