uefi: Implement chainloading support

This commit is contained in:
mintsuki 2021-05-06 04:31:05 +02:00
parent 96b987273d
commit db3a41bc4c
8 changed files with 150 additions and 29 deletions

View File

@ -213,10 +213,14 @@ struct volume *disk_volume_from_efi_handle(EFI_HANDLE *efi_handle) {
EFI_DISK_IO *disk_io = NULL;
EFI_BLOCK_IO *block_io = NULL;
uefi_call_wrapper(gBS->HandleProtocol, 3, efi_handle, &disk_io_guid,
&disk_io);
uefi_call_wrapper(gBS->HandleProtocol, 3, efi_handle, &block_io_guid,
&block_io);
status = uefi_call_wrapper(gBS->HandleProtocol, 3, efi_handle, &disk_io_guid,
&disk_io);
if (status)
return NULL;
status = uefi_call_wrapper(gBS->HandleProtocol, 3, efi_handle, &block_io_guid,
&block_io);
if (status)
return NULL;
uint64_t signature = BUILD_ID;
uint64_t orig;
@ -233,6 +237,7 @@ struct volume *disk_volume_from_efi_handle(EFI_HANDLE *efi_handle) {
if (volume_index[i]->drive == 0xe0)
return volume_index[i];
}
return NULL;
}

View File

@ -24,11 +24,28 @@ void stage3_common(void);
#if defined (uefi)
EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
// Invalid return address of 0 to end stacktraces here
asm volatile (
"push 0\n\t"
"xor eax, eax\n\t"
"jmp uefi_entry\n\t"
:
: "D" (ImageHandle), "S" (SystemTable)
: "memory"
);
__builtin_unreachable();
}
__attribute__((noreturn))
void uefi_entry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
gST = SystemTable;
gBS = SystemTable->BootServices;
gRT = SystemTable->RuntimeServices;
efi_image_handle = ImageHandle;
EFI_STATUS status;
init_memmap();
term_vbe(0, 0);
@ -38,24 +55,29 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable
disk_create_index();
EFI_GUID loaded_img_prot_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
EFI_LOADED_IMAGE_PROTOCOL *loaded_image = NULL;
EFI_HANDLE current_handle = ImageHandle;
for (;;) {
EFI_GUID loaded_img_prot_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
EFI_LOADED_IMAGE_PROTOCOL *loaded_image = NULL;
uefi_call_wrapper(gBS->HandleProtocol, 3, ImageHandle, &loaded_img_prot_guid,
&loaded_image);
status = uefi_call_wrapper(gBS->HandleProtocol, 3,
current_handle, &loaded_img_prot_guid,
&loaded_image);
boot_volume = disk_volume_from_efi_handle(loaded_image->DeviceHandle);
if (boot_volume == NULL) {
panic("Can't determine boot disk");
if (status) {
panic("HandleProtocol failure (%x)\n", status);
}
boot_volume = disk_volume_from_efi_handle(loaded_image->DeviceHandle);
if (boot_volume != NULL)
stage3_common();
if (loaded_image->ParentHandle == 0)
panic("Can't determine boot disk");
current_handle = loaded_image->ParentHandle;
}
// Invalid return address of 0 to end stacktraces here
asm volatile (
"push 0\n\t"
"jmp stage3_common\n\t"
);
__builtin_unreachable();
}
#endif
@ -99,11 +121,7 @@ void stage3_common(void) {
} else if (!strcmp(proto, "linux")) {
linux_load(config, cmdline);
} else if (!strcmp(proto, "chainload")) {
#if defined (bios)
chainload(config);
#elif defined (uefi)
panic("UEFI Limine does not support the chainload boot protocol");
#endif
}
panic("Invalid protocol specified");

View File

