From de0ca39bcf728213f15f46e2941207621a4ad794 Mon Sep 17 00:00:00 2001 From: Justin Miller Date: Mon, 1 May 2023 09:24:13 -0700 Subject: [PATCH] [FREELDR] Enable UEFI boot for i386 and amd64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stanislav Motylkov Co-authored-by: Hermès BÉLUSCA - MAÏTO --- .../freeldr/freeldr/arch/uefi/amd64/uefiasm.S | 85 ++++++++++ boot/freeldr/freeldr/arch/uefi/i386/uefiasm.S | 109 +++++++++++++ boot/freeldr/freeldr/arch/uefi/stubs.c | 6 - boot/freeldr/freeldr/arch/uefi/ueficon.c | 1 - boot/freeldr/freeldr/arch/uefi/uefihw.c | 149 ++++++++++++++++++ boot/freeldr/freeldr/arch/uefi/uefildr.c | 55 ++++++- boot/freeldr/freeldr/arch/uefi/uefimem.c | 81 ++++------ boot/freeldr/freeldr/arch/uefi/uefisetup.c | 1 - boot/freeldr/freeldr/uefi.cmake | 13 +- 9 files changed, 435 insertions(+), 65 deletions(-) create mode 100644 boot/freeldr/freeldr/arch/uefi/amd64/uefiasm.S create mode 100644 boot/freeldr/freeldr/arch/uefi/i386/uefiasm.S create mode 100644 boot/freeldr/freeldr/arch/uefi/uefihw.c diff --git a/boot/freeldr/freeldr/arch/uefi/amd64/uefiasm.S b/boot/freeldr/freeldr/arch/uefi/amd64/uefiasm.S new file mode 100644 index 0000000000000..c4cd78d1e0b3c --- /dev/null +++ b/boot/freeldr/freeldr/arch/uefi/amd64/uefiasm.S @@ -0,0 +1,85 @@ +/* + * PROJECT: FreeLoader UEFI Support + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: x64 assembly UEFI escape helper functions + * COPYRIGHT: Copyright 2023 Justin Miller + */ + +#include +#include +#include + +EXTERN UefiServiceStack:QWORD +EXTERN BasicStack:QWORD +EXTERN ExecuteLoaderCleanly:PROC +EXTERN UefiExitBootServices:PROC + +.code64 + +// void _exituefi(VOID) +PUBLIC _exituefi +_exituefi: + /* Save non-volatile registers */ + push rbp + push rsi + push rdi + push rbx + + /* Save the old stack */ + mov rbx, rsp + + /* Load the new stack */ + xor rbp, rbp + mov rsp, qword ptr UefiServiceStack[rip] + + /* Call the entry routine, passing the parameters */ + mov rax, UefiExitBootServices[rip] + call rax + + /* Retore old stack */ + mov rsp, rbx + + /* Retore non-volatiles */ + pop rbx + pop rdi + pop rsi + pop rbp + +#ifdef _USE_ML + lgdt fword ptr [_gdtptr] +#else + lgdt cs:[_gdtptr][rip] /* GAS isn't my friend - avoid letting it generate absolute addressing */ +#endif + + /* All done */ + ret + +// void _changestack(VOID) +PUBLIC _changestack +_changestack: + mov rax, rsp + mov rsp, BasicStack[rip] + push rax + call ExecuteLoaderCleanly[rip] + ret + +.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 + .quad gdt, 0 /* Base Address */ +#endif + +END diff --git a/boot/freeldr/freeldr/arch/uefi/i386/uefiasm.S b/boot/freeldr/freeldr/arch/uefi/i386/uefiasm.S new file mode 100644 index 0000000000000..64de25daa20c2 --- /dev/null +++ b/boot/freeldr/freeldr/arch/uefi/i386/uefiasm.S @@ -0,0 +1,109 @@ +/* + * PROJECT: FreeLoader UEFI Support + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: i386 assembly UEFI escape helper functions + * COPYRIGHT: Copyright 2023 Justin Miller + */ + +#include +#include +#include + +PUBLIC _gdtptr +PUBLIC _i386idtptr +PUBLIC __changestack +EXTERN _UefiServiceStack:DWORD +EXTERN _i386Idt:DWORD +EXTERN _ExecuteLoaderCleanly:PROC +EXTERN _UefiExitBootServices:PROC +EXTERN _BasicStack:DWORD +.code32 + +// void __exituefi(VOID) +PUBLIC __exituefi +__exituefi: + push ebp + push esi + push edi + push ebx + + /* Save the old stack */ + mov ebx, esp + + /* Load the new stack */ + xor ebp, ebp + mov esp, _UefiServiceStack + + /* Call the entry routine, passing the parameters */ + call _UefiExitBootServices + + /* Retore old stack */ + mov esp, ebx + + /* Retore non-volatiles */ + pop ebx + pop edi + pop esi + pop ebp + +#ifdef _USE_ML + lidt fword ptr ds:[_i386idtptr] + lgdt fword ptr [_gdtptr] +#else + lgdt cs:[_gdtptr] + lidt _i386idtptr +#endif + + /* All done */ + ret + +// void __reloadsegment(VOID) +PUBLIC __changestack +__changestack: + mov eax, esp + mov esp, _BasicStack + push eax + call _ExecuteLoaderCleanly + 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 ac5cebab51cdb..e9263d60ba3df 100644 --- a/boot/freeldr/freeldr/arch/uefi/stubs.c +++ b/boot/freeldr/freeldr/arch/uefi/stubs.c @@ -43,12 +43,6 @@ UefiGetExtendedBIOSData(PULONG ExtendedBIOSDataArea, } -PCONFIGURATION_COMPONENT_DATA -UefiHwDetect(VOID) -{ - return 0; -} - VOID UefiPcBeep(VOID) { diff --git a/boot/freeldr/freeldr/arch/uefi/ueficon.c b/boot/freeldr/freeldr/arch/uefi/ueficon.c index 000b6b9d3a73b..6dc6eb5b8b6f9 100644 --- a/boot/freeldr/freeldr/arch/uefi/ueficon.c +++ b/boot/freeldr/freeldr/arch/uefi/ueficon.c @@ -138,6 +138,5 @@ UefiConsGetCh(VOID) /* UEFI will stack input requests, we have to clear it */ Key.UnicodeChar = 0; Key.ScanCode = 0; - GlobalSystemTable->ConIn->Reset(GlobalSystemTable->ConIn, FALSE); return KeyOutput; } diff --git a/boot/freeldr/freeldr/arch/uefi/uefihw.c b/boot/freeldr/freeldr/arch/uefi/uefihw.c new file mode 100644 index 0000000000000..8dcf960227451 --- /dev/null +++ b/boot/freeldr/freeldr/arch/uefi/uefihw.c @@ -0,0 +1,149 @@ +/* + * 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) +{ + UINTN 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(acpi2_guid))) + { + rsdp = (RSDP_DESCRIPTOR*)GlobalSystemTable->ConfigurationTable[i].VendorTable; + break; + } + } + + return rsdp; +} + +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 */ +#if defined(_M_IX86) || defined(_M_AMD64) + FldrCreateSystemKey(&SystemKey, "AT/AT COMPATIBLE"); +#elif defined(_M_IA64) + FldrCreateSystemKey(&SystemKey, "Intel Itanium processor family"); +#elif defined(_M_ARM) || defined(_M_ARM64) + FldrCreateSystemKey(&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/uefildr.c b/boot/freeldr/freeldr/arch/uefi/uefildr.c index ef0dd85cba396..9f801d978a8c8 100644 --- a/boot/freeldr/freeldr/arch/uefi/uefildr.c +++ b/boot/freeldr/freeldr/arch/uefi/uefildr.c @@ -8,11 +8,16 @@ #include #include +DBG_DEFAULT_CHANNEL(WARNING); /* GLOBALS ********************************************************************/ EFI_HANDLE GlobalImageHandle; EFI_SYSTEM_TABLE *GlobalSystemTable; +PVOID UefiServiceStack; +PVOID BasicStack; + +void _changestack(VOID); /* FUNCTIONS ******************************************************************/ @@ -25,15 +30,61 @@ EfiEntry( GlobalImageHandle = ImageHandle; GlobalSystemTable = SystemTable; - BootMain(NULL); + /* Needed for default settings */ + CmdLineParse(""); + + /* Debugger pre-initialization */ + DebugInit(0); + + MachInit(""); + + /* UI pre-initialization */ + if (!UiInitialize(FALSE)) + { + UiMessageBoxCritical("Unable to initialize UI."); + goto Quit; + } + + /* Initialize memory manager */ + if (!MmInitializeMemoryManager()) + { + UiMessageBoxCritical("Unable to initialize memory manager."); + goto Quit; + } + + /* Initialize I/O subsystem */ + FsInit(); + + /* 0x32000 is what UEFI defines, but we can go smaller if we want */ + BasicStack = (PVOID)((ULONG_PTR)0x32000 + (ULONG_PTR)MmAllocateMemoryWithType(0x32000, LoaderOsloaderStack)); + _changestack(); + +Quit: + /* If we reach this point, something went wrong before, therefore reboot */ + Reboot(); UNREACHABLE; return 0; } +void +ExecuteLoaderCleanly(PVOID PreviousStack) +{ + TRACE("ExecuteLoaderCleanly Entry\n"); + UefiServiceStack = PreviousStack; + + RunLoader(); + UNREACHABLE; +} + #ifndef _M_ARM VOID __cdecl Reboot(VOID) { - + //TODO: Replace with a true firmware reboot eventually + WARN("Something has gone wrong - halting FreeLoader\n"); + for (;;) + { + NOTHING; + } } #endif diff --git a/boot/freeldr/freeldr/arch/uefi/uefimem.c b/boot/freeldr/freeldr/arch/uefi/uefimem.c index 03a62150ef966..464b1f11783aa 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; @@ -39,6 +40,8 @@ EFI_HANDLE PublicBootHandle; PVOID ExitStack; PVOID EndofExitStack; +void _exituefi(VOID); + /* FUNCTIONS *****************************************************************/ static @@ -85,56 +88,13 @@ VOID UefiSetMemory( _Inout_ PFREELDR_MEMORY_DESCRIPTOR MemoryMap, _In_ ULONG_PTR BaseAddress, - _In_ PFN_COUNT Size, + _In_ PFN_COUNT SizeInPages, _In_ TYPE_OF_MEMORY MemoryType) { ULONG_PTR BasePage, PageCount; BasePage = BaseAddress / EFI_PAGE_SIZE; - PageCount = Size; - - /* Add the memory descriptor */ - FreeldrDescCount = AddMemoryDescriptor(MemoryMap, - UNUSED_MAX_DESCRIPTOR_COUNT, - BasePage, - PageCount, - MemoryType); -} - -VOID -ReserveMemory( - _Inout_ PFREELDR_MEMORY_DESCRIPTOR MemoryMap, - _In_ ULONG_PTR BaseAddress, - _In_ PFN_NUMBER Size, - _In_ TYPE_OF_MEMORY MemoryType, - _In_ PCHAR Usage) -{ - ULONG_PTR BasePage, PageCount; - ULONG i; - - BasePage = BaseAddress / PAGE_SIZE; - PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, Size); - - for (i = 0; i < FreeldrDescCount; i++) - { - /* Check for conflicting descriptor */ - if ((MemoryMap[i].BasePage < BasePage + PageCount) && - (MemoryMap[i].BasePage + MemoryMap[i].PageCount > BasePage)) - { - /* Check if the memory is free */ - if (MemoryMap[i].MemoryType != LoaderFree) - { - FrLdrBugCheckWithMessage( - MEMORY_INIT_FAILURE, - __FILE__, - __LINE__, - "Failed to reserve memory in the range 0x%Ix - 0x%Ix for %s", - BaseAddress, - Size, - Usage); - } - } - } + PageCount = SizeInPages; /* Add the memory descriptor */ FreeldrDescCount = AddMemoryDescriptor(MemoryMap, @@ -256,19 +216,36 @@ UefiMemGetMemoryMap(ULONG *MemoryMapSize) } } - UefiSetMemory(FreeldrMem, - MapEntry->PhysicalStart, - MapEntry->NumberOfPages, - MemoryType); + /* Sometimes our loader can be loaded into higher memory than we ever allocate */ + if (MemoryType == LoaderLoadedProgram) + { + if (((MapEntry->PhysicalStart + (MapEntry->NumberOfPages * PAGE_SIZE)) >> EFI_PAGE_SHIFT) > LoaderPagesSpanned) + { + /* This value needs to be adjusted if this occurs */ + LoaderPagesSpanned = ((MapEntry->PhysicalStart + (MapEntry->NumberOfPages * PAGE_SIZE)) >> EFI_PAGE_SHIFT); + } + } + + /* We really don't want to touch these reserved spots at all */ + if (MemoryType != LoaderReserve) + { + UefiSetMemory(FreeldrMem, + MapEntry->PhysicalStart, + MapEntry->NumberOfPages, + MemoryType); + } MapEntry = NEXT_MEMORY_DESCRIPTOR(MapEntry, DescriptorSize); } + /* Windows expects the first page to be reserved, otherwise it asserts. + * However it can be just a free page on some UEFI systems. */ + UefiSetMemory(FreeldrMem, 0x000000, 1, LoaderFirmwarePermanent); *MemoryMapSize = FreeldrDescCount; return FreeldrMem; } -static VOID +VOID UefiExitBootServices(VOID) { UINTN MapKey; @@ -306,7 +283,5 @@ UefiExitBootServices(VOID) VOID UefiPrepareForReactOS(VOID) { - UefiExitBootServices(); - ExitStack = MmAllocateMemoryWithType(EXIT_STACK_SIZE, LoaderOsloaderStack); - EndofExitStack = (PVOID)((ULONG_PTR)ExitStack + EXIT_STACK_SIZE); + _exituefi(); } 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/uefi.cmake b/boot/freeldr/freeldr/uefi.cmake index 76483f0529ef2..a3bc6a7e2e09d 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 @@ -23,11 +24,14 @@ list(APPEND UEFILDR_ARC_SOURCE arch/vgafont.c) if(ARCH STREQUAL "i386") + list(APPEND UEFILDR_ARC_SOURCE + arch/i386/i386idt.c) list(APPEND UEFILDR_COMMON_ASM_SOURCE + arch/uefi/i386/uefiasm.S arch/i386/i386trap.S) - elseif(ARCH STREQUAL "amd64") - #TBD + list(APPEND UEFILDR_COMMON_ASM_SOURCE + arch/uefi/amd64/uefiasm.S) elseif(ARCH STREQUAL "arm") list(APPEND UEFILDR_ARC_SOURCE arch/arm/macharm.c @@ -88,6 +92,11 @@ set_target_properties(uefildr PROPERTIES SUFFIX ".efi") target_compile_definitions(uefildr PRIVATE UEFIBOOT) +# On AMD64 we only map 1GB with freeloader, tell UEFI to keep us low! +if(ARCH STREQUAL "amd64") + set_image_base(uefildr 0x10000) +endif() + if(MSVC) if(NOT ARCH STREQUAL "arm") target_link_options(uefildr PRIVATE /DYNAMICBASE:NO)