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>
277 lines
10 KiB
C
277 lines
10 KiB
C
// SPDX-License-Identifier: Apache-2.0
|
|
#pragma once
|
|
#ifndef SCHOS_EFI_H
|
|
#define SCHOS_EFI_H
|
|
|
|
// The parts of UEFI this loader actually uses, written from the
|
|
// specification.
|
|
//
|
|
// Not gnu-efi and not EDK II. Both are large dependencies for something this
|
|
// small, and both raise a licensing question the project does not need to
|
|
// answer -- see docs/licensing.md. What is here is the handful of structures
|
|
// and function pointers needed to read a file, ask for the framebuffer, take
|
|
// the memory map and leave: perhaps two hundred lines against tens of
|
|
// thousands.
|
|
//
|
|
// Everything is called through function pointers in tables the firmware hands
|
|
// us, using the Microsoft x64 calling convention. clang's
|
|
// --target=x86_64-unknown-windows produces that natively, which is why no
|
|
// __attribute__((ms_abi)) appears anywhere below.
|
|
//
|
|
// Fields this loader never touches are left as `void *` padding rather than
|
|
// spelled out. The offsets are what matter and they are preserved exactly;
|
|
// naming a field we do not use would only invite it to drift.
|
|
|
|
typedef unsigned char UINT8;
|
|
typedef unsigned short UINT16;
|
|
typedef unsigned int UINT32;
|
|
typedef unsigned long long UINT64;
|
|
typedef long long INTN;
|
|
typedef unsigned long long UINTN;
|
|
typedef UINT16 CHAR16;
|
|
typedef UINT8 BOOLEAN;
|
|
typedef void *EFI_HANDLE;
|
|
typedef UINTN EFI_STATUS;
|
|
typedef UINT64 EFI_PHYSICAL_ADDRESS;
|
|
typedef UINT64 EFI_VIRTUAL_ADDRESS;
|
|
|
|
#define EFI_SUCCESS 0
|
|
#define EFI_BUFFER_TOO_SMALL ((EFI_STATUS)(0x8000000000000000ULL | 5))
|
|
#define EFI_ERROR(s) (((INTN)(s)) < 0)
|
|
|
|
typedef struct {
|
|
UINT32 Data1;
|
|
UINT16 Data2;
|
|
UINT16 Data3;
|
|
UINT8 Data4[8];
|
|
} EFI_GUID;
|
|
|
|
// --- memory ---------------------------------------------------------------
|
|
|
|
typedef enum {
|
|
AllocateAnyPages,
|
|
AllocateMaxAddress,
|
|
AllocateAddress
|
|
} EFI_ALLOCATE_TYPE;
|
|
|
|
// Only the types this loader has to reason about are named. The rule it
|
|
// applies is simply which of them are free for the kernel to use.
|
|
#define EfiReservedMemoryType 0
|
|
#define EfiLoaderCode 1
|
|
#define EfiLoaderData 2
|
|
#define EfiBootServicesCode 3
|
|
#define EfiBootServicesData 4
|
|
#define EfiRuntimeServicesCode 5
|
|
#define EfiRuntimeServicesData 6
|
|
#define EfiConventionalMemory 7
|
|
#define EfiUnusableMemory 8
|
|
#define EfiACPIReclaimMemory 9
|
|
#define EfiACPIMemoryNVS 10
|
|
#define EfiMemoryMappedIO 11
|
|
#define EfiMemoryMappedIOPortSpace 12
|
|
#define EfiPalCode 13
|
|
#define EfiPersistentMemory 14
|
|
|
|
typedef struct {
|
|
UINT32 Type;
|
|
UINT32 Pad;
|
|
EFI_PHYSICAL_ADDRESS PhysicalStart;
|
|
EFI_VIRTUAL_ADDRESS VirtualStart;
|
|
UINT64 NumberOfPages;
|
|
UINT64 Attribute;
|
|
} EFI_MEMORY_DESCRIPTOR;
|
|
|
|
// --- simple text output ---------------------------------------------------
|
|
|
|
typedef struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
|
|
void *Reset;
|
|
EFI_STATUS (*OutputString)(struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
|
|
CHAR16 *String);
|
|
void *TestString;
|
|
void *QueryMode;
|
|
void *SetMode;
|
|
void *SetAttribute;
|
|
EFI_STATUS (*ClearScreen)(struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This);
|
|
void *SetCursorPosition;
|
|
void *EnableCursor;
|
|
void *Mode;
|
|
} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
|
|
|
|
// --- boot services --------------------------------------------------------
|
|
|
|
typedef struct {
|
|
char Hdr[24];
|
|
void *RaiseTPL;
|
|
void *RestoreTPL;
|
|
|
|
EFI_STATUS (*AllocatePages)(EFI_ALLOCATE_TYPE Type, UINTN MemoryType,
|
|
UINTN Pages, EFI_PHYSICAL_ADDRESS *Memory);
|
|
EFI_STATUS (*FreePages)(EFI_PHYSICAL_ADDRESS Memory, UINTN Pages);
|
|
EFI_STATUS (*GetMemoryMap)(UINTN *MemoryMapSize,
|
|
EFI_MEMORY_DESCRIPTOR *MemoryMap,
|
|
UINTN *MapKey, UINTN *DescriptorSize,
|
|
UINT32 *DescriptorVersion);
|
|
EFI_STATUS (*AllocatePool)(UINTN PoolType, UINTN Size, void **Buffer);
|
|
EFI_STATUS (*FreePool)(void *Buffer);
|
|
|
|
void *CreateEvent;
|
|
void *SetTimer;
|
|
void *WaitForEvent;
|
|
void *SignalEvent;
|
|
void *CloseEvent;
|
|
void *CheckEvent;
|
|
|
|
void *InstallProtocolInterface;
|
|
void *ReinstallProtocolInterface;
|
|
void *UninstallProtocolInterface;
|
|
EFI_STATUS (*HandleProtocol)(EFI_HANDLE Handle, EFI_GUID *Protocol,
|
|
void **Interface);
|
|
void *Reserved;
|
|
void *RegisterProtocolNotify;
|
|
void *LocateHandle;
|
|
void *LocateDevicePath;
|
|
void *InstallConfigurationTable;
|
|
|
|
void *LoadImage;
|
|
void *StartImage;
|
|
void *Exit;
|
|
void *UnloadImage;
|
|
EFI_STATUS (*ExitBootServices)(EFI_HANDLE ImageHandle, UINTN MapKey);
|
|
|
|
void *GetNextMonotonicCount;
|
|
EFI_STATUS (*Stall)(UINTN Microseconds);
|
|
void *SetWatchdogTimer;
|
|
|
|
void *ConnectController;
|
|
void *DisconnectController;
|
|
|
|
void *OpenProtocol;
|
|
void *CloseProtocol;
|
|
void *OpenProtocolInformation;
|
|
|
|
void *ProtocolsPerHandle;
|
|
void *LocateHandleBuffer;
|
|
EFI_STATUS (*LocateProtocol)(EFI_GUID *Protocol, void *Registration,
|
|
void **Interface);
|
|
} EFI_BOOT_SERVICES;
|
|
|
|
typedef struct {
|
|
char Hdr[24];
|
|
CHAR16 *FirmwareVendor;
|
|
UINT32 FirmwareRevision;
|
|
EFI_HANDLE ConsoleInHandle;
|
|
void *ConIn;
|
|
EFI_HANDLE ConsoleOutHandle;
|
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
|
|
EFI_HANDLE StandardErrorHandle;
|
|
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
|
|
void *RuntimeServices;
|
|
EFI_BOOT_SERVICES *BootServices;
|
|
UINTN NumberOfTableEntries;
|
|
void *ConfigurationTable;
|
|
} EFI_SYSTEM_TABLE;
|
|
|
|
// --- configuration tables -------------------------------------------------
|
|
//
|
|
// Where UEFI publishes things a BIOS left lying in low memory. The ACPI RSDP is
|
|
// the one that matters here: the kernel finds it by scanning the EBDA and
|
|
// 0xE0000-0x100000, which is a BIOS convention that firmware is under no
|
|
// obligation to honour -- and OVMF does not.
|
|
|
|
#define EFI_ACPI_20_TABLE_GUID \
|
|
{ 0x8868E871, 0xE4F1, 0x11D3, { 0xBC, 0x22, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 } }
|
|
#define EFI_ACPI_10_TABLE_GUID \
|
|
{ 0xEB9D2D30, 0x2D88, 0x11D3, { 0x9A, 0x16, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D } }
|
|
|
|
typedef struct {
|
|
EFI_GUID VendorGuid;
|
|
void *VendorTable;
|
|
} EFI_CONFIGURATION_TABLE;
|
|
|
|
// --- loaded image ---------------------------------------------------------
|
|
|
|
#define EFI_LOADED_IMAGE_PROTOCOL_GUID \
|
|
{ 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } }
|
|
|
|
typedef struct {
|
|
UINT32 Revision;
|
|
EFI_HANDLE ParentHandle;
|
|
void *SystemTable;
|
|
EFI_HANDLE DeviceHandle; // the volume this image was loaded from
|
|
void *FilePath;
|
|
void *Reserved;
|
|
UINT32 LoadOptionsSize;
|
|
void *LoadOptions;
|
|
void *ImageBase;
|
|
UINT64 ImageSize;
|
|
UINTN ImageCodeType;
|
|
UINTN ImageDataType;
|
|
void *Unload;
|
|
} EFI_LOADED_IMAGE_PROTOCOL;
|
|
|
|
// --- file system ----------------------------------------------------------
|
|
|
|
#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
|
|
{ 0x0964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } }
|
|
|
|
#define EFI_FILE_MODE_READ 0x0000000000000001ULL
|
|
|
|
typedef struct EFI_FILE_PROTOCOL {
|
|
UINT64 Revision;
|
|
EFI_STATUS (*Open)(struct EFI_FILE_PROTOCOL *This,
|
|
struct EFI_FILE_PROTOCOL **NewHandle,
|
|
CHAR16 *FileName, UINT64 OpenMode, UINT64 Attributes);
|
|
EFI_STATUS (*Close)(struct EFI_FILE_PROTOCOL *This);
|
|
void *Delete;
|
|
EFI_STATUS (*Read)(struct EFI_FILE_PROTOCOL *This, UINTN *BufferSize,
|
|
void *Buffer);
|
|
void *Write;
|
|
EFI_STATUS (*GetPosition)(struct EFI_FILE_PROTOCOL *This, UINT64 *Position);
|
|
EFI_STATUS (*SetPosition)(struct EFI_FILE_PROTOCOL *This, UINT64 Position);
|
|
void *GetInfo;
|
|
void *SetInfo;
|
|
void *Flush;
|
|
} EFI_FILE_PROTOCOL;
|
|
|
|
typedef struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL {
|
|
UINT64 Revision;
|
|
EFI_STATUS (*OpenVolume)(struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
|
|
EFI_FILE_PROTOCOL **Root);
|
|
} EFI_SIMPLE_FILE_SYSTEM_PROTOCOL;
|
|
|
|
// --- graphics output ------------------------------------------------------
|
|
|
|
#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID \
|
|
{ 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A } }
|
|
|
|
#define PixelRedGreenBlueReserved8BitPerColor 0
|
|
#define PixelBlueGreenRedReserved8BitPerColor 1
|
|
#define PixelBitMask 2
|
|
#define PixelBltOnly 3
|
|
|
|
typedef struct {
|
|
UINT32 Version;
|
|
UINT32 HorizontalResolution;
|
|
UINT32 VerticalResolution;
|
|
UINT32 PixelFormat;
|
|
UINT32 PixelInformation[4];
|
|
UINT32 PixelsPerScanLine;
|
|
} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION;
|
|
|
|
typedef struct {
|
|
UINT32 Mode;
|
|
UINT32 MaxMode;
|
|
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
|
|
UINTN SizeOfInfo;
|
|
EFI_PHYSICAL_ADDRESS FrameBufferBase;
|
|
UINTN FrameBufferSize;
|
|
} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE;
|
|
|
|
typedef struct EFI_GRAPHICS_OUTPUT_PROTOCOL {
|
|
void *QueryMode;
|
|
void *SetMode;
|
|
void *Blt;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode;
|
|
} EFI_GRAPHICS_OUTPUT_PROTOCOL;
|
|
|
|
#endif /* SCHOS_EFI_H */
|