1/* 2 * A static 'bootloader' for ARMv7 platforms. 3 * 4 * This tool loads and relocates the boot driver (into physical addresses) and 5 * the CPU driver into kernel virtual. It also constructs a multiboot image, 6 * and places the lot into an ELF file with a single loadable segment. Thus, 7 * if this ELF file is passed to a simulator, or loaded onto a pandaboard, on 8 * jumping to its start address, we're ready to go, just as if we'd been 9 * started by a dynamic bootloader. 10 * 11 * Copyright (c) 2016, ETH Zurich. 12 * All rights reserved. 13 * 14 * This file is distributed under the terms in the attached LICENSE file. 15 * If you do not find this file, copies can be found by writing to: 16 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group. 17 */ 18 19#include <sys/stat.h> 20#include <sys/types.h> 21 22#include <assert.h> 23#include <errno.h> 24#include <fcntl.h> 25#include <libelf.h> 26#include <limits.h> 27#include <stdarg.h> 28#include <stdint.h> 29#include <stdio.h> 30#include <stdlib.h> 31#include <string.h> 32#include <unistd.h> 33 34/* We need to be able to parse menu.lst files, create multiboot images. */ 35#include "../../include/grubmenu.h" 36#include "../../include/multiboot.h" 37 38/* XXX - this should be taken from the kernel offsets.h. */ 39#define KERNEL_WINDOW 0x80000000 40#define BASE_PAGE_SIZE (1<<12) 41 42#undef DEBUG 43 44#ifdef DEBUG 45#define DBG(format, ...) printf(format, ## __VA_ARGS__) 46#else 47#define DBG(format, ...) 48#endif 49 50/* Keep physical addresses and kernel virtual addresses separated, as far as 51 * possible. */ 52typedef uint32_t kvaddr_t; 53typedef uint32_t paddr_t; 54 55/*** A Linear Memory Allocator ***/ 56 57static paddr_t phys_alloc_start; 58 59static uint32_t 60round_up(uint32_t x, uint32_t y) { 61 assert(y > 0); 62 uint32_t z= x + (y - 1); 63 return z - (z % y); 64} 65 66/* Advance the allocator to an address with the given alignment. */ 67static paddr_t 68align_alloc(paddr_t align) { 69 phys_alloc_start= round_up(phys_alloc_start, align); 70 return phys_alloc_start; 71} 72 73/* Allocate an aligned block. */ 74static paddr_t 75phys_alloc(size_t size, size_t align) { 76 align_alloc(align); 77 paddr_t addr= phys_alloc_start; 78 phys_alloc_start+= size; 79 return addr; 80} 81 82/*** Failure Handling ***/ 83 84void 85fail(const char *fmt, ...) { 86 va_list ap; 87 va_start(ap, fmt); 88 vfprintf(stderr, fmt, ap); 89 va_end(ap); 90 exit(EXIT_FAILURE); 91} 92 93static void 94fail_errno(const char *fmt, ...) { 95 char s[1024]; 96 97 va_list ap; 98 va_start(ap, fmt); 99 vsnprintf(s, 1024, fmt, ap); 100 va_end(ap); 101 102 perror(s); 103 exit(EXIT_FAILURE); 104} 105 106static void 107fail_elf(const char *s) { 108 fprintf(stderr, "%s: %s\n", s, elf_errmsg(elf_errno())); 109 exit(EXIT_FAILURE); 110} 111 112struct loaded_image { 113 void *segment; 114 paddr_t segment_base; /* Unrelocated. */ 115 size_t segment_size; 116 117 size_t loaded_size; 118 paddr_t loaded_paddr; 119 kvaddr_t loaded_vaddr; 120 121 kvaddr_t relocated_entry; 122 const char *extrasym_name; 123 void *extrasym_ptr; 124 125 void *shdrs, *symtab, *strtab, *shstrtab; 126 size_t shdrs_size, symtab_size, strtab_size, shstrtab_size; 127 size_t shdrs_entsize, symtab_entsize; 128}; 129 130/* Load and relocate an ELF, with the given offset between the physical 131 * address at which it is loaded, and the virtual address at which it 132 * executes. For the boot driver, the offset is zero. Return a variety of 133 * information about the loaded image. */ 134static void * 135load(int in_fd, uint32_t vp_offset, struct loaded_image *image, 136 int save_sections) { 137 /* Open the ELF. */ 138 Elf *elf= elf_begin(in_fd, ELF_C_READ, NULL); 139 if(!elf) fail_elf("elf_begin"); 140 141 /* Grab the unrelocated entry address from the header. */ 142 Elf32_Ehdr *ehdr= elf32_getehdr(elf); 143 if(!ehdr) fail_elf("elf32_getehdr"); 144 uint32_t entry= ehdr->e_entry; 145 146 /* Grab the program headers i.e. the list of loadable segments. */ 147 size_t phnum; 148 if(elf_getphdrnum(elf, &phnum)) fail_elf("elf_getphnum"); 149 150 Elf32_Phdr *ph= elf32_getphdr(elf); 151 if(!ph) fail_elf("elf_getphdr"); 152 153 DBG("%d program segments.\n", phnum); 154 155 /* Grab the raw ELF data. */ 156 size_t elfsize; 157 void *elfdata= elf_rawfile(elf, &elfsize); 158 if(!elfdata) fail_elf("elf_rawfile"); 159 160 /* Find the section header names. */ 161 Elf_Scn *shstrscn= elf_getscn(elf, ehdr->e_shstrndx); 162 if(!shstrscn) fail_elf("elf_getscn"); 163 Elf32_Shdr *shstrshdr= elf32_getshdr(shstrscn); 164 if(!shstrshdr) fail_elf("elf_getshdr"); 165 assert(shstrshdr->sh_offset + shstrshdr->sh_size <= elfsize); 166 char *shstr= (char *)(elfdata + shstrshdr->sh_offset); 167 if(save_sections) { 168 /* Save a copy, if we've been asked to. */ 169 image->shstrtab_size= shstrshdr->sh_size; 170 image->shstrtab= malloc(image->shstrtab_size); 171 if(!image->shstrtab) fail_errno("malloc"); 172 memcpy(image->shstrtab, shstr, image->shstrtab_size); 173 } 174 175 /* Save the section headers, if required. */ 176 if(save_sections) { 177 size_t sh_totalsize= ehdr->e_shnum * ehdr->e_shentsize; 178 assert(ehdr->e_shoff + sh_totalsize <= elfsize); 179 180 image->shdrs_size= sh_totalsize; 181 image->shdrs_entsize= ehdr->e_shentsize; 182 image->shdrs= malloc(sh_totalsize); 183 if(!image->shdrs) fail_errno("malloc"); 184 memcpy(image->shdrs, elfdata + ehdr->e_shoff, sh_totalsize); 185 } 186 187 /* We need the dynamic relocation section, the string table, and the 188 * dynamic symbol table. */ 189 Elf32_Shdr *shdr_rel= NULL, *shdr_sym= NULL; 190 191 /* Find the dynamic relocation section. */ 192 Elf_Scn *scn; 193 for(scn= elf_nextscn(elf, NULL); scn; scn= elf_nextscn(elf, scn)) { 194 195 Elf32_Shdr *shdr= elf32_getshdr(scn); 196 if(!shdr) fail_elf("elf_getshdr"); 197 198 switch(shdr->sh_type) { 199 case SHT_REL: 200 if(shdr_rel) fail("Found two relocation tables.\n"); 201 shdr_rel= shdr; 202 break; 203 case SHT_DYNSYM: 204 if(shdr_sym) fail("Found two dynamic symbol tables.\n"); 205 shdr_sym= shdr; 206 break; 207 case SHT_SYMTAB: 208 /* Save a copy of the symbol table. */ 209 if(save_sections) { 210 if(image->symtab) fail("Found two symbol tables.\n"); 211 212 image->symtab_size= shdr->sh_size; 213 image->symtab_entsize= shdr->sh_entsize; 214 image->symtab= malloc(shdr->sh_size); 215 if(!image->symtab) fail_errno("malloc"); 216 217 assert(shdr->sh_offset + shdr->sh_size <= elfsize); 218 memcpy(image->symtab, elfdata + shdr->sh_offset, 219 shdr->sh_size); 220 } 221 break; 222 case SHT_STRTAB: 223 /* Save the main string table. */ 224 if(save_sections && 225 !strcmp(shstr + shdr->sh_name, ".strtab")) { 226 if(image->strtab) fail("Found two string tables.\n"); 227 228 image->strtab_size= shdr->sh_size; 229 image->strtab= malloc(shdr->sh_size); 230 if(!image->strtab) fail_errno("malloc"); 231 232 assert(shdr->sh_offset + shdr->sh_size <= elfsize); 233 memcpy(image->strtab, elfdata + shdr->sh_offset, 234 shdr->sh_size); 235 } 236 break; 237 case SHT_RELA: 238 fail("Didn't expect a RELA section.\n"); 239 } 240 } 241 242 if(!shdr_rel) fail("Didn't find a relocation table.\n"); 243 if(!shdr_sym) fail("Didn't find a dynamic symbol table.\n"); 244 245 /* Find the got_base symbol, and its unrelocated address. */ 246 uint32_t got_base = 0, got_base_reloc = 0; 247 int got_symidx= -1; 248 /* If the caller asked us to locate another symbol, this is it. */ 249 uint32_t extrasym_initaddr = 0; 250 { 251 int found_extrasym= 0; 252 253 /* The dynamic symbol table should link to the dynamic string table. */ 254 int dynstr_idx= shdr_sym->sh_link; 255 if(dynstr_idx == 0) fail("No link to the string table.\n"); 256 Elf_Scn *scn_str= elf_getscn(elf, dynstr_idx); 257 if(!scn_str) fail_elf("elf_getscn"); 258 Elf32_Shdr *shdr_str= elf32_getshdr(scn_str); 259 if(!shdr_str) fail_elf("elf32_getshdr"); 260 if(shdr_str->sh_type != SHT_STRTAB) 261 fail("Invalid dynamic string table.\n"); 262 /* This is the base of the string table, as loaded into RAM. */ 263 char *str_base= (char *)elfdata + shdr_str->sh_offset; 264 265 /* Walk the symbol table, and find the symbol for the global offset 266 * table, 'got_base'. */ 267 size_t entries= shdr_sym->sh_size / shdr_sym->sh_entsize; 268 void *base= elfdata + shdr_sym->sh_offset; 269 for(size_t i= 0; i < entries; i++) { 270 Elf32_Sym *sym= 271 (Elf32_Sym *)(base + i * shdr_sym->sh_entsize); 272 273 if(!strcmp("got_base", str_base + sym->st_name)) { 274 DBG("Found got_base at %08x\n", sym->st_value); 275 /* Remember the unrelocated address of the GOT. */ 276 got_base= sym->st_value; 277 /* Remember the symbol index, so we can spot it, when it's 278 * later mentioned in a relocation. */ 279 got_symidx= i; 280 } 281 282 /* If we're looking for an extra symbol, do so. */ 283 if(image->extrasym_name && 284 !strcmp(image->extrasym_name, str_base + sym->st_name)) { 285 DBG("Found %s at %08x\n", image->extrasym_name, 286 sym->st_value); 287 extrasym_initaddr= sym->st_value; 288 found_extrasym= 1; 289 } 290 } 291 if(got_symidx == -1) fail("No got_base symbol.\n"); 292 if(image->extrasym_name && !found_extrasym) 293 fail("No %s symbol\n", image->extrasym_name); 294 } 295 296 /* Find the first loadable segment, and load it. */ 297 void *loaded_segment= NULL; 298 int found_got_base= 0, found_entry= 0, found_extrasym= 0; 299 size_t sidx; 300 for(sidx= 0; sidx < phnum && ph[sidx].p_type != PT_LOAD; sidx++); 301 if(sidx == phnum) fail("No loadable segments.\n"); 302 Elf32_Phdr *phdr= &ph[sidx]; 303 304 /* Record the unrelocated base address of the segment. */ 305 image->segment_base= phdr->p_vaddr; 306 image->segment_size= phdr->p_memsz; 307 308 /* Segments are aligned to BASE_PAGE_SIZE (4k) by default. If the 309 * segment has a greater alignment restriction, we use that, but 310 * only if it's a multiple of the page size, as we want to stay 311 * page-aligned. */ 312 uint32_t seg_align; 313 if(phdr->p_align > BASE_PAGE_SIZE) { 314 if(phdr->p_align % BASE_PAGE_SIZE != 0) { 315 fail("Alignment of segment %u (%u)" 316 " isn't a multiple of %u\n", 317 sidx, phdr->p_align, BASE_PAGE_SIZE); 318 } 319 320 seg_align= phdr->p_align; 321 DBG("Increasing alignment to %u to match segment %zu\n", 322 seg_align, sidx); 323 } 324 else seg_align= BASE_PAGE_SIZE; 325 326 /* Allocate target memory. Keep it to a multiple of the page 327 * size. */ 328 image->loaded_size= round_up(phdr->p_memsz, BASE_PAGE_SIZE); 329 image->loaded_paddr= phys_alloc(image->loaded_size, seg_align); 330 image->loaded_vaddr= image->loaded_paddr + vp_offset; 331 DBG("Allocated %zu at VA %08x (PA %08x) for segment %zu\n", 332 image->loaded_size, 333 image->loaded_vaddr, 334 image->loaded_paddr, sidx); 335 336 /* Check whether we've found the GOT. */ 337 if(phdr->p_vaddr <= got_base && 338 (got_base - phdr->p_vaddr) < phdr->p_memsz) { 339 got_base_reloc= 340 image->loaded_vaddr + (got_base - phdr->p_vaddr); 341 DBG("got_base is in segment %zu, " 342 "relocated %08x to VA %08x\n", 343 sidx, got_base, got_base_reloc); 344 found_got_base= 1; 345 } 346 347 /* Check whether we've found the entry point. */ 348 if(phdr->p_vaddr <= entry && 349 (entry - phdr->p_vaddr) < phdr->p_memsz) { 350 image->relocated_entry= 351 image->loaded_vaddr + (entry - phdr->p_vaddr); 352 DBG("entry is in segment %zu, VA %08x\n", 353 sidx, image->relocated_entry); 354 found_entry= 1; 355 } 356 357 /* Allocate a buffer into which to load the segment. */ 358 loaded_segment= calloc(image->loaded_size, 1); 359 if(!loaded_segment) fail_errno("calloc"); 360 image->segment= loaded_segment; 361 362 if(phdr->p_offset + phdr->p_filesz > elfsize) { 363 fail("Segment extends outside file.\n"); 364 } 365 366 /* Copy it to the buffer. */ 367 memcpy(loaded_segment, 368 elfdata + phdr->p_offset, 369 phdr->p_filesz); 370 371 /* If we're looking for another symbol, check whether it's in this 372 * segment. We will already have found its unrelocated address 373 * when we walked the symbol table. */ 374 if(image->extrasym_name && 375 phdr->p_vaddr <= extrasym_initaddr && 376 (extrasym_initaddr - phdr->p_vaddr) < phdr->p_memsz) { 377 uint32_t extrasym_offset= extrasym_initaddr - phdr->p_vaddr; 378 DBG("%s is in segment %zu, offset %d\n", 379 image->extrasym_name, sidx, extrasym_offset); 380 /* Return the address within the loaded image. */ 381 image->extrasym_ptr= loaded_segment + extrasym_offset; 382 found_extrasym= 1; 383 } 384 385 if(!found_got_base) fail("got_base not in any loadable segment.\n"); 386 if(!found_entry) fail("entry point not in any loadable segment.\n"); 387 if(image->extrasym_name && !found_extrasym) 388 fail("%s not in any loadable segment.\n", image->extrasym_name); 389 390 /* Now that all segments have been allocated, apply relocations. */ 391 { 392 size_t rel_count= shdr_rel->sh_size / shdr_rel->sh_entsize; 393 void *rel_table= elfdata + shdr_rel->sh_offset; 394 for(size_t i= 0; i < rel_count; i++) { 395 Elf32_Rel *rel= 396 (Elf32_Rel *)(rel_table + i * shdr_rel->sh_entsize); 397 398 int sym= ELF32_R_SYM(rel->r_info), 399 typ= ELF32_R_TYPE(rel->r_info); 400 401 /* Process the relocation if it's in the first loadable 402 * segment, otherwise ignore it. */ 403 if(phdr->p_vaddr > rel->r_offset || 404 rel->r_offset >= phdr->p_vaddr + phdr->p_memsz) { 405 printf("Ignoring relocation at %08x outside all " 406 "loadable segments.\n", rel->r_offset); 407 continue; 408 } 409 410 /* Find the value to relocate. */ 411 uint32_t offset_within_segment= rel->r_offset - phdr->p_vaddr; 412 uint32_t *value= 413 (uint32_t *)(loaded_segment + offset_within_segment); 414 415 /* There should be only section-relative relocations, except for 416 * one absolute relocation for the GOT. */ 417 if(typ == R_ARM_RELATIVE && sym == 0) { 418 /* Perform the relocation. */ 419 uint32_t reloc_offset= image->loaded_vaddr - phdr->p_vaddr; 420 DBG("Rel @ %08x: %08x -> %08x\n", 421 rel->r_offset, *value, *value + reloc_offset); 422 *value+= reloc_offset; 423 } 424 else if(typ == R_ARM_ABS32 && sym == got_symidx) { 425 DBG("Rel @ %08x: %08x -> %08x\n", 426 rel->r_offset, *value, got_base_reloc); 427 /* As this is an absolute address, we need apply the kernel 428 * window offset (if any). */ 429 *value= got_base_reloc; 430 } 431 else fail("Invalid relocation at %08x, typ=%d, sym=%d\n", 432 rel->r_offset, typ, sym); 433 } 434 } 435 436 if(elf_end(elf) < 0) fail_elf("elf_end"); 437 438 return image->segment; 439} 440 441/*** Output ELF Creation ***/ 442 443static char *global_strings; 444static size_t global_strings_size= 0; 445 446static void 447init_strings(void) { 448 global_strings_size= 1; 449 global_strings= calloc(global_strings_size, 1); 450 if(!global_strings) fail_errno("malloc"); 451} 452 453static size_t 454add_string(const char *s) { 455 /* The new string begins just past the current end. */ 456 size_t start= global_strings_size; 457 458 /* Extend the buffer. */ 459 global_strings_size+= strlen(s) + 1; 460 global_strings= realloc(global_strings, global_strings_size); 461 if(!global_strings) fail_errno("realloc"); 462 463 /* Copy the new string in. */ 464 strcpy(global_strings + start, s); 465 466 /* Return the index of the new string. */ 467 return start; 468} 469 470/* Keep track of where we are in the output ELF file. */ 471#define ELF_HEADER_SPACE 0x4000 472 473static size_t current_elf_offset= 0; 474 475static size_t 476get_elf_offset(void) { 477 return current_elf_offset; 478} 479 480static size_t 481increase_elf_offset(size_t n) { 482 size_t old_offset= current_elf_offset; 483 current_elf_offset+= n; 484 return old_offset; 485} 486 487static size_t 488align_elf_offset(size_t align) { 489 current_elf_offset= round_up(current_elf_offset, align); 490 return current_elf_offset; 491} 492 493static void 494advance_elf_offset(size_t n) { 495 assert(n + ELF_HEADER_SPACE >= current_elf_offset); 496 current_elf_offset= n + ELF_HEADER_SPACE; 497} 498 499/* Keep track of the highest physical address we've allocated, so we know how 500 * large the loadable segment is. */ 501static paddr_t greatest_paddr= 0; 502 503/* Add an image (module or multiboot header) in its own section. */ 504static Elf32_Shdr * 505add_blob(Elf *elf, const char *name, void *image, size_t size, 506 paddr_t paddr) { 507 /* Create the section. */ 508 Elf_Scn *scn= elf_newscn(elf); 509 if(!scn) fail_elf("elf_newscn"); 510 511 /* Add the image as a new data blob. */ 512 Elf_Data *data= elf_newdata(scn); 513 if(!data) fail_elf("elf_newdata"); 514 515 data->d_align= 1; 516 data->d_buf= image; 517 data->d_off= 0; 518 data->d_size= size; 519 data->d_type= ELF_T_BYTE; 520 data->d_version= EV_CURRENT; 521 522 /* Initialise the section header. */ 523 Elf32_Shdr *shdr= elf32_getshdr(scn); 524 if(!shdr) fail_elf("elf32_getshdr"); 525 526 if(name) shdr->sh_name= add_string(name); 527 else shdr->sh_name= 0; 528 shdr->sh_type= SHT_PROGBITS; 529 shdr->sh_flags= SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; 530 /* The loader ELF contains the *physical* addresses. */ 531 shdr->sh_addr= (uint32_t)paddr; 532 shdr->sh_size= size; 533 shdr->sh_offset= increase_elf_offset(size); 534 535 paddr_t last_byte= paddr + size - 1; 536 if(last_byte > greatest_paddr) greatest_paddr= last_byte; 537 538 return shdr; 539} 540 541/* Add a loaded image as a blob, without individual section headers. */ 542static Elf32_Shdr * 543add_image(Elf *elf, const char *name, struct loaded_image *image) { 544 return add_blob(elf, name, image->segment, image->loaded_size, 545 image->loaded_paddr); 546} 547 548/* Update any addresses stored in this table. */ 549void 550update_table(uint32_t sh_type, void *section_data, size_t sh_size, 551 size_t sh_entsize, kvaddr_t segment_base, kvaddr_t loaded_vaddr, 552 size_t *index_map, size_t nshdr) { 553 switch(sh_type) { 554 case SHT_DYNSYM: 555 case SHT_SYMTAB: { 556 size_t nsym= sh_size / sh_entsize; 557 DBG("Relocating %zu symbols.\n", nsym); 558 559 for(size_t i= 0; i < nsym; i++) { 560 Elf32_Sym *sym= section_data + i * sh_entsize; 561 562 /* Absolute values needn't be relocated. */ 563 if(sym->st_shndx == SHN_ABS) continue; 564 565 /* These shouldn't appear in executables. */ 566 assert(sym->st_shndx != SHN_COMMON); 567 568 /* Update the section index. */ 569 assert(sym->st_shndx < nshdr); 570 sym->st_shndx= index_map[sym->st_shndx]; 571 572 /* Skip the null symbol. */ 573 if(sym->st_shndx == SHN_UNDEF) continue; 574 575 /* Relocate the symbol to its loaded KV address. */ 576 sym->st_value= (sym->st_value - segment_base) + loaded_vaddr; 577 } 578 579 break; 580 } 581 case SHT_REL: { 582 size_t nrel= sh_size / sh_entsize; 583 DBG("Rebasing %zu relocations.\n", nrel); 584 585 for(size_t i= 0; i < nrel; i++) { 586 Elf32_Rel *rel= section_data + i * sh_entsize; 587 588 /* Update the relocation's target address. */ 589 rel->r_offset= (rel->r_offset - segment_base) + loaded_vaddr; 590 } 591 592 break; 593 } 594 case SHT_RELA: 595 fail("Didn't expect RELA sections.\n"); 596 } 597} 598 599/* Add a loaded image by including all its loadable sections, and its symbol 600 * and string tables. */ 601Elf32_Shdr * 602add_image_with_sections(Elf *elf, struct loaded_image *image) { 603 Elf32_Shdr *first_shdr= NULL; 604 605 assert(image->shdrs); 606 assert(image->shstrtab); 607 608 size_t nshdr= image->shdrs_size / image->shdrs_entsize; 609 DBG("%zu section headers to translate\n", nshdr); 610 611 size_t *new_index= alloca(nshdr * sizeof(size_t)); 612 bzero(new_index, nshdr * sizeof(size_t)); 613 614 Elf_Scn **new_scn= alloca(nshdr * sizeof(Elf_Scn *)); 615 bzero(new_scn, nshdr * sizeof(Elf_Scn *)); 616 617 /* For every allocatable section within the loadable segment, relocate it 618 * and add it to the output ELF. */ 619 for(size_t i= 0; i < nshdr; i++) { 620 Elf32_Shdr *shdr= image->shdrs + i * image->shdrs_entsize; 621 622 if(!(shdr->sh_flags & SHF_ALLOC)) { 623 DBG("section %zu not allocatable.\n", i); 624 continue; 625 } 626 627 if(shdr->sh_addr < image->segment_base || 628 shdr->sh_addr >= image->segment_base + image->segment_size) { 629 DBG("section %zu not in the loaded segment.\n", i); 630 continue; 631 } 632 633 assert(shdr->sh_addr + shdr->sh_size <= 634 image->segment_base + image->segment_size); 635 636 const char *name= image->shstrtab + shdr->sh_name; 637 DBG("Adding section %zu: %s\n", i, name); 638 639 /* Create the section. */ 640 new_scn[i]= elf_newscn(elf); 641 if(!new_scn[i]) fail_elf("elf_newscn"); 642 643 size_t ndx= elf_ndxscn(new_scn[i]); 644 if(ndx == SHN_UNDEF) fail_elf("elf_ndxscn"); 645 new_index[i]= ndx; 646 DBG("New section index is %zu\n", ndx); 647 648 uint32_t offset_in_seg= shdr->sh_addr - image->segment_base; 649 void *section_data= image->segment + offset_in_seg; 650 651 /* The previous section's size may have not have taken us up to our 652 * base address, so warp forward. */ 653 advance_elf_offset(offset_in_seg); 654 655 /* Add the section data. */ 656 Elf_Data *data= elf_newdata(new_scn[i]); 657 if(!data) fail_elf("elf_newdata"); 658 659 /* Add the correct block of the loaded segment. */ 660 data->d_align= 1; /* XXX */ 661 data->d_buf= section_data; 662 data->d_off= 0; 663 data->d_size= shdr->sh_size; 664 data->d_type= ELF_T_BYTE; 665 data->d_version= EV_CURRENT; 666 667 /* Create a new section header, with relocated addresses. */ 668 Elf32_Shdr *new_shdr= elf32_getshdr(new_scn[i]); 669 if(!new_shdr) fail_elf("elf32_getshdr"); 670 if(!first_shdr) first_shdr= new_shdr; 671 672 new_shdr->sh_name= add_string(name); 673 new_shdr->sh_type= shdr->sh_type; 674 new_shdr->sh_flags= shdr->sh_flags; 675 /* Relocate the segment address. */ 676 new_shdr->sh_addr= image->loaded_vaddr + offset_in_seg; 677 new_shdr->sh_offset= increase_elf_offset(shdr->sh_size); 678 new_shdr->sh_size= shdr->sh_size; 679 new_shdr->sh_link= shdr->sh_link; /* We'll update this soon. */ 680 new_shdr->sh_info= shdr->sh_info; 681 new_shdr->sh_addralign= shdr->sh_addralign; 682 new_shdr->sh_entsize= shdr->sh_entsize; 683 684 DBG("Section base %08x, size %x\n", new_shdr->sh_addr, 685 new_shdr->sh_size); 686 DBG("Section offset %u\n", new_shdr->sh_offset); 687 DBG("Align %d %d\n", shdr->sh_addralign, 688 new_shdr->sh_addr % shdr->sh_addralign); 689 690 //assert(new_shdr->sh_offset % new_shdr->sh_addralign == 0); 691 692 paddr_t paddr= image->loaded_paddr + offset_in_seg; 693 paddr_t last_byte= paddr + shdr->sh_size - 1; 694 if(last_byte > greatest_paddr) greatest_paddr= last_byte; 695 } 696 697 /* Now that all sections have been allocated new headers, walk through and 698 * update any section->section links, and modify symbol and relocation 699 * tables. */ 700 for(size_t i= 0; i < nshdr; i++) { 701 if(!new_scn[i]) continue; 702 703 Elf32_Shdr *shdr= elf32_getshdr(new_scn[i]); 704 if(!shdr) fail_elf("elf32_getshdr"); 705 706 assert(shdr->sh_link < nshdr); 707 shdr->sh_link= new_index[shdr->sh_link]; 708 709 uint32_t offset_in_seg= shdr->sh_addr - image->loaded_vaddr; 710 void *section_data= image->segment + offset_in_seg; 711 712 /* If this is a symbol or relocation table, any addresses in it must 713 * be relocated. */ 714 update_table(shdr->sh_type, section_data, shdr->sh_size, 715 shdr->sh_entsize, image->segment_base, 716 image->loaded_vaddr, new_index, nshdr); 717 } 718 719 /* Update the pointers in the symbol table now, while we've got the 720 * information to do it. */ 721 update_table(SHT_SYMTAB, image->symtab, image->symtab_size, 722 image->symtab_entsize, image->segment_base, 723 image->loaded_vaddr, new_index, nshdr); 724 725 return first_shdr; 726} 727 728/* Add the non-loadable tables from an image. This is separated from 729 * load_image_with_sections(), as they need to come last, such that we have a 730 * contiguous loadable segment. */ 731static void 732add_tables(Elf *elf, struct loaded_image *image) { 733 /* Add the string table for the loaded image. */ 734 size_t strtabndx; 735 { 736 assert(image->strtab); 737 738 /* Create the section. */ 739 Elf_Scn *scn= elf_newscn(elf); 740 if(!scn) fail_elf("elf_newscn"); 741 742 strtabndx= elf_ndxscn(scn); 743 if(strtabndx == SHN_UNDEF) fail_elf("elf_ndxscn"); 744 745 Elf_Data *data= elf_newdata(scn); 746 if(!data) fail_elf("elf_newdata"); 747 748 data->d_align= 1; 749 data->d_buf= image->strtab; 750 data->d_off= 0; 751 data->d_size= image->strtab_size; 752 data->d_type= ELF_T_BYTE; 753 data->d_version= EV_CURRENT; 754 755 /* Initialise the section header. */ 756 Elf32_Shdr *shdr= elf32_getshdr(scn); 757 if(!shdr) fail_elf("elf32_getshdr"); 758 759 shdr->sh_name= add_string(".strtab"); 760 shdr->sh_type= SHT_STRTAB; 761 shdr->sh_offset= increase_elf_offset(image->strtab_size); 762 shdr->sh_size= image->strtab_size; 763 shdr->sh_flags= 0; 764 shdr->sh_addr= 0; 765 } 766 767 /* Add the symbol table. */ 768 { 769 assert(image->symtab); 770 771 /* Create the section. */ 772 Elf_Scn *scn= elf_newscn(elf); 773 if(!scn) fail_elf("elf_newscn"); 774 775 Elf_Data *data= elf_newdata(scn); 776 if(!data) fail_elf("elf_newdata"); 777 778 data->d_align= 1; 779 data->d_buf= image->symtab; 780 data->d_off= 0; 781 data->d_size= image->symtab_size; 782 data->d_type= ELF_T_BYTE; 783 data->d_version= EV_CURRENT; 784 785 /* Initialise the section header. */ 786 Elf32_Shdr *shdr= elf32_getshdr(scn); 787 if(!shdr) fail_elf("elf32_getshdr"); 788 789 /* Elf32_Rel must be aligned to 4 bytes. */ 790 align_elf_offset(4); 791 792 shdr->sh_name= add_string(".symtab"); 793 shdr->sh_type= SHT_SYMTAB; 794 shdr->sh_flags= 0; 795 shdr->sh_addr= 0; 796 shdr->sh_offset= increase_elf_offset(image->symtab_size); 797 shdr->sh_size= image->symtab_size; 798 shdr->sh_link= strtabndx; /* Link the string table. */ 799 shdr->sh_entsize= image->symtab_entsize; 800 } 801} 802 803/* Add the section name string table. */ 804static void 805add_strings(Elf *elf) { 806 Elf_Scn *scn= elf_newscn(elf); 807 if(!scn) fail_elf("elf_newscn"); 808 809 size_t nameidx= add_string(".shstrtab"); 810 811 Elf_Data *data= elf_newdata(scn); 812 if(!data) fail_elf("elf_newdata"); 813 814 data->d_align= 1; 815 data->d_buf= global_strings; 816 data->d_off= 0; 817 data->d_size= global_strings_size; 818 data->d_type= ELF_T_BYTE; 819 data->d_version= EV_CURRENT; 820 821 /* Initialise the string table section header. */ 822 Elf32_Shdr *shdr= elf32_getshdr(scn); 823 if(!shdr) fail_elf("elf32_getshdr"); 824 825 shdr->sh_name= nameidx; 826 shdr->sh_type= SHT_STRTAB; 827 shdr->sh_flags= SHF_STRINGS; 828 shdr->sh_offset= increase_elf_offset(global_strings_size); 829 shdr->sh_size= global_strings_size; 830 shdr->sh_addralign= 1; 831 832 elf_setshstrndx(elf, elf_ndxscn(scn)); 833}; 834 835static void 836join_paths(char *dst, const char *src1, const char *src2) { 837 strcpy(dst, src1); 838 dst[strlen(src1)]= '/'; 839 strcpy(dst + strlen(src1) + 1, src2); 840} 841 842struct 843loaded_module { 844 void *data; 845 paddr_t paddr; 846 size_t len; 847 const char *shortname; 848}; 849 850/* Load an ELF file as a raw data blob. */ 851void 852raw_load(const char *path, struct loaded_module *m) { 853 struct stat mstat; 854 855 if(stat(path, &mstat)) fail_errno("stat: %s", path); 856 857 size_t data_len= mstat.st_size; 858 m->len= round_up(data_len, BASE_PAGE_SIZE); 859 m->data= calloc(m->len, 1); 860 if(!m->data) fail_errno("calloc"); 861 m->paddr= phys_alloc(m->len, BASE_PAGE_SIZE); 862 863 printf("Allocated 0x%zxB at PA %08x for %s\n", m->len, m->paddr, path); 864 865 FILE *f= fopen(path, "r"); 866 size_t read_len= fread(m->data, 1, data_len, f); 867 if(read_len != data_len) fail_errno("fread"); 868 if(fclose(f)) fail_errno("fclose"); 869} 870 871/*** Multiboot ***/ 872 873/* Create the multiboot header, using only *physical* addresses. */ 874void * 875create_multiboot_info(struct menu_lst *menu, struct loaded_module *modules, 876 size_t *mb_size, paddr_t *mb_base) { 877 size_t size; 878 879 /* Calculate the size of the multiboot info header, not including the 880 * module ELF images themselves, but including the MMAP, and the 881 * command-line strings. */ 882 size= sizeof(struct multiboot_info); 883 884 /* Include NULL terminator, and separating space. */ 885 size+= strlen(menu->kernel.path) + strlen(menu->kernel.args) + 2; 886 887 /* Module headers and command-line strings. */ 888 size+= menu->nmodules * sizeof(struct multiboot_modinfo); 889 for(size_t i= 0; i < menu->nmodules; i++) { 890 size+= strlen(menu->modules[i].path) + 891 strlen(menu->modules[i].args) + 2; 892 } 893 894 /* Memory map. */ 895 size+= menu->mmap_len * sizeof(struct multiboot_mmap); 896 897 /* Allocate target addresses. */ 898 paddr_t base= phys_alloc(size, BASE_PAGE_SIZE); 899 printf("Allocated %luB at PA %08x for multiboot\n", size, base); 900 *mb_size= size; 901 *mb_base= base; 902 903 /* Allocate our host buffer. */ 904 void *mb= calloc(size, 1); 905 if(!mb) fail_errno("calloc"); 906 907 /* Lay the multiboot info out as follows: 908 --------------------------- 909 struct multiboot_info; 910 --------------------------- 911 struct multiboot_mmap[]; 912 --------------------------- 913 struct multiboot_modinfo[]; 914 --------------------------- 915 char strings[]; 916 --------------------------- 917 */ 918 struct multiboot_info *mbi= mb; 919 920 paddr_t mmap_base= base + sizeof(struct multiboot_info); 921 struct multiboot_mmap *mmap= mb + sizeof(struct multiboot_info); 922 923 paddr_t modinfo_base= mmap_base + 924 menu->mmap_len * sizeof(struct multiboot_mmap); 925 struct multiboot_modinfo *modinfo= (void *)mmap + 926 menu->mmap_len * sizeof(struct multiboot_mmap); 927 928 paddr_t strings_base= modinfo_base + 929 menu->nmodules * sizeof(struct multiboot_modinfo); 930 char *strings= (void *)modinfo + 931 menu->nmodules * sizeof(struct multiboot_modinfo); 932 size_t strings_idx= 0; 933 934 /* Fill in the info header */ 935 mbi->flags= MULTIBOOT_INFO_FLAG_HAS_CMDLINE 936 | MULTIBOOT_INFO_FLAG_HAS_MODS 937 | MULTIBOOT_INFO_FLAG_HAS_MMAP; 938 939 /* Concatenate the path and arguments, separated by a space. */ 940 mbi->cmdline= strings_base + strings_idx; 941 strcpy(strings + strings_idx, menu->kernel.path); 942 strings_idx+= strlen(menu->kernel.path); 943 strings[strings_idx]= ' '; 944 strings_idx+= 1; 945 strcpy(strings + strings_idx, menu->kernel.args); 946 strings_idx+= strlen(menu->kernel.args) + 1; 947 948 mbi->mods_count= menu->nmodules; 949 mbi->mods_addr= modinfo_base; 950 951 mbi->mmap_length= menu->mmap_len; 952 mbi->mmap_addr= mmap_base; 953 954 /* Add the MMAP entries. */ 955 for(size_t i= 0; i < menu->mmap_len; i++) { 956 mmap[i].size= sizeof(struct multiboot_mmap); 957 mmap[i].base_addr= menu->mmap[i].base; 958 mmap[i].length= menu->mmap[i].length; 959 mmap[i].type= menu->mmap[i].type; 960 } 961 962 /* Add the modinfo headers. */ 963 for(size_t i= 0; i < menu->nmodules; i++) { 964 modinfo[i].mod_start= modules[i].paddr; 965 modinfo[i].mod_end= 966 modules[i].paddr + modules[i].len; 967 968 modinfo[i].string= strings_base + strings_idx; 969 strcpy(strings + strings_idx, menu->modules[i].path); 970 strings_idx+= strlen(menu->modules[i].path); 971 strings[strings_idx]= ' '; 972 strings_idx+= 1; 973 strcpy(strings + strings_idx, menu->modules[i].args); 974 strings_idx+= strlen(menu->modules[i].args) + 1; 975 } 976 977 return mb; 978} 979 980/*** Main ***/ 981 982void 983usage(const char *name) { 984 fail("Usage: %s <menu.lst> <boot driver> <output filename>\n" 985 " <build directory> <physical base address>\n", 986 name); 987} 988 989/* Find the first (lowest base address) RAM region. */ 990static struct menu_mmap_entry * 991first_ram_region(struct menu_lst *menu) { 992 struct menu_mmap_entry *first= NULL; 993 uint64_t lowest_base= UINT64_MAX; 994 995 for(uint32_t i= 0; i < menu->mmap_len; i++) { 996 struct menu_mmap_entry *e= &menu->mmap[i]; 997 998 if(e->type == MULTIBOOT_MEM_TYPE_RAM && e->base < lowest_base) { 999 lowest_base= e->base; 1000 first= e; 1001 } 1002 } 1003 1004 return first; 1005} 1006 1007int 1008main(int argc, char **argv) { 1009 char pathbuf[PATH_MAX+1]; 1010 1011 if(argc != 6) usage(argv[0]); 1012 1013 const char *menu_lst= argv[1], 1014 *bootdriver= argv[2], 1015 *outfile= argv[3], 1016 *buildroot= argv[4]; 1017 1018 errno= 0; 1019 paddr_t phys_base= strtoul(argv[5], NULL, 0); 1020 if(errno) fail_errno("strtoul"); 1021 1022 printf("ARM Static Bootloader\n"); 1023 1024 /* Read the menu.lst file. */ 1025 printf("Reading boot configuration from %s\n", menu_lst); 1026 struct menu_lst *menu= read_menu_lst(menu_lst); 1027 1028 /* Check that the requested base address is inside the first RAM region. */ 1029 struct menu_mmap_entry *ram_region= first_ram_region(menu); 1030 if(!ram_region) fail("No RAM regions defined.\n"); 1031 if(ram_region->base > (uint64_t)UINT32_MAX) 1032 fail("This seems to be a 64-bit memory map.\n"); 1033 if(phys_base < ram_region->base || 1034 phys_base >= ram_region->base + ram_region->length) { 1035 fail("Requested base address %08x is outside the first RAM region.\n", 1036 phys_base); 1037 } 1038 paddr_t ram_start= (paddr_t)ram_region->base; 1039 uint32_t kernel_offset= KERNEL_WINDOW - ram_start; 1040 1041 /* Begin allocation at the requested start address. */ 1042 phys_alloc_start= phys_base; 1043 printf("Beginning allocation at PA %08x (VA %08x)\n", 1044 phys_base, phys_base + kernel_offset); 1045 1046 if(elf_version(EV_CURRENT) == EV_NONE) 1047 fail("ELF library version out of date.\n"); 1048 1049 /*** Load the boot driver. ***/ 1050 1051 /* Open the boot driver ELF. */ 1052 printf("Loading %s\n", bootdriver); 1053 int bd_fd= open(bootdriver, O_RDONLY); 1054 if(bd_fd < 0) fail_errno("open"); 1055 1056 /* Load and relocate it. */ 1057 struct loaded_image bd_image; 1058 bd_image.extrasym_name= "boot_arguments"; 1059 void *bd_loaded= 1060 load(bd_fd, 0, /* The boot driver executes in physical space. */ 1061 &bd_image, 1062 1); /* Copy section and symbol data. */ 1063 assert(bd_loaded != NULL); 1064 1065 printf("Boot driver entry point: PA %08x\n", 1066 (paddr_t)bd_image.relocated_entry); 1067 1068 /* Close the ELF. */ 1069 if(close(bd_fd) < 0) fail_errno("close"); 1070 1071 /*** Load the CPU driver. ***/ 1072 1073 /* Open the kernel ELF. */ 1074 join_paths(pathbuf, buildroot, menu->kernel.path); 1075 1076 printf("Loading %s\n", pathbuf); 1077 int cpu_fd= open(pathbuf, O_RDONLY); 1078 if(cpu_fd < 0) fail_errno("open"); 1079 1080 /* Load and relocate it. */ 1081 struct loaded_image cpu_image; 1082 cpu_image.extrasym_name= NULL; 1083 void *cpu_loaded= 1084 load(cpu_fd, kernel_offset, &cpu_image, 0); 1085 assert(cpu_loaded != NULL); 1086 1087 printf("CPU driver entry point: VA %08x\n", cpu_image.relocated_entry); 1088 1089 /* Close the ELF. */ 1090 if(close(cpu_fd) < 0) fail_errno("close"); 1091 1092 /*** Load the modules. ***/ 1093 1094 struct loaded_module *modules= 1095 calloc(menu->nmodules, sizeof(struct loaded_module)); 1096 if(!modules) fail_errno("calloc"); 1097 1098 for(size_t i= 0; i < menu->nmodules; i++) { 1099 join_paths(pathbuf, buildroot, menu->modules[i].path); 1100 raw_load(pathbuf, &modules[i]); 1101 1102 /* Use the filename as a short identifier. */ 1103 const char *lastslash= strrchr(menu->modules[i].path, '/'); 1104 if(lastslash) modules[i].shortname= lastslash + 1; 1105 else modules[i].shortname= ""; 1106 } 1107 1108 /*** Create the multiboot info header. ***/ 1109 size_t mb_size; 1110 paddr_t mb_base; 1111 void *mb_image= create_multiboot_info(menu, modules, &mb_size, &mb_base); 1112 1113 /* Set the 'static_multiboot' pointer to the kernel virtual address of the 1114 * multiboot image. Pass the CPU driver entry point. */ 1115 *(kvaddr_t *)(bd_image.extrasym_ptr + 0)= 1116 mb_base + kernel_offset; 1117 *(kvaddr_t *)(bd_image.extrasym_ptr + 4)= 1118 cpu_image.relocated_entry; /* Already virtual. */ 1119 *(kvaddr_t *)(bd_image.extrasym_ptr + 8)= 1120 cpu_image.loaded_vaddr; /* Already virtual. */ 1121 1122 /*** Write the output file. ***/ 1123 1124 init_strings(); 1125 1126 /* Open the output image file. */ 1127 printf("Writing to %s\n", outfile); 1128 int out_fd= open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 1129 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | 1130 S_IROTH | S_IWOTH); 1131 if(out_fd < 0) fail_errno("open"); 1132 1133 /* Create the output ELF file. */ 1134 Elf *out_elf= elf_begin(out_fd, ELF_C_WRITE, NULL); 1135 if(!out_elf) fail_elf("elf_begin"); 1136 1137 /* We need to lay our sections out explicitly. */ 1138 if(!elf_flagelf(out_elf, ELF_C_SET, ELF_F_LAYOUT)) fail_elf("elf_flagelf"); 1139 1140 /* Create the ELF header. */ 1141 Elf32_Ehdr *out_ehdr= elf32_newehdr(out_elf); 1142 if(!out_ehdr) fail_elf("elf32_newehdr"); 1143 1144 /* Little-endian ARM executable. */ 1145 out_ehdr->e_ident[EI_DATA]= ELFDATA2LSB; 1146 out_ehdr->e_type= ET_EXEC; 1147 out_ehdr->e_machine= EM_ARM; 1148 out_ehdr->e_entry= bd_image.relocated_entry; 1149 /* Program headers after the executable header. */ 1150 increase_elf_offset(sizeof(Elf32_Ehdr)); 1151 out_ehdr->e_phoff= get_elf_offset(); 1152 1153 /* Create a single program header (segment) to cover everything that we 1154 * need to load. */ 1155 Elf32_Phdr *out_phdr= elf32_newphdr(out_elf, 1); 1156 if(!out_phdr) fail_elf("elf32_newphdr"); 1157 increase_elf_offset(sizeof(Elf32_Phdr)); 1158 1159 /* Advance to an aligned address to make section alignment easier. */ 1160 advance_elf_offset(0); 1161 1162 /* The boot driver, CPU driver and multiboot image all get their own 1163 * sections. */ 1164 size_t loadable_segment_offset= get_elf_offset(); 1165 Elf32_Shdr *fst_shdr= add_image_with_sections(out_elf, &bd_image); 1166 assert(fst_shdr != NULL); 1167 advance_elf_offset(cpu_image.loaded_paddr - phys_base); 1168 Elf32_Shdr *cpu_shdr= add_image(out_elf, ".cpudriver", &cpu_image); 1169 assert(cpu_shdr != NULL); 1170 for(size_t i= 0; i < menu->nmodules; i++) { 1171 char name[32]; 1172 snprintf(name, 32, ".elf.%s", modules[i].shortname); 1173 advance_elf_offset(modules[i].paddr - phys_base); 1174 add_blob(out_elf, name, modules[i].data, modules[i].len, 1175 modules[i].paddr); 1176 } 1177 advance_elf_offset(mb_base - phys_base); 1178 add_blob(out_elf, ".multiboot", mb_image, mb_size, mb_base); 1179 size_t end_of_segment= get_elf_offset(); 1180 1181 /* Add the boot driver's string and symbol tables. */ 1182 add_tables(out_elf, &bd_image); 1183 1184 /* Add the string table. This must be the last section added, as it 1185 * contains the names of all other sections. */ 1186 add_strings(out_elf); 1187 1188 /* Elf32_Shdr must be aligned to 4 bytes. */ 1189 align_elf_offset(4); 1190 1191 /* Place the section headers. */ 1192 out_ehdr->e_shoff= get_elf_offset(); 1193 1194 size_t total_size= end_of_segment - loadable_segment_offset; 1195 if(total_size > ram_region->length) 1196 fail("Overflowed the first RAM region.\n"); 1197 1198 out_phdr->p_type= PT_LOAD; 1199 out_phdr->p_offset= loadable_segment_offset; 1200 out_phdr->p_vaddr= phys_base; /* Load at physical address. */ 1201 out_phdr->p_paddr= phys_base; /* Actually ignored. */ 1202 /* This is dodgy, but GEM5 refuses to load an image that doesn't have a 1203 * BSS, and hence a larger memsz then filesz. Purely a hack, and luckily 1204 * doesn't seem to affect non-dodgy simulators. */ 1205 out_phdr->p_memsz= round_up(total_size + 1, BASE_PAGE_SIZE); 1206 out_phdr->p_filesz= total_size; 1207 out_phdr->p_align= 1; 1208 out_phdr->p_flags= PF_X | PF_W | PF_R; 1209 1210 elf_flagphdr(out_elf, ELF_C_SET, ELF_F_DIRTY); 1211 1212 /* Write the file. */ 1213 if(elf_update(out_elf, ELF_C_WRITE) < 0) fail_elf("elf_update"); 1214 1215 if(elf_end(out_elf) < 0) fail_elf("elf_update"); 1216 if(close(out_fd) < 0) fail_errno("close"); 1217 1218 return EXIT_SUCCESS; 1219} 1220