From e04cbd39cfdb8d52ca48839725f12f0d372c6725 Mon Sep 17 00:00:00 2001 From: Justin Miller Date: Mon, 1 May 2023 09:24:13 -0700 Subject: [PATCH] [UEFI] 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 | 90 +++++++++++ boot/freeldr/freeldr/arch/uefi/i386/uefiasm.S | 119 ++++++++++++++ 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 | 50 +++++- boot/freeldr/freeldr/arch/uefi/uefimem.c | 35 +++- boot/freeldr/freeldr/arch/uefi/uefisetup.c | 1 - boot/freeldr/freeldr/uefi.cmake | 9 +- 9 files changed, 441 insertions(+), 19 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..9db8106e2b945 --- /dev/null +++ b/boot/freeldr/freeldr/arch/uefi/amd64/uefiasm.S @@ -0,0 +1,90 @@ +/* + * 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 + + /* All done */ + ret + +// void _changestack(VOID) +PUBLIC _changestack +_changestack: + mov rax, rsp + mov rsp, BasicStack[rip] + push rax + call ExecuteLoaderCleanly[rip] + ret + +// void _changegdt(VOID) +PUBLIC _changegdt +_changegdt: +#ifdef _USE_ML + lgdt fword ptr [_gdtptr] +#else + lgdt cs:[_gdtptr][rip] /* GAS isn't my friend - avoid letting it generate absolute addressing */ +#endif + 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..37f16fc0c7270 --- /dev/null +++ b/boot/freeldr/freeldr/arch/uefi/i386/uefiasm.S @@ -0,0 +1,119 @@ +/* + * 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 +PUBLIC __changegdt +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 + + + /* All done */ + ret + +// void __reloadsegment(VOID) +PUBLIC __changestack +__changestack: + mov eax, esp + mov esp, _BasicStack + push eax + call _ExecuteLoaderCleanly + ret + + +PUBLIC __changegdt +__changegdt: +#ifdef _USE_ML + lgdt fword ptr [_gdtptr] +#else + lgdt cs:[_gdtptr] +#endif + /* Load the IDT */ +#ifdef _USE_ML + lidt fword ptr ds:[_i386idtptr] +#else + lidt _i386idtptr +#endif + 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..06905c980bc0b 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,58 @@ EfiEntry( GlobalImageHandle = ImageHandle; GlobalSystemTable = SystemTable; - BootMain(NULL); + /* 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, LoaderLoadedProgram)); + _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("Stopping freeloader something has gone wrong - Freezing"); + for(;;) + { + } } #endif diff --git a/boot/freeldr/freeldr/arch/uefi/uefimem.c b/boot/freeldr/freeldr/arch/uefi/uefimem.c index 03a62150ef966..e5f06c0a6d639 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,9 @@ EFI_HANDLE PublicBootHandle; PVOID ExitStack; PVOID EndofExitStack; +void _changegdt(VOID); +void _exituefi(VOID); + /* FUNCTIONS *****************************************************************/ static @@ -256,19 +260,35 @@ 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); } + /* Reserve the first page, as on some UEFI systems it can be free */ + UefiSetMemory(FreeldrMem, 0x000000, 1, LoaderFirmwarePermanent); *MemoryMapSize = FreeldrDescCount; return FreeldrMem; } -static VOID +VOID UefiExitBootServices(VOID) { UINTN MapKey; @@ -306,7 +326,6 @@ UefiExitBootServices(VOID) VOID UefiPrepareForReactOS(VOID) { - UefiExitBootServices(); - ExitStack = MmAllocateMemoryWithType(EXIT_STACK_SIZE, LoaderOsloaderStack); - EndofExitStack = (PVOID)((ULONG_PTR)ExitStack + EXIT_STACK_SIZE); + _exituefi(); + _changegdt(); } 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..fd4b430554e3f 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 @@ -87,6 +91,7 @@ add_executable(uefildr ${UEFILDR_BASE_SOURCE}) set_target_properties(uefildr PROPERTIES SUFFIX ".efi") target_compile_definitions(uefildr PRIVATE UEFIBOOT) +set_image_base(uefildr 0x10000) if(MSVC) if(NOT ARCH STREQUAL "arm")