1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (c) 2014 Joyent, Inc. All rights reserved. 14 * Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> 15 */ 16 17 #include "fakeloader.h" 18 19 #include <sys/types.h> 20 #include <sys/param.h> 21 #include <sys/elf.h> 22 #include <sys/atag.h> 23 #include <sys/sysmacros.h> 24 #include <sys/machparam.h> 25 26 #include <vm/pte.h> 27 28 /* 29 * This is the stock ARM fake uniboot loader. 30 * 31 * Here's what we have to do: 32 * o Read the atag header and find the combined archive header 33 * o Determine the set of mappings we need to add for the following: 34 * - unix 35 * - boot_archive 36 * - atags 37 * o Enable unaligned access 38 * o Enable virtual memory 39 * 40 * There are several important constraints that we have here: 41 * 42 * o We cannot use any .data! Several loaders that come before us are broken 43 * and only provide us with the ability to map our .text and potentially our 44 * .bss. We should strive to avoid even that if we can. 45 */ 46 47 #ifdef DEBUG 48 #define FAKELOAD_DPRINTF(x) fakeload_puts(x) 49 #else 50 #define FAKELOAD_DPRINTF(x) 51 #endif /* DEBUG */ 52 53 /* 54 * XXX ASSUMES WE HAVE Free memory following the boot archive 55 */ 56 static uintptr_t freemem; 57 static uintptr_t pt_arena; 58 static uintptr_t pt_arena_max; 59 static uint32_t *pt_addr; 60 static int nl2pages; 61 62 /* Simple copy routines */ 63 void 64 bcopy(const void *s, void *d, size_t n) 65 { 66 const char *src = s; 67 char *dest = d; 68 69 if (n == 0 || s == d) 70 return; 71 72 if (dest < src && dest + n < src) { 73 /* dest overlaps with the start of src, copy forward */ 74 for (; n > 0; n--, src++, dest++) 75 *dest = *src; 76 } else { 77 /* src overlaps with start of dest or no overlap, copy rev */ 78 src += n - 1; 79 dest += n - 1; 80 for (; n > 0; n--, src--, dest--) 81 *dest = *src; 82 } 83 } 84 85 void 86 bzero(void *s, size_t n) 87 { 88 char *c = s; 89 while (n > 0) { 90 *c = 0; 91 c++; 92 n--; 93 } 94 } 95 96 static void 97 fakeload_puts(const char *str) 98 { 99 while (*str != '\0') { 100 fakeload_backend_putc(*str); 101 str++; 102 } 103 } 104 105 static void 106 fakeload_panic(const char *reason) 107 { 108 fakeload_puts("panic!\n"); 109 fakeload_puts(reason); 110 fakeload_puts("\n"); 111 fakeload_puts("spinning forever... goodbye...\n"); 112 for (;;) 113 ; 114 } 115 116 static void 117 fakeload_ultostr(unsigned long value) 118 { 119 char buf[16]; 120 ulong_t t, val = (ulong_t)value; 121 char c; 122 char *ptr = &(buf[14]); 123 buf[15] = '\0'; 124 125 do { 126 c = (char)('0' + val - 16 * (t = (val >> 4))); 127 if (c > '9') 128 c += 'A' - '9' - 1; 129 *--ptr = c; 130 } while ((val = t) != 0); 131 132 *--ptr = 'x'; 133 *--ptr = '0'; 134 fakeload_puts(ptr); 135 } 136 137 static void 138 fakeload_selfmap(atag_header_t *chain) 139 { 140 atag_illumos_mapping_t aim; 141 142 aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE; 143 aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING; 144 aim.aim_paddr = 0x7000; 145 aim.aim_vaddr = aim.aim_paddr; 146 aim.aim_plen = 0x3000; 147 aim.aim_vlen = aim.aim_plen; 148 aim.aim_mapflags = PF_R | PF_X | PF_LOADER; 149 atag_append(chain, &aim.aim_header); 150 } 151 152 static void 153 fakeload_map_1mb(uintptr_t pa, uintptr_t va, int prot) 154 { 155 int entry; 156 armpte_t *pte; 157 arm_l1s_t *l1e; 158 159 entry = ARMPT_VADDR_TO_L1E(va); 160 pte = &pt_addr[entry]; 161 if (ARMPT_L1E_ISVALID(*pte)) 162 fakeload_panic("armboot_mmu: asked to map a mapped region!\n"); 163 l1e = (arm_l1s_t *)pte; 164 *pte = 0; 165 l1e->al_type = ARMPT_L1_TYPE_SECT; 166 /* Assume it's not device memory */ 167 l1e->al_bbit = 1; 168 l1e->al_cbit = 1; 169 l1e->al_tex = 1; 170 l1e->al_sbit = 1; 171 172 if (!(prot & PF_X)) 173 l1e->al_xn = 1; 174 l1e->al_domain = 0; 175 176 if (prot & PF_W) { 177 l1e->al_ap2 = 1; 178 l1e->al_ap = 1; 179 } else { 180 l1e->al_ap2 = 0; 181 l1e->al_ap = 1; 182 } 183 l1e->al_ngbit = 0; 184 l1e->al_issuper = 0; 185 l1e->al_addr = ARMPT_PADDR_TO_L1SECT(pa); 186 } 187 188 /* 189 * Set freemem to be 1 MB aligned at the end of boot archive. While the L1 Page 190 * table only needs to be 16 KB aligned, we opt for 1 MB alignment so that way 191 * we can map it and all the other L2 page tables we might need. If we don't do 192 * this, it'll become problematic for unix to actually modify this. 193 */ 194 static void 195 fakeload_pt_arena_init(const atag_initrd_t *aii) 196 { 197 int entry, i; 198 armpte_t *pte; 199 arm_l1s_t *l1e; 200 201 pt_arena = aii->ai_start + aii->ai_size; 202 if (pt_arena & MMU_PAGEOFFSET1M) { 203 pt_arena &= MMU_PAGEMASK1M; 204 pt_arena += MMU_PAGESIZE1M; 205 } 206 pt_arena_max = pt_arena + 4 * MMU_PAGESIZE1M; 207 freemem = pt_arena_max; 208 209 /* Set up the l1 page table by first invalidating it */ 210 pt_addr = (armpte_t *)pt_arena; 211 pt_arena += ARMPT_L1_SIZE; 212 bzero(pt_addr, ARMPT_L1_SIZE); 213 for (i = 0; i < 4; i++) 214 fakeload_map_1mb((uintptr_t)pt_addr + i * MMU_PAGESIZE1M, 215 (uintptr_t)pt_addr + i * MMU_PAGESIZE1M, 216 PF_R | PF_W); 217 } 218 219 /* 220 * This is our generally entry point. We're passed in the entry point of the 221 * header. 222 */ 223 static uintptr_t 224 fakeload_archive_mappings(atag_header_t *chain, const void *addr, 225 atag_illumos_status_t *aisp) 226 { 227 atag_illumos_mapping_t aim; 228 fakeloader_hdr_t *hdr; 229 Elf32_Ehdr *ehdr; 230 Elf32_Phdr *phdr; 231 int nhdrs, i; 232 uintptr_t ret; 233 uintptr_t text = 0, data = 0; 234 size_t textln = 0, dataln = 0; 235 236 hdr = (fakeloader_hdr_t *)addr; 237 238 if (hdr->fh_magic[0] != FH_MAGIC0) 239 fakeload_panic("fh_magic[0] is wrong!\n"); 240 if (hdr->fh_magic[1] != FH_MAGIC1) 241 fakeload_panic("fh_magic[1] is wrong!\n"); 242 if (hdr->fh_magic[2] != FH_MAGIC2) 243 fakeload_panic("fh_magic[2] is wrong!\n"); 244 if (hdr->fh_magic[3] != FH_MAGIC3) 245 fakeload_panic("fh_magic[3] is wrong!\n"); 246 247 if (hdr->fh_unix_size == 0) 248 fakeload_panic("hdr unix size is zero\n"); 249 if (hdr->fh_unix_offset == 0) 250 fakeload_panic("hdr unix offset is zero\n"); 251 if (hdr->fh_archive_size == 0) 252 fakeload_panic("hdr archive size is zero\n"); 253 if (hdr->fh_archive_offset == 0) 254 fakeload_panic("hdr archive_offset is zero\n"); 255 256 ehdr = (Elf32_Ehdr *)((uintptr_t)addr + hdr->fh_unix_offset); 257 258 if (ehdr->e_ident[EI_MAG0] != ELFMAG0) 259 fakeload_panic("magic[0] wrong"); 260 if (ehdr->e_ident[EI_MAG1] != ELFMAG1) 261 fakeload_panic("magic[1] wrong"); 262 if (ehdr->e_ident[EI_MAG2] != ELFMAG2) 263 fakeload_panic("magic[2] wrong"); 264 if (ehdr->e_ident[EI_MAG3] != ELFMAG3) 265 fakeload_panic("magic[3] wrong"); 266 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) 267 fakeload_panic("wrong elfclass"); 268 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) 269 fakeload_panic("wrong encoding"); 270 if (ehdr->e_ident[EI_OSABI] != ELFOSABI_SOLARIS) 271 fakeload_panic("wrong os abi"); 272 if (ehdr->e_ident[EI_ABIVERSION] != EAV_SUNW_CURRENT) 273 fakeload_panic("wrong abi version"); 274 if (ehdr->e_type != ET_EXEC) 275 fakeload_panic("unix is not an executable"); 276 if (ehdr->e_machine != EM_ARM) 277 fakeload_panic("unix is not an ARM Executible"); 278 if (ehdr->e_version != EV_CURRENT) 279 fakeload_panic("wrong version"); 280 if (ehdr->e_phnum == 0) 281 fakeload_panic("no program headers"); 282 ret = ehdr->e_entry; 283 284 FAKELOAD_DPRINTF("validated unix's headers\n"); 285 286 nhdrs = ehdr->e_phnum; 287 phdr = (Elf32_Phdr *)((uintptr_t)addr + hdr->fh_unix_offset + 288 ehdr->e_phoff); 289 for (i = 0; i < nhdrs; i++, phdr++) { 290 if (phdr->p_type != PT_LOAD) { 291 fakeload_puts("skipping non-PT_LOAD header\n"); 292 continue; 293 } 294 295 if (phdr->p_filesz == 0 || phdr->p_memsz == 0) { 296 fakeload_puts("skipping PT_LOAD with 0 file/mem\n"); 297 continue; 298 } 299 300 /* 301 * Create a mapping record for this in the atags. 302 */ 303 aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE; 304 aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING; 305 aim.aim_paddr = (uintptr_t)addr + hdr->fh_unix_offset + 306 phdr->p_offset; 307 aim.aim_plen = phdr->p_filesz; 308 aim.aim_vaddr = phdr->p_vaddr; 309 aim.aim_vlen = phdr->p_memsz; 310 /* Round up vlen to be a multiple of 4k */ 311 if (aim.aim_vlen & 0xfff) { 312 aim.aim_vlen &= ~0xfff; 313 aim.aim_vlen += 0x1000; 314 } 315 aim.aim_mapflags = phdr->p_flags; 316 atag_append(chain, &aim.aim_header); 317 318 /* 319 * When built with highvecs we need to account for the fact that 320 * _edata, _etext and _end are built assuming that the highvecs 321 * are normally part of our segments. ld is not doing anything 322 * wrong, but this breaks the assumptions that krtld currently 323 * has. As such, unix will use this information to overwrite the 324 * normal entry points that krtld uses in a similar style to 325 * SPARC. 326 */ 327 if (aim.aim_vaddr != 0xffff0000) { 328 if ((phdr->p_flags & PF_W) != 0) { 329 data = aim.aim_vaddr; 330 dataln = aim.aim_vlen; 331 } else { 332 text = aim.aim_vaddr; 333 textln = aim.aim_vlen; 334 } 335 } 336 } 337 338 aisp->ais_stext = text; 339 aisp->ais_etext = text + textln; 340 aisp->ais_sdata = data; 341 aisp->ais_edata = data + dataln; 342 343 /* 1:1 map the boot archive */ 344 aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE; 345 aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING; 346 aim.aim_paddr = (uintptr_t)addr + hdr->fh_archive_offset; 347 aim.aim_plen = hdr->fh_archive_size; 348 aim.aim_vaddr = aim.aim_paddr; 349 aim.aim_vlen = aim.aim_plen; 350 aim.aim_mapflags = PF_R | PF_W | PF_X; 351 atag_append(chain, &aim.aim_header); 352 aisp->ais_archive = aim.aim_paddr; 353 aisp->ais_archivelen = aim.aim_plen; 354 355 return (ret); 356 } 357 358 static void 359 fakeload_mkatags(atag_header_t *chain) 360 { 361 atag_illumos_status_t ais; 362 atag_illumos_mapping_t aim; 363 364 bzero(&ais, sizeof (ais)); 365 bzero(&aim, sizeof (aim)); 366 367 ais.ais_header.ah_size = ATAG_ILLUMOS_STATUS_SIZE; 368 ais.ais_header.ah_tag = ATAG_ILLUMOS_STATUS; 369 atag_append(chain, &ais.ais_header); 370 aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE; 371 aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING; 372 atag_append(chain, &aim.aim_header); 373 } 374 375 static uintptr_t 376 fakeload_alloc_l2pt(void) 377 { 378 uintptr_t ret; 379 380 if (pt_arena & ARMPT_L2_MASK) { 381 ret = pt_arena; 382 ret &= ~ARMPT_L2_MASK; 383 ret += ARMPT_L2_SIZE; 384 pt_arena = ret + ARMPT_L2_SIZE; 385 } else { 386 ret = pt_arena; 387 pt_arena = ret + ARMPT_L2_SIZE; 388 } 389 if (pt_arena >= pt_arena_max) { 390 fakeload_puts("pt_arena, max\n"); 391 fakeload_ultostr(pt_arena); 392 fakeload_puts("\n"); 393 fakeload_ultostr(pt_arena_max); 394 fakeload_puts("\n"); 395 fakeload_puts("l2pts alloced\n"); 396 fakeload_ultostr(nl2pages); 397 fakeload_puts("\n"); 398 fakeload_panic("ran out of page tables!"); 399 } 400 401 bzero((void *)ret, ARMPT_L2_SIZE); 402 nl2pages++; 403 return (ret); 404 } 405 406 /* 407 * Finally, do all the dirty work. Let's create some page tables. The L1 page 408 * table is full of 1 MB mappings by default. The L2 Page table is 1k in size 409 * and covers that 1 MB. We're going to always create L2 page tables for now 410 * which will use 4k and 64k pages. 411 */ 412 static void 413 fakeload_map(armpte_t *pt, uintptr_t pstart, uintptr_t vstart, size_t len, 414 uint32_t prot) 415 { 416 int entry, chunksize; 417 armpte_t *pte, *l2pt; 418 arm_l1pt_t *l1pt; 419 420 /* 421 * Make sure both pstart + vstart are 4k aligned, along with len. 422 */ 423 if (pstart & MMU_PAGEOFFSET) 424 fakeload_panic("pstart is not 4k aligned"); 425 if (vstart & MMU_PAGEOFFSET) 426 fakeload_panic("vstart is not 4k aligned"); 427 if (len & MMU_PAGEOFFSET) 428 fakeload_panic("len is not 4k aligned"); 429 430 /* 431 * We're going to logically deal with each 1 MB chunk at a time. 432 */ 433 while (len > 0) { 434 if (vstart & MMU_PAGEOFFSET1M) { 435 chunksize = MIN(len, MMU_PAGESIZE1M - 436 (vstart & MMU_PAGEOFFSET1M)); 437 } else { 438 chunksize = MIN(len, MMU_PAGESIZE1M); 439 } 440 441 entry = ARMPT_VADDR_TO_L1E(vstart); 442 pte = &pt[entry]; 443 444 if (!ARMPT_L1E_ISVALID(*pte)) { 445 uintptr_t l2table; 446 447 if (!(vstart & MMU_PAGEOFFSET1M) && 448 !(pstart & MMU_PAGEOFFSET1M) && 449 len == MMU_PAGESIZE1M) { 450 fakeload_map_1mb(pstart, vstart, prot); 451 vstart += MMU_PAGESIZE1M; 452 pstart += MMU_PAGESIZE1M; 453 len -= MMU_PAGESIZE1M; 454 continue; 455 } 456 457 l2table = fakeload_alloc_l2pt(); 458 *pte = 0; 459 l1pt = (arm_l1pt_t *)pte; 460 l1pt->al_type = ARMPT_L1_TYPE_L2PT; 461 l1pt->al_ptaddr = ARMPT_ADDR_TO_L1PTADDR(l2table); 462 } else if ((*pte & ARMPT_L1_TYPE_MASK) != ARMPT_L1_TYPE_L2PT) { 463 fakeload_panic("encountered l1 entry that's not a " 464 "pointer to a level 2 table\n"); 465 } else { 466 l1pt = (arm_l1pt_t *)pte; 467 } 468 469 /* Now that we have the l1pt fill in l2 entries */ 470 l2pt = (void *)(l1pt->al_ptaddr << ARMPT_L1PT_TO_L2_SHIFT); 471 len -= chunksize; 472 while (chunksize > 0) { 473 arm_l2e_t *l2pte; 474 475 entry = ARMPT_VADDR_TO_L2E(vstart); 476 pte = &l2pt[entry]; 477 478 #ifdef MAP_DEBUG 479 fakeload_puts("4k page pa->va, l2root, entry\n"); 480 fakeload_ultostr(pstart); 481 fakeload_puts("->"); 482 fakeload_ultostr(vstart); 483 fakeload_puts(", "); 484 fakeload_ultostr((uintptr_t)l2pt); 485 fakeload_puts(", "); 486 fakeload_ultostr(entry); 487 fakeload_puts("\n"); 488 #endif 489 490 if ((*pte & ARMPT_L2_TYPE_MASK) != 491 ARMPT_L2_TYPE_INVALID) 492 fakeload_panic("found existing l2 page table, " 493 "overlap in requested mappings detected!"); 494 /* Map vaddr to our paddr! */ 495 l2pte = ((arm_l2e_t *)pte); 496 *pte = 0; 497 if (!(prot & PF_X)) 498 l2pte->ale_xn = 1; 499 l2pte->ale_ident = 1; 500 if (prot & PF_DEVICE) { 501 l2pte->ale_bbit = 1; 502 l2pte->ale_cbit = 0; 503 l2pte->ale_tex = 0; 504 l2pte->ale_sbit = 1; 505 } else { 506 l2pte->ale_bbit = 1; 507 l2pte->ale_cbit = 1; 508 l2pte->ale_tex = 1; 509 l2pte->ale_sbit = 1; 510 } 511 if (prot & PF_W) { 512 l2pte->ale_ap2 = 1; 513 l2pte->ale_ap = 1; 514 } else { 515 l2pte->ale_ap2 = 0; 516 l2pte->ale_ap = 1; 517 } 518 l2pte->ale_ngbit = 0; 519 l2pte->ale_addr = ARMPT_PADDR_TO_L2ADDR(pstart); 520 521 chunksize -= MMU_PAGESIZE; 522 vstart += MMU_PAGESIZE; 523 pstart += MMU_PAGESIZE; 524 } 525 } 526 } 527 528 static void 529 fakeload_create_map(armpte_t *pt, atag_illumos_mapping_t *aimp) 530 { 531 #ifdef MAP_DEBUG 532 fakeload_puts("paddr->vaddr\n"); 533 fakeload_ultostr(aimp->aim_paddr); 534 fakeload_puts("->"); 535 fakeload_ultostr(aimp->aim_vaddr); 536 fakeload_puts("\n"); 537 fakeload_puts("plen-vlen\n"); 538 fakeload_ultostr(aimp->aim_plen); 539 fakeload_puts("-"); 540 fakeload_ultostr(aimp->aim_vlen); 541 fakeload_puts("\n"); 542 #endif /* MAP_DEBUG */ 543 544 /* 545 * Can we map this in place or do we need to basically allocate a new 546 * region and bcopy everything into place for proper alignment? 547 * 548 * Criteria for this: we have a vlen > plen. plen is not page aligned. 549 */ 550 if (aimp->aim_vlen > aimp->aim_plen || 551 (aimp->aim_paddr & MMU_PAGEOFFSET) != 0) { 552 uintptr_t start; 553 554 if (aimp->aim_mapflags & PF_NORELOC) 555 fakeload_panic("tried to reloc unrelocatable mapping"); 556 #ifdef MAP_DEBUG 557 FAKELOAD_DPRINTF("reloacting paddr\n"); 558 #endif 559 start = freemem; 560 if (start & MMU_PAGEOFFSET) { 561 start &= MMU_PAGEMASK; 562 start += MMU_PAGESIZE; 563 } 564 bcopy((void *)aimp->aim_paddr, (void *)start, 565 aimp->aim_plen); 566 if (aimp->aim_vlen > aimp->aim_plen) { 567 bzero((void *)(start + aimp->aim_plen), 568 aimp->aim_vlen - aimp->aim_plen); 569 } 570 aimp->aim_paddr = start; 571 freemem = start + aimp->aim_vlen; 572 #ifdef MAP_DEBUG 573 fakeload_puts("new paddr: "); 574 fakeload_ultostr(start); 575 fakeload_puts("\n"); 576 #endif /* MAP_DEBUG */ 577 } 578 579 /* 580 * Now that everything has been set up, go ahead and map the new region. 581 */ 582 fakeload_map(pt, aimp->aim_paddr, aimp->aim_vaddr, aimp->aim_vlen, 583 aimp->aim_mapflags); 584 #ifdef MAP_DEBUG 585 FAKELOAD_DPRINTF("\n"); 586 #endif /* MAP_DEBUG */ 587 } 588 589 void 590 fakeload_init(void *ident, void *ident2, void *atag) 591 { 592 atag_header_t *hdr; 593 atag_header_t *chain = (atag_header_t *)atag; 594 const atag_initrd_t *initrd; 595 atag_illumos_status_t *aisp; 596 atag_illumos_mapping_t *aimp; 597 uintptr_t unix_start; 598 599 fakeload_backend_init(); 600 fakeload_puts("Hello from the loader\n"); 601 initrd = (atag_initrd_t *)atag_find(chain, ATAG_INITRD2); 602 if (initrd == NULL) 603 fakeload_panic("missing the initial ramdisk\n"); 604 605 /* 606 * Create the status atag header and the initial mapping record for the 607 * atags. We'll hold onto both of these. 608 */ 609 fakeload_mkatags(chain); 610 aisp = (atag_illumos_status_t *)atag_find(chain, ATAG_ILLUMOS_STATUS); 611 if (aisp == NULL) 612 fakeload_panic("can't find ATAG_ILLUMOS_STATUS"); 613 aimp = (atag_illumos_mapping_t *)atag_find(chain, ATAG_ILLUMOS_MAPPING); 614 if (aimp == NULL) 615 fakeload_panic("can't find ATAG_ILLUMOS_MAPPING"); 616 FAKELOAD_DPRINTF("created proto atags\n"); 617 618 fakeload_pt_arena_init(initrd); 619 620 fakeload_selfmap(chain); 621 622 /* 623 * Map the boot archive and all of unix 624 */ 625 unix_start = fakeload_archive_mappings(chain, 626 (const void *)(uintptr_t)initrd->ai_start, aisp); 627 FAKELOAD_DPRINTF("filled out unix and the archive's mappings\n"); 628 629 /* 630 * Fill in the atag mapping header for the atags themselves. 1:1 map it. 631 */ 632 aimp->aim_paddr = (uintptr_t)chain & ~0xfff; 633 aimp->aim_plen = atag_length(chain) & ~0xfff; 634 aimp->aim_plen += 0x1000; 635 aimp->aim_vaddr = aimp->aim_paddr; 636 aimp->aim_vlen = aimp->aim_plen; 637 aimp->aim_mapflags = PF_R | PF_W | PF_NORELOC; 638 639 /* 640 * Let the backend add mappings 641 */ 642 fakeload_backend_addmaps(chain); 643 644 /* 645 * Turn on unaligned access 646 */ 647 FAKELOAD_DPRINTF("turning on unaligned access\n"); 648 fakeload_unaligned_enable(); 649 FAKELOAD_DPRINTF("successfully enabled unaligned access\n"); 650 651 /* 652 * To turn on the MMU we need to do the following: 653 * o Program all relevant CP15 registers 654 * o Program 1st and 2nd level page tables 655 * o Invalidate and Disable the I/D-cache 656 * o Fill in the last bits of the ATAG_ILLUMOS_STATUS atag 657 * o Turn on the MMU in SCTLR 658 * o Jump to unix 659 */ 660 661 /* Last bits of the atag */ 662 aisp->ais_freemem = freemem; 663 aisp->ais_version = 1; 664 aisp->ais_ptbase = (uintptr_t)pt_addr; 665 666 /* 667 * Our initial page table is a series of 1 MB sections. While we really 668 * should map 4k pages, for the moment we're just going to map 1 MB 669 * regions, yay team! 670 */ 671 hdr = chain; 672 FAKELOAD_DPRINTF("creating mappings\n"); 673 while (hdr != NULL) { 674 if (hdr->ah_tag == ATAG_ILLUMOS_MAPPING) 675 fakeload_create_map(pt_addr, 676 (atag_illumos_mapping_t *)hdr); 677 hdr = atag_next(hdr); 678 } 679 680 /* 681 * Now that we've mapped everything, update the status atag. 682 */ 683 aisp->ais_freeused = freemem - aisp->ais_freemem; 684 aisp->ais_pt_arena = pt_arena; 685 aisp->ais_pt_arena_max = pt_arena_max; 686 687 /* Cache disable */ 688 FAKELOAD_DPRINTF("Flushing and disabling caches\n"); 689 armv6_dcache_flush(); 690 armv6_dcache_disable(); 691 armv6_dcache_inval(); 692 armv6_icache_disable(); 693 armv6_icache_inval(); 694 695 /* Program the page tables */ 696 FAKELOAD_DPRINTF("programming cp15 regs\n"); 697 fakeload_pt_setup((uintptr_t)pt_addr); 698 699 700 /* MMU Enable */ 701 FAKELOAD_DPRINTF("see you on the other side\n"); 702 fakeload_mmu_enable(); 703 704 FAKELOAD_DPRINTF("why helo thar\n"); 705 706 /* we should never come back */ 707 fakeload_exec(ident, ident2, chain, unix_start); 708 fakeload_panic("hit the end of the world\n"); 709 }