From 370f7e8d229a19675ebb542c0e8749d3c45ea24c Mon Sep 17 00:00:00 2001 From: Justin Miller Date: Mon, 1 May 2023 09:24:13 -0700 Subject: [PATCH] [UEFI][ENVIRON] Enable UEFI boot for i386 and amd64 Add some some small fixes found during testing Implement UEFI keystrokes leave UEFI environment correctly and pass boot --- .../freeldr/arch/uefi/arch/amd64/uefiasm.S | 46 ++++++ .../freeldr/arch/uefi/arch/i386/uefiasm.S | 84 ++++++++++ boot/freeldr/freeldr/arch/uefi/stubs.c | 18 --- boot/freeldr/freeldr/arch/uefi/ueficon.c | 71 ++++++++ boot/freeldr/freeldr/arch/uefi/uefihw.c | 151 ++++++++++++++++++ boot/freeldr/freeldr/arch/uefi/uefimem.c | 11 ++ boot/freeldr/freeldr/arch/uefi/uefisetup.c | 1 - .../freeldr/freeldr/ntldr/arch/amd64/winldr.c | 40 +++++ boot/freeldr/freeldr/ntldr/arch/i386/winldr.c | 42 +++++ boot/freeldr/freeldr/ntldr/winldr.c | 4 + boot/freeldr/freeldr/ntldr/winldr.h | 4 + boot/freeldr/freeldr/uefi.cmake | 10 +- 12 files changed, 460 insertions(+), 22 deletions(-) create mode 100644 boot/freeldr/freeldr/arch/uefi/arch/amd64/uefiasm.S create mode 100644 boot/freeldr/freeldr/arch/uefi/arch/i386/uefiasm.S create mode 100644 boot/freeldr/freeldr/arch/uefi/uefihw.c diff --git a/boot/freeldr/freeldr/arch/uefi/arch/amd64/uefiasm.S b/boot/freeldr/freeldr/arch/uefi/arch/amd64/uefiasm.S new file mode 100644 index 0000000000000..61df7fac598fe --- /dev/null +++ b/boot/freeldr/freeldr/arch/uefi/arch/amd64/uefiasm.S @@ -0,0 +1,46 @@ +/* + * PROJECT: FreeLoader UEFI Support + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: UEFI assembly exit code + * COPYRIGHT: Copyright 2023 Justin Miller + */ + +#include +#include +#include + +.code64 +EXTERN UefiExitToKernel:PROC +EXTERN EndofExitStack:QWORD +PUBLIC gdtptr + +.align 8 +gdt: + .word HEX(0000), HEX(0000), HEX(0000), HEX(0000) /* 00: NULL descriptor */ + .word HEX(0000), HEX(0000), HEX(0000), HEX(0000) /* 08: */ + .word HEX(0000), HEX(0000), HEX(9800), HEX(0020) /* 10: long mode CS */ + .word HEX(FFFF), HEX(0000), HEX(F300), HEX(00CF) /* 18: long mode DS */ + .word HEX(FFFF), HEX(0000), HEX(9E00), HEX(0000) /* 20: 16-bit real mode CS */ + .word HEX(FFFF), HEX(0000), HEX(9200), HEX(0000) /* 28: 16-bit real mode DS */ + .word HEX(FFFF), HEX(0000), HEX(9B00), HEX(00CF) /* 30: compat mode CS */ + +/* GDT table pointer */ +gdtptr: + .word HEX(37) /* Limit */ +#ifdef _USE_ML + .quad gdt /* Base Address */ +#else + .long gdt, 0 /* Base Address */ +#endif + +PUBLIC __ExitUefi +__ExitUefi: +#ifdef _USE_ML + lgdt fword ptr gdtptr +#else + lgdt cs:gdtptr +#endif + mov rsp, EndofExitStack + call UefiExitToKernel + hlt +END diff --git a/boot/freeldr/freeldr/arch/uefi/arch/i386/uefiasm.S b/boot/freeldr/freeldr/arch/uefi/arch/i386/uefiasm.S new file mode 100644 index 0000000000000..919bf6d0fd361 --- /dev/null +++ b/boot/freeldr/freeldr/arch/uefi/arch/i386/uefiasm.S @@ -0,0 +1,84 @@ +/* + * PROJECT: FreeLoader UEFI Support + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: UEFI assembly exit code + * COPYRIGHT: Copyright 2023 Justin Miller + */ + +#include +#include +#include + +.code32 +PUBLIC _gdtptr +PUBLIC _i386idtptr +EXTERN _i386Idt:DWORD +EXTERN _EndofExitStack:DWORD +EXTERN _UefiExitToKernel:PROC + +// VOID _LeaveUEFIStack(VOID); +PUBLIC __LeaveUEFIStack +__LeaveUEFIStack: +#ifdef _USE_ML + lgdt fword ptr _gdtptr + lidt fword ptr ds:[_i386idtptr] +#else + lgdt cs:_gdtptr + lidt _i386idtptr +#endif + mov esp, _EndofExitStack + call _UefiExitToKernel + +// void __reloadsegment(VOID) +PUBLIC __reloadsegment +__reloadsegment: + mov ax, PMODE_DS + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + nop + ret + + .align 4 /* force 4-byte alignment */ +gdt: + /* NULL Descriptor */ + .word HEX(0000) + .word HEX(0000) + .word HEX(0000) + .word HEX(0000) + + /* 32-bit flat CS */ + .word HEX(FFFF) + .word HEX(0000) + .word HEX(9A00) + .word HEX(00CF) + + /* 32-bit flat DS */ + .word HEX(FFFF) + .word HEX(0000) + .word HEX(9200) + .word HEX(00CF) + + /* 16-bit real mode CS */ + .word HEX(FFFF) + .word HEX(0000) + .word HEX(9E00) + .word HEX(0000) + + /* 16-bit real mode DS */ + .word HEX(FFFF) + .word HEX(0000) + .word HEX(9200) + .word HEX(0000) + +/* GDT table pointer */ +_gdtptr: + .word HEX(27) /* Limit */ + .long gdt, 0 /* Base Address */ + +_i386idtptr: + .word 255 /* Limit */ + .long _i386Idt /* Base Address */ +END diff --git a/boot/freeldr/freeldr/arch/uefi/stubs.c b/boot/freeldr/freeldr/arch/uefi/stubs.c index 513f9f8f85df7..0cd3e1270f89b 100644 --- a/boot/freeldr/freeldr/arch/uefi/stubs.c +++ b/boot/freeldr/freeldr/arch/uefi/stubs.c @@ -50,30 +50,12 @@ UefiGetExtendedBIOSData(PULONG ExtendedBIOSDataArea, } -PCONFIGURATION_COMPONENT_DATA -UefiHwDetect(VOID) -{ - return 0; -} - VOID UefiPcBeep(VOID) { /* Not possible on UEFI, for now */ } -BOOLEAN -UefiConsKbHit(VOID) -{ - return FALSE; -} - -int -UefiConsGetCh(void) -{ - return 0; -} - VOID UefiHwIdle(VOID) { diff --git a/boot/freeldr/freeldr/arch/uefi/ueficon.c b/boot/freeldr/freeldr/arch/uefi/ueficon.c index 944d9707bc753..ab94c45cdee2f 100644 --- a/boot/freeldr/freeldr/arch/uefi/ueficon.c +++ b/boot/freeldr/freeldr/arch/uefi/ueficon.c @@ -16,6 +16,8 @@ extern EFI_SYSTEM_TABLE* GlobalSystemTable; static unsigned CurrentCursorX = 0; static unsigned CurrentCursorY = 0; static unsigned CurrentAttr = 0x0f; +static EFI_INPUT_KEY Key; +static BOOLEAN scancode; /* FUNCTIONS ******************************************************************/ @@ -59,3 +61,72 @@ UefiConsPutChar(int c) CurrentCursorY++; } } + +/* Read into the public Keystroke handler */ +BOOLEAN +UefiConsKbHit(VOID) +{ + Key.UnicodeChar = 0; + Key.ScanCode = 0; + GlobalSystemTable->ConIn->ReadKeyStroke(GlobalSystemTable->ConIn, &Key); + + if (Key.UnicodeChar != 0) + { + scancode = FALSE; + return TRUE; + } + else if (Key.ScanCode != 0) + { + scancode = TRUE; + return TRUE; + } + + return FALSE; +} + +int +UefiConsGetCh(void) +{ + /* The UEFI Scan codes are in an entirely different order than BIOS. */ + if (scancode) + { + switch (Key.ScanCode) + { + case SCAN_UP: + return KEY_UP; + case SCAN_DOWN: + return KEY_DOWN; + case SCAN_RIGHT: + return KEY_RIGHT; + case SCAN_LEFT: + return KEY_LEFT; + case SCAN_F1: + return KEY_F1; + case SCAN_F2: + return KEY_F2; + case SCAN_F3: + return KEY_F3; + case SCAN_F4: + return KEY_F4; + case SCAN_F5: + return KEY_F5; + case SCAN_F6: + return KEY_F6; + case SCAN_F7: + return KEY_F7; + case SCAN_F8: + return KEY_F8; + case SCAN_F9: + return KEY_F9; + case SCAN_F10: + return KEY_F10; + case SCAN_ESC: + return KEY_ESC; + } + return Key.ScanCode; + } + else + { + return Key.UnicodeChar; + } +} diff --git a/boot/freeldr/freeldr/arch/uefi/uefihw.c b/boot/freeldr/freeldr/arch/uefi/uefihw.c new file mode 100644 index 0000000000000..57a6e1f71dfb6 --- /dev/null +++ b/boot/freeldr/freeldr/arch/uefi/uefihw.c @@ -0,0 +1,151 @@ +/* + * PROJECT: FreeLoader UEFI Support + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Hardware detection routines + * COPYRIGHT: Copyright 2022 Justin Miller + */ + +/* INCLUDES ******************************************************************/ + +#include + +#include +DBG_DEFAULT_CHANNEL(WARNING); + +/* GLOBALS *******************************************************************/ + +extern EFI_SYSTEM_TABLE * GlobalSystemTable; +extern EFI_HANDLE GlobalImageHandle; +extern UCHAR PcBiosDiskCount; +extern EFI_MEMORY_DESCRIPTOR* EfiMemoryMap; +extern UINT32 FreeldrDescCount; + +BOOLEAN AcpiPresent = FALSE; + +/* FUNCTIONS *****************************************************************/ + +static +PRSDP_DESCRIPTOR +FindAcpiBios(VOID) +{ + UINT32 i; + RSDP_DESCRIPTOR* rsdp = NULL; + EFI_GUID acpi2_guid = EFI_ACPI_20_TABLE_GUID; + + for (i = 0; i < GlobalSystemTable->NumberOfTableEntries; i++) + { + if (!memcmp(&GlobalSystemTable->ConfigurationTable[i].VendorGuid, &acpi2_guid, sizeof(EFI_GUID))) + { + rsdp = (RSDP_DESCRIPTOR*)GlobalSystemTable->ConfigurationTable[i].VendorTable; + break; + } + } + + return rsdp; +} + +static +VOID +DetectAcpiBios(PCONFIGURATION_COMPONENT_DATA SystemKey, ULONG *BusNumber) +{ + PCONFIGURATION_COMPONENT_DATA BiosKey; + PCM_PARTIAL_RESOURCE_LIST PartialResourceList; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; + PRSDP_DESCRIPTOR Rsdp; + PACPI_BIOS_DATA AcpiBiosData; + ULONG TableSize; + + Rsdp = FindAcpiBios(); + + if (Rsdp) + { + /* Set up the flag in the loader block */ + AcpiPresent = TRUE; + + /* Calculate the table size */ + TableSize = FreeldrDescCount * sizeof(BIOS_MEMORY_MAP) + + sizeof(ACPI_BIOS_DATA) - sizeof(BIOS_MEMORY_MAP); + + /* Set 'Configuration Data' value */ + PartialResourceList = FrLdrHeapAlloc(sizeof(CM_PARTIAL_RESOURCE_LIST) + + TableSize, TAG_HW_RESOURCE_LIST); + if (PartialResourceList == NULL) + { + ERR("Failed to allocate resource descriptor\n"); + return; + } + + RtlZeroMemory(PartialResourceList, sizeof(CM_PARTIAL_RESOURCE_LIST) + TableSize); + PartialResourceList->Version = 0; + PartialResourceList->Revision = 0; + PartialResourceList->Count = 1; + + PartialDescriptor = &PartialResourceList->PartialDescriptors[0]; + PartialDescriptor->Type = CmResourceTypeDeviceSpecific; + PartialDescriptor->ShareDisposition = CmResourceShareUndetermined; + PartialDescriptor->u.DeviceSpecificData.DataSize = TableSize; + + /* Fill the table */ + AcpiBiosData = (PACPI_BIOS_DATA)&PartialResourceList->PartialDescriptors[1]; + + if (Rsdp->revision > 0) + { + TRACE("ACPI >1.0, using XSDT address\n"); + AcpiBiosData->RSDTAddress.QuadPart = Rsdp->xsdt_physical_address; + } + else + { + TRACE("ACPI 1.0, using RSDT address\n"); + AcpiBiosData->RSDTAddress.LowPart = Rsdp->rsdt_physical_address; + } + + AcpiBiosData->Count = FreeldrDescCount; + memcpy(AcpiBiosData->MemoryMap, EfiMemoryMap, + FreeldrDescCount * sizeof(BIOS_MEMORY_MAP)); + + TRACE("RSDT %p, data size %x\n", Rsdp->rsdt_physical_address, + TableSize); + + /* Create new bus key */ + FldrCreateComponentKey(SystemKey, + AdapterClass, + MultiFunctionAdapter, + 0x0, + 0x0, + 0xFFFFFFFF, + "ACPI BIOS", + PartialResourceList, + sizeof(CM_PARTIAL_RESOURCE_LIST) + TableSize, + &BiosKey); + + /* Increment bus number */ + (*BusNumber)++; + } +} + +PCONFIGURATION_COMPONENT_DATA +UefiHwDetect(VOID) +{ + PCONFIGURATION_COMPONENT_DATA SystemKey; + ULONG BusNumber = 0; + + TRACE("DetectHardware()\n"); + + /* Create the 'System' key */ + FldrCreateSystemKey(&SystemKey); +#if defined(_M_IX86) || defined(_M_AMD64) /* Taken from Windows 11 */ + FldrSetIdentifier(SystemKey, "AT/AT COMPATIBLE"); +#elif defined(_M_IA64) /* Taken from Windows XP 64-bit*/ + FldrSetIdentifier(SystemKey, "Intel Itanium processor family"); +#elif defined(_M_ARM) || defined(_M_ARM64) /* Taken from Windows RT/11 */ + FldrSetIdentifier(SystemKey, "ARM processor family"); +#else + #error "Please define a system key for your architecture" +#endif + + /* Detect ACPI */ + DetectAcpiBios(SystemKey, &BusNumber); + + TRACE("DetectHardware() Done\n"); + return SystemKey; +} diff --git a/boot/freeldr/freeldr/arch/uefi/uefimem.c b/boot/freeldr/freeldr/arch/uefi/uefimem.c index 03a62150ef966..68df64099c09e 100644 --- a/boot/freeldr/freeldr/arch/uefi/uefimem.c +++ b/boot/freeldr/freeldr/arch/uefi/uefimem.c @@ -27,6 +27,7 @@ AddMemoryDescriptor( /* GLOBALS *******************************************************************/ +extern ULONG LoaderPagesSpanned; extern EFI_SYSTEM_TABLE* GlobalSystemTable; extern EFI_HANDLE GlobalImageHandle; extern REACTOS_INTERNAL_BGCONTEXT framebufferData; @@ -256,6 +257,16 @@ UefiMemGetMemoryMap(ULONG *MemoryMapSize) } } + /* Sometimes our loader can be loaded into higher memory than we ever allocate */ + if (MemoryType == LoaderLoadedProgram) + { + if ((MapEntry->PhysicalStart / EFI_PAGE_SIZE) > LoaderPagesSpanned) + { + /* This value needs to be adjusted if this occurs */ + LoaderPagesSpanned = (MapEntry->PhysicalStart / EFI_PAGE_SIZE); + } + } + UefiSetMemory(FreeldrMem, MapEntry->PhysicalStart, MapEntry->NumberOfPages, diff --git a/boot/freeldr/freeldr/arch/uefi/uefisetup.c b/boot/freeldr/freeldr/arch/uefi/uefisetup.c index 01d1be758a1b0..ec3b0d405a6c6 100644 --- a/boot/freeldr/freeldr/arch/uefi/uefisetup.c +++ b/boot/freeldr/freeldr/arch/uefi/uefisetup.c @@ -14,7 +14,6 @@ DBG_DEFAULT_CHANNEL(WARNING); extern EFI_SYSTEM_TABLE* GlobalSystemTable; extern EFI_HANDLE GlobalImageHandle; -BOOLEAN AcpiPresent = FALSE; /* FUNCTIONS ******************************************************************/ diff --git a/boot/freeldr/freeldr/ntldr/arch/amd64/winldr.c b/boot/freeldr/freeldr/ntldr/arch/amd64/winldr.c index 5c8043728442c..bf258bf31b2a6 100644 --- a/boot/freeldr/freeldr/ntldr/arch/amd64/winldr.c +++ b/boot/freeldr/freeldr/ntldr/arch/amd64/winldr.c @@ -429,3 +429,43 @@ VOID MempDump(VOID) { } + +#ifdef UEFIBOOT +PLOADER_PARAMETER_BLOCK PubLoaderBlockVA; +KERNEL_ENTRY_POINT PubKiSystemStartup; + +extern ULONG LoaderPagesSpanned; + +void __ExitUefi(VOID); + +VOID +WinldrFinalizeBoot(PLOADER_PARAMETER_BLOCK LoaderBlockVA, + KERNEL_ENTRY_POINT KiSystemStartup) +{ + TRACE("Preparing to jump to kernel\n"); + PubLoaderBlockVA = LoaderBlockVA; + PubKiSystemStartup = KiSystemStartup; + __ExitUefi(); +} + +VOID +UefiExitToKernel(VOID) +{ + WinLdrSetProcessorContext(); + + /* Save final value of LoaderPagesSpanned */ + PubLoaderBlockVA->Extension->LoaderPagesSpanned = LoaderPagesSpanned; + + TRACE("Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n", + PubKiSystemStartup, PubLoaderBlockVA); + + /* Zero KI_USER_SHARED_DATA page */ + RtlZeroMemory((PVOID)KI_USER_SHARED_DATA, MM_PAGE_SIZE); + + WinLdrpDumpMemoryDescriptors(PubLoaderBlockVA); + WinLdrpDumpBootDriver(PubLoaderBlockVA); + + /* Pass control */ + (*PubKiSystemStartup)(PubLoaderBlockVA); +} +#endif diff --git a/boot/freeldr/freeldr/ntldr/arch/i386/winldr.c b/boot/freeldr/freeldr/ntldr/arch/i386/winldr.c index ec91b7313a159..91c27d1df1bb6 100644 --- a/boot/freeldr/freeldr/ntldr/arch/i386/winldr.c +++ b/boot/freeldr/freeldr/ntldr/arch/i386/winldr.c @@ -744,3 +744,45 @@ MempDump(VOID) } } #endif + +#ifdef UEFIBOOT +PLOADER_PARAMETER_BLOCK PubLoaderBlockVA; +KERNEL_ENTRY_POINT PubKiSystemStartup; + +extern ULONG LoaderPagesSpanned; + +VOID _LeaveUEFIStack(VOID); + +VOID +WinldrFinalizeBoot(PLOADER_PARAMETER_BLOCK LoaderBlockVA, + KERNEL_ENTRY_POINT KiSystemStartup) +{ + TRACE("Preparing to jump to kernel\n"); + PubLoaderBlockVA = LoaderBlockVA; + PubKiSystemStartup = KiSystemStartup; + _LeaveUEFIStack(); +} + +VOID +UefiExitToKernel(VOID) +{ + WinLdrSetProcessorContext(); + + /* Save final value of LoaderPagesSpanned */ + PubLoaderBlockVA->Extension->LoaderPagesSpanned = LoaderPagesSpanned; + + TRACE("Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n", + PubKiSystemStartup, PubLoaderBlockVA); + + /* Zero KI_USER_SHARED_DATA page */ + RtlZeroMemory((PVOID)KI_USER_SHARED_DATA, MM_PAGE_SIZE); + + WinLdrpDumpMemoryDescriptors(PubLoaderBlockVA); + WinLdrpDumpBootDriver(PubLoaderBlockVA); + WinLdrpDumpArcDisks(PubLoaderBlockVA); + + /* Pass control */ + (*PubKiSystemStartup)(PubLoaderBlockVA); +} + +#endif diff --git a/boot/freeldr/freeldr/ntldr/winldr.c b/boot/freeldr/freeldr/ntldr/winldr.c index 9f51a5417218b..e81240f7752f0 100644 --- a/boot/freeldr/freeldr/ntldr/winldr.c +++ b/boot/freeldr/freeldr/ntldr/winldr.c @@ -1238,6 +1238,10 @@ LoadAndBootWindowsCommon( /* Map pages and create memory descriptors */ WinLdrSetupMemoryLayout(LoaderBlock); +#ifdef UEFIBOOT + WinldrFinalizeBoot(LoaderBlockVA, KiSystemStartup); +#endif + /* Set processor context */ WinLdrSetProcessorContext(); diff --git a/boot/freeldr/freeldr/ntldr/winldr.h b/boot/freeldr/freeldr/ntldr/winldr.h index 20a20ba7cce02..7a9b900cadfa8 100644 --- a/boot/freeldr/freeldr/ntldr/winldr.h +++ b/boot/freeldr/freeldr/ntldr/winldr.h @@ -172,6 +172,10 @@ MempSetupPaging(IN PFN_NUMBER StartPage, IN PFN_NUMBER NumberOfPages, IN BOOLEAN KernelMapping); +VOID +WinldrFinalizeBoot(PLOADER_PARAMETER_BLOCK LoaderBlockVA, + KERNEL_ENTRY_POINT KiSystemStartup); + VOID MempUnmapPage(PFN_NUMBER Page); diff --git a/boot/freeldr/freeldr/uefi.cmake b/boot/freeldr/freeldr/uefi.cmake index 76483f0529ef2..7ce9cda354960 100644 --- a/boot/freeldr/freeldr/uefi.cmake +++ b/boot/freeldr/freeldr/uefi.cmake @@ -16,6 +16,7 @@ list(APPEND UEFILDR_ARC_SOURCE arch/uefi/stubs.c arch/uefi/ueficon.c arch/uefi/uefidisk.c + arch/uefi/uefihw.c arch/uefi/uefimem.c arch/uefi/uefisetup.c arch/uefi/uefiutil.c @@ -24,10 +25,13 @@ list(APPEND UEFILDR_ARC_SOURCE if(ARCH STREQUAL "i386") list(APPEND UEFILDR_COMMON_ASM_SOURCE - arch/i386/i386trap.S) - + arch/i386/i386trap.S + arch/uefi/arch/i386/uefiasm.S) + list(APPEND UEFILDR_ARC_SOURCE + arch/i386/i386idt.c) elseif(ARCH STREQUAL "amd64") - #TBD + list(APPEND UEFILDR_COMMON_ASM_SOURCE + arch/uefi/arch/amd64/uefiasm.S) elseif(ARCH STREQUAL "arm") list(APPEND UEFILDR_ARC_SOURCE arch/arm/macharm.c