@ -113,7 +113,7 @@ int fread(struct file_handle *fd, void *buf, uint64_t loc, uint64_t count) {
void *freadall(struct file_handle *fd, uint32_t type) {
if (fd->is_memfile) {
memmap_alloc_range((uint64_t)(size_t)fd->fd, fd->size, type, false, true, false, false);
memmap_alloc_range((uint64_t)(size_t)fd->fd, ALIGN_UP(fd->size, 4096), type, false, true, false, false);
return fd->fd;
} else {
void *ret = ext_mem_alloc_type(fd->size, type);

View File

@ -15,6 +15,7 @@
#define MEMMAP_KERNEL_AND_MODULES 0x1001
#define MEMMAP_FRAMEBUFFER 0x1002
#define MEMMAP_EFI_RECLAIMABLE 0x2000
#define MEMMAP_EFI_LOADER 0x2001
extern struct e820_entry_t memmap[];
extern size_t memmap_entries;
@ -31,6 +32,7 @@ void *conv_mem_alloc(size_t count);
#if defined (uefi)
void pmm_reclaim_uefi_mem(void);
void pmm_release_uefi_mem(void);
#endif
#endif

View File

@ -69,6 +69,8 @@ static const char *memmap_type(uint32_t type) {
return "Kernel/Modules";
case MEMMAP_EFI_RECLAIMABLE:
return "EFI reclaimable";
case MEMMAP_EFI_LOADER:
return "EFI loader";
default:
return "???";
}
@ -280,7 +282,7 @@ void init_memmap(void) {
our_type = MEMMAP_EFI_RECLAIMABLE; break;
case EfiLoaderCode:
case EfiLoaderData:
our_type = MEMMAP_BOOTLOADER_RECLAIMABLE; break;
our_type = MEMMAP_EFI_LOADER; break;
case EfiACPIReclaimMemory:
our_type = MEMMAP_ACPI_RECLAIMABLE; break;
case EfiACPIMemoryNVS:
@ -323,13 +325,14 @@ void init_memmap(void) {
AllocateAddress, EfiLoaderData, memmap[i].length / 4096, &base);
if (status)
panic("AllocatePages %x", status);
panic("pmm: AllocatePages failure (%x)", status);
}
}
void pmm_reclaim_uefi_mem(void) {
for (size_t i = 0; i < memmap_entries; i++) {
if (memmap[i].type != MEMMAP_EFI_RECLAIMABLE)
if (memmap[i].type != MEMMAP_EFI_RECLAIMABLE
&& memmap[i].type != MEMMAP_EFI_LOADER)
continue;
memmap[i].type = MEMMAP_USABLE;
@ -337,6 +340,25 @@ void pmm_reclaim_uefi_mem(void) {
sanitise_entries(false);
}
void pmm_release_uefi_mem(void) {
EFI_STATUS status;
for (size_t i = 0; i < memmap_entries; i++) {
if (memmap[i].type != MEMMAP_USABLE
&& memmap[i].type != MEMMAP_BOOTLOADER_RECLAIMABLE) {
continue;
}
status = uefi_call_wrapper(gBS->FreePages, 2,
memmap[i].base, memmap[i].length / 4096);
if (status)
panic("pmm: FreePages failure (%x)", status);
}
allocations_disallowed = true;
}
#endif
void *ext_mem_alloc(size_t count) {

View File

@ -1,5 +1,3 @@
#if defined (bios)
#include <stddef.h>
#include <stdint.h>
#include <protos/chainload.h>
@ -8,8 +6,17 @@
#include <lib/blib.h>
#include <drivers/disk.h>
#include <lib/term.h>
#include <lib/fb.h>
#include <lib/uri.h>
#include <lib/print.h>
#include <sys/idt.h>
#include <drivers/vga_textmode.h>
#include <mm/pmm.h>
#if defined (uefi)
# include <efi.h>
#endif
#if defined (bios)
__attribute__((noinline))
__attribute__((section(".realmode")))
@ -95,4 +102,65 @@ void chainload(char *config) {
spinup(drive);
}
#elif defined (uefi)
void chainload(char *config) {
EFI_STATUS status;
char *image_path = config_get_value(config, 0, "IMAGE_PATH");
if (image_path == NULL)
panic("chainload: IMAGE_PATH not specified");
struct file_handle *image = ext_mem_alloc(sizeof(struct file_handle));
if (!uri_open(image, image_path))
panic("chainload: Could not open image");
void *ptr = freadall(image, MEMMAP_RESERVED);
term_deinit();
int req_width = 0, req_height = 0, req_bpp = 0;
char *resolution = config_get_value(config, 0, "RESOLUTION");
if (resolution != NULL)
parse_resolution(&req_width, &req_height, &req_bpp, resolution);
struct fb_info fbinfo;
if (!fb_init(&fbinfo, req_width, req_height, req_bpp))
panic("chainload: Unable to set video mode");
pmm_release_uefi_mem();
MEMMAP_DEVICE_PATH memdev_path[2];
memdev_path[0].Header.Type = HARDWARE_DEVICE_PATH;
memdev_path[0].Header.SubType = HW_MEMMAP_DP;
memdev_path[0].Header.Length[0] = sizeof(MEMMAP_DEVICE_PATH);
memdev_path[0].Header.Length[1] = sizeof(MEMMAP_DEVICE_PATH) >> 8;
memdev_path[0].MemoryType = EfiLoaderData;
memdev_path[0].StartingAddress = (uintptr_t)ptr;
memdev_path[0].EndingAddress = (uintptr_t)ptr + image->size;
memdev_path[1].Header.Type = END_DEVICE_PATH_TYPE;
memdev_path[1].Header.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
memdev_path[1].Header.Length[0] = sizeof(MEMMAP_DEVICE_PATH);
memdev_path[1].Header.Length[1] = sizeof(MEMMAP_DEVICE_PATH) >> 8;
EFI_HANDLE new_handle = 0;
status = uefi_call_wrapper(gBS->LoadImage, 6, 0, efi_image_handle, memdev_path,
ptr, image->size, &new_handle);
if (status) {
panic("chainload: LoadImage failure (%x)", status);
}
status = uefi_call_wrapper(gBS->StartImage, 3, new_handle, NULL, NULL);
if (status) {
panic("chainload: StartImage failure (%x)", status);
}
__builtin_unreachable();
}
#endif

View File

@ -564,6 +564,7 @@ void linux_load(char *config, char *cmdline) {
switch (e820_table[i].type) {
case MEMMAP_BOOTLOADER_RECLAIMABLE:
case MEMMAP_EFI_RECLAIMABLE:
case MEMMAP_EFI_LOADER:
e820_table[i].type = MEMMAP_USABLE;
break;
}

View File

@ -20,6 +20,11 @@ KERNEL_CMDLINE=Woah! Another example!
MODULE_PATH=boot:///boot/bg.bmp
MODULE_STRING=yooooo
:EFI Chainloading
PROTOCOL=chainload
IMAGE_PATH=boot:///EFI/BOOT/BOOTX64.EFI
:+Legacy
::Stivale Test