uefi: Implement chainloading support
This commit is contained in:
parent
96b987273d
commit
db3a41bc4c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue