diff --git a/BOOT/ENVIRON/INC/bootmgr.h b/BOOT/ENVIRON/INC/bootmgr.h index 6905ed5..d68991a 100644 --- a/BOOT/ENVIRON/INC/bootmgr.h +++ b/BOOT/ENVIRON/INC/bootmgr.h @@ -17,6 +17,27 @@ Abstract: #define _BOOTMGR_H #include +#include "efi.h" + +// +// Set machine type. +// +#if defined(__x86_64__) +#define BOOT_MACHINE_TYPE IMAGE_FILE_MACHINE_AMD64 +#elif defined(__i386__) +#define BOOT_MACHINE_TYPE IMAGE_FILE_MACHINE_I386 +#endif + +// +// No address translation. +// +#define BOOT_TRANSLATION_TYPE 0 + +// +// Use EFI page size. +// +#define PAGE_SIZE EFI_PAGE_SIZE +#define PAGE_SHIFT EFI_PAGE_SHIFT #define BOOT_INPUT_PARAMETERS_SIGNATURE 0x50504120544f4f42 /* "BOOT APP" */ #define BOOT_INPUT_PARAMETERS_VERSION 2 @@ -24,8 +45,82 @@ Abstract: typedef struct { ULONGLONG Signature; ULONG Version; + ULONG Size; + + // + // Machine information. + // + ULONG MachineType; + ULONG TranslationType; + + // + // Image information. + // + PVOID ImageBase; + ULONG ImageSize; + + // + // Offsets to ancillary structures. + // + ULONG MemoryInfoOffset; + ULONG ApplicationEntryOffset; + ULONG BootDeviceOffset; + ULONG FirmwareDataOffset; + ULONG ReturnDataOffset; + + ULONG PlatformDataOffset; } BOOT_INPUT_PARAMETERS, *PBOOT_INPUT_PARAMETERS; +#define BOOT_APPLICATION_ENTRY_SIGNATURE 0x544e4550415442 + +typedef struct { + ULONGLONG Signature; +} BOOT_APPLICATION_ENTRY, *PBOOT_APPLICATION_ENTRY; + +#define BOOT_MEMORY_INFO_VERSION 1 + +typedef struct { + ULONG Version; + ULONG MdlOffset; + ULONG DescriptorCount; + ULONG DescriptorSize; + ULONG BasePageOffset; +} BOOT_MEMORY_INFO, *PBOOT_MEMORY_INFO; + +#define MEMORY_FLAG_CACHE_WB 0x08 +#define MEMORY_TYPE_BOOT_APPLICATION 0xd0000002 + +typedef struct { + LIST_ENTRY ListEntry; + + ULONGLONG BasePage; + ULONG Pages; + + ULONG Flags; + ULONG Type; +} BOOT_MEMORY_DESCRIPTOR, *PBOOT_MEMORY_DESCRIPTOR; + +#define BOOT_FIRMWARE_DATA_VERSION 2 + +typedef struct { + ULONG Version; + ULONG Reserved; + EFI_HANDLE ImageHandle; + EFI_SYSTEM_TABLE *SystemTable; +} BOOT_FIRMWARE_DATA, *PBOOT_FIRMWARE_DATA; + +#define BOOT_RETURN_DATA_VERSION 1 + +typedef struct { + ULONG Version; + NTSTATUS Status; + ULONG Flags; +} BOOT_RETURN_DATA, *PBOOT_RETURN_DATA; + +typedef struct { + ULONG Size; +} BOOT_DEVICE, *PBOOT_DEVICE; + NTSTATUS BmMain ( IN PBOOT_INPUT_PARAMETERS InputParameters diff --git a/BOOT/ENVIRON/INC/efiapi.h b/BOOT/ENVIRON/INC/efiapi.h index 9f6ea0c..88240e4 100644 --- a/BOOT/ENVIRON/INC/efiapi.h +++ b/BOOT/ENVIRON/INC/efiapi.h @@ -107,6 +107,22 @@ typedef struct { #define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 #define EFI_BOOT_SERVICES_REVISION EFI_SPECIFICATION_VERSION +typedef +EFI_STATUS +(EFIAPI *EFI_ALLOCATE_PAGES) ( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_FREE_PAGES) ( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN Pages + ); + typedef EFI_STATUS (EFIAPI *EFI_HANDLE_PROTOCOL) ( @@ -121,8 +137,8 @@ typedef struct _EFI_BOOT_SERVICES { EFI_HANDLE RaiseTPL; EFI_HANDLE RestoreTPL; - EFI_HANDLE AllocatePages; - EFI_HANDLE FreePages; + EFI_ALLOCATE_PAGES AllocatePages; + EFI_FREE_PAGES FreePages; EFI_HANDLE GetMemoryMap; EFI_HANDLE AllocatePool; EFI_HANDLE FreePool; diff --git a/BOOT/ENVIRON/INC/ntdef.h b/BOOT/ENVIRON/INC/ntdef.h index 1d790d3..0c593d7 100644 --- a/BOOT/ENVIRON/INC/ntdef.h +++ b/BOOT/ENVIRON/INC/ntdef.h @@ -146,4 +146,35 @@ typedef union ULARGE_INTEGER { #define FIELD_OFFSET(type, field) ((ULONG)__builtin_offsetof(type, field)) #endif +// +// Alignment helpers. +// +#define ALIGN_DOWN(x, a) ((x) & ~((a) - 1)) +#define ALIGN_UP(x, a) ALIGN_DOWN((x) + (a) - 1, a) + +// +// Doubly-linked list entry. +// +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *ForwardLink; + struct _LIST_ENTRY *BackLink; +} LIST_ENTRY, *PLIST_ENTRY; + +// +// Runtime library definitions. +// + +PVOID +RtlCopyMemory ( + PVOID Destination, + CONST PVOID Source, + ULONG Length + ); + +PVOID +RtlZeroMemory ( + PVOID Destination, + ULONG Length + ); + #endif diff --git a/BOOT/ENVIRON/LIB/EFI/efiinit.c b/BOOT/ENVIRON/LIB/EFI/efiinit.c index 44d5358..be3bb8f 100644 --- a/BOOT/ENVIRON/LIB/EFI/efiinit.c +++ b/BOOT/ENVIRON/LIB/EFI/efiinit.c @@ -17,6 +17,80 @@ Abstract: #include "efi.h" UCHAR EfiInitScratch[2048]; +const EFI_GUID EfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL; +const EFI_GUID EfiDevicePathProtocol = DEVICE_PATH_PROTOCOL; + +VOID +EfiInitpCreateApplicationEntry ( + IN EFI_SYSTEM_TABLE *SystemTable, + IN OUT PBOOT_APPLICATION_ENTRY Entry, + IN ULONG BufferSize, + IN EFI_DEVICE_PATH *DevicePath, + IN EFI_DEVICE_PATH *FilePath, + IN PWCHAR LoadOptions, + IN ULONG LoadOptionsSize, + OUT PULONG BufferUsed, + OUT PBOOT_DEVICE *Device + ) + +/*++ + +Routine Description: + + Creates an application entry structure for the boot application. + +Arguments: + + SystemTable - Pointer to the EFI system table. + + Entry - A buffer to put the entry in. + + BufferSize - The amount of available space in the buffer. + + DevicePath - The device path for the application. + + FilePath - The file path for the application. + + LoadOptions - Firmware load options string. + + LoadOptionsSize - Length of the string pointed to by LoadOptions. + + BufferUsed - Returns the amount of buffer space used by the routine. + + Device - Returns a pointer to the device the application was loaded from. + +Return Value: + + None. + +--*/ + +{ + // + // Require enough space for the application entry. + // + if (BufferSize < sizeof(BOOT_APPLICATION_ENTRY)) { + *BufferUsed = 0; + return; + } + + // + // Set up application entry structure. + // + RtlZeroMemory(Entry, sizeof(BOOT_APPLICATION_ENTRY)); + Entry->Signature = BOOT_APPLICATION_ENTRY_SIGNATURE; + + // + // TODO: This routine is not fully implemented. + // + (VOID)SystemTable; + (VOID)DevicePath; + (VOID)FilePath; + (VOID)LoadOptions; + (VOID)LoadOptionsSize; + (VOID)Device; + *BufferUsed = sizeof(BOOT_APPLICATION_ENTRY); +} PBOOT_INPUT_PARAMETERS EfiInitCreateInputParameters ( @@ -44,17 +118,131 @@ Return Value: { ULONG ScratchUsed = 0; + ULONG ApplicationEntrySize = 0; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS BadPageAddress; + EFI_LOADED_IMAGE *LoadedImage; + EFI_DEVICE_PATH *DevicePath; PBOOT_INPUT_PARAMETERS InputParameters; + PBOOT_MEMORY_INFO MemoryInfo; + PBOOT_MEMORY_DESCRIPTOR MemoryDescriptor; + PBOOT_DEVICE BootDevice; + PBOOT_FIRMWARE_DATA FirmwareData; + PBOOT_RETURN_DATA ReturnData; - (VOID)ImageHandle; - (VOID)SystemTable; + // + // Page 0x102 may be broken on some machines. + // It is mapped here so that it does not get used. + // + BadPageAddress = 0x102 << PAGE_SHIFT; + SystemTable->BootServices->AllocatePages(AllocateAddress, EfiLoaderData, 1, &BadPageAddress); + // + // Get boot manager image information. + // + Status = SystemTable->BootServices->HandleProtocol( + ImageHandle, + (EFI_GUID*)&EfiLoadedImageProtocol, + (VOID**)&LoadedImage + ); + if (Status != EFI_SUCCESS) { + return NULL; + } + + // + // Get boot manager image device path. + // + Status = SystemTable->BootServices->HandleProtocol( + LoadedImage->DeviceHandle, + (EFI_GUID*)&EfiDevicePathProtocol, + (VOID**)&DevicePath + ); + if (Status != EFI_SUCCESS) { + return NULL; + } + + // + // Create input parameters structure. + // InputParameters = (PBOOT_INPUT_PARAMETERS)(&EfiInitScratch[ScratchUsed]); + ScratchUsed += sizeof(BOOT_INPUT_PARAMETERS); InputParameters->Signature = BOOT_INPUT_PARAMETERS_SIGNATURE; InputParameters->Version = BOOT_INPUT_PARAMETERS_VERSION; - ScratchUsed += sizeof(BOOT_INPUT_PARAMETERS); + InputParameters->MachineType = BOOT_MACHINE_TYPE; + InputParameters->TranslationType = BOOT_TRANSLATION_TYPE; + InputParameters->ImageBase = LoadedImage->ImageBase; + InputParameters->ImageSize = LoadedImage->ImageSize; - /* TODO: Create additional parameter structures */ + // + // Create memory info structure. + // + InputParameters->MemoryInfoOffset = ScratchUsed; + MemoryInfo = (PBOOT_MEMORY_INFO)(&EfiInitScratch[ScratchUsed]); + ScratchUsed += sizeof(BOOT_MEMORY_INFO); + MemoryInfo->Version = BOOT_MEMORY_INFO_VERSION; + MemoryInfo->MdlOffset = sizeof(BOOT_MEMORY_INFO); + MemoryInfo->DescriptorCount = 1; + MemoryInfo->DescriptorSize = sizeof(BOOT_MEMORY_DESCRIPTOR); + MemoryInfo->BasePageOffset = FIELD_OFFSET(BOOT_MEMORY_DESCRIPTOR, BasePage); + // + // Create a memory descriptor for the boot manager image. + // + MemoryDescriptor = (PBOOT_MEMORY_DESCRIPTOR)(&EfiInitScratch[ScratchUsed]); + ScratchUsed += sizeof(BOOT_MEMORY_DESCRIPTOR); + MemoryDescriptor->BasePage = (UINTN)InputParameters->ImageBase >> PAGE_SHIFT; + MemoryDescriptor->Pages = ALIGN_UP(InputParameters->ImageSize, PAGE_SIZE) >> PAGE_SHIFT; + MemoryDescriptor->Flags = MEMORY_FLAG_CACHE_WB; + MemoryDescriptor->Type = MEMORY_TYPE_BOOT_APPLICATION; + + // + // Create an application entry for the boot application. + // + InputParameters->ApplicationEntryOffset = ScratchUsed; + EfiInitpCreateApplicationEntry( + SystemTable, + (PBOOT_APPLICATION_ENTRY)(&EfiInitScratch[ScratchUsed]), + sizeof(EfiInitScratch) - ScratchUsed, + DevicePath, + LoadedImage->FilePath, + LoadedImage->LoadOptions, + LoadedImage->LoadOptionsSize, + &ApplicationEntrySize, + &BootDevice + ); + ScratchUsed += ApplicationEntrySize; + + // + // Copy application device to scratch area. + // + InputParameters->BootDeviceOffset = ScratchUsed; + if (BootDevice != NULL) { + RtlCopyMemory(&EfiInitScratch[ScratchUsed], BootDevice, BootDevice->Size); + ScratchUsed += BootDevice->Size; + } else { + RtlZeroMemory(&EfiInitScratch[ScratchUsed], sizeof(BOOT_DEVICE)); + ScratchUsed += sizeof(BOOT_DEVICE); + } + + // + // Create firmware data structure. + // + InputParameters->FirmwareDataOffset = ScratchUsed; + FirmwareData = (PBOOT_FIRMWARE_DATA)(&EfiInitScratch[ScratchUsed]); + ScratchUsed += sizeof(BOOT_FIRMWARE_DATA); + FirmwareData->Version = BOOT_FIRMWARE_DATA_VERSION; + FirmwareData->Reserved = 0; + FirmwareData->ImageHandle = ImageHandle; + FirmwareData->SystemTable = SystemTable; + + // + // Create return data structure. + // + InputParameters->ReturnDataOffset = ScratchUsed; + ReturnData = (PBOOT_RETURN_DATA)(&EfiInitScratch[ScratchUsed]); + ScratchUsed += sizeof(BOOT_RETURN_DATA); + ReturnData->Version = BOOT_RETURN_DATA_VERSION; + + InputParameters->Size = ScratchUsed; return InputParameters; } diff --git a/BOOT/ENVIRON/LIB/bootlib.c b/BOOT/ENVIRON/LIB/bootlib.c index 8048a7e..395ae76 100644 --- a/BOOT/ENVIRON/LIB/bootlib.c +++ b/BOOT/ENVIRON/LIB/bootlib.c @@ -15,6 +15,16 @@ Abstract: #include "bootlib.h" +// +// Total size of required structures. +// +#define MIN_INPUT_PARAMETERS_SIZE ( \ + sizeof(BOOT_INPUT_PARAMETERS) + \ + sizeof(BOOT_MEMORY_INFO) + \ + sizeof(BOOT_FIRMWARE_DATA) + \ + sizeof(BOOT_RETURN_DATA) \ + ) + NTSTATUS InitializeLibrary ( IN PBOOT_INPUT_PARAMETERS InputParameters, @@ -45,7 +55,9 @@ Return Value: // // Verify input parameters structure. // - if (InputParameters == NULL || InputParameters->Signature != BOOT_INPUT_PARAMETERS_SIGNATURE) { + if (InputParameters == NULL || + InputParameters->Signature != BOOT_INPUT_PARAMETERS_SIGNATURE || + InputParameters->Size < MIN_INPUT_PARAMETERS_SIZE) { return STATUS_INVALID_PARAMETER; } diff --git a/BOOT/ENVIRON/LIB/rtl.c b/BOOT/ENVIRON/LIB/rtl.c new file mode 100644 index 0000000..f190a35 --- /dev/null +++ b/BOOT/ENVIRON/LIB/rtl.c @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) 2024, Quinn Stephens. +Provided under the BSD 3-Clause license. + +Module Name: + + rtl.c + +Abstract: + + Runtime library routines. + +--*/ + +#include + +PVOID +RtlCopyMemory ( + PVOID Destination, + CONST PVOID Source, + ULONG Length + ) + +/*++ + +Routine Description: + + Copies a block of memory from Source to Destination. + +Arguments: + + Destination - the address to copy to. + + Source - the address to copy from. + + Length - the number of bytes to copy. + +Return Value: + + Returns Destination. + +--*/ + +{ + for (ULONG Index = 0; Index < Length; Index++) { + ((PCHAR)Destination)[Index] = ((PCHAR)Source)[Index]; + } + + return Destination; +} + + +PVOID +RtlZeroMemory ( + PVOID Destination, + ULONG Length + ) + +/*++ + +Routine Description: + + Sets a block of memory to zero. + +Arguments: + + Destination - the address to zero at. + + Length - the number of bytes to set. + +Return Value: + + Returns Destination. + +--*/ + +{ + for (ULONG Index = 0; Index < Length; Index++) { + ((PCHAR)Destination)[Index] = 0; + } + + return Destination; +}