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.
This commit is contained in:
Curle 2019-09-11 23:44:11 +01:00
parent 51af007cd5
commit 8a54815712
3 changed files with 925 additions and 0 deletions

99
include/efiboot.h Normal file
View File

@ -0,0 +1,99 @@
#pragma once
#include <efi/efi.h>
#include <efi/efilib.h>
#include <stddef.h>
#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 };

View File

@ -618,6 +618,8 @@ static const char* ExceptionStrings[] = {
/* = Sync Functions = */ /* = Sync Functions = */
/* ============================================================= */ /* ============================================================= */
int kernel_main(FILELOADER_PARAMS* FLOP);
/* Required functions */ /* Required functions */
size_t strlen(const char* string); size_t strlen(const char* string);

824
kernel/boot.c Normal file
View File

@ -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 <efiboot.h>
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);
}