1/* 2 * An EFI loader for Barrelfish 3 * 4 * This is an EFI app which loads the Multiboot2 image and execute 5 * the bootloader. 6 * This object file is linked together with the Multiboot2 image into one object 7 * 8 * Copyright (c) 2018, ETH Zurich. 9 * All rights reserved. 10 * 11 * This file is distributed under the terms in the attached LICENSE file. 12 * If you do not find this file, copies can be found by writing to: 13 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 14 */ 15 16#include <stdlib.h> 17#include <string.h> 18 19#include <efi/efi.h> 20#include <efi/efilib.h> 21#include <multiboot2.h> 22#include <barrelfish_kpi/types.h> 23#include <barrelfish_kpi/arm_core_data.h> 24#include "blob.h" 25#include "vm.h" 26 27typedef enum { 28 EfiBarrelfishFirstMemType= 0x80000000, 29 30 EfiBarrelfishCPUDriver= 0x80000000, 31 EfiBarrelfishCPUDriverStack= 0x80000001, 32 EfiBarrelfishMultibootData= 0x80000002, 33 EfiBarrelfishELFData= 0x80000003, 34 EfiBarrelfishBootPageTable= 0x80000004, 35 EfiBarrelfishCoreData= 0x80000005, 36 37 EfiBarrelfishMaxMemType 38} EFI_BARRELFISH_MEMORY_TYPE; 39 40static const char *mmap_types[] = { 41 "reserved", 42 "LD code", 43 "LD data", 44 "BS code", 45 "BS data", 46 "RS code", 47 "RS data", 48 "available", 49 "unusable", 50 "ACPI reclaim", 51 "ACPI NVS", 52 "MMIO", 53 "ports", 54 "PAL code", 55 "persist" 56}; 57 58static const char *bf_mmap_types[] = { 59 "BF code", 60 "BF stack", 61 "BF multiboot", 62 "BF module", 63 "BF page table", 64 "BF core data", 65}; 66 67#define MAX_L1_TABLES 512 68struct page_tables { 69 size_t nL1; 70 71 union aarch64_descriptor *L0_table; 72 union aarch64_descriptor *L1_tables[MAX_L1_TABLES]; 73} page_tables; 74 75struct config { 76 struct multiboot_info *multiboot; 77 struct multiboot_tag_efi_mmap *mmap_tag; 78 struct multiboot_tag_string *cmd_tag; 79 EFI_PHYSICAL_ADDRESS modules; 80 EFI_VIRTUAL_ADDRESS boot_driver_entry; 81 EFI_PHYSICAL_ADDRESS cpu_driver_entry; 82 EFI_PHYSICAL_ADDRESS cpu_driver_stack; 83 size_t cpu_driver_stack_size; 84 struct page_tables *tables; 85}; 86 87typedef void boot_driver(uint32_t magic, void *pointer); 88 89extern char barrelfish_blob_start[1]; 90 91#define KERNEL_OFFSET 0xffff000000000000 92#define KERNEL_STACK_SIZE 0x4000 93 94#define ATTR_CACHED 0 95#define ATTR_DEVICE 1 96 97#define ROUND_UP(x, y) (((x) + ((y) - 1)) & ~((y) - 1)) 98#define COVER(x, y) (((x) + ((y)-1)) / (y)) 99#define ROUND_DOWN(x, y) (((x) / (y)) * (y)) 100#define MIN(x, y) ((x) < (y) ? (x) : (y)) 101 102#define BLOB_ADDRESS(offset) (barrelfish_blob_start + (offset)) 103 104/* Copy a base+length string into a null-terminated string. Destination 105 * buffer must be large enough to hold the terminator i.e. n+1 characters. */ 106static inline void 107ntstring(char *dest, const char *src, size_t len) { 108 memcpy(dest, src, len); 109 dest[len]= '\0'; 110} 111 112#define MEM_MAP_SIZE 8192 113char mmap[MEM_MAP_SIZE]; 114UINTN mmap_size, mmap_key, mmap_d_size; 115UINT32 mmap_d_ver; 116 117static EFI_STATUS 118update_memory_map(void) 119{ 120 EFI_STATUS status; 121 size_t mmap_n_desc, i; 122 123 /* Grab the current table from UEFI. */ 124 mmap_size = MEM_MAP_SIZE; 125 status = ST->BootServices->GetMemoryMap( 126 &mmap_size, 127 (void *) &mmap, 128 &mmap_key, 129 &mmap_d_size, 130 &mmap_d_ver 131 ); 132 if (status == EFI_BUFFER_TOO_SMALL) { 133 Print(L"The memory map is %dB, but MEM_MAP_SIZE is %d.\n", 134 mmap_size, MEM_MAP_SIZE); 135 Print(L"This is compile-time limit in Hagfish - please report " 136 L"this overflow, it's a bug.\n"); 137 return status; 138 } else if (EFI_ERROR(status)) { 139 Print(L"Unable to get memory map: %x\n", status); 140 return status; 141 } 142 143 mmap_n_desc = mmap_size / mmap_d_size; 144 145 return EFI_SUCCESS; 146} 147 148static EFI_STATUS 149relocate_memory_map(void) { 150 if (!mmap_size) { 151 return EFI_LOAD_ERROR; 152 } 153 154 size_t mmap_n_desc = mmap_size / mmap_d_size; 155 156 for (size_t i= 0; i < mmap_n_desc; i++) { 157 EFI_MEMORY_DESCRIPTOR *desc = 158 (EFI_MEMORY_DESCRIPTOR *)(mmap + i * mmap_d_size); 159 // 1:1 mapping into kernel window 160 desc->VirtualStart = desc->PhysicalStart + KERNEL_OFFSET; 161 } 162 163 return EFI_SUCCESS; 164} 165 166static void 167print_memory_map(int update) 168{ 169 if (update) { 170 update_memory_map(); 171 } 172 173 size_t mmap_n_desc = mmap_size / mmap_d_size; 174 175 Print(L"Memory map at %lx, key: %x, descriptor version: %x\n", 176 mmap, mmap_key, mmap_d_ver); 177 Print(L"Got %d memory map entries of %dB (%dB).\n", 178 mmap_n_desc, mmap_d_size, mmap_size); 179 180 Print(L"Type PStart PEnd " 181 " Size Attributes\n"); 182 for (UINTN i = 0; i < mmap_n_desc; i++) { 183 EFI_MEMORY_DESCRIPTOR *desc = ((void *) mmap) + (mmap_d_size * i); 184 185 const char *description; 186 if (desc->Type < EfiMaxMemoryType) { 187 description= mmap_types[desc->Type]; 188 } 189 else if ( 190 EfiBarrelfishFirstMemType <= desc->Type && 191 desc->Type < EfiBarrelfishMaxMemType 192 ) { 193 description = bf_mmap_types[desc->Type - EfiBarrelfishFirstMemType]; 194 } 195 else { 196 description= "???"; 197 } 198 199 Print(L"%-13a %016lx %016lx %9ldkB %01x\n", 200 description, 201 desc->PhysicalStart, 202 desc->PhysicalStart + (desc->NumberOfPages << 12) - 1, 203 (desc->NumberOfPages << 12) / 1024, 204 desc->Attribute); 205 } 206} 207 208#define BLOCK_16G (ARMv8_HUGE_PAGE_SIZE * 16ULL) 209#define BLOCK_16G_MASK (ARMv8_HUGE_PAGE_SIZE * 16ULL) 210 211static EFI_STATUS 212page_table_set_attr(struct config *cfg, uint64_t start, uint64_t end, uint64_t attr) { 213 uint64_t base = ROUND_DOWN(start, ARMv8_HUGE_PAGE_SIZE) 214 / ARMv8_HUGE_PAGE_SIZE; 215 216 uint64_t last = COVER(end, ARMv8_HUGE_PAGE_SIZE); 217 218 while (base < last) { 219 size_t table_number = base >> ARMv8_BLOCK_BITS; 220 size_t table_index = base & ARMv8_BLOCK_MASK; 221 union aarch64_descriptor *desc = 222 &cfg->tables->L1_tables[table_number][table_index]; 223 desc->block_l1.attrindex = attr; 224 225 base++; 226 } 227 228 return EFI_SUCCESS; 229} 230 231static EFI_STATUS 232build_page_tables(struct config *cfg) { 233 EFI_STATUS status = EFI_SUCCESS; 234 235 /* We need the current memory map to set memory attributes */ 236 status = update_memory_map(); 237 if (EFI_ERROR(status)) { 238 Print(L"Failed to update memory map\n"); 239 } 240 241 /* Page table book keeping in static buffer 242 * so we don't need malloc & friends 243 */ 244 cfg->tables = &page_tables; 245 246 /* Map up to the highest RAM address supplied by EFI. XXX - this is a 247 * heuristic, and may fail. Unless there's a more clever way to do 248 * discovery, we might need to bite the bullet and map all 48 bits (2MB of 249 * kernel page tables!). All we really need is that the kernel gets all 250 * RAM, and the debug serial port - it shouldn't actually touch anything 251 * else. */ 252 uint64_t first_address, last_address; 253 first_address = 0; 254 last_address = ((1UL << 48) - 1); 255 256 /* We will map in aligned 16G blocks, as each requires only one TLB 257 * entry. */ 258 uint64_t window_start, window_length; 259 window_start = first_address & ~BLOCK_16G; 260 window_length = ROUND_UP(last_address - window_start, BLOCK_16G); 261 262 status = BS->AllocatePages( 263 AllocateAnyPages, 264 EfiBarrelfishBootPageTable, 265 1, 266 (EFI_PHYSICAL_ADDRESS *)&cfg->tables->L0_table 267 ); 268 if (EFI_ERROR(status)) { 269 Print(L"Failed to allocate L0 page table.\n"); 270 goto build_page_tables_fail; 271 } 272 memset(cfg->tables->L0_table, 0, BASE_PAGE_SIZE); 273 274 /* Count the number of L1 tables (512GB) blocks required to cover the 275 * physical mapping window. */ 276 cfg->tables->nL1 = 0; 277 uint64_t L1base = window_start & ~ARMv8_TOP_TABLE_SIZE; 278 uint64_t L1addr; 279 for (L1addr = window_start & ~ARMv8_TOP_TABLE_SIZE; 280 L1addr < window_start + window_length; 281 L1addr += ARMv8_TOP_TABLE_SIZE) { 282 cfg->tables->nL1++; 283 } 284 ASSERT(cfg->tables->nL1 <= MAX_L1_TABLES) 285 286 /* Allocate the L1 tables. 287 * We allocate them all in one big chunk 288 * as otherwise the memory map size explodes 289 */ 290 Print(L"Allocating %d L1 tables (%dB)\n", cfg->tables->nL1, cfg->tables->nL1 * BASE_PAGE_SIZE); 291 EFI_PHYSICAL_ADDRESS L1_memory; 292 status = BS->AllocatePages( 293 AllocateAnyPages, 294 EfiBarrelfishBootPageTable, 295 cfg->tables->nL1, 296 &L1_memory 297 ); 298 if (EFI_ERROR(status)) { 299 Print(L"Failed to allocate L1 page tables.\n"); 300 goto build_page_tables_fail; 301 } 302 memset((void *)L1_memory, 0, cfg->tables->nL1 * BASE_PAGE_SIZE); 303 Print(L"L1 tables start at 0x%lx\n", L1_memory); 304 305 for (size_t i = 0; i < cfg->tables->nL1; i++) { 306 cfg->tables->L1_tables[i] = (union aarch64_descriptor *)(L1_memory + i * BASE_PAGE_SIZE); 307 308 /* Map the L1 into the L0. */ 309 size_t L0_index = (L1base >> ARMv8_TOP_TABLE_BITS) + i; 310 cfg->tables->L0_table[L0_index].d.base = 311 (uint64_t)cfg->tables->L1_tables[i] >> ARMv8_BASE_PAGE_BITS; 312 cfg->tables->L0_table[L0_index].d.mb1 = 1; /* Page table */ 313 cfg->tables->L0_table[L0_index].d.valid = 1; 314 } 315 316 /* Install the 1GB block mappings. */ 317 uint64_t firstblock = window_start / ARMv8_HUGE_PAGE_SIZE; 318 uint64_t nblocks = window_length / ARMv8_HUGE_PAGE_SIZE; 319 for (uint64_t block = firstblock; block < firstblock + nblocks; block++) { 320 size_t table_number= block >> ARMv8_BLOCK_BITS; 321 size_t table_index= block & ARMv8_BLOCK_MASK; 322 union aarch64_descriptor *desc = 323 &cfg->tables->L1_tables[table_number][table_index]; 324 325 // We first map all block non-contiguous but later set the bit 326 // if possible 327 desc->block_l1.contiguous = 0; 328 desc->block_l1.base = block; 329 /* Mark the accessed flag, so we don't get a fault. */ 330 desc->block_l1.af = 1; 331 /* Outer shareable - coherent. */ 332 desc->block_l1.sh = 3; 333 /* EL1+ only. */ 334 desc->block_l1.ap = 0; 335 // device memory by default 336 desc->block_l1.attrindex = ATTR_DEVICE; 337 /* A block. */ 338 desc->block_l1.mb0 = 0; 339 desc->block_l1.valid = 1; 340 } 341 342 // set all memory regions to cached 343 size_t mmap_n_desc = mmap_size / mmap_d_size; 344 for (size_t i = 0; i < mmap_n_desc; i++) { 345 EFI_MEMORY_DESCRIPTOR *desc = (void *) (mmap + i * mmap_d_size); 346 /* We're only looking for MMIO. */ 347 if (desc->Type != EfiMemoryMappedIO 348 && desc->Type != EfiMemoryMappedIOPortSpace) { 349 page_table_set_attr(cfg, desc->PhysicalStart, desc->PhysicalStart + BASE_PAGE_SIZE * desc->NumberOfPages, ATTR_CACHED); 350 } 351 } 352 353 // set the contiguous bit if possible 354 for (uint64_t block = firstblock; block < firstblock + nblocks; block += 16) { 355 BOOLEAN all_same = TRUE; 356 uint64_t attr; 357 for (uint64_t offset = 0; offset < 16; offset++) { 358 size_t table_number = (block + offset) >> ARMv8_BLOCK_BITS; 359 size_t table_index = (block + offset) & ARMv8_BLOCK_MASK; 360 union aarch64_descriptor *desc = 361 &cfg->tables->L1_tables[table_number][table_index]; 362 if (offset == 0) { 363 attr = desc->block_l1.attrindex; 364 } 365 else if (attr != desc->block_l1.attrindex) { 366 all_same = FALSE; 367 break; 368 } 369 } 370 if (all_same) { 371 // all entries in current block have the same attrindex value 372 // so we can set the contiguous bit 373 for (uint64_t offset = 0; offset < 16; offset++) { 374 size_t table_number = (block + offset) >> ARMv8_BLOCK_BITS; 375 size_t table_index = (block + offset) & ARMv8_BLOCK_MASK; 376 union aarch64_descriptor *desc = 377 &cfg->tables->L1_tables[table_number][table_index]; 378 desc->block_l1.contiguous = 1; 379 } 380 } 381 } 382 383 return EFI_SUCCESS; 384 385build_page_tables_fail: 386 if (cfg->tables) { 387 if (cfg->tables->L1_tables) { 388 size_t i; 389 for (i= 0; i < cfg->tables->nL1; i++) { 390 if (cfg->tables->L1_tables[i]) 391 BS->FreePages((EFI_PHYSICAL_ADDRESS)cfg->tables->L1_tables[i], 1); 392 } 393 } 394 if (cfg->tables->L0_table) { 395 BS->FreePages((EFI_PHYSICAL_ADDRESS)cfg->tables->L0_table, 1); 396 } 397 } 398 399 return status; 400} 401 402static void 403relocate_elf(EFI_PHYSICAL_ADDRESS segment_start, uint64_t virtual_offset, 404 struct Blob_relocation *relocations, 405 uint64_t no_relocations) 406{ 407 Print(L"Relocating ELF %lx %lx %d\n", 408 segment_start, relocations, no_relocations); 409 for (uint64_t i = 0; i < no_relocations; i++) { 410 *(uint64_t *)(segment_start + relocations[i].offset) = 411 segment_start + virtual_offset + relocations[i].addend; 412 } 413} 414 415static EFI_STATUS 416relocate_boot_driver(struct Blob *blob_info, struct config *cfg) 417{ 418 EFI_STATUS status; 419 420 /* Should be page aligend */ 421 ASSERT(blob_info->boot_driver_segment_size % BASE_PAGE_SIZE == 0); 422 423 EFI_PHYSICAL_ADDRESS boot_driver; 424 status = BS->AllocatePages( 425 AllocateAnyPages, 426 EfiBarrelfishCPUDriver, 427 blob_info->boot_driver_segment_size / BASE_PAGE_SIZE, 428 &boot_driver 429 ); 430 if (EFI_ERROR(status)) { 431 Print(L"Error allocating memory for boot driver segment: %d\n", status); 432 return status; 433 } 434 435 memcpy((void *)boot_driver, BLOB_ADDRESS(blob_info->boot_driver_segment), blob_info->boot_driver_segment_size); 436 437 struct Blob_relocation *boot_driver_relocations = 438 (struct Blob_relocation *)BLOB_ADDRESS(blob_info->boot_driver_relocations); 439 relocate_elf( 440 boot_driver, 441 0, 442 boot_driver_relocations, 443 blob_info->boot_driver_relocations_count 444 ); 445 446 cfg->boot_driver_entry = boot_driver + blob_info->boot_driver_entry; 447 448 return EFI_SUCCESS; 449} 450 451static EFI_STATUS 452relocate_cpu_driver(struct Blob *blob_info, struct config *cfg) 453{ 454 EFI_STATUS status; 455 456 /* Should be page aligend */ 457 ASSERT(blob_info->cpu_driver_segment_size % BASE_PAGE_SIZE == 0); 458 459 EFI_PHYSICAL_ADDRESS cpu_driver; 460 status = BS->AllocatePages( 461 AllocateAnyPages, 462 EfiBarrelfishCPUDriver, 463 blob_info->cpu_driver_segment_size / BASE_PAGE_SIZE, 464 &cpu_driver 465 ); 466 if (EFI_ERROR(status)) { 467 Print(L"Error allocating memory for CPU driver segment: %d\n", status); 468 return status; 469 } 470 471 memcpy((void *)cpu_driver, BLOB_ADDRESS(blob_info->cpu_driver_segment), blob_info->cpu_driver_segment_size); 472 473 struct Blob_relocation *cpu_driver_relocations = 474 (struct Blob_relocation *)BLOB_ADDRESS(blob_info->cpu_driver_relocations); 475 relocate_elf( 476 cpu_driver, 477 KERNEL_OFFSET, 478 cpu_driver_relocations, 479 blob_info->cpu_driver_relocations_count 480 ); 481 482 cfg->cpu_driver_entry = cpu_driver + blob_info->cpu_driver_entry + KERNEL_OFFSET; 483 484 status = BS->AllocatePages( 485 AllocateAnyPages, 486 EfiBarrelfishCPUDriverStack, 487 KERNEL_STACK_SIZE / BASE_PAGE_SIZE, 488 &cfg->cpu_driver_stack 489 ); 490 if (EFI_ERROR(status)) { 491 Print(L"Error allocating memory for CPU driver stack: %d\n", status); 492 return status; 493 } 494 495 cfg->cpu_driver_stack_size = KERNEL_STACK_SIZE; 496 497 Print( 498 L"Relocated CPU driver entry point is %lx, stack at %lx\n", 499 cfg->cpu_driver_entry, 500 cfg->cpu_driver_stack 501 ); 502 503 return EFI_SUCCESS; 504} 505 506static EFI_STATUS 507relocate_modules(struct Blob *blob_info, struct config *cfg) 508{ 509 EFI_STATUS status; 510 511 /* Should be page aligend */ 512 ASSERT(blob_info->modules_size % BASE_PAGE_SIZE == 0); 513 514 status = BS->AllocatePages( 515 AllocateAnyPages, 516 EfiBarrelfishELFData, 517 blob_info->modules_size / BASE_PAGE_SIZE, 518 &cfg->modules 519 ); 520 if (EFI_ERROR(status)) { 521 Print(L"Error allocating memory for modules: %d\n", status); 522 return status; 523 } 524 525 memcpy((void *)cfg->modules, BLOB_ADDRESS(blob_info->modules), blob_info->modules_size); 526 return EFI_SUCCESS; 527} 528 529static EFI_STATUS 530relocate_multiboot(struct Blob *blob_info, struct config *cfg) 531{ 532 EFI_STATUS status; 533 534 /* Should be page aligend */ 535 ASSERT(blob_info->multiboot_size % BASE_PAGE_SIZE == 0); 536 537 EFI_PHYSICAL_ADDRESS memory; 538 status = BS->AllocatePages( 539 AllocateAnyPages, 540 EfiBarrelfishMultibootData, 541 blob_info->multiboot_size / BASE_PAGE_SIZE, 542 (EFI_PHYSICAL_ADDRESS *)&cfg->multiboot 543 ); 544 if (EFI_ERROR(status)) { 545 Print(L"Error allocating memory for multiboot info: %d\n", status); 546 return status; 547 } 548 549 memcpy(cfg->multiboot, BLOB_ADDRESS(blob_info->multiboot), blob_info->multiboot_size); 550 551 /* Module start & end pointed into the blob. 552 * Now they need to point into the module region 553 */ 554 uint64_t module_offset = (uint64_t)cfg->modules - blob_info->modules; 555 556 Print(L"Relocating multiboot info: %lx\n", cfg->multiboot); 557 /* We don't have an end tag yet, but EFI mmap tag is last */ 558 struct multiboot_tag *tag; 559 for (tag = cfg->multiboot->tags; tag->type != MULTIBOOT_TAG_TYPE_EFI_MMAP; tag = (void *)tag + tag->size) { 560 Print(L"%lx: tag %d:%d\n", tag, tag->type, tag->size); 561 562 if (tag->type == MULTIBOOT_TAG_TYPE_MODULE_64) { 563 struct multiboot_tag_module_64 *mtag = (struct multiboot_tag_module_64 *)tag; 564 Print(L"\tbefore %lx:%lx\n", mtag->mod_start, mtag->mod_end); 565 mtag->mod_start += module_offset; 566 mtag->mod_end += module_offset; 567 Print(L"\tafter %lx:%lx\n", mtag->mod_start, mtag->mod_end); 568 } 569 else if (tag->type == MULTIBOOT_TAG_TYPE_CMDLINE) { 570 cfg->cmd_tag = (struct multiboot_tag_string *)tag; 571 } 572 } 573 574 ASSERT(tag->type == MULTIBOOT_TAG_TYPE_EFI_MMAP); 575 cfg->mmap_tag = (struct multiboot_tag_efi_mmap *)tag; 576 577 return EFI_SUCCESS; 578} 579 580static struct armv8_core_data * 581create_core_data(struct config *cfg) 582{ 583 EFI_STATUS status; 584 585 struct armv8_core_data *core_data; 586 status = BS->AllocatePages( 587 AllocateAnyPages, 588 EfiBarrelfishCoreData, 589 1, 590 (EFI_PHYSICAL_ADDRESS *)&core_data 591 ); 592 if (EFI_ERROR(status)) { 593 Print(L"Error allocating memory for core data: %d\n", status); 594 return NULL; 595 } 596 597 memset(core_data, 0, BASE_PAGE_SIZE); 598 599 core_data->boot_magic = ARMV8_BOOTMAGIC_BSP; 600 core_data->cpu_driver_stack = 601 (lpaddr_t)cfg->cpu_driver_stack + cfg->cpu_driver_stack_size - 16; 602 core_data->cpu_driver_stack_limit = (lpaddr_t)cfg->cpu_driver_stack; 603 core_data->cpu_driver_entry = (lvaddr_t)cfg->cpu_driver_entry; 604 core_data->page_table_root = (genpaddr_t)cfg->tables->L0_table; 605 ntstring( 606 core_data->cpu_driver_cmdline, 607 cfg->cmd_tag->string, 608 MIN( 609 cfg->cmd_tag->size - sizeof(struct multiboot_tag_string), 610 sizeof(core_data->cpu_driver_cmdline) - 1 611 ) 612 ); 613 614 core_data->multiboot_image.base = (lpaddr_t)cfg->multiboot; 615 core_data->multiboot_image.length = cfg->multiboot->total_size; 616 core_data->efi_mmap = (lpaddr_t)cfg->mmap_tag; 617 618 return core_data; 619} 620 621EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, 622 EFI_SYSTEM_TABLE * SystemTable) 623{ 624 EFI_STATUS status; 625 626 InitializeLib(ImageHandle, SystemTable); 627 628 struct Blob *blob_info = (struct Blob *)BLOB_ADDRESS(0); 629 Print(L"Blob is at: 0x%lx\n", blob_info); 630 Print(L"Magic: %lx\n", blob_info->magic); 631 632 struct config cfg; 633 634 status = relocate_boot_driver(blob_info, &cfg); 635 if (EFI_ERROR(status)) { 636 Print(L"Failed to relocate boot driver\n"); 637 return status; 638 } 639 640 status = relocate_cpu_driver(blob_info, &cfg); 641 if (EFI_ERROR(status)) { 642 Print(L"Failed to relocate CPU driver\n"); 643 return status; 644 } 645 646 status = relocate_modules(blob_info, &cfg); 647 if (EFI_ERROR(status)) { 648 Print(L"Failed to relocate modules\n"); 649 return status; 650 } 651 652 status = relocate_multiboot(blob_info, &cfg); 653 if (EFI_ERROR(status)) { 654 Print(L"Failed to relocate multiboot info\n"); 655 return status; 656 } 657 658 status = build_page_tables(&cfg); 659 if (EFI_ERROR(status)) { 660 Print(L"Failed to build page tables\n"); 661 return status; 662 } 663 664 struct armv8_core_data *core_data = create_core_data(&cfg); 665 666 Print(L"Terminating boot services and jumping to image at 0x%lx\n", cfg.boot_driver_entry); 667 Print(L"Core data pointer is %lx\n", core_data); 668 669 print_memory_map(1); 670 671 status = update_memory_map(); 672 if (EFI_ERROR(status)) { 673 Print(L"Failed to update memory map\n"); 674 } 675 676 status = ST->BootServices->ExitBootServices(ImageHandle, mmap_key); 677 if (EFI_ERROR(status)) { 678 Print(L"Error exiting boot services: %d, %x\n", status, mmap_key); 679 return status; 680 } 681 682 /*** EFI boot services are now terminated, we're on our own. */ 683 status = relocate_memory_map(); 684 if (EFI_ERROR(status)) { 685 return EFI_SUCCESS; 686 } 687 688 /* The last thing we do is complete the multiboot info: 689 * Set the EFI mmap and end tag 690 */ 691 cfg.mmap_tag->size = ROUND_UP(sizeof(struct multiboot_tag_efi_mmap) + mmap_size, 8); 692 cfg.mmap_tag->descr_size = mmap_d_size; 693 cfg.mmap_tag->descr_vers = mmap_d_ver; 694 memcpy(cfg.mmap_tag->efi_mmap, mmap, mmap_size); 695 696 struct multiboot_tag *end_tag = (void *)cfg.mmap_tag + cfg.mmap_tag->size; 697 end_tag->type = MULTIBOOT_TAG_TYPE_END; 698 end_tag->size = ROUND_UP(sizeof(struct multiboot_tag), 8); 699 cfg.multiboot->total_size = (void *)end_tag + end_tag->size - (void *)cfg.multiboot; 700 701 status = ST->RuntimeServices->SetVirtualAddressMap( 702 mmap_size, 703 mmap_d_size, 704 mmap_d_ver, 705 (void *) &mmap 706 ); 707 if (EFI_ERROR(status)) { 708 return status; 709 } 710 711 // Jump to the bootloader, the blob can be reused 712 (*((boot_driver *) (cfg.boot_driver_entry))) (MULTIBOOT2_BOOTLOADER_MAGIC, core_data); 713 714 return EFI_SUCCESS; 715} 716