From 8a54815712d6f9a0f33f0a929fb567df45e7ded3 Mon Sep 17 00:00:00 2001 From: Curle Date: Wed, 11 Sep 2019 23:44:11 +0100 Subject: [PATCH] Add all of the functionality to allow the kernel to boot itself. This is a trimmed down version of Syncboot integrated into the kernel. The plan is, eventually, to allow the kernel to be booted by Syncboot, but that'll take a lot of research into QEMU. This was just quicker to do. This isn't tested, as I still need to figure out how to compile the EFI entry point separately. They can be linked together, however. That's why the kernel is designed around a PE32+ format. --- include/efiboot.h | 99 ++++++ include/kernel.h | 2 + kernel/boot.c | 824 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 925 insertions(+) create mode 100644 include/efiboot.h create mode 100644 kernel/boot.c diff --git a/include/efiboot.h b/include/efiboot.h new file mode 100644 index 0000000..2f7a6c3 --- /dev/null +++ b/include/efiboot.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include + +#define MAJOR_VER 2 +#define MINOR_VER 5 + +#ifdef DEBUG + #define METADATA_SHOW + #define WATCHDOG_TIMER_DISABLE + #define MAIN_DEBUG + #define GFX_DEBUG_MAIN + #define GFX_DEBUG_NAMING + #define LOADER_DEBUG_MAIN + #define LOADER_DEBUG_PE + #define LOADER_DEBUG_DOS + #define LOADER_DEBUG_ELF + #define LOADER_DEBUG_FINAL + #define MEMORY_SHOW + #define MEMORY_CHECK +#endif + +/* ==================== Text File Magic Numbers ==================== */ +/* Required to make sure that the configuration file is encoded properly. + * The magic number is set automatically by all text editors, including Notepad. */ + +#define UTF8_BOM_LE 0xBFBBEF // Little Endian +#define UTF8_BOM_BE 0xEFBBBF // Big Endian + +#define UTF16_BOM_LE 0xFEFF +#define UTF16_BOM_BE 0xFFFE + + +/* ==================== Fileloader Structs ==================== */ + +/* These are the structs passed to the kernel file when it's called by the bootloader. + * More information about this can be found in main.c */ + +typedef struct { + EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE* GPUs; // Information about each graphics output unit (one or more per GPU) + size_t FBCount; // The amount of framebuffers available. +} GFX_INFO; + +typedef struct { + uint32_t UEFI_Version; // Version of the firmware running + uint32_t Bootloader_MajorVersion; // Major and + uint32_t Bootloader_MinorVersion; // minor version of the bootloader itself. + + uint32_t Memory_Descriptor_Version; + size_t Memory_Descriptor_Size; // Size of each memory descriptor + EFI_MEMORY_DESCRIPTOR* Memory_Map; // System memory map, as an array of EFI_MEMORY_DESCRIPTORs + size_t Memory_Map_Size; // Total size of the memory map + + EFI_PHYSICAL_ADDRESS Kernel_Base; // The physical (absolute) address of the start of the kernel + size_t Kernel_Pages; // How many pages (of 4KiB) the kernel takes up + + CHAR16* ESP_Path; // The drive root of the EFI System Partition + size_t ESP_Path_Length; // Size in bytes of the ESP_Path string + CHAR16* Kernel_Path; // Kernel's file path relative to the ESP_Path + size_t Kernel_Path_Length; // Size in bytes of the Kernel_Path string + CHAR16* Kernel_Options; // Options given to the kernel, taken from the 2nd line of the + size_t Kernel_Options_Length; // Size in bytes of the Kernel_Options string + + EFI_RUNTIME_SERVICES* RTServices; // The UEFI Runtime Services + GFX_INFO* GPU_INFO; // Information about all available graphics devices + EFI_FILE_INFO* FileMeta; // Kernel file metadata + EFI_CONFIGURATION_TABLE* ConfigTables; // UEFI system configuration tables + size_t ConfigTables_Length; +} FILELOADER_PARAMS; + +static const CHAR16 pixelFormats[5][17] = { + L"RGBReserved 8bpp", + L"BGRReserved 8bpp", + L"PixelBitMask ", + L"PixelBltOnly ", + L"PixelFormatMax " +}; + +uint8_t Language[6] = { 'e','n','-','U','S','\0' }; +uint8_t Language2[3] = { 'e','n','\0' }; +uint8_t Language3[4] = { 'e','n','g','\0' }; + +CHAR16 DefaultDriverName[10] = L"No Driver"; +CHAR16 DefaultControllerName[14] = L"No Controller"; +CHAR16 DefaultChildName[9] = L"No Child"; + + +/* ==================== Sanity Checks ==================== */ + +#define PROBLEM_DRIVERS 4 // There are 4 known drivers that claim to control anything you ask it. This causes problems. + +const CHAR16 AmiPS2Driver[16] = L"AMI PS/2 Driver"; // This driver controls a "Generic PS/2 Keyboard" +const CHAR16 AsixUSBEthDriver[34] = L"ASIX AX88772B Ethernet Driver 1.0"; // This driver controls "ASIX AX88772B USB Fast Ethernet Controller" +const CHAR16 SocketLayerDriver[20] = L"Socket Layer Driver"; // This driver controls a "Socket Layer" +const CHAR16 Asix10100EthernetDriver[24] = L"AX88772 Ethernet Driver"; // This driver controls "AX88772 10/100 Ethernet" +const CHAR16* const Problematic_Drivers[PROBLEM_DRIVERS] = { AmiPS2Driver, AsixUSBEthDriver, SocketLayerDriver, Asix10100EthernetDriver }; + diff --git a/include/kernel.h b/include/kernel.h index 56119bd..423dcf3 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -618,6 +618,8 @@ static const char* ExceptionStrings[] = { /* = Sync Functions = */ /* ============================================================= */ +int kernel_main(FILELOADER_PARAMS* FLOP); + /* Required functions */ size_t strlen(const char* string); diff --git a/kernel/boot.c b/kernel/boot.c new file mode 100644 index 0000000..ed8e2ce --- /dev/null +++ b/kernel/boot.c @@ -0,0 +1,824 @@ +/************************ + *** Team Kitty, 2019 *** + *** Sync *** + ***********************/ + +/* This file should do the work of bootloading the kernel. + * Most of this work is taken from the Syncboot project, + * https://git.gemwire.uk/gwdev/Syncboot + * + * All it does it set up graphics and transfer into our kernel. + * At this stage the kernel is available for configuration, but + * this will require more testing before being properly implemented. + */ + +#include + +EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) { + InitializeLib(ImageHandle, SystemTable); // Initialize EFILIB. + /* Provides the following definitions: + - ST = SystemTable + - BS = SystemTable->BootServices + - RT = SystemTable->RuntimeServices + */ + + EFI_STATUS Status; + size_t Mode; + + Print(L"\n%H========== Sync Bootloading ==========%N\r\n"); + + /* Get the time */ + EFI_TIME Now; + Status = RT->GetTime(&Now, NULL); + if (EFI_ERROR(Status)) { + Print(L"Error fetching time.\r\n"); + } else { + /* and then print it. */ + Print(L"Time now is %02hhu/%02hhu/%04hu - %02hhu:%02hhu:%02hhu.%u\r\n\n", Now.Month, Now.Day, Now.Year, Now.Hour, Now.Minute, Now.Second, Now.Nanosecond); + } + + Print(L"Press S for slow mode, D for debug mode, or nothing for blitz mode.\r\n"); + + Status = WaitForSingleEvent(ST->ConIn->WaitForKey, 10000000); + if(Status != EFI_TIMEOUT) { + EFI_INPUT_KEY Key = { 0 }; + Status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key); + if(!(EFI_ERROR(Status))) { + switch(Key.UnicodeChar) { + case L"s": + Mode = 1; + break; + case L"d": + #define DEBUG + break; + default: + Mode = 0; + break; + } + + Status = ST->ConIn->Reset(ST->ConIn, FALSE); + } + } + + GFX_INFO* Gfx; + Status = BS->AllocatePool(EfiLoaderData, sizeof(GFX_INFO), (void**)&Gfx); + if(EFI_ERROR(Status)) { + Print(L"Error at Gfx AllocatePool\r\n"); + } + + Gfx->FBCount = 0; + size_t GfxInfoSize, xGfxHandles, xNm2Handles, xDevPathHandles, DeviceInd; + uint32_t GfxMode; + EFI_INPUT_KEY Key; + Key.UnicodeChar = 0; + + CHAR16* DriverDisplayName = DefaultDriverName; + CHAR16* ControllerDisplayName = DefaultControllerName; + CHAR16* ChildDisplayName = DefaultChildName; + + EFI_HANDLE* GfxHandles; + + Status = BS->LocateHandleBuffer(ByProtocol, &GraphicsOutputProtocol, NULL, &xGfxHandles, &GfxHandles); + if(EFI_ERROR(Status)) { + Print(L"Error at Gfx LocateHAndle\r\n"); + } + + if(xGfxHandles == 1) { + Print(L"There is 1 GOP device.\r\n"); + } else { + Print(L"There are %llu GOP devices.\r\n", xGfxHandles); + } + + CHAR16** DeviceNames; + Status = BS->AllocatePool(EfiBootServicesData, sizeof(CHAR16*)*xGfxHandles, (void**)&DeviceNames); + if(EFI_ERROR(Status)) { + Print(L"Error at Gfx NameBuffer AllocatePool\r\n"); + } + + EFI_HANDLE* Name2Handles; + Status = BS->LocateHandleBuffer(ByProtocol, &ComponentName2Protocol, NULL, &xNm2Handles, &Name2Handles); + if(EFI_ERROR(Status)) { + Print(L"Error at Gfx Name2Handles LocateBuffer\r\n"); + } + + EFI_HANDLE* DevicePaths; + Status = BS->LocateHandleBuffer(ByProtocol, &DevicePathProtocol, NULL, &xDevPathHandles, &DevicePaths); + if (EFI_ERROR(Status)) { + Print(L"DevicePathHandles LocateBuffer error\r\n"); + } + + for(DeviceInd = 0; DeviceInd < xGfxHandles; DeviceInd++) { + DriverDisplayName = DefaultDriverName; + ControllerDisplayName = DefaultControllerName; + ChildDisplayName = DefaultChildName; + + EFI_DEVICE_PATH* GfxDevicePath; + + Status = BS->OpenProtocol(GfxHandles[DeviceInd], &DevicePathProtocol, (void**)&GfxDevicePath, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(Status == EFI_SUCCESS) { + size_t ControllerPathSize = DevicePathSize(GfxDevicePath) - DevicePathNodeLength(GfxDevicePath) + 4; + EFI_DEVICE_PATH* CurDevicePath; + size_t ControllerInd = 0; + + for(ControllerInd = 0; ControllerInd < xDevPathHandles; ControllerInd++) { + Status = BS->OpenProtocol(DevicePaths[ControllerInd], &DriverBindingProtocol, NULL, NULL, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (!EFI_ERROR(Status)) + continue; + + Status = BS->OpenProtocol(DevicePaths[ControllerInd], &LoadedImageProtocol, NULL, NULL, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (!EFI_ERROR(Status)) + continue; + + // Graphics controllers don't have SimpleFileSystem, so we need to load a proper filesystem. + Status = BS->OpenProtocol(DevicePaths[ControllerInd], &FileSystemProtocol, NULL, NULL, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (!EFI_ERROR(Status)) + continue; + + // I'll be honest, i don't know why. There are no PS/2 keyboard ports on UEFI2 compatible PCIe GPUs, but without this check it fails to boot. + Status = BS->OpenProtocol(DevicePaths[ControllerInd], &SerialIoProtocol, NULL, NULL, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL); + if (!EFI_ERROR(Status)) + continue; + + Status = BS->OpenProtocol(DevicePaths[ControllerInd], &DevicePathProtocol, (void**)&CurDevicePath, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + Print(L"DevicePathHandles OpenProtocol error\r\n"); + } + + size_t CurControllerPathSize = DevicePathSize(GfxDevicePath); + + if(CurControllerPathSize != ControllerPathSize) + continue; + + if(LibMatchDevicePaths(CurDevicePath, GfxDevicePath)) { + for(size_t Name2DriverIndex = 0; Name2DriverIndex < xNm2Handles; Name2DriverIndex++) { + void* ManagedInterface; + Status = BS->OpenProtocol(DevicePaths[ControllerInd], &PciIoProtocol, &ManagedInterface, Name2Handles[Name2DriverIndex]. DevicePaths[ControllerInd], EFI_OPEN_PROTOCOL_BY_DRIVER); + if(!EFI_ERROR(Status)) { + Status = BS->CloseProtocol(DevicePaths[ControllerInd], &PciIoProtocol, Name2Handles[Name2DriverIndex], DevicePaths[ControllerInd]); + if(EFI_ERROR(Status)) { + Print(L"DevicePaths Name2Handles CloseProtocol error\r\n"); + } + continue; + } else if (Status != EFI_ALREADY_STARTED) { + continue; + } + + EFI_COMPONENT_NAME2_PROTOCOL* Name2Device; + + Status = BS->OpenProtocol(Name2Handles[Name2DriverIndex], &ComponentName2Protocol, (void**)&Name2Device, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(EFI_ERROR(Status)) { + Print(L"Name2Device OpenProtocol error\r\n"); + } + + Status = Name2Device->GetDriverName(Name2Device, Language, &DriverDisplayName); + if (Status == EFI_UNSUPPORTED) { // Wrong language. + Status = Name2Device->GetDriverName(Name2Device, Language2, &DriverDisplayName); + if (Status == EFI_UNSUPPORTED) { + Status = Name2Device->GetDriverName(Name2Device, Language3, &DriverDisplayName); + } + } + + if (EFI_ERROR(Status)) { + Print(L"Name2Device GetDriverName error\r\n"); + + if (Status == EFI_UNSUPPORTED) { // None of our languages will work. + Print(L"The first 10 characters of the supported language are:\r\n"); + for (uint32_t p = 0; p < 10; p++) { + Print(L"%c", Name2Device->SupportedLanguages[p]); + } + Print(L"\r\n"); + } + // The driver doesn't follow specifications if we get this far, so we give it the default. + DriverDisplayName = DefaultDriverName; + } + + Status = Name2Device->GetControllerName(Name2Device, DevicePaths[ControllerInd], NULL, Language, &ControllerDisplayName); // The child should be NULL to get the controller's name. + if (Status == EFI_UNSUPPORTED) { + Status = Name2Device->GetControllerName(Name2Device, DevicePaths[ControllerInd], NULL, Language2, &ControllerDisplayName); + if (Status == EFI_UNSUPPORTED) { + Status = Name2Device->GetControllerName(Name2Device, DevicePaths[ControllerInd], NULL, Language3, &ControllerDisplayName); + } + } + if(EFI_ERROR(Status)) { + Print(L"Name2Device GetControllerName error\r\n"); + } + + Status = Name2Device->GetControllerName(Name2Device, DevicePaths[ControllerInd], GfxHandles[DeviceInd], Language, &ChildDisplayName); + if (Status == EFI_UNSUPPORTED) { + Status = Name2Device->GetControllerName(Name2Device, DevicePaths[ControllerInd], GfxHandles[DeviceInd], Language2, &ChildDisplayName); + if (Status == EFI_UNSUPPORTED) { + Status = Name2Device->GetControllerName(Name2Device, DevicePaths[ControllerInd], GfxHandles[DeviceInd], Language3, &ChildDisplayName); + + } + } + + + if (EFI_ERROR(Status)) { + Print(L"Name2Device GetControllerName error\r\n"); + + if (Status == EFI_UNSUPPORTED) { + Print(L"First 10 characters of the supported language:\r\n"); + for (uint32_t p = 0; p < 10; p++) { + Print(L"%c", Name2Device->SupportedLanguages[p]); + } + Print(L"\r\n"); + } + + ChildDisplayName = DefaultChildName; + } + + break; + } + + break; + } + } // End of ControllerIndex + + + if((ControllerDisplayName == DefaultControllerName) && (DriverDisplayName == DefaultDriverName) && (ChildDisplayName == DefaultChildName)) { + // Filter controller index by DriverBinding, LoadedImage, FileSystem and SerialIO protocols. + } + } else if (Status == EFI_UNSUPPORTED) { + Print(L"VM or BIOS graphics device found.\r\n"); + } else if (EFI_ERROR(Status)) { + Print(L"GraphicsHandles GfxDevicePath error.\r\n"); + } + } + + if(xGfxHandles > 1) { + DeviceInd = 2; + size_t Timeout = 5; + + Print(L"Graphics devices:\r\n"); + for(size_t DeviceNumber = 0; DeviceNumber < xGfxHandles; DeviceNumber++) { + Print(L"%s", DeviceNames[DeviceNumber]); + } + Print(L"\r\n"); + + if(Mode) { + Print(L"%E==================== Graphics Configuration ==================== %N \r\n"); + Print(L"Choose an option: \r\n"); + Print(L"0. Configure each device individually\r\n"); + Print(L"1. Configure one device\r\n"); + Print(L"2. Configure all devices to use the native resolution of the device they're connected to \r\n"); + Print(L"3. Configure all devices to use a 1024x768 resolution.\r\n"); + Print(L"%ENote: Not all displays may be active. The ones which are, are determined by the GPU firmware. I have no control over them.%N\r\n"); + + while(Timeout) { + Print(L"Please select an option. Defaulting to %llu in %llu .\r", DeviceInd, Timeout); + Status = WaitForSingleEvent(ST->ConIn->WaitForKey, 10000000); + if (Status != EFI_TIMEOUT) { + Status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key); + if (EFI_ERROR(Status)) { + + Print(L"\nError reading keystroke. 0x%llx\r\n", Status); + return Status; + } + + Print(L"\n\nOption %c.\r\n\n", Key.UnicodeChar); + break; + } + Timeout -= 1; + + if (!Timeout) { + Print(L"Defaulting to option %llu.\r\n\n", DeviceInd); + break; + } + } + + if (Timeout) { + DeviceInd = (size_t)(Key.UnicodeChar - 0x30); + } + + Key.UnicodeChar = 0; + Status = ST->ConIn->Reset(ST->ConIn, FALSE); + if (EFI_ERROR(Status)) { + Print(L"Error resetting input buffer: 0x%llx\r\n", Status); + return Status; + } + } else { + // Blitz mode. Straight into mode 3. + DeviceInd = 3; + } + + } + size_t GOPInfoSize; + + if((xGfxHandles > 1) && (DeviceInd == 0)) { + Gfx->FBCount = xGfxHandles; + + Status = BS->AllocatePool(EfiLoaderData, Gfx->FBCount * sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), (void**)&Gfx->GPUs); + if(EFI_ERROR(Status)) { + Print(L"GPUs AllocatePool error"); + } + + for(DeviceInd = 0; DeviceInd < xGfxHandles; DeviceInd++) { + EFI_GRAPHICS_OUTPUT_PROTOCOL* GOPTable; + + Status = BS->OpenProtocol(GfxHandles[DeviceInd], &GraphicsOutputProtocol, (void**)&GOPTable, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(EFI_ERROR(Status)) { + Print(L"GraphicsTable OpenProtocol error"); + } + + if(GOPTable->Mode->MaxMode == 1) { + GfxMode = 0; + } else { + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* GOPInfo2; + while (0x30 > Key.UnicodeChar || Key.UnicodeChar > (0x30 + GOPTable->Mode->MaxMode - 1)) { + Print(L"%s", DeviceNames[DeviceInd]); + Print(L"\r\n"); + Print(L"%u available graphics modes.\r\n\n", GOPTable->Mode->MaxMode); + Print(L"Current mode: %c\r\n", GOPTable->Mode->Mode + 0x30); + for (GfxMode = 0; GfxMode < GOPTable->Mode->MaxMode; GfxMode++) { + Status = GOPTable->QueryMode(GOPTable, GfxMode, &GOPInfoSize, &GOPInfo2); + if (EFI_ERROR(Status)) { + Print(L"GraphicsTable QueryMode error: 0x%llx\r\n", Status); + return Status; + } + Print(L"%c. %ux%u, Pixels Per SCNLN: &u, Pixel format: %s\r\n", GfxMode + 0x30, GOPInfo2->HorizontalResolution, GOPInfo2->VerticalResolution, GOPInfo2->PixelsPerScanLine, GOPInfo2->PixelFormat); + Status = BS->FreePool(GOPInfo2); + if (EFI_ERROR(Status)) { + Print(L"Error freeing GOPInfo2: 0x%llx\r\n", Status); + return Status; + } + } + + Print(L"\r\nPlease select a graphics mode. (0-%c)\r\n", 0x30 + GOPTable->Mode->MaxMode - 1); + Status = ST->ConIn->Reset(ST->ConIn, NULL); + //while (Key.UnicodeChar < 0x30 || Key.UnicodeChar - 0x30 < GOPTable->Mode->MaxMode) { + Status = ST->ConIn->Reset(ST->ConIn, NULL); + while ((Status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key)) == EFI_NOT_READY); + //} + Print(L"\r\nSelected graphics mode %c.\r\n", Key.UnicodeChar); + } + + GfxMode = (uint32_t)(Key.UnicodeChar - 0x30); + + Print(L"Setting graphics mode %u.\r\n", GfxMode + 1); + } + + Status = GOPTable->SetMode(GOPTable, GfxMode); + if (EFI_ERROR(Status)) { + Print(L"GraphicsTable SetMode error: 0x%llx\r\n", Status); + return Status; + } + Status = BS->AllocatePool(EfiLoaderData, GOPTable->Mode->SizeOfInfo, (void**)&Gfx->GPUs[DeviceInd].Info); + if (EFI_ERROR(Status)) { + Print(L"GOPMode->Info AllocatePool error: 0x%llx\r\n", Status); + return Status; + } + + Gfx->GPUs[DeviceInd].MaxMode = GOPTable->Mode->MaxMode; + Gfx->GPUs[DeviceInd].Mode = GOPTable->Mode->Mode; + Gfx->GPUs[DeviceInd].SizeOfInfo = GOPTable->Mode->SizeOfInfo; + Gfx->GPUs[DeviceInd].FrameBufferSize = GOPTable->Mode->FrameBufferSize; + Gfx->GPUs[DeviceInd].FrameBufferBase = GOPTable->Mode->FrameBufferBase; + *(Gfx->GPUs[DeviceInd].Info) = *(GOPTable->Mode->Info); + + } // End loop + + } else if((xGfxHandles > 1) && (DeviceInd == 1)) { + // Configure one device + Gfx->FBCount = 1; + Status = BS->AllocatePool(EfiLoaderData, Gfx->FBCount * sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), (void**)&Gfx->GPUs); + if (EFI_ERROR(Status)) { + Print(L"GPUs AllocatePool error: 0x%llx\r\n", Status); + return Status; + } + while (0x30 > Key.UnicodeChar || Key.UnicodeChar > (0x30 + xGfxHandles - 1)) { + for (size_t DeviceNumIterator = 0; DeviceNumIterator < xGfxHandles; DeviceNumIterator++) { + Print(L"%s", DeviceNames[DeviceNumIterator]); + } + Print(L"\r\n"); + Print(L"Please select an output device to configure. (0-%llu)\r\n", xGfxHandles - 1); + while ((ST->ConIn->ReadKeyStroke(ST->ConIn, &Key)) == EFI_NOT_READY); + Print(L"\r\nDevice %c selected.\r\n\n", Key.UnicodeChar); + } + DeviceInd = (size_t)(Key.UnicodeChar - 0x30); + Key.UnicodeChar = 0; + + EFI_GRAPHICS_OUTPUT_PROTOCOL *GOPTable; + Status = BS->OpenProtocol(GfxHandles[DeviceInd], &GraphicsOutputProtocol, (void**)&GOPTable, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + Print(L"GraphicsTable OpenProtocol error: 0x%llx\r\n", Status); + return Status; + } + + if(GOPTable->Mode->MaxMode == 1) { + GfxMode = 0; + } else { + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* GOPInfo2; + while (0x30 > Key.UnicodeChar || Key.UnicodeChar > (0x30 + GOPTable->Mode->MaxMode - 1)) { + Print(L"%s\r\n", DeviceNames[DeviceInd]); + Print(L"%u available graphics modes.\r\n\n", GOPTable->Mode->MaxMode); + Print(L"Current mode: %c\r\n", GOPTable->Mode->Mode + 0x30); + for (GfxMode = 0; GfxMode < GOPTable->Mode->MaxMode; GfxMode++) { + Status = GOPTable->QueryMode(GOPTable, GfxMode, &GOPInfoSize, &GOPInfo2); + if (EFI_ERROR(Status)) { + Print(L"GraphicsTable QueryMode error: 0x%llx\r\n", Status); + } + Print(L"%c. %ux%u, PxPerScanLine: %u, PxFormat: %s\r\n", GfxMode + 0x30, GOPInfo2->HorizontalResolution, GOPInfo2->VerticalResolution, GOPInfo2->PixelsPerScanLine, pixelFormats[GOPInfo2->PixelFormat]); + // Don't need GOPInfo2 anymore + Status = BS->FreePool(GOPInfo2); + if (EFI_ERROR(Status)) { + Print(L"Error freeing GOPInfo2 pool. 0x%llx\r\n", Status); + } + } + + Print(L"\r\nPlease select a graphics mode. (0 - %c)\r\n", 0x30 + GOPTable->Mode->MaxMode - 1); + while ((Status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key)) == EFI_NOT_READY); + Print(L"\r\nSelected graphics mode %c.\r\n\n", Key.UnicodeChar); + } + + GfxMode = (uint32_t)(Key.UnicodeChar - 0x30); + Key.UnicodeChar = 0; + Print(L"Setting graphics mode %u of %u.\r\n\n", GfxMode + 1, GOPTable->Mode->MaxMode); + + } + + Status = GOPTable->SetMode(GOPTable, GfxMode); + if (EFI_ERROR(Status)) { + Print(L"GraphicsTable SetMode error. 0x%llx\r\n", Status); + } + DeviceInd = 0; + Status = BS->AllocatePool(EfiLoaderData, GOPTable->Mode->SizeOfInfo, (void**)&Gfx->GPUs[DeviceInd].Info); + if (EFI_ERROR(Status)) { + Print(L"GOP Mode->Info AllocatePool error. 0x%llx\r\n", Status); + } + + Gfx->GPUs[DeviceInd].MaxMode = GOPTable->Mode->MaxMode; + Gfx->GPUs[DeviceInd].Mode = GOPTable->Mode->Mode; + Gfx->GPUs[DeviceInd].SizeOfInfo = GOPTable->Mode->SizeOfInfo; + Gfx->GPUs[DeviceInd].FrameBufferSize = GOPTable->Mode->FrameBufferSize; + Gfx->GPUs[DeviceInd].FrameBufferBase = GOPTable->Mode->FrameBufferBase; + *(Gfx->GPUs[DeviceInd].Info) = *(GOPTable->Mode->Info); + } else if((xGfxHandles > 1) && (DeviceInd == 2)) { + // Native resolutions. Does not work right now. + Gfx->FBCount = xGfxHandles; + Status = BS->AllocatePool(EfiLoaderData, Gfx->FBCount * sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), (void**)&Gfx->GPUs); + if(EFI_ERROR(Status)) { + Print(L"GPUs AllocatePool error.\r\n"); + } + + for(DeviceInd = 0; DeviceInd < xGfxHandles; DeviceInd++) { + EFI_GRAPHICS_OUTPUT_PROTOCOL* GOPTable; + + Status = BS->OpenProtocol(GfxHandles[DeviceInd], &GraphicsOutputProtocol, (void**)&GOPTable, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(EFI_ERROR(Status)) { + Print(L"GraphicsTable OpenProtocol error.\r\n"); + } + + GfxMode = 0; + Status = GOPTable->SetMode(GOPTable, GfxMode); + if(EFI_ERRROR(Status)) { + Print(L"GraphicsTable SetMode error\r\n"); + } + + Status = BS->AllocatePool(EfiLoaderData, GOPTable->Mode->SizeOfInfo, (void**)&Gfx->GPUs[DeviceInd].Info); + if(EFI_ERROR(Status)) { + Print(L"GOP Mode->Info AllocatePool error.\r\n"); + } + + Gfx->GPUs[DeviceInd].MaxMode = GOPTable->Mode->MaxMode; + Gfx->GPUs[DeviceInd].Mode = GOPTable->Mode; + Gfx->GPUs[DeviceInd].SizeOfInfo = GOPTable->Mode->SizeOfInfo; + Gfx->GPUs[DeviceInd].FrameBufferSize = GOPTable->Mode->FrameBufferSize; + Gfx->GPUs[DeviceInd].FrameBufferBase = GOPTable->Mode->FrameBufferBase; + *(Gfx->GPUs[DeviceInd].Info) = *(GOPTable->Mode->Info); + } + + } else if((xGfxHandles > 1) && (DeviceInd == 3)) { + // Set all to 1024x768 + // This is Windows' default resolution, so every UEFI device supports it. + + Gfx->FBCount = xGfxHandles; + Status = BS->AllocatePool(EfiLoaderData, Gfx->FBCount * sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), (void**)&Gfx->GPUs); + + if(EFI_ERROR(Status)) { + Print(L"GPUs AllocatePool error.\r\n"); + } + + for(DeviceInd = 0; DeviceInd < xGfxHandles; DeviceInd++) { + EFI_GRAPHICS_OUTPUT_PROTOCOL* GOPTable; + Status = BS->OpenProtocol(GfxHandles[DeviceInd], &GraphicsOutputProtocol, (void**)&GOPTable, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(EFI_ERROR(Status)) { + Print(L"GraphicsTable OpenProtocol error.\r\n"); + } + + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* GOPInfo2; + size_t GOPInfoSize; + + for(GfxMode = 0; GfxMode < GOPTable->Mode->MaxMode; GfxMode++) { + Status = GOPTable->QueryMode(GOPTable, GfxMode, &GOPInfoSize, &GOPInfo2); + if(EFI_ERROR(Status)) { + Print(L"GraphicsTable QueryMode error\r\n"); + } + + if((GOPInfo2->HorizontalResolution == 1024) & (GOPInfo2->VerticalResolution == 768)) { + Status = BS->FreePool(GOPInfo2); + if(EFI_ERROR(Status)) { + Print(L"Error freeing GOPInfo2\r\n"); + } + + break; + } + + Status = BS->FreePool(GOPInfo2); + if(EFI_ERROR(Status)) { + Print(L"Error freeing GOPInfo2\r\n"); + } + + } + + if(GfxMode == GOPTable->Mode->MaxMode) { + Print(L"No 1024x768 mode. Defaulting to first available mode.\r\n"); + GfxMode = 0; + } + + Status = GOPTable->SetMode(GOPTable, GfxMode); + if(EFI_ERROR(Status)) { + Print(L"GraphicsTable SetMode Error\r\n"); + } + + Status = BS->AllocatePool(EfiLoaderData, GOPTable->Mode->SizeOfInfo, (void**)Gfx->GPUs[DeviceInd].Info); + if(EFI_ERROR(Status)) { + Print(L"GOP Mode->Info AllocatePool Error\r\n"); + } + + Gfx->GPUs[DeviceInd].MaxMode = GOPTable->Mode->MaxMode; + Gfx->GPUs[DeviceInd].Mode = GOPTable->Mode->Mode; + Gfx->GPUs[DeviceInd].SizeOfInfo = GOPTable->Mode->SizeOfInfo; + Gfx->GPUs[DeviceInd].FrameBufferSize = GOPTable->Mode->FrameBufferSize; + Gfx->GPUs[DeviceInd].FrameBufferBase = GOPTable->Mode->FrameBufferBase; + *(Gfx->GPUs[DeviceInd].Info) = *(GOPTable->Mode->Info); + + } + + } else { + // xGfxDevices = 1 + // AKA, only one GPU. + // The most common case for hardware. + // Rare for VMs. + + Gfx->FBCount = 1; + Status = BS->AllocatePool(EfiLoaderData, Gfx->FBCount * sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), (void**)&Gfx->GPUs); + + if(EFI_ERROR(Status)) { + Print(L"GPUs AllocatePool error.\r\n"); + } + + DeviceInd = 0; + + EFI_GRAPHICS_OUTPUT_PROTOCOL* GOPTable; + Status = BS->OpenProtocol(GfxHandles[DeviceInd], &GraphicsOutputProtocol, (void**)&GOPTable, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(EFI_ERROR(Status)) { + Print(L"GraphicsTable OpenProtocol error.\r\n"); + } + + if(GOPTable->Mode->MaxMode == 1) { + GfxMode = 0; + } else { + uint32_t DefaultMode = 0; + size_t Timeout = 5; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* GOPInfo2; + while (0x30 > Key.UnicodeChar || Key.UnicodeChar > (0x30 + GOPTable->Mode->MaxMode - 1)) { + Print(L"%s\r\n", DeviceNames[DeviceInd]); + Print(L"%u available graphics modes.\r\n\n", GOPTable->Mode->MaxMode); + Print(L"Current mode: %c\r\n", GOPTable->Mode->Mode + 0x30); + for (GfxMode = 0; GfxMode < GOPTable->Mode->MaxMode; GfxMode++) { + Status = GOPTable->QueryMode(GOPTable, GfxMode, &GOPInfoSize, &GOPInfo2); + if (EFI_ERROR(Status)) { + Print(L"GraphicsTable QueryMode error.\r\n"); + } + Print(L"%c, %ux%u, %u pixels per scan line, Pixel format %s\r\n", GfxMode + 0x30, GOPInfo2->HorizontalResolution, GOPInfo2->VerticalResolution, GOPInfo2->PixelsPerScanLine, pixelFormats[GOPInfo2->PixelFormat]); + Status = BS->FreePool(GOPInfo2); + if (EFI_ERROR(Status)) { + Print(L"Error freeing GOPInfo2 pool.\r\n"); + } + } + Print(L"\r\n"); + while (Timeout) { + Print(L"Please select a graphics mode. (0 - %c). Defaulting to mode %c in %llu... \r", 0x30 + GOPTable->Mode->MaxMode - 1, DefaultMode + 0x30, Timeout); + Status = WaitForSingleEvent(ST->ConIn->WaitForKey, 10000000); + if (Status != EFI_TIMEOUT) { + Status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key); + if (EFI_ERROR(Status)) { + Print(L"Error reading keystroke.\r\n"); + } + Print(L"\n\nSelected graphics mode %c.\r\n\n", Key.UnicodeChar); + break; + } + Timeout -= 1; + } + if (!Timeout) { + Print(L"\n\nDefaulting to mode %c..\r\n\n", DefaultMode + 0x30); + GfxMode = DefaultMode; + break; + } + } + + if (Timeout) { + GfxMode = (uint32_t)(Key.UnicodeChar - 0x30); + } + + Key.UnicodeChar = 0; + Print(L"Setting graphics mode %u of %u.\r\n\n", GfxMode + 1, GOPTable->Mode->MaxMode); + } + + Status = GOPTable->SetMode(GOPTable, GfxMode); + if (EFI_ERROR(Status)) { + Print(L"GOPTable SetMode error.\r\n"); + } + + Status = BS->AllocatePool(EfiLoaderData, GOPTable->Mode->SizeOfInfo, (void**)&Gfx->GPUs[DeviceInd].Info); + if (EFI_ERROR(Status)) { + Print(L"GOP Mode->Info AllocatePool error.\r\n"); + } + + Gfx->GPUs[DeviceInd].MaxMode = GOPTable->Mode->MaxMode; + Gfx->GPUs[DeviceInd].Mode = GOPTable->Mode->Mode; + Gfx->GPUs[DeviceInd].SizeOfInfo = GOPTable->Mode->SizeOfInfo; + Gfx->GPUs[DeviceInd].MaxMode = GOPTable->Mode->MaxMode; + Gfx->GPUs[DeviceInd].FrameBufferSize = GOPTable->Mode->FrameBufferSize; + Gfx->GPUs[DeviceInd].FrameBufferBase = GOPTable->Mode->FrameBufferBase; + + *(Gfx->GPUs[DeviceInd].Info) = *(GOPTable->Mode->Info); + } + + for(size_t StringNamesFree = 0; StringNamesFree < xGfxHandles; StringNamesFree++) { + Status = BS->FreePool(DeviceNames[StringNamesFree]); + if (EFI_ERROR(Status)) { + Print(L"NameBuffer[%llu] (%s) FreePool error.\r\n"); + } + } + + Status = BS->FreePool(DeviceNames); + if (EFI_ERROR(Status)) { + Print(L"NameBuffer FreePool error.\r\n"); + } + + Status = BS->FreePool(GfxHandles); + if (EFI_ERROR(Status)) { + Print(L"GfxHandles FreePool error.\r\n"); + } + + /* ================================== END OF GRAPHICS ================================== */ + + // Do we dare? + FILELOADER_PARAMS* Params; + + Status = BS->AllocatePool(EfiLoaderData, sizeof(FILELOADER_PARAMS), (void**)&Params); + if(EFI_ERROR(Status)) { + Print(L"Error allocating Loader Params.\r\n"); + } + + // Get information about the boot file + + EFI_PHYSICAL_ADDRESS KernelBase = 0; + size_t KernelPages = 0; + + EFI_LOADED_IMAGE_PROTOCOL* LoadedImage; + + Status = BS->OpenProtocol(ImageHandle, &LoadedImageProtocol, (void**)&LoadedImage, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(EFI_ERROR(Status)) { + Print(L"LoadedImageProtocol error\r\n"); + } + + Print(L"Sync loaded at 0x%llx\n", LoadedImage->ImageBase); + + CHAR16* ESPRootTemp = DevicePathToStr(DevicePathFromHandle(LoadedImage->DeviceHandle)); + size_t ESPRootSize = StrSize(ESPRootTemp); + + CHAR16* ESPRoot; + + Status = BS->AllocatePool(EfiLoaderData, ESPRootSize, (void**)&ESPRoot); + if(EFI_ERROR(Status)) { + Print(L"ESPRoot AllocatePool error.\r\n"); + } + + CopyMem(ESPRoot, ESPRootTemp, ESPRootSize); + + Status = BS->FreePool(ESPRootTemp); + if(EFI_ERROR(Status)) { + Print(L"ESPRoot FreePool error.\r\n"); + } + + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* FileSystem; + + Status = BS->OpenProtocol(LoadedImage->DeviceHandle, &FileSystemProtocol, (void**)&FileSystem, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if(EFI_ERROR(Status)) { + Print(L"FileSystem OpenProtocol Error\r\n"); + } + + EFI_FILE* CurrentDriveRoot; + + Status = FileSystem->OpenVolume(FileSystem, &CurrentDriveRoot); + if(EFI_ERROR(Status)) { + Print(L"FileSystem OpenVolume error\r\n"); + } + + size_t KernelPathSize = ESPRootSize + StrSize("BOOTX64.EFI"); + CHAR16* KernelPath = ESPRoot + L"BOOTX64.EFI"; + Print(L"Kernel Path is %s", KernelPath); + + Status = BS->AllocatePool(EfiLoaderData, KernelPathSize, (void**)&KernelPath); + if(EFI_ERROR(Status)) { + Print(L"KernelPath AllocatePool error.\r\n"); + } + + EFI_FILE* KernelFile; + + Status = CurrentDriveRoot->Open(CurrentDriveRoot, &KernelFile, KernelPath, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY); + if(EFI_ERROR(Status)) { + Print(L"Unknown error opening boot file. Aborting.\r\n"); + for(;;) {} + } + + size_t FileInfoSize; + Status = KernelFile->GetInfo(KernelFile, &gEfiFileInfoGuid, &FileInfoSize, NULL); + EFI_FILE_INFO* KernelFileInfo; + + Status = BS->AllocatePool(EfiLoaderData, FileInfoSize, (void**)&KernelFileInfo); + if(EFI_ERROR(Status)) { + Print(L"FileInfo AllocatePool error.\r\n"); + } + + Status = KernelFile->GetInfo(KernelFile, &gEfiFileInfoGuid, &FileInfoSize, KernelFileInfo); + if(EFI_ERROR(Status)) { + Print(L"Kernel file GetInfo error.\r\n"); + } + + size_t MapSize = 0; + size_t MapKey = 0; + size_t MapDescSize = 0; + + uint32_t MapDescriptorVersion = 0; + + EFI_MEMORY_DESCRIPTOR* Map = NULL; + + Status = BS->GetMemoryMap(&MapSize, Map, &MapKey, &MapDescSize, &MapDescriptorVersion); + if(Status == EFI_BUFFER_TOO_SMALL) { + Status = BS->AllocatePool(EfiLoaderData, MapSize, (void**)&Map); + if(EFI_ERROR(Status)) { + Print(L"Memory map AllocatePool error.\r\n"); + for(;;) {} + } + + Status = BS->GetMemoryMap(&MapSize, Map, &MapKey, &MapDescSize, &MapDescriptorVersion); + } + + Status = BS->ExitBootServices(ImageHandle, MapKey); + if(EFI_ERROR(Status)) { + Status = BS->FreePool(Map); + if(EFI_ERROR(Status)) { + Print(L"Error freeing memory map after failed EBS.\r\n"); + for(;;) {} + } + + MapSize = 0; + Status = BS->GetMemoryMap(&MapSize, Map, &MapKey, &MapDescSize, &MapDescriptorVersion); + if(Status == EFI_BUFFER_TOO_SMALL) { + Status = BS->AllocatePool(EfiLoaderData, MapSize, (void**)&Map); + if(EFI_ERROR(Status)) { + Print(L"Memory map AllocatePool error.\r\n"); + for(;;) {} + } + + Status = BS->GetMemoryMap(&MapSize, Map, &MapKey, &MapDescSize, &MapDescriptorVersion); + } + + Status = BS->ExitBootServices(ImageHandle, MapKey); + } + + + if(EFI_ERROR(Status)) { + Print(L"Errors occurred during boot. Will not go blindly into the night.\r\n"); + for (;;) {} + } + + + Params->UEFI_Version = ST->Hdr.Revision; + Params->Bootloader_MajorVersion = MAJOR_VER; + Params->Bootloader_MinorVersion = MINOR_VER; + Params->Memory_Descriptor_Version = MapDescriptorVersion; + Params->Memory_Descriptor_Size = MapDescSize; + + Params->Kernel_Base = KernelBase; + Params->Kernel_Pages = KernelPages; + + Params->ESP_Path = ESPRoot; + Params->ESP_Path_Length = ESPRootSize; + Params->Kernel_Path = KernelPath; + Params->Kernel_Path_Length = KernelPathSize; + Params->Kernel_Options = L""; + Params->Kernel_Options_Length = 0; + Params->RTServices = RT; + Params->GPU_INFO = Gfx; + Params->FileMeta = KernelFileInfo; + + Params->ConfigTables = ST->ConfigurationTable; + Params->ConfigTables_Length = ST->NumberOfTableEntries; + + kernel_main(Params); + +} \ No newline at end of file