2#include "pedigree/kernel/processor/armv7/UefiHandoff.h"
6#include "exit_boot_services.h"
8typedef uint16_t efi_char16_t;
17typedef efi_status_t (*efi_handle_protocol_t)(efi_handle_t,
efi_guid_t*,
void**);
18typedef efi_status_t (*efi_allocate_pages_t)(uint32_t, uint32_t, uintptr_t, uint64_t*);
24 efi_allocate_pages_t allocate_pages;
26 efi_get_memory_map_t get_memory_map;
29 uint8_t before_handle_protocol[9 * 4];
30 efi_handle_protocol_t handle_protocol;
31 void* reserved_after_handle_protocol;
32 void* register_protocol_notify;
34 void* locate_device_path;
35 void* install_configuration_table;
40 efi_exit_boot_services_t exit_boot_services;
45 efi_status_t (*output_string)(
void*, efi_char16_t*);
50 efi_char16_t* firmware_vendor;
51 uint32_t firmware_revision;
52 efi_handle_t console_in_handle;
54 efi_handle_t console_out_handle;
56 efi_handle_t standard_error_handle;
58 void* runtime_services;
60 uint32_t configuration_table_entries;
61 void* configuration_table;
69 efi_status_t (*read)(
efi_file_t*, uint32_t*,
void*);
78 efi_status_t (*open_volume)(
void*,
efi_file_t**);
83 efi_handle_t parent_handle;
85 efi_handle_t device_handle;
95 uint16_t type, machine;
97 uint32_t entry, program_offset, section_offset;
99 uint16_t header_size, program_size, program_count;
100 uint16_t section_size, section_count, section_string_index;
104 uint32_t type, offset, virtual_address, physical_address;
105 uint32_t file_size, memory_size, flags, alignment;
108#define EFI_LOADER_DATA 2
109#define EFI_ALLOCATE_MAX_ADDRESS 1
110#define EFI_ALLOCATE_ADDRESS 2
111#define EFI_FILE_MODE_READ 1
112#define MAX_PHYSICAL_ADDRESS 0x7fffffffULL
113#define MAX_KERNEL_FILE_SIZE (64ULL * 1024 * 1024)
114#define MAX_ROOTFS_SIZE (512ULL * 1024 * 1024)
117 0x5b1b31a1, 0x9562, 0x11d2, {0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}};
119 0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}};
121 0x09576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}};
123 0xb1b621d5, 0xf19c, 0x41a5, {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}};
126 if (table && table->con_out) {
127 table->con_out->output_string(table->con_out,
message);
132 if (a->a != b->a || a->b != b->b || a->c != b->c) {
135 for (
unsigned i = 0; i < 8; ++i) {
136 if (a->d[i] != b->d[i]) {
144 if (!bytes || bytes > MAX_PHYSICAL_ADDRESS - 4095) {
147 uint64_t address = MAX_PHYSICAL_ADDRESS;
148 const efi_status_t status = table->boot_services->allocate_pages(
149 EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA, (bytes + 4095) / 4096, &address);
150 return status == EFI_SUCCESS ? (
void*)address : 0;
153static void copy(
void* destination,
const void* source, uint64_t count) {
154 uint8_t* to = destination;
155 const uint8_t* from = source;
156 for (uint64_t i = 0; i < count; ++i) {
161static void zero(
void* destination, uint64_t count) {
162 uint8_t* bytes = destination;
163 for (uint64_t i = 0; i < count; ++i) {
168static void clean_buffer(uint32_t address, uint32_t size) {
170 __asm__
volatile(
"mrc p15, 0, %0, c0, c0, 1" :
"=r"(ctr));
171 const uint32_t line_size = 4U << ((ctr >> 16) & 15);
172 const uint32_t end = address + size;
173 for (uint32_t cursor = address & ~(line_size - 1); cursor < end; cursor += line_size) {
174 __asm__
volatile(
"mcr p15, 0, %0, c7, c10, 1" : :
"r"(cursor) :
"memory");
179 uint64_t maximum, uint64_t* length) {
181 if (root->open(root, &file, path, EFI_FILE_MODE_READ, 0) != EFI_SUCCESS) {
185 uint32_t info_size =
sizeof(info);
186 if (file->get_info(file, (
efi_guid_t*)&file_info_guid, &info_size, info) != EFI_SUCCESS ||
187 info[1] == 0 || info[1] > maximum) {
188 print(table, (efi_char16_t*)L
"UEFI: file info failed\r\n");
192 void* buffer = allocate(table, info[1] + 1);
194 print(table, (efi_char16_t*)L
"UEFI: file allocation failed\r\n");
198 uint64_t position = 0;
199 while (position < info[1]) {
200 uint32_t requested = info[1] - position;
201 if (file->read(file, &requested, (uint8_t*)buffer + position) != EFI_SUCCESS || !requested) {
202 print(table, (efi_char16_t*)L
"UEFI: file read failed\r\n");
206 position += requested;
208 ((uint8_t*)buffer)[position] = 0;
214static int load_kernel(
efi_system_table_t* table,
const uint8_t* data, uint64_t length,
220 if (header->ident[0] != 0x7f || header->ident[1] !=
'E' || header->ident[2] !=
'L' ||
221 header->ident[3] !=
'F' || header->ident[4] != 1 || header->ident[5] != 1 ||
222 header->machine != 40 || header->type != 2 ||
223 header->program_size !=
sizeof(
elf32_program_t) || !header->program_count ||
224 header->program_offset > length ||
225 header->program_count > (length - header->program_offset) / header->program_size) {
228 int entry_loaded = 0;
229 for (uint16_t i = 0; i < header->program_count; ++i) {
232 if (program->type != 1) {
235 if (!program->memory_size || program->file_size > program->memory_size ||
236 program->offset > length || program->file_size > length - program->offset ||
237 (program->physical_address & 4095) || program->physical_address > MAX_PHYSICAL_ADDRESS ||
238 program->memory_size > MAX_PHYSICAL_ADDRESS - program->physical_address) {
241 uint64_t address = program->physical_address;
242 if (table->boot_services->allocate_pages(EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
243 (program->memory_size + 4095) / 4096,
244 &address) != EFI_SUCCESS) {
247 copy((
void*)address, data + program->offset, program->file_size);
248 zero((uint8_t*)address + program->file_size, program->memory_size - program->file_size);
249 clean_buffer(address, program->memory_size);
250 if (header->entry >= address && header->entry - address < program->memory_size) {
254 __asm__
volatile(
"dsb sy\n mcr p15, 0, %0, c7, c5, 0\n dsb sy\n isb" : :
"r"(0) :
"memory");
255 *entry = header->entry;
259static void enter_kernel(uint32_t entry, uint32_t handoff)
__attribute__((noreturn));
260static void enter_kernel(uint32_t entry, uint32_t handoff) {
264 "mrc p15, 0, r12, c1, c0, 0\n"
267 "bic r12, r12, #0x1000\n"
268 "mcr p15, 0, r12, c1, c0, 0\n"
274 :
"r"(ARMV7_UEFI_HANDOFF_MAGIC),
"r"(handoff),
"r"(entry)
275 :
"r0",
"r1",
"r12",
"memory");
277 __asm__
volatile(
"wfi");
282 print(table, (efi_char16_t*)L
"Pedigree ARMv7 UEFI loader\r\n");
286 for (uint32_t i = 0; i < table->configuration_table_entries; ++i) {
287 if (same_guid(&tables[i].guid, &fdt_guid)) {
288 fdt = (uint32_t)tables[i].table;
291 if (!fdt || fdt >= 0x80000000U) {
292 print(table, (efi_char16_t*)L
"UEFI: no usable FDT\r\n");
293 return EFI_LOAD_ERROR;
295 const uint8_t* firmware_fdt = (
const uint8_t*)fdt;
296 const uint32_t fdt_size = ((uint32_t)firmware_fdt[4] << 24) | ((uint32_t)firmware_fdt[5] << 16) |
297 ((uint32_t)firmware_fdt[6] << 8) | firmware_fdt[7];
298 if (firmware_fdt[0] != 0xd0 || firmware_fdt[1] != 0x0d || firmware_fdt[2] != 0xfe ||
299 firmware_fdt[3] != 0xed || fdt_size < 40 || fdt_size > 2 * 1024 * 1024) {
300 print(table, (efi_char16_t*)L
"UEFI: invalid FDT\r\n");
301 return EFI_LOAD_ERROR;
303 void* fdt_copy = allocate(table, fdt_size);
305 print(table, (efi_char16_t*)L
"UEFI: FDT allocation failed\r\n");
306 return EFI_LOAD_ERROR;
308 copy(fdt_copy, firmware_fdt, fdt_size);
309 fdt = (uint32_t)fdt_copy;
310 print(table, (efi_char16_t*)L
"UEFI: FDT platform\r\n");
314 if (table->boot_services->handle_protocol(image, (
efi_guid_t*)&loaded_image_guid,
315 (
void**)&loaded) != EFI_SUCCESS ||
316 table->boot_services->handle_protocol(loaded->device_handle, (
efi_guid_t*)&file_system_guid,
317 (
void**)&filesystem) != EFI_SUCCESS) {
318 print(table, (efi_char16_t*)L
"UEFI: filesystem unavailable\r\n");
319 return EFI_LOAD_ERROR;
322 if (filesystem->open_volume(filesystem, &root) != EFI_SUCCESS) {
323 print(table, (efi_char16_t*)L
"UEFI: cannot open ESP\r\n");
324 return EFI_LOAD_ERROR;
327 uint64_t kernel_length = 0, rootfs_length = 0, cmdline_length = 0;
328 uint8_t* kernel_file = read_file(table, root, (efi_char16_t*)L
"\\EFI\\PEDIGREE\\current\\kernel",
329 MAX_KERNEL_FILE_SIZE, &kernel_length);
330 uint8_t* rootfs = read_file(table, root, (efi_char16_t*)L
"\\EFI\\PEDIGREE\\current\\rootfs.img",
331 MAX_ROOTFS_SIZE, &rootfs_length);
332 char* cmdline = read_file(table, root, (efi_char16_t*)L
"\\EFI\\PEDIGREE\\current\\cmdline", 4095,
336 print(table, (efi_char16_t*)L
"UEFI: kernel read failed\r\n");
337 return EFI_LOAD_ERROR;
340 print(table, (efi_char16_t*)L
"UEFI: command line read failed\r\n");
341 return EFI_LOAD_ERROR;
343 for (uint64_t i = 0; i < cmdline_length; ++i) {
344 if (!cmdline[i] || cmdline[i] ==
'\r' || cmdline[i] ==
'\n') {
351 if (!load_kernel(table, kernel_file, kernel_length, &entry)) {
352 print(table, (efi_char16_t*)L
"UEFI: cannot load ARMv7 kernel\r\n");
353 return EFI_LOAD_ERROR;
356 void* raw_map = allocate(table, 16 * 4096);
359 if (!raw_map || !normalized || !handoff) {
360 print(table, (efi_char16_t*)L
"UEFI: memory map allocation failed\r\n");
361 return EFI_LOAD_ERROR;
363 print(table, (efi_char16_t*)L
"UEFI: entering kernel\r\n");
364 uint32_t normalized_bytes = 0;
365 int exit_attempted = 0;
366 const efi_status_t status = exit_boot_services_with_map(
367 table->boot_services->get_memory_map, table->boot_services->exit_boot_services, image,
368 raw_map, 16 * 4096, normalized, 16 * 4096, &normalized_bytes, &exit_attempted);
369 if (status != EFI_SUCCESS) {
370 if (!exit_attempted) {
371 print(table, (efi_char16_t*)L
"UEFI: ExitBootServices failed\r\n");
375 const uint32_t initrd_start = (uint32_t)rootfs;
379 initrd_start + (uint32_t)rootfs_length,
381 (uint32_t)normalized,
383 clean_buffer((uint32_t)handoff,
sizeof(*handoff));
384 clean_buffer(fdt, fdt_size);
385 clean_buffer((uint32_t)normalized, normalized_bytes);
386 clean_buffer((uint32_t)cmdline, (uint32_t)cmdline_length + 1);
388 clean_buffer(initrd_start, (uint32_t)rootfs_length);
390 __asm__
volatile(
"dsb sy" : : :
"memory");
391 enter_kernel(entry, (uint32_t)handoff);