1#include <sys/types.h> 2#include <sys/stat.h> 3 4#include <assert.h> 5#include <errno.h> 6#include <limits.h> 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10#include <unistd.h> 11 12#define KERNEL_OFFSET 0xffff000000000000 13 14#include "build_multiboot.h" 15#include "config.h" 16#include "efi.h" 17#include "util.h" 18 19void usage(char *name) { 20 fprintf(stderr, "usage: %s <config> <ram size> <shim image> <fs root>" 21 " <output file> [-d]\n", name); 22 exit(EXIT_FAILURE); 23} 24 25void fail(char *name) { 26 perror(name); 27 exit(EXIT_FAILURE); 28} 29 30void elf_fail(char *name) { 31 fprintf(stderr, "%s: %s\n", name, elf_errmsg(elf_errno())); 32 exit(EXIT_FAILURE); 33} 34 35/* Read the complete contents of a file. */ 36void * 37load_file(const char *path, size_t *length, size_t *alloc) { 38 FILE *file= fopen(path, "r"); 39 if(!file) fail("fopen"); 40 41 struct stat stat; 42 if(fstat(fileno(file), &stat) < 0) fail("stat"); 43 44 /* Allocate a page-sized zero-initialised buffer. */ 45 size_t alloc_size= ROUNDUP(stat.st_size, PAGE_4k); 46 char *buf= calloc(alloc_size, 1); 47 if(!buf) fail("calloc"); 48 49 if(fread(buf, 1, stat.st_size, file) != stat.st_size) fail("fread"); 50 51 if(fclose(file) != 0) fail("fclose"); 52 53 *length= stat.st_size; 54 *alloc= alloc_size; 55 return buf; 56} 57 58/* Load the ELF image for a component, and fill the relevant fields in the 59 * configuration struct. */ 60int 61load_component(char *basepath, size_t bplen, struct component_config *comp, 62 char *buf) { 63 if(bplen + comp->path_len >= PATH_MAX) { 64 errno= ENAMETOOLONG; 65 return -1; 66 } 67 68 /* Append the component path to the FS base path, and null terminate. */ 69 memcpy(basepath + bplen, buf + comp->path_start, comp->path_len); 70 basepath[bplen + comp->path_len]= '\0'; 71 72 /* Canonicalise the path. */ 73 char path[PATH_MAX]; 74 if(!realpath(basepath, path)) { 75 fprintf(stderr, "Couldn't find %s\n", path); 76 fail("relpath"); 77 } 78 79 /* Load the ELF */ 80#if 0 81 printf("Loading component %s\n", path); 82#endif 83 comp->image= load_file(path, &comp->image_size, &comp->alloc_size); 84 85 return 0; 86} 87 88/* Fill the preallocated EFI memory map in. */ 89efi_memory_descriptor * 90build_efi_mmap(struct config *config, size_t mmap_len, 91 size_t first_region, uint64_t ram_size) { 92 efi_memory_descriptor *mmap= 93 (efi_memory_descriptor *)config->mmap_start; 94 95 /* Write the tag. */ 96 config->mmap_tag->type= MULTIBOOT_TAG_TYPE_EFI_MMAP; 97 config->mmap_tag->size= sizeof(struct multiboot_tag_efi_mmap) + 98 mmap_len * sizeof(efi_memory_descriptor); 99 config->mmap_tag->descr_size= sizeof(efi_memory_descriptor); 100 config->mmap_tag->descr_vers= 1; 101 102 if((ram_size & (PAGE_4k-1)) != 0) { 103 fprintf(stderr, "RAM size %lu isn't a multiple of 4k.\n", ram_size); 104 exit(EXIT_FAILURE); 105 } 106 107 /* Calculate the sizes of the two windows - fill the lower one first. */ 108 uint64_t region_one, region_two; 109 if(ram_size < 2 * (1UL<<30)) { 110 region_one= ram_size; 111 region_two= 0; 112 } 113 else { 114 region_one= 2 * (1UL<<30); 115 region_two = ram_size - region_one; 116 } 117 assert(region_two <= 6 * (1UL<<30)); 118 119 /* The first 2GiB RAM window starts at 0x80000000, or 2GiB, on sensible 120 * ARM platforms, such as this one. */ 121 mmap[first_region].Type= EfiConventionalMemory; 122 mmap[first_region].PhysicalStart= 0x80000000; 123 mmap[first_region].VirtualStart= 0x80000000; 124 mmap[first_region].NumberOfPages= region_one / PAGE_4k; 125 mmap[first_region].Attribute= 0; /* XXX - this should change. */ 126 127 /* Add the second region, only if required. It must be allocated. */ 128 if(region_two > 0) { 129 assert(first_region + 1 < mmap_len); 130 /* On platforms that follow the "Principles of ARM Memory Maps" 131 * whitepaper, the second RAM window begins at 0x880000000, or 2GiB + 132 * 32GiB, and is 30GiB in length. The pattern repeats, such that an 133 * n-bit physical address space has 2^(n-1)B of RAM windows. On some 134 * platforms (including the fast models), the region 0x800000000 - 135 * 0x87fffffff aliases the first RAM window, giving a contiguous 136 * window in a 36-bit or greater PA space. Using the aliased 137 * addresses, however, is a bad idea - physical memory aliases are 138 * not good for the caches. */ 139 mmap[first_region+1].Type= EfiConventionalMemory; 140 mmap[first_region+1].PhysicalStart= 0x880000000; 141 mmap[first_region+1].VirtualStart= 0x880000000; 142 mmap[first_region+1].NumberOfPages= region_two / PAGE_4k; 143 mmap[first_region+1].Attribute= 0; /* XXX - this should change. */ 144 } 145 146 /* We only need two windows to map up to 32GiB of RAM, which is already 147 * more than the fast models support. */ 148 149 return mmap; 150} 151 152void 153check_alloc(uint64_t allocbase, efi_memory_descriptor *mmap, size_t region) { 154 if(allocbase >= mmap[region].PhysicalStart + 155 mmap[region].NumberOfPages * PAGE_4k) { 156 fprintf(stderr, "Ran out of room in the first memory region.\n"); 157 fprintf(stderr, "Region: %lx-%lx, allocbase=%lx\n", 158 mmap[region].PhysicalStart, 159 mmap[region].PhysicalStart + 160 mmap[region].NumberOfPages * PAGE_4k, 161 allocbase); 162 exit(EXIT_FAILURE); 163 } 164} 165 166void * 167load_cpudriver(Elf *kernel_elf, void *kernel_raw, size_t kernel_size, 168 uint64_t virt_base, uint64_t *loaded_size, uint64_t *alloc, 169 uint64_t *entry) { 170 size_t phnum; 171 if(elf_getphdrnum(kernel_elf, &phnum)) elf_fail("elf_getphdrnum"); 172 173 Elf64_Phdr *phdrs= elf64_getphdr(kernel_elf); 174 if(!phdrs) elf_fail("elf64_getphdr"); 175 176 /* Find the dynamic segment, and calculate the base and limit for the 177 * loadable region. */ 178 uint64_t base= UINT64_MAX, limit= 0; 179 size_t dseg; 180 int have_dseg= 0; 181 for(size_t kseg= 0; kseg < phnum; kseg++) { 182 if(phdrs[kseg].p_type == PT_DYNAMIC) { 183 if(have_dseg) { 184 fprintf(stderr, "Two PT_DYNAMIC segments.\n"); 185 exit(EXIT_FAILURE); 186 } 187 dseg= kseg; 188 have_dseg= 1; 189 } 190 else if(phdrs[kseg].p_type == PT_LOAD) { 191 if(phdrs[kseg].p_vaddr < base) 192 base= phdrs[kseg].p_vaddr; 193 194 assert(phdrs[kseg].p_memsz <= UINT64_MAX - phdrs[kseg].p_vaddr); 195 if(phdrs[kseg].p_vaddr + phdrs[kseg].p_memsz > limit) 196 limit= phdrs[kseg].p_vaddr + phdrs[kseg].p_memsz; 197 } 198 } 199 if(!have_dseg) { 200 fprintf(stderr, "No PT_DYNAMIC segment.\n"); 201 exit(EXIT_FAILURE); 202 } 203 204 /* Relocate the entry point. */ 205 Elf64_Ehdr *ehdr= elf64_getehdr(kernel_elf); 206 if(!ehdr) elf_fail("elf64_getehdr"); 207 *entry= virt_base + (ehdr->e_entry - base); 208 209 /* Allocate the target region. */ 210 *loaded_size= limit - base + 1; 211 *alloc= ROUNDUP(*loaded_size, PAGE_4k); 212 void *cpudriver= malloc(*alloc); 213 if(!cpudriver) fail("malloc"); 214 bzero(cpudriver, *alloc); 215 216 /* Copy all loadable segments. */ 217 int loaded_something= 0; 218 for(size_t kseg= 0; kseg < phnum; kseg++) { 219 Elf64_Phdr *ph= &phdrs[kseg]; 220 if(ph->p_type == PT_LOAD) { 221 assert(ph->p_offset < kernel_size); 222 assert(ph->p_offset + ph->p_filesz < kernel_size); 223 224 void *seg_vbase= cpudriver + (ph->p_vaddr - base); 225 memcpy(seg_vbase, kernel_raw + ph->p_offset, ph->p_filesz); 226 227 loaded_something= 1; 228 } 229 } 230 231 if(!loaded_something) { 232 fprintf(stderr, "No loadable segments in CPU driver ELF.\n"); 233 exit(EXIT_FAILURE); 234 } 235 236 /* Process the dynamic linking section. */ 237 Elf64_Phdr *dhdr= &phdrs[dseg]; 238 size_t dtnum= dhdr->p_filesz / sizeof(Elf64_Dyn); 239 Elf64_Dyn *dt= (Elf64_Dyn *)(kernel_raw + dhdr->p_offset); 240 void *rela_base= NULL; 241 size_t rela_entsize= 0, rela_count= 0; 242 for(size_t i= 0; i < dtnum && dt[i].d_tag != DT_NULL; i++) { 243 switch(dt[i].d_tag) { 244 case DT_RELA: 245 /* The address of the relocation section is given as an 246 * unrelocated virtual address, inside the loaded segment. We 247 * need to rebase it. */ 248 rela_base= cpudriver + (dt[i].d_un.d_ptr - base); 249 break; 250 case DT_RELAENT: 251 rela_entsize= dt[i].d_un.d_val; 252 break; 253 case DT_RELACOUNT: 254 rela_count= dt[i].d_un.d_val; 255 break; 256 257 case DT_RELASZ: 258 case DT_TEXTREL: 259 case DT_DEBUG: 260 break; /* Ignored */ 261 262 case DT_REL: 263 case DT_RELENT: 264 case DT_RELCOUNT: 265 fprintf(stderr, "Unsupported relocation type: DT_REL\n"); 266 exit(EXIT_FAILURE); 267 268 default: 269 printf("Warning, ignoring dynamic section entry, tag %lx\n", 270 dt[i].d_tag); 271 } 272 } 273 if(!rela_base || !rela_entsize || !rela_count) { 274 printf("Warning: no relocation (RELA) section.\n"); 275 return cpudriver; 276 } 277 278 /* Process the relocations. */ 279 for(size_t i= 0; i < rela_count; i++, rela_base+= rela_entsize) { 280 Elf64_Rela *rela= (Elf64_Rela *)rela_base; 281 282 if(ELF64_R_SYM(rela->r_info) != 0) { 283 fprintf(stderr, "Unsupported symbol-based relocation at %lx.\n", 284 rela->r_offset); 285 exit(EXIT_FAILURE); 286 } 287 288 /* Find the target, inside the loaded segment. */ 289 uint64_t *target= cpudriver + (rela->r_offset - base); 290 291#if 0 292 printf("%lx[%lx] (%p): %lx ->", rela->r_offset, 293 rela->r_addend, target, *target); 294#endif 295 296 switch(ELF64_R_TYPE(rela->r_info)) { 297 /* Our one supported relocation type. */ 298 case R_AARCH64_RELATIVE: { 299 /* Relocation: Delta(S) + A */ 300 *target= (rela->r_addend - base) + virt_base; 301 break; 302 } 303 304 default: 305 fprintf(stderr, "Unsupported relocation type (%lu) at %lx.\n", 306 ELF64_R_TYPE(rela->r_info), rela->r_offset); 307 exit(EXIT_FAILURE); 308 } 309#if 0 310 printf(" %lx\n", *target); 311#endif 312 } 313 314 return cpudriver; 315} 316 317void * 318load_shim(Elf *shim_elf, void *shim_raw, size_t shim_size, 319 uint64_t virt_base, uint64_t *loaded_size, uint64_t *alloc, 320 uint64_t kernel_table, uint64_t kernel_stack_top, 321 uint64_t multiboot, uint64_t entry, uint64_t *shim_entry, 322 int quiet) { 323 size_t phnum; 324 if(elf_getphdrnum(shim_elf, &phnum)) elf_fail("elf_getphdrnum"); 325 326 Elf64_Phdr *phdrs= elf64_getphdr(shim_elf); 327 if(!phdrs) elf_fail("elf64_getphdr"); 328 329 /* Calculate the base and limit for the loadable region. */ 330 uint64_t base= UINT64_MAX, limit= 0; 331 for(size_t kseg= 0; kseg < phnum; kseg++) { 332 if(phdrs[kseg].p_type == PT_LOAD) { 333 if(phdrs[kseg].p_vaddr < base) 334 base= phdrs[kseg].p_vaddr; 335 336 assert(phdrs[kseg].p_memsz <= UINT64_MAX - phdrs[kseg].p_vaddr); 337 if(phdrs[kseg].p_vaddr + phdrs[kseg].p_memsz > limit) 338 limit= phdrs[kseg].p_vaddr + phdrs[kseg].p_memsz; 339 } 340 } 341 342 /* Relocate the entry point. */ 343 Elf64_Ehdr *ehdr= elf64_getehdr(shim_elf); 344 if(!ehdr) elf_fail("elf64_getehdr"); 345 *shim_entry= virt_base + (ehdr->e_entry - base); 346 347 /* Allocate the target region. */ 348 *loaded_size= limit - base + 1; 349 *alloc= ROUNDUP(*loaded_size, PAGE_4k); 350 void *shim= malloc(*alloc); 351 if(!shim) fail("malloc"); 352 bzero(shim, *alloc); 353 354 /* Copy all loadable segments. */ 355 int loaded_something= 0; 356 for(size_t kseg= 0; kseg < phnum; kseg++) { 357 Elf64_Phdr *ph= &phdrs[kseg]; 358 if(ph->p_type == PT_LOAD) { 359 assert(ph->p_offset < shim_size); 360 assert(ph->p_offset + ph->p_filesz < shim_size); 361 362 void *seg_vbase= shim + (ph->p_vaddr - base); 363 memcpy(seg_vbase, shim_raw + ph->p_offset, ph->p_filesz); 364 365 loaded_something= 1; 366 } 367 } 368 369 if(!loaded_something) { 370 fprintf(stderr, "No loadable segments in shim ELF.\n"); 371 exit(EXIT_FAILURE); 372 } 373 374 /* Find the symbol and string tables. */ 375 Elf_Scn *scn= NULL; 376 Elf64_Word sh_type; 377 Elf64_Shdr *sh_symtab= NULL, *sh_strtab= NULL; 378 while((scn= elf_nextscn(shim_elf, scn)) != NULL) { 379 if(!scn) elf_fail("elf_nextscn"); 380 381 Elf64_Shdr *shdr= elf64_getshdr(scn); 382 if(!shdr) elf_fail("elf64_getshdr"); 383 sh_type= shdr->sh_type; 384 385 if(sh_type == SHT_REL || sh_type == SHT_RELA) { 386 fprintf(stderr, "Shim requires relocation.\n"); 387 exit(EXIT_FAILURE); 388 } 389 390 if(sh_type == SHT_SYMTAB) sh_symtab= shdr; 391 if(sh_type == SHT_STRTAB) sh_strtab= shdr; 392 } 393 if(!sh_symtab) { 394 fprintf(stderr, "Missing symbol table.\n"); 395 exit(EXIT_FAILURE); 396 } 397 if(!sh_strtab) { 398 fprintf(stderr, "Missing symbol table.\n"); 399 exit(EXIT_FAILURE); 400 } 401 402 /* Find the pointer fields to fill in. */ 403 int have_kernel_table= 0, have_kernel_stack_top= 0, 404 have_multiboot= 0, have_entry= 0; 405 const char *strings= (const char *)(shim_raw + sh_strtab->sh_offset); 406 for(size_t i= 0; i < sh_symtab->sh_size; i+= sizeof(Elf64_Sym)) { 407 Elf64_Sym *sym= (Elf64_Sym *)(shim_raw + sh_symtab->sh_offset + i); 408 409 /* Find the symbol name. */ 410 const char *name= strings + sym->st_name; 411 412 /* Find the symbol in the loaded image. */ 413 uint64_t *target= shim + (sym->st_value - base); 414 415 /* Check for the target symbols. */ 416 uint64_t value; 417 if(!strcmp("p_kernel_table", name)) { 418 have_kernel_table= 1; 419 value= kernel_table; 420 } 421 else if(!strcmp("p_kernel_stack_top", name)) { 422 have_kernel_stack_top= 1; 423 value= kernel_stack_top; 424 } 425 else if(!strcmp("p_multiboot", name)) { 426 have_multiboot= 1; 427 value= multiboot; 428 } 429 else if(!strcmp("p_entry", name)) { 430 have_entry= 1; 431 value= entry; 432 } 433 else continue; 434 435 /* Update the pointer. */ 436 if(!quiet) { 437 printf("Setting %s at %lx to %lx\n", 438 name, virt_base + (sym->st_value - base), value); 439 } 440 *target= value; 441 } 442 if(!(have_kernel_table && have_kernel_stack_top && 443 have_multiboot && have_entry)) { 444 fprintf(stderr, "Missing shim symbol.\n"); 445 exit(EXIT_FAILURE); 446 } 447 448 return shim; 449} 450 451/* A descriptor for the next-level table. 452 * These are the same at all levels. */ 453struct table_descriptor { 454 uint64_t type :2; // == 3 -> Table 455 uint64_t ign0 :10; // Ignored 456 uint64_t base_address :28; // Table address 457 uint64_t sbz0 :12; // sbz 458 uint64_t ign1 :7; // Ignored 459 460 /* Hierarchical lookup attributes */ 461 uint64_t pxn :1; // Privileged eXecute Never 462 uint64_t xn :1; // eXecute Never 463 uint64_t ap :2; // Access Permissions 464 uint64_t ns :1; // NonSecure 465}; 466 467union armv8_l1_entry { 468 uint64_t raw; 469 470 /* An L1 entry for a 1GB block (page) */ 471 struct { 472 uint64_t type :2; // == 1 -> Block 473 474 /* Lower block attributes */ 475 uint64_t ai :3; 476 uint64_t ns :1; 477 uint64_t ap :2; // AP 478 uint64_t sh :2; // AP 479 uint64_t af :1; // AF 480 uint64_t ng :1; // NG 481 482 uint64_t sbz0 :18; 483 uint64_t base_address :18; // block base address 484 uint64_t sbz1 :4; 485 486 /* Upper block attributes */ 487 uint64_t ch :1; // CH 488 uint64_t pxn :1; // PXN 489 uint64_t xn :1; // XN 490 uint64_t res :4; // Reserved 491 uint64_t ign1 :5; // Ignored 492 } block; 493}; 494 495#define BIT(n) (1ULL << (n)) 496#define MASK(n) (BIT(n) - 1) 497#define PTABLE_ENTRY_BITS 3 498#define PTABLE_ENTRY_SIZE BIT(PTABLE_ENTRY_BITS) 499#define PTABLE_BITS 9 500#define PTABLE_SIZE BIT(PTABLE_BITS + PTABLE_ENTRY_BITS) 501#define PTABLE_NUM_ENTRIES BIT(PTABLE_BITS) 502 503enum armv8_entry_type { 504 ARMv8_Ln_INVALID = 0, 505 ARMv8_Ln_BLOCK = 1, 506 ARMv8_Ln_TABLE = 3, 507 ARMv8_L3_PAGE = 3 508}; 509 510void * 511alloc_kernel_pt(size_t *pt_size, uint64_t table_base, 512 efi_memory_descriptor *mmap, size_t mmap_len) { 513 /* Allocate one L0 & one L1 table, in a contiguous block. An L0 514 * translation unit i.e. an L1 table, maps 512GiB with our translation 515 * settings, which is more than enough for a one-to-one kernel physical 516 * window. */ 517 void *block= calloc(2, PTABLE_SIZE); 518 if(!block) fail("calloc"); 519 520 struct table_descriptor *l0_table= 521 (struct table_descriptor *)block; 522 union armv8_l1_entry *l1_table= 523 (union armv8_l1_entry *)(block + PTABLE_SIZE); 524 525 /* Map the first two 1GiB blocks as device memory, using memory attribute 526 * 1, which we'll set to nGnRnE. */ 527 for(size_t j= 0; j < 2; j++) { 528 l1_table[j].block.type= ARMv8_Ln_BLOCK; 529 l1_table[j].block.ai= 1; /* Memory type 1 */ 530 l1_table[j].block.ns= 1; /* Non-secure. */ 531 l1_table[j].block.ap= 0; /* R/W EL1, no access EL0 */ 532 l1_table[j].block.sh= 2; /* Outer shareable - this is actually 533 ignored anyway. */ 534 l1_table[j].block.af= 1; /* Accessed/dirty - don't fault */ 535 l1_table[j].block.ng= 0; /* Global mapping */ 536 l1_table[j].block.base_address= j; /* PA = j << 30 */ 537 l1_table[j].block.ch= 1; /* Contiguous, combine TLB entries */ 538 l1_table[j].block.pxn= 1; /* Nonexecutable. */ 539 l1_table[j].block.xn= 1; /* Nonexecutable. */ 540 } 541 542 /* Map all RAM regions using contiguous 1GiB blocks. Use memory attribute 543 * 0, which we will set to fully-cacheable Normal memory. */ 544 for(size_t i= 0; i < mmap_len; i++) { 545 efi_memory_descriptor *d= &mmap[i]; 546 547 if(d->Type == EfiConventionalMemory) { 548 if(d->VirtualStart + d->NumberOfPages * PAGE_4k >= BIT(39)) { 549 fprintf(stderr, "RAM region %i lies above 512GB!\n", (int)i); 550 exit(EXIT_FAILURE); 551 } 552 553 if((d->VirtualStart & MASK(30)) != 0) { 554 fprintf(stderr, "RAM region %i not 1GB-aligned!\n", (int)i); 555 exit(EXIT_FAILURE); 556 } 557 558 if((d->NumberOfPages & MASK(18)) != 0) { 559 fprintf(stderr, "RAM region %i not 1GB-aligned!\n", (int)i); 560 exit(EXIT_FAILURE); 561 } 562 563 size_t ptbase= d->VirtualStart >> 30; 564 size_t ptend= ptbase + (d->NumberOfPages >> 18); 565 566 assert(ptbase < PTABLE_NUM_ENTRIES && 567 ptend < PTABLE_NUM_ENTRIES); 568 569 for(size_t j= ptbase; j < ptend; j++) { 570 l1_table[j].block.type= ARMv8_Ln_BLOCK; 571 l1_table[j].block.ai= 0; /* Memory type 0 */ 572 l1_table[j].block.ns= 1; /* Non-secure. */ 573 l1_table[j].block.ap= 0; /* R/W EL1, no access EL0 */ 574 l1_table[j].block.sh= 3; /* Inner-shareable, fully coherent */ 575 l1_table[j].block.af= 1; /* Accessed/dirty - don't fault */ 576 l1_table[j].block.ng= 0; /* Global mapping */ 577 l1_table[j].block.base_address= j; /* PA = j << 30 */ 578 l1_table[j].block.ch= 1; /* Contiguous, combine TLB entries */ 579 l1_table[j].block.pxn= 0; /* Executable. */ 580 l1_table[j].block.xn= 0; /* Executable. */ 581 } 582 } 583 } 584 585 uint64_t l1_base= table_base + PTABLE_SIZE; 586 587 /* Map the L1 table into the L0. */ 588 l0_table[0].type= ARMv8_Ln_TABLE; 589 l0_table[0].base_address= l1_base >> 12; 590 l0_table[0].pxn= 0; /* Executable. */ 591 l0_table[0].xn= 0; /* Executable. */ 592 l0_table[0].ap= 0; /* No permission masking. */ 593 l0_table[0].ns= 1; /* Non-secure. */ 594 595 *pt_size= 2 * PTABLE_SIZE; 596 return (void *)block; 597} 598 599int 600main(int argc, char *argv[]) { 601 if(argc < 6 || argc > 7) usage(argv[0]); 602 603 const char *config_path= argv[1], 604 *shim_path= argv[3], 605 *base_path= argv[4], 606 *out_path= argv[5]; 607 608 errno= 0; 609 uint64_t ram_size= strtoul(argv[2], NULL, 0); 610 if(errno) fail("strtoul"); 611 612 int debug_details= 0; 613 if(argc == 7 && !strcmp("-d", argv[6])) debug_details= 1; 614 615 /* Load the configuration. */ 616 size_t config_size, config_alloc; 617 char *config_raw= 618 (char *)load_file(config_path, &config_size, &config_alloc); 619 620 /* Parse the configuration. */ 621 struct config *config= parse_config(config_raw, config_size); 622 if(!config) exit(EXIT_FAILURE); 623 624 /* Construct the working buffer for paths. */ 625 char basepath_buf[PATH_MAX]; 626 size_t basepath_len; 627 strncpy(basepath_buf, base_path, PATH_MAX); 628 basepath_len= strlen(base_path); 629 630 /* Load the kernel ELF. */ 631 assert(config->kernel); 632 if(load_component(basepath_buf, basepath_len, 633 config->kernel, config_raw) != 0) { 634 fail("load_component"); 635 } 636 637 if(elf_version(EV_CURRENT) == EV_NONE) 638 elf_fail("elf_version"); 639 640 /* Start parsing the kernel ELF. */ 641 Elf *kernel_elf= 642 elf_memory((char *)config->kernel->image, 643 config->kernel->image_size); 644 if(!kernel_elf) elf_fail("elf_memory"); 645 646 /* Load all modules. */ 647 size_t n_modules= 0; 648 for(struct component_config *comp= config->first_module; 649 comp; comp= comp->next) { 650 n_modules++; 651 if(load_component(basepath_buf, basepath_len, comp, config_raw) != 0) 652 fail("load_component"); 653 } 654 655 /* How many RAM regions are there? If there's more than 2GiB, it'll be 656 * split into two. */ 657 if(ram_size > 8 * (1UL<<30)) { 658 fprintf(stderr, "The models only support <= 8GiB of RAM.\n"); 659 exit(EXIT_FAILURE); 660 } 661 size_t ram_regions; 662 if(ram_size > 2 * (1UL<<30)) ram_regions= 2; 663 else ram_regions= 1; 664 665 /* The EFI memory map contains one entry for each loaded module, one for 666 * each RAM region, and 5 fixed entries: The loaded CPU driver, the CPU 667 * driver's stack, the CPU driver's page tables, the Multiboot header, and 668 * the CPU driver ELF. */ 669 size_t mmap_len= n_modules + ram_regions + 5; 670 /* The RAM regions are at the end, thus the first is at n_modules + 5. */ 671 size_t first_region= n_modules + 5; 672 673 /* Create the multiboot header, now that we know how big the memory map 674 * needs to be. */ 675 void *mb_header= 676 create_multiboot2_info(config, kernel_elf, 677 mmap_len * sizeof(efi_memory_descriptor)); 678 if(!mb_header) { 679 fprintf(stderr, "Couldn't build the multiboot header.\n"); 680 exit(EXIT_FAILURE); 681 } 682 683 /* Build the EFI memory map. We leave uninitialised entries at the 684 * beginning for the kernel, all modules, the CPU driver's loadable 685 * segment & stack, the MB header, and the boot page table. */ 686 efi_memory_descriptor *mmap= 687 build_efi_mmap(config, mmap_len, first_region, ram_size); 688 689 /* Start allocating at the beginning of the first physical region. */ 690 uint64_t allocbase= mmap[first_region].PhysicalStart; 691 uint64_t loadbase= allocbase; 692 693 /* Load the CPU driver into physical RAM, and relocate for the kernel 694 * window. */ 695 uint64_t kernel_start= allocbase; 696 uint64_t cpudriver_size, cpudriver_alloc, cpudriver_entry; 697 void *cpudriver= 698 load_cpudriver(kernel_elf, config->kernel->image, 699 config->kernel->image_size, 700 KERNEL_OFFSET + kernel_start, 701 &cpudriver_size, &cpudriver_alloc, &cpudriver_entry); 702 703 /* Allocate the CPU driver's loadable segment. */ 704 allocbase= ROUNDUP(allocbase + cpudriver_size, PAGE_4k); 705 check_alloc(allocbase, mmap, first_region); 706 mmap[0].Type= EfiBarrelfishCPUDriver; 707 mmap[0].PhysicalStart= kernel_start; 708 mmap[0].VirtualStart= kernel_start; 709 mmap[0].NumberOfPages= roundpage(cpudriver_size); 710 mmap[0].Attribute= 0; /* XXX */ 711 712 /* Now allocate the CPU driver's stack. */ 713 config->kernel_stack= allocbase; 714 uint64_t kernel_stack_alloc= ROUNDUP(config->stack_size, PAGE_4k); 715 allocbase= ROUNDUP(allocbase + kernel_stack_alloc, PAGE_4k); 716 check_alloc(allocbase, mmap, first_region); 717 mmap[1].Type= EfiBarrelfishCPUDriverStack; 718 mmap[1].PhysicalStart= config->kernel_stack; 719 mmap[1].VirtualStart= config->kernel_stack; 720 mmap[1].NumberOfPages= roundpage(config->stack_size); 721 mmap[1].Attribute= 0; /* XXX */ 722 723 /* Allocate frames for the CPU driver's root page table. */ 724 uint64_t kernel_table= allocbase; 725 size_t kernel_pt_size; 726 void *kernel_pt= 727 alloc_kernel_pt(&kernel_pt_size, kernel_table, mmap, mmap_len); 728 mmap[2].Type= EfiBarrelfishBootPageTable; 729 mmap[2].PhysicalStart= allocbase; 730 mmap[2].VirtualStart= allocbase; 731 mmap[2].NumberOfPages= 1; 732 mmap[2].Attribute= 0; /* XXX */ 733 allocbase+= kernel_pt_size; 734 check_alloc(allocbase, mmap, first_region); 735 736 /* Allocate space for the multiboot header. */ 737 uint64_t multiboot= allocbase; 738 mmap[3].Type= EfiBarrelfishMultibootData; 739 mmap[3].PhysicalStart= allocbase; 740 mmap[3].VirtualStart= allocbase; 741 mmap[3].NumberOfPages= roundpage(config->multiboot_size); 742 mmap[3].Attribute= 0; /* XXX */ 743 allocbase= ROUNDUP(allocbase + config->multiboot_size, PAGE_4k); 744 check_alloc(allocbase, mmap, first_region); 745 746 /* Allocate room for the CPU driver ELF. */ 747 config->kernel->image_address= allocbase; 748 allocbase= ROUNDUP(allocbase + config->kernel->image_size, PAGE_4k); 749 check_alloc(allocbase, mmap, first_region); 750 mmap[4].Type= EfiBarrelfishELFData; 751 mmap[4].PhysicalStart= config->kernel->image_address; 752 mmap[4].VirtualStart= config->kernel->image_address; 753 mmap[4].NumberOfPages= roundpage(config->kernel->image_size); 754 mmap[4].Attribute= 0; /* XXX */ 755 756 /* Update the multiboot tag. */ 757 config->kernel->tag->mod_start= 758 (multiboot_uint64_t)config->kernel->image_address; 759 config->kernel->tag->mod_end= 760 (multiboot_uint64_t)(config->kernel->image_address + 761 (config->kernel->image_size - 1)); 762 763 if(!debug_details) { 764 printf("ELF %.*s %luB @ 0x%lx\n", 765 (int)config->kernel->path_len, 766 config_raw + config->kernel->path_start, 767 config->kernel->image_size, 768 config->kernel->image_address); 769 } 770 771 /* Allocate all remaining modules. We've allocated 5 mmap entries so far, 772 * so this will bring us up to n_modules+5. */ 773 struct component_config *m; 774 size_t i_mmap; 775 for(i_mmap= 5, m= config->first_module; m; i_mmap++, m= m->next) { 776 m->image_address= allocbase; 777 allocbase= ROUNDUP(allocbase + m->image_size, PAGE_4k); 778 check_alloc(allocbase, mmap, first_region); 779 mmap[i_mmap].Type= EfiBarrelfishELFData; 780 mmap[i_mmap].PhysicalStart= m->image_address; 781 mmap[i_mmap].VirtualStart= m->image_address; 782 mmap[i_mmap].NumberOfPages= roundpage(m->image_size); 783 mmap[i_mmap].Attribute= 0; /* XXX */ 784 785 /* Update the multiboot tag. */ 786 m->tag->mod_start= 787 (multiboot_uint64_t)m->image_address; 788 m->tag->mod_end= 789 (multiboot_uint64_t)(m->image_address + 790 (m->image_size - 1)); 791 792 if(!debug_details) { 793 printf("ELF %.*s %luB @ 0x%lx\n", 794 (int)m->path_len, 795 config_raw + m->path_start, 796 m->image_size, 797 m->image_address); 798 } 799 } 800 801 /* Update the first physical region, to exclude everthing we've just 802 * allocated. */ 803 uint64_t space_used= allocbase - mmap[first_region].PhysicalStart; 804 mmap[first_region].PhysicalStart= allocbase; 805 mmap[first_region].VirtualStart= allocbase; 806 mmap[first_region].NumberOfPages-= roundpage(space_used); 807 808 /* Load the shim at the beginning of the updated free region: this way the 809 * CPU driver will simply reuse the memory, without needing to know that 810 * the shim was ever used. */ 811 812 /* Load the ELF. */ 813 size_t shim_size, shim_raw_alloc; 814 void *shim_raw= load_file(shim_path, &shim_size, &shim_raw_alloc); 815 Elf *shim_elf= elf_memory((char *)shim_raw, shim_size); 816 if(!shim_elf) elf_fail("elf_memory"); 817 818 /* Relocate and initialise the shim. n.b. it jumps to the *physical* 819 * kernel entry point. */ 820 uint64_t shim_loaded_size, shim_alloc, shim_entry; 821 uint64_t shim_base= mmap[first_region].PhysicalStart; 822 void *shim= 823 load_shim(shim_elf, shim_raw, shim_size, shim_base, 824 &shim_loaded_size, &shim_alloc, kernel_table, 825 /* Stack must be 16-byte aligned. */ 826 config->kernel_stack + kernel_stack_alloc - 16, 827 multiboot + KERNEL_OFFSET, 828 cpudriver_entry - KERNEL_OFFSET, &shim_entry, 829 debug_details); 830 831 /* Print the memory map. */ 832 if(!debug_details) print_mmap(mmap, mmap_len); 833 834 FILE *outfile; 835 836 /* Open the output file for writing. */ 837 outfile= fopen(out_path, "w"); 838 if(!outfile) fail("fopen"); 839 840 size_t image_size= 0; 841 842 /* Write the loaded & relocated CPU driver. */ 843 if(!debug_details) { 844 if(fwrite(cpudriver, 1, cpudriver_alloc, outfile) != 845 cpudriver_alloc) { 846 fail("fwrite"); 847 } 848 } 849 image_size+= cpudriver_alloc; 850 851 /* Write the (empty) kernel stack. */ 852 void *stack= calloc(1, PAGE_4k); 853 if(!stack) fail("calloc"); 854 for(size_t i= 0; i < roundpage(config->stack_size); i++) { 855 if(!debug_details) { 856 if(fwrite(stack, 1, PAGE_4k, outfile) != PAGE_4k) { 857 fail("fwrite"); 858 } 859 } 860 image_size+= PAGE_4k; 861 } 862 free(stack); 863 864 /* Write the root page table. */ 865 if(!debug_details) { 866 if(fwrite(kernel_pt, 1, kernel_pt_size, outfile) != kernel_pt_size) { 867 fail("fwrite"); 868 } 869 } 870 image_size+= kernel_pt_size; 871 872 /* Write the multiboot header (including the memory map). */ 873 if(!debug_details) { 874 if(fwrite(config->multiboot, 1, config->multiboot_alloc, outfile) 875 != config->multiboot_alloc) { 876 fail("fwrite"); 877 } 878 } 879 image_size+= config->multiboot_alloc; 880 881 /* Write the kernel ELF. */ 882 if(!debug_details) { 883 if(fwrite(config->kernel->image, 1, 884 config->kernel->alloc_size, outfile) 885 != config->kernel->alloc_size) { 886 fail("fwrite"); 887 } 888 } 889 image_size+= config->kernel->alloc_size; 890 891 /* Write all module ELFs. */ 892 for(m= config->first_module; m; m= m->next) { 893 if(!debug_details) { 894 if(fwrite(m->image, 1, m->alloc_size, outfile) != m->alloc_size) { 895 fail("fwrite"); 896 } 897 } 898 image_size+= m->alloc_size; 899 } 900 901 /* Write the loaded shim. */ 902 if(!debug_details) { 903 if(fwrite(shim, 1, shim_loaded_size, outfile) != shim_loaded_size) { 904 fail("fwrite"); 905 } 906 } 907 image_size+= shim_loaded_size; 908 909 if(!debug_details) { 910 printf("Load address: 0x%lx\n", loadbase); 911 printf("Image size (bytes): %lu\n", image_size); 912 printf("Entry point: 0x%lx\n", shim_entry); 913 } 914 915 if(debug_details) { 916 fprintf(outfile, "load_address\t0x%lx\n", loadbase); 917 fprintf(outfile, "shim_address\t0x%lx\n", shim_base); 918 fprintf(outfile, "vminit_address\t0x%lx\n", kernel_start); 919 fprintf(outfile, "cpudriver_address\t0x%lx\n", 920 KERNEL_OFFSET + kernel_start); 921 fprintf(outfile, "entry_point\t0x%lx\n", shim_entry); 922 } 923 924 if(fclose(outfile)) fail("fclose"); 925 926 return EXIT_SUCCESS; 927} 928