11#include "exit_boot_services.h"
12#include "framebuffer.h"
13#include "load_options.h"
15typedef uint16_t efi_char16_t;
27typedef efi_status_t (*efi_handle_protocol_t)(efi_handle_t,
efi_guid_t*,
void**);
28typedef efi_status_t (*efi_allocate_pages_t)(uint32_t, uint32_t, uint64_t, uint64_t*);
29typedef efi_status_t (*efi_locate_device_path_t)(
efi_guid_t*,
void**, efi_handle_t*);
30typedef efi_status_t (*efi_locate_handle_buffer_t)(uint32_t,
efi_guid_t*,
void*, uint64_t*,
32typedef efi_status_t (*efi_locate_protocol_t)(
efi_guid_t*,
void*,
void**);
42 efi_free_pool_t free_pool;
43 uint8_t before_handle_protocol[9 * 8];
44 efi_handle_protocol_t handle_protocol;
45 void* reserved_after_handle_protocol;
46 void* register_protocol_notify;
48 efi_locate_device_path_t locate_device_path;
49 void* install_configuration_table;
54 efi_exit_boot_services_t exit_boot_services;
55 uint8_t between_exit_and_open[5 * 8];
58 void* open_protocol_information;
59 void* protocols_per_handle;
60 efi_locate_handle_buffer_t locate_handle_buffer;
61 efi_locate_protocol_t locate_protocol;
64typedef efi_status_t (*efi_output_string_t)(
void*, efi_char16_t*);
67 efi_output_string_t output_string;
72 efi_char16_t* firmware_vendor;
73 uint32_t firmware_revision;
74 efi_handle_t console_in_handle;
76 efi_handle_t console_out_handle;
78 efi_handle_t standard_error_handle;
80 void* runtime_services;
82 uint64_t configuration_table_entries;
83 void* configuration_table;
88typedef efi_status_t (*efi_file_close_t)(
efi_file_t*);
89typedef efi_status_t (*efi_file_read_t)(
efi_file_t*, uint64_t*,
void*);
95 efi_file_close_t close;
101 efi_file_get_info_t get_info;
112 efi_handle_t parent_handle;
114 efi_handle_t device_handle;
117 uint32_t load_options_size;
127typedef struct efi_configuration_table {
142 uint32_t module_count;
144 uint32_t section_count;
145 uint32_t section_entry_size;
146 uint32_t section_string_index;
147 uint64_t section_headers;
149 uint32_t memory_map_length;
150 uint32_t memory_map_entry_size;
151 uint64_t command_line;
154 uint64_t framebuffer;
155 uint32_t framebuffer_width;
156 uint32_t framebuffer_height;
157 uint32_t framebuffer_pitch;
158 uint32_t framebuffer_bpp;
159 uint32_t framebuffer_format;
162_Static_assert(
sizeof(bootstrap_info_t) == 108,
"bootstrap wire layout must match the kernel");
164typedef struct elf64_header {
170 uint64_t program_header_offset;
171 uint64_t section_header_offset;
173 uint16_t header_size;
174 uint16_t program_header_size;
175 uint16_t program_header_count;
176 uint16_t section_header_size;
177 uint16_t section_header_count;
178 uint16_t section_string_index;
181typedef struct elf64_program_header {
185 uint64_t virtual_address;
186 uint64_t physical_address;
188 uint64_t memory_size;
192typedef struct elf64_section_header {
205#define EFI_ALLOCATE_MAX_ADDRESS 1
206#define EFI_ALLOCATE_ADDRESS 2
207#define EFI_LOADER_DATA 4
208#define EFI_FILE_MODE_READ 1
209#define EFI_CONVENTIONAL_MEMORY 7
210#define EFI_ACPI_RECLAIM_MEMORY 9
211#define EFI_ACPI_MEMORY_NVS 10
212#define EFI_LOCATE_BY_PROTOCOL 2
213#define EFI_DEVICE_PATH_TYPE_END 0x7f
214#define EFI_DEVICE_PATH_TYPE_MEDIA 4
215#define EFI_DEVICE_PATH_SUBTYPE_FILE_PATH 4
216#define BOOTSTRAP_FLAG_CMDLINE 0x001
217#define BOOTSTRAP_FLAG_UEFI 0x080
218#define EFI_PAGE_SIZE 4096
219#define BOOTSTRAP_FLAG_MODULES 0x002
220#define BOOTSTRAP_FLAG_ELF 0x004
221#define BOOTSTRAP_FLAG_MEMORY_MAP 0x008
222#define BOOTSTRAP_FLAG_ACPI 0x010
223#define BOOTSTRAP_FLAG_SMBIOS 0x020
224#define BOOTSTRAP_FLAG_FRAMEBUFFER 0x040
225#define PHYS_ALIAS 0xffff800000000000ULL
226#define KERNEL_BASE 0xffffffff7ff00000ULL
231 0x5b1b31a1, 0x9562, 0x11d2, {0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}};
232static const efi_guid_t simple_file_system_guid = {
233 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}};
235 0x09576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}};
237 0x8868e871, 0xe4f1, 0x11d3, {0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81}};
239 0xeb9d2d31, 0x2d88, 0x11d3, {0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d}};
240static const efi_guid_t graphics_output_guid = {
241 0x9042a9de, 0x23dc, 0x4a38, {0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a}};
243 0xbd8c1056, 0x9f36, 0x44ec, {0x92, 0xa8, 0xa6, 0x33, 0x7f, 0x81, 0x79, 0x86}};
245 0x09576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}};
246static const efi_char16_t current_prefix[] = L
"\\EFI\\PEDIGREE\\current\\";
247static const efi_char16_t known_good_prefix[] = L
"\\EFI\\PEDIGREE\\known-good\\";
248static const efi_char16_t debug_prefix[] = L
"\\EFI\\PEDIGREE\\debug\\";
249static const efi_char16_t removable_prefix[] = L
"\\EFI\\BOOT\\";
256 if (services->handle_protocol(graphics_handle, (
efi_guid_t*)&edid_active_guid, (
void**)&edid) ==
261 efi_handle_t* outputs = 0;
264 if (services->locate_handle_buffer(EFI_LOCATE_BY_PROTOCOL, (
efi_guid_t*)&edid_active_guid, 0,
265 &count, &outputs) == EFI_SUCCESS &&
267 for (uint64_t i = 0; i < count && !edid; ++i) {
269 efi_handle_t owner = 0;
270 if (services->handle_protocol(outputs[i], (
efi_guid_t*)&device_path_guid, &path) !=
273 services->locate_device_path((
efi_guid_t*)&graphics_output_guid, &path, &owner) !=
275 owner != graphics_handle)
277 if (services->handle_protocol(outputs[i], (
efi_guid_t*)&edid_active_guid, (
void**)&edid) !=
283 services->free_pool(outputs);
287static void prepare_framebuffer(bootstrap_info_t* info) {
291 if (services->handle_protocol(g_system_table->console_out_handle,
293 (
void**)&console) != EFI_SUCCESS)
295 const uint64_t console_address = console && console->mode ? console->mode->framebuffer : 0;
296 efi_handle_t* handles = 0;
299 if (services->locate_handle_buffer(EFI_LOCATE_BY_PROTOCOL, (
efi_guid_t*)&graphics_output_guid, 0,
300 &count, &handles) == EFI_SUCCESS &&
304 for (
unsigned pass = 0; pass < 3 && !selected; ++pass) {
305 for (uint64_t i = 0; i < count && !selected; ++i) {
308 if (services->handle_protocol(handles[i], (
efi_guid_t*)&device_path_guid, &path) !=
311 services->handle_protocol(handles[i], (
efi_guid_t*)&graphics_output_guid,
312 (
void**)&graphics) != EFI_SUCCESS ||
316 uint32_t width, height;
317 const int associated =
318 handles[i] == g_system_table->console_out_handle ||
319 (console_address && graphics->mode && graphics->mode->framebuffer == console_address);
320 unsigned priority = 2;
323 else if (preferred_framebuffer_size(edid, &width, &height))
325 if (priority == pass)
326 selected = select_framebuffer_mode(graphics, services->free_pool, edid, &framebuffer);
331 services->free_pool(handles);
333 !select_framebuffer_mode(console, services->free_pool,
334 framebuffer_edid(g_system_table->console_out_handle), &framebuffer))
337 info->framebuffer = framebuffer.address;
338 info->framebuffer_width = framebuffer.width;
339 info->framebuffer_height = framebuffer.height;
340 info->framebuffer_pitch = framebuffer.pitch;
341 info->framebuffer_bpp = framebuffer.bpp;
342 info->framebuffer_format = framebuffer.format;
343 info->flags |= BOOTSTRAP_FLAG_FRAMEBUFFER;
346static void zero(
void* p, uint64_t size) {
347 uint8_t* bytes = (uint8_t*)p;
352static void copy(
void* destination,
const void* source, uint64_t size) {
353 uint8_t* d = (uint8_t*)destination;
354 const uint8_t* s = (
const uint8_t*)source;
360 const efi_char16_t* name, efi_char16_t* path,
361 uint64_t path_capacity) {
362 const efi_char16_t* prefix = current_prefix;
363 uint64_t prefix_length =
sizeof(current_prefix) /
sizeof(current_prefix[0]) - 1;
364 efi_char16_t* file_path = 0;
365 uint64_t file_path_length = 0;
366 efi_device_path_t* node = loaded_image ? (efi_device_path_t*)loaded_image->file_path : 0;
368 while (node && node->length >=
sizeof(*node) && node->type != EFI_DEVICE_PATH_TYPE_END) {
369 if (node->type == EFI_DEVICE_PATH_TYPE_MEDIA &&
370 node->subtype == EFI_DEVICE_PATH_SUBTYPE_FILE_PATH) {
371 file_path = (efi_char16_t*)(node + 1);
372 file_path_length = (node->length -
sizeof(*node)) /
sizeof(efi_char16_t);
374 node = (efi_device_path_t*)((uint8_t*)node + node->length);
378 uint64_t separator = 0;
379 int has_separator = 0;
381 while (length < file_path_length && file_path[length]) {
382 if (file_path[length] ==
'\\') {
390 if (file_path && has_separator) {
392 prefix_length = separator + 1;
393 uint64_t removable_media_length =
sizeof(removable_prefix) /
sizeof(removable_prefix[0]) - 1;
394 if (prefix_length == removable_media_length) {
395 int is_removable_media_path = 1;
396 for (uint64_t i = 0; i < removable_media_length; ++i) {
397 if (prefix[i] != removable_prefix[i])
398 is_removable_media_path = 0;
400 if (is_removable_media_path) {
401 prefix = current_prefix;
402 prefix_length =
sizeof(current_prefix) /
sizeof(current_prefix[0]) - 1;
407 if (
options->directory == UEFI_BOOT_DIRECTORY_KNOWN_GOOD) {
408 prefix = known_good_prefix;
409 prefix_length =
sizeof(known_good_prefix) /
sizeof(known_good_prefix[0]) - 1;
410 }
else if (
options->directory == UEFI_BOOT_DIRECTORY_CURRENT) {
411 prefix = current_prefix;
412 prefix_length =
sizeof(current_prefix) /
sizeof(current_prefix[0]) - 1;
413 }
else if (
options->directory == UEFI_BOOT_DIRECTORY_DEBUG) {
414 prefix = debug_prefix;
415 prefix_length =
sizeof(debug_prefix) /
sizeof(debug_prefix[0]) - 1;
418 uint64_t name_length = 0;
419 while (name[name_length])
421 if (prefix_length + name_length + 1 > path_capacity)
424 for (uint64_t i = 0; i < prefix_length; ++i)
426 for (uint64_t i = 0; i < name_length; ++i)
427 path[prefix_length + i] = name[i];
428 path[prefix_length + name_length] = 0;
432static void print(
const efi_char16_t*
message) {
433 if (g_system_table && g_system_table->con_out)
434 g_system_table->con_out->output_string(g_system_table->con_out, (efi_char16_t*)
message);
437static uint64_t pages_for(uint64_t size) {
438 return (size + EFI_PAGE_SIZE - 1) >> 12;
441static void* allocate_pages(uint64_t size, uint64_t max_address) {
442 uint64_t address = max_address;
443 efi_status_t status = ((efi_allocate_pages_t)g_system_table->boot_services->allocate_pages)(
444 EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA, pages_for(size), &address);
445 return status == EFI_SUCCESS ? (
void*)address : 0;
448static void* allocate_at(uint64_t address, uint64_t size) {
449 uint64_t location = address;
450 efi_status_t status = ((efi_allocate_pages_t)g_system_table->boot_services->allocate_pages)(
451 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, pages_for(size), &location);
452 return status == EFI_SUCCESS ? (
void*)location : 0;
457 uint64_t size =
sizeof(info);
458 if (file->get_info(file, (
efi_guid_t*)&file_info_guid, &size, info) != EFI_SUCCESS)
460 return *(uint64_t*)(info + 8);
463static void* read_file(
efi_file_t* root, efi_char16_t* path, uint64_t* length) {
465 if (root->open(root, &file, path, EFI_FILE_MODE_READ, 0) != EFI_SUCCESS)
467 uint64_t size = file_size(file);
468 void* buffer = size ? allocate_pages(size + 1, 0xffffffffULL) : 0;
469 if (!buffer || file->read(file, &size, buffer) != EFI_SUCCESS) {
473 ((uint8_t*)buffer)[size] = 0;
479static int open_boot_filesystem(
efi_loaded_image_t* loaded_image, efi_char16_t* probe_path,
481 efi_handle_t filesystem_handle = loaded_image->device_handle;
486 if (g_system_table->boot_services->handle_protocol(filesystem_handle,
488 (
void**)&filesystem) == EFI_SUCCESS &&
489 filesystem->open_volume(filesystem, &root) == EFI_SUCCESS &&
490 root->open(root, &probe, probe_path, EFI_FILE_MODE_READ, 0) == EFI_SUCCESS) {
492 *filesystem_out = filesystem;
499 void* device_path = loaded_image->file_path;
500 if (g_system_table->boot_services->locate_device_path &&
501 g_system_table->boot_services->locate_device_path(
502 (
efi_guid_t*)&simple_file_system_guid, &device_path, &filesystem_handle) == EFI_SUCCESS &&
503 g_system_table->boot_services->handle_protocol(filesystem_handle,
505 (
void**)&filesystem) == EFI_SUCCESS &&
506 filesystem->open_volume(filesystem, &root) == EFI_SUCCESS &&
507 root->open(root, &probe, probe_path, EFI_FILE_MODE_READ, 0) == EFI_SUCCESS) {
509 *filesystem_out = filesystem;
517 if (!g_system_table->boot_services->locate_handle_buffer)
519 efi_handle_t* handles = 0;
520 uint64_t handle_count = 0;
521 if (g_system_table->boot_services->locate_handle_buffer(EFI_LOCATE_BY_PROTOCOL,
523 &handle_count, &handles) != EFI_SUCCESS)
525 for (uint64_t i = 0; i < handle_count; ++i) {
528 if (g_system_table->boot_services->handle_protocol(handles[i],
530 (
void**)&filesystem) != EFI_SUCCESS ||
531 filesystem->open_volume(filesystem, &root) != EFI_SUCCESS)
533 if (root->open(root, &probe, probe_path, EFI_FILE_MODE_READ, 0) == EFI_SUCCESS) {
535 *filesystem_out = filesystem;
544static void enter_kernel(uint64_t entry, uint64_t info)
__attribute__((noreturn));
545static void enter_kernel(uint64_t entry, uint64_t info) {
546 __asm__
volatile(
"cli\n\tmov %0, %%rbx\n\tjmp *%1" : :
"r"(info),
"r"(entry) :
"memory");
548 __asm__
volatile(
"hlt");
552 g_system_table = system_table;
553 print((efi_char16_t*)L
"Pedigree UEFI loader\r\n");
556 if (system_table->boot_services->handle_protocol(image, (
efi_guid_t*)&loaded_image_guid,
557 (
void**)&loaded_image) != EFI_SUCCESS) {
558 print((efi_char16_t*)L
"UEFI: loaded-image protocol failed\r\n");
563 if (!parse_load_options(loaded_image->load_options, loaded_image->load_options_size, &
options)) {
564 print((efi_char16_t*)L
"UEFI: invalid load options\r\n");
568 static const efi_char16_t kernel_name[] = L
"kernel";
569 static const efi_char16_t initrd_name[] = L
"initrd.tar";
570 static const efi_char16_t cmdline_name[] = L
"cmdline";
571 efi_char16_t kernel_path[256];
572 efi_char16_t initrd_path[256];
573 efi_char16_t cmdline_path[256];
574 if (!build_artifact_path(loaded_image, &
options, kernel_name, kernel_path, 256) ||
575 !build_artifact_path(loaded_image, &
options, initrd_name, initrd_path, 256) ||
576 !build_artifact_path(loaded_image, &
options, cmdline_name, cmdline_path, 256)) {
577 print((efi_char16_t*)L
"UEFI: loader path is too long\r\n");
582 if (!open_boot_filesystem(loaded_image, kernel_path, &filesystem, &root)) {
583 print((efi_char16_t*)L
"UEFI: filesystem protocol failed\r\n");
586 uint64_t kernel_length = 0;
587 uint64_t initrd_length = 0;
588 uint64_t cmdline_length = 0;
589 uint8_t* kernel_file = (uint8_t*)read_file(root, kernel_path, &kernel_length);
590 uint8_t* initrd = (uint8_t*)read_file(root, initrd_path, &initrd_length);
591 uint8_t* cmdline = (uint8_t*)read_file(root, cmdline_path, &cmdline_length);
592 if (!kernel_file || !initrd || !cmdline) {
593 print((efi_char16_t*)L
"UEFI: file read failed\r\n");
596 if (
options.arguments_length) {
597 char* combined = (
char*)allocate_pages(UEFI_COMMAND_LINE_CAPACITY, 0xffffffffULL);
598 if (!combined || !append_load_options(cmdline, cmdline_length, &
options, combined,
599 UEFI_COMMAND_LINE_CAPACITY)) {
600 print((efi_char16_t*)L
"UEFI: invalid combined command line\r\n");
603 cmdline = (uint8_t*)combined;
606 if (kernel_length <
sizeof(*header) || header->ident[0] != 0x7f || header->ident[1] !=
'E' ||
607 header->ident[2] !=
'L' || header->ident[3] !=
'F' || header->ident[4] != 2 ||
608 header->machine != 0x3e) {
609 print((efi_char16_t*)L
"UEFI: invalid ELF\r\n");
612 print((efi_char16_t*)L
"UEFI: loading kernel\r\n");
614 for (uint16_t i = 0; i < header->program_header_count; ++i) {
615 elf64_program_header_t* program =
616 (elf64_program_header_t*)(kernel_file + header->program_header_offset +
617 i * header->program_header_size);
618 if (program->type != PT_LOAD)
620 uint8_t* destination = (uint8_t*)allocate_at(program->physical_address, program->memory_size);
622 print((efi_char16_t*)L
"UEFI: kernel allocation failed\r\n");
625 copy(destination, kernel_file + program->offset, program->file_size);
626 if (program->memory_size > program->file_size)
627 zero(destination + program->file_size, program->memory_size - program->file_size);
630 if (header->section_header_offset && header->section_header_count) {
631 for (uint16_t i = 0; i < header->section_header_count; ++i) {
632 elf64_section_header_t* section =
633 (elf64_section_header_t*)(kernel_file + header->section_header_offset +
634 i * header->section_header_size);
635 if (!(section->flags & SHF_ALLOC) && section->size)
636 section->address = PHYS_ALIAS + (uint64_t)kernel_file + section->offset;
640 bootstrap_info_t* info = (bootstrap_info_t*)allocate_pages(4 * EFI_PAGE_SIZE, 0xffffffffULL);
641 void* memory_map = allocate_pages(128 * EFI_PAGE_SIZE, 0xffffffffULL);
642 void* normalized_memory_map = allocate_pages(128 * EFI_PAGE_SIZE, 0xffffffffULL);
643 if (!info || !memory_map || !normalized_memory_map) {
644 print((efi_char16_t*)L
"UEFI: metadata allocation failed\r\n");
648 zero(info, 4 * EFI_PAGE_SIZE);
649 modules[0].base = (uint64_t)initrd;
650 modules[0].end = modules[0].base + initrd_length;
652 BOOTSTRAP_FLAG_CMDLINE | BOOTSTRAP_FLAG_MODULES | BOOTSTRAP_FLAG_ELF | BOOTSTRAP_FLAG_UEFI;
653 info->module_count = 1;
654 info->modules = PHYS_ALIAS + (uint64_t)modules;
655 info->section_count = header->section_header_count;
656 info->section_entry_size = header->section_header_size;
657 info->section_string_index = header->section_string_index;
658 info->section_headers = PHYS_ALIAS + (uint64_t)kernel_file + header->section_header_offset;
659 info->command_line = PHYS_ALIAS + (uint64_t)cmdline;
661 for (uint64_t i = 0; i < system_table->configuration_table_entries; ++i) {
664 if (table->vendor_guid.a == acpi20_guid.a && table->vendor_guid.b == acpi20_guid.b &&
665 table->vendor_guid.c == acpi20_guid.c) {
666 info->flags |= BOOTSTRAP_FLAG_ACPI;
667 info->acpi_rsdp = PHYS_ALIAS + (uint64_t)table->vendor_table;
669 if (table->vendor_guid.a == smbios_guid.a && table->vendor_guid.b == smbios_guid.b &&
670 table->vendor_guid.c == smbios_guid.c) {
671 info->flags |= BOOTSTRAP_FLAG_SMBIOS;
672 info->smbios = PHYS_ALIAS + (uint64_t)table->vendor_table;
676 prepare_framebuffer(info);
678 uint32_t normalized_bytes = 0;
679 int exit_attempted = 0;
680 const efi_get_memory_map_t get_map =
681 (efi_get_memory_map_t)system_table->boot_services->get_memory_map;
682 const efi_exit_boot_services_t exit_services = system_table->boot_services->exit_boot_services;
683 const efi_status_t exit_status =
684 exit_boot_services_with_map(get_map, exit_services, image, memory_map, 128 * EFI_PAGE_SIZE,
686 128 * EFI_PAGE_SIZE, &normalized_bytes, &exit_attempted);
687 if (exit_status != EFI_SUCCESS) {
688 if (!exit_attempted) {
689 print((efi_char16_t*)L
"UEFI: invalid or unavailable memory map\r\n");
693 __asm__
volatile(
"cli" :::
"memory");
695 __asm__
volatile(
"hlt");
697 info->flags |= BOOTSTRAP_FLAG_MEMORY_MAP;
698 info->memory_map = PHYS_ALIAS + (uint64_t)normalized_memory_map;
699 info->memory_map_length = normalized_bytes;
702 enter_kernel(header->entry - KERNEL_BASE, PHYS_ALIAS + (uint64_t)info);