refactor: drop posix-uefi from bootloader
Replace the vendored POSIX-UEFI runtime with a small local EFI entry and header so the bootloader depends only on the UEFI interfaces it actually uses. Made-with: Cursor
This commit is contained in:
+166
-100
@@ -1,144 +1,210 @@
|
||||
#include "uefi/uefi.h" // IWYU pragma: keep
|
||||
#include "uefi/uefi.h"
|
||||
#include "../../Common/bootinfo.h"
|
||||
|
||||
void print(wchar_t* msg) {
|
||||
ST->ConOut->OutputString(ST->ConOut, msg);
|
||||
#define PAGE_SIZE 0x1000
|
||||
#define WSTR(str) ((wchar_t*)L##str)
|
||||
|
||||
static wchar_t* kernel_path = WSTR("ksOSKernel.bin");
|
||||
static efi_guid_t dtb_guid = {
|
||||
0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}
|
||||
};
|
||||
|
||||
static void print(const wchar_t* msg) {
|
||||
ST->ConOut->OutputString(ST->ConOut, (wchar_t*)msg);
|
||||
}
|
||||
|
||||
efi_status_t die() {
|
||||
while(1) __asm__ volatile("wfi");
|
||||
static efi_status_t die(void) {
|
||||
while (1) {
|
||||
__asm__ volatile("wfi");
|
||||
}
|
||||
|
||||
return EFI_ABORTED;
|
||||
}
|
||||
|
||||
int compare_guid(efi_guid_t* a, efi_guid_t* b) {
|
||||
uint8_t* p1 = (uint8_t*)a;
|
||||
uint8_t* p2 = (uint8_t*)b;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (p1[i] != p2[i]) return 0;
|
||||
static efi_status_t fail(const wchar_t* msg) {
|
||||
print(msg);
|
||||
return die();
|
||||
}
|
||||
|
||||
static int guid_equal(const efi_guid_t* lhs, const efi_guid_t* rhs) {
|
||||
const uint8_t* lhs_bytes = (const uint8_t*)lhs;
|
||||
const uint8_t* rhs_bytes = (const uint8_t*)rhs;
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (lhs_bytes[i] != rhs_bytes[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
efi_gop_t* gop = NULL;
|
||||
efi_guid_t gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||
ST->BootServices->LocateProtocol(&gop_guid, 0, (void**)&gop);
|
||||
|
||||
efi_guid_t dtb_guid = {0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}};
|
||||
void* dtbAddress = NULL;
|
||||
|
||||
for (uintn_t i = 0; i < ST->NumberOfTableEntries; i++) {
|
||||
if (compare_guid(&ST->ConfigurationTable[i].VendorGuid, &dtb_guid)) {
|
||||
dtbAddress = ST->ConfigurationTable[i].VendorTable;
|
||||
break;
|
||||
static void* find_configuration_table(const efi_guid_t* guid) {
|
||||
for (uintn_t i = 0; i < ST->NumberOfTableEntries; ++i) {
|
||||
if (guid_equal(&ST->ConfigurationTable[i].VendorGuid, guid)) {
|
||||
return ST->ConfigurationTable[i].VendorTable;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dtbAddress) {
|
||||
print(L"Failed to find DTB!\r\n");
|
||||
return die();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
efi_loaded_image_protocol_t* loaded_image;
|
||||
efi_guid_t lip_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
||||
gBS->HandleProtocol(IM, &lip_guid, (void**)&loaded_image);
|
||||
|
||||
efi_simple_file_system_protocol_t* fs;
|
||||
efi_guid_t sfsp_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
||||
gBS->HandleProtocol(loaded_image->DeviceHandle, &sfsp_guid, (void**)&fs);
|
||||
|
||||
efi_file_handle_t* root;
|
||||
fs->OpenVolume(fs, &root);
|
||||
|
||||
efi_file_handle_t* kernel_file;
|
||||
uintn_t kinfo_size = 0;
|
||||
efi_file_info_t* kfile_info = NULL;
|
||||
efi_guid_t fi_guid = EFI_FILE_INFO_GUID;
|
||||
|
||||
efi_status_t status = root->Open(root, &kernel_file, L"ksOSKernel.bin", EFI_FILE_MODE_READ, 0);
|
||||
static efi_status_t open_root_volume(efi_file_handle_t** root) {
|
||||
efi_loaded_image_protocol_t* loaded_image = NULL;
|
||||
efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
||||
efi_status_t status = gBS->HandleProtocol(IM, &loaded_image_guid, (void**)&loaded_image);
|
||||
if (EFI_ERROR(status)) {
|
||||
print(L"Cant find ksOSKernel.bin\r\n");
|
||||
return die();
|
||||
return status;
|
||||
}
|
||||
|
||||
status = kernel_file->GetInfo(kernel_file, &fi_guid, &kinfo_size, NULL);
|
||||
if (status == EFI_BUFFER_TOO_SMALL) {
|
||||
gBS->AllocatePool(EfiLoaderData, kinfo_size, (void**)&kfile_info);
|
||||
status = kernel_file->GetInfo(kernel_file, &fi_guid, &kinfo_size, kfile_info);
|
||||
}
|
||||
|
||||
uint64_t kernel_size = kfile_info->FileSize;
|
||||
uintn_t kernel_size_read = (uintn_t)kernel_size;
|
||||
|
||||
uintn_t kernel_pages = (kernel_size + 0xFFF) / 0x1000;
|
||||
efi_physical_address_t kernel_addr = 0;
|
||||
|
||||
status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, kernel_pages, &kernel_addr);
|
||||
efi_simple_file_system_protocol_t* fs = NULL;
|
||||
efi_guid_t filesystem_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
||||
status = gBS->HandleProtocol(loaded_image->DeviceHandle, &filesystem_guid, (void**)&fs);
|
||||
if (EFI_ERROR(status)) {
|
||||
print(L"Failed to allocate ANY memory for kernel!\r\n");
|
||||
return die();
|
||||
return status;
|
||||
}
|
||||
|
||||
kernel_file->Read(kernel_file, &kernel_size_read, (void*)kernel_addr); \
|
||||
printf("Kernel loaded at %p\r\n", (void*)kernel_addr);
|
||||
return fs->OpenVolume(fs, root);
|
||||
}
|
||||
|
||||
Bootinfo* bootInfo = (Bootinfo*)malloc(sizeof(Bootinfo));
|
||||
bootInfo->magic = BOOTINFO_MAGIC;
|
||||
static efi_status_t read_file_info(efi_file_handle_t* file, efi_file_info_t** file_info) {
|
||||
efi_guid_t file_info_guid = EFI_FILE_INFO_GUID;
|
||||
uintn_t file_info_size = 0;
|
||||
efi_status_t status = file->GetInfo(file, &file_info_guid, &file_info_size, NULL);
|
||||
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||
return status;
|
||||
}
|
||||
|
||||
bootInfo->kernelInfo.kernelAddress = (void*)kernel_addr;
|
||||
bootInfo->kernelInfo.kernelSize = kernel_size;
|
||||
status = gBS->AllocatePool(EfiLoaderData, file_info_size, (void**)file_info);
|
||||
if (EFI_ERROR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
bootInfo->framebuffer.base = (BIUInt32*)gop->Mode->FrameBufferBase;
|
||||
bootInfo->framebuffer.baseSize = gop->Mode->FrameBufferSize;
|
||||
bootInfo->framebuffer.height = gop->Mode->Information->VerticalResolution;
|
||||
bootInfo->framebuffer.width = gop->Mode->Information->HorizontalResolution;
|
||||
bootInfo->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
||||
return file->GetInfo(file, &file_info_guid, &file_info_size, *file_info);
|
||||
}
|
||||
|
||||
bootInfo->dtb = dtbAddress;
|
||||
printf("DTB located at: %p\r\n", (void*)dtbAddress);
|
||||
|
||||
static efi_status_t load_kernel(efi_file_handle_t* root, efi_physical_address_t* kernel_addr, uint64_t* kernel_size) {
|
||||
efi_file_handle_t* kernel_file = NULL;
|
||||
efi_file_info_t* kernel_info = NULL;
|
||||
efi_status_t status = root->Open(root, &kernel_file, kernel_path, EFI_FILE_MODE_READ, 0);
|
||||
if (EFI_ERROR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = read_file_info(kernel_file, &kernel_info);
|
||||
if (EFI_ERROR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
*kernel_size = kernel_info->FileSize;
|
||||
|
||||
uintn_t bytes_to_read = (uintn_t)*kernel_size;
|
||||
uintn_t kernel_pages = (*kernel_size + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
*kernel_addr = 0;
|
||||
|
||||
status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, kernel_pages, kernel_addr);
|
||||
if (EFI_ERROR(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = kernel_file->Read(kernel_file, &bytes_to_read, (void*)*kernel_addr);
|
||||
if (EFI_ERROR(status) || bytes_to_read != (uintn_t)*kernel_size) {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
static efi_status_t populate_memory_map(Bootinfo* boot_info) {
|
||||
uintn_t map_size = 0;
|
||||
efi_memory_descriptor_t *map = NULL;
|
||||
uintn_t map_key;
|
||||
uintn_t desc_size;
|
||||
uint32_t desc_version;
|
||||
efi_memory_descriptor_t* map = NULL;
|
||||
uintn_t map_key = 0;
|
||||
uintn_t descriptor_size = 0;
|
||||
uint32_t descriptor_version = 0;
|
||||
|
||||
efi_status_t status = gBS->GetMemoryMap(&map_size, NULL, &map_key, &descriptor_size, &descriptor_version);
|
||||
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||
return status;
|
||||
}
|
||||
|
||||
print(L"Almost ready to jump :D. Working with memory map\r\n");
|
||||
|
||||
gBS->GetMemoryMap(&map_size, NULL, &map_key, &desc_size, &desc_version);
|
||||
map_size += 4096;
|
||||
// woah letsgoo
|
||||
map_size += PAGE_SIZE;
|
||||
status = gBS->AllocatePool(EfiLoaderData, map_size, (void**)&map);
|
||||
if (EFI_ERROR(status)) {
|
||||
print(L"Failed to allocate pool\r\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
do {
|
||||
status = gBS->GetMemoryMap(&map_size, map, &map_key, &desc_size, &desc_version);
|
||||
while (1) {
|
||||
status = gBS->GetMemoryMap(&map_size, map, &map_key, &descriptor_size, &descriptor_version);
|
||||
if (EFI_ERROR(status)) {
|
||||
break;
|
||||
return status;
|
||||
}
|
||||
|
||||
bootInfo->memoryMap.descriptorSize = desc_size;
|
||||
bootInfo->memoryMap.descriptorVersion = desc_version;
|
||||
bootInfo->memoryMap.mapSize = map_size;
|
||||
bootInfo->memoryMap.mapKey = map_key;
|
||||
bootInfo->memoryMap.map = map;
|
||||
|
||||
boot_info->memoryMap.descriptorSize = descriptor_size;
|
||||
boot_info->memoryMap.descriptorVersion = descriptor_version;
|
||||
boot_info->memoryMap.mapSize = map_size;
|
||||
boot_info->memoryMap.mapKey = map_key;
|
||||
boot_info->memoryMap.map = map;
|
||||
|
||||
status = gBS->ExitBootServices(IM, map_key);
|
||||
if (status == EFI_SUCCESS) {
|
||||
break; // FUCK OFF;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
map_size += 2 * desc_size;
|
||||
} while (EFI_ERROR(status));
|
||||
|
||||
typedef void (__attribute__((sysv_abi)) *kentry)(Bootinfo*);
|
||||
kentry kmain = (kentry)kernel_addr;
|
||||
map_size += 2 * descriptor_size;
|
||||
}
|
||||
}
|
||||
|
||||
kmain(bootInfo); // yay! :D
|
||||
efi_status_t bootloader_main(void) {
|
||||
efi_gop_t* gop = NULL;
|
||||
efi_guid_t gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||
efi_status_t status = ST->BootServices->LocateProtocol(&gop_guid, 0, (void**)&gop);
|
||||
if (EFI_ERROR(status) || gop == NULL) {
|
||||
return fail(WSTR("Failed to locate GOP\r\n"));
|
||||
}
|
||||
|
||||
void* dtb_address = find_configuration_table(&dtb_guid);
|
||||
if (dtb_address == NULL) {
|
||||
return fail(WSTR("Failed to find DTB\r\n"));
|
||||
}
|
||||
|
||||
efi_file_handle_t* root = NULL;
|
||||
status = open_root_volume(&root);
|
||||
if (EFI_ERROR(status)) {
|
||||
return fail(WSTR("Failed to open boot volume\r\n"));
|
||||
}
|
||||
|
||||
efi_physical_address_t kernel_addr = 0;
|
||||
uint64_t kernel_size = 0;
|
||||
status = load_kernel(root, &kernel_addr, &kernel_size);
|
||||
if (EFI_ERROR(status)) {
|
||||
return fail(WSTR("Failed to load ksOSKernel.bin\r\n"));
|
||||
}
|
||||
|
||||
Bootinfo* boot_info = NULL;
|
||||
status = gBS->AllocatePool(EfiLoaderData, sizeof(Bootinfo), (void**)&boot_info);
|
||||
if (EFI_ERROR(status) || boot_info == NULL) {
|
||||
return fail(WSTR("Failed to allocate boot info\r\n"));
|
||||
}
|
||||
|
||||
boot_info->magic = BOOTINFO_MAGIC;
|
||||
boot_info->kernelInfo.kernelAddress = (void*)kernel_addr;
|
||||
boot_info->kernelInfo.kernelSize = kernel_size;
|
||||
boot_info->framebuffer.base = (BIUInt32*)gop->Mode->FrameBufferBase;
|
||||
boot_info->framebuffer.baseSize = gop->Mode->FrameBufferSize;
|
||||
boot_info->framebuffer.height = gop->Mode->Information->VerticalResolution;
|
||||
boot_info->framebuffer.width = gop->Mode->Information->HorizontalResolution;
|
||||
boot_info->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
||||
boot_info->dtb = dtb_address;
|
||||
|
||||
print(WSTR("Almost ready to jump. Reading memory map\r\n"));
|
||||
status = populate_memory_map(boot_info);
|
||||
if (EFI_ERROR(status)) {
|
||||
return fail(WSTR("Failed to exit boot services\r\n"));
|
||||
}
|
||||
|
||||
typedef void (*kernel_entry_t)(Bootinfo*);
|
||||
kernel_entry_t kernel_main = (kernel_entry_t)kernel_addr;
|
||||
kernel_main(boot_info);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user