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 167 if (prot & PF_DEVICE) { 168 l1e->al_bbit = 1; 169 l1e->al_cbit = 0; 170 l1e->al_tex = 0; 171 l1e->al_sbit = 1; 172 } else { 173 l1e->al_bbit = 1; 174 l1e->al_cbit = 1; 175 l1e->al_tex = 1; 176 l1e->al_sbit = 1; 177 } 178 179 if (!(prot & PF_X)) 180 l1e->al_xn = 1; 181 l1e->al_domain = 0; 182 183 if (prot & PF_W) { 184 l1e->al_ap2 = 1; 185 l1e->al_ap = 1; 186 } else { 187 l1e->al_ap2 = 0; 188 l1e->al_ap = 1; 189 } 190 l1e->al_ngbit = 0; 191 l1e->al_issuper = 0; 192 l1e->al_addr = ARMPT_PADDR_TO_L1SECT(pa); 193 } 194 195 /* 196 * Set freemem to be 1 MB aligned at the end of boot archive. While the L1 Page 197 * table only needs to be 16 KB aligned, we opt for 1 MB alignment so that way 198 * we can map it and all the other L2 page tables we might need. If we don't do 199 * this, it'll become problematic for unix to actually modify this. 200 */ 201 static void 202 fakeload_pt_arena_init(const atag_initrd_t *aii) 203 { 204 int entry, i; 205 armpte_t *pte; 206 arm_l1s_t *l1e; 207 208 pt_arena = aii->ai_start + aii->ai_size; 209 if (pt_arena & MMU_PAGEOFFSET1M) { 210 pt_arena &= MMU_PAGEMASK1M; 211 pt_arena += MMU_PAGESIZE1M; 212 } 213 pt_arena_max = pt_arena + 4 * MMU_PAGESIZE1M; 214 freemem = pt_arena_max; 215 216 /* Set up the l1 page table by first invalidating it */ 217 pt_addr = (armpte_t *)pt_arena; 218 pt_arena += ARMPT_L1_SIZE; 219 bzero(pt_addr, ARMPT_L1_SIZE); 220 for (i = 0; i < 4; i++) 221 fakeload_map_1mb((uintptr_t)pt_addr + i * MMU_PAGESIZE1M, 222 (uintptr_t)pt_addr + i * MMU_PAGESIZE1M, 223 PF_R | PF_W); 224 } 225 226 /* 227 * This is our generally entry point. We're passed in the entry point of the 228 * header. 229 */ 230 static uintptr_t 231 fakeload_archive_mappings(atag_header_t *chain, const void *addr, 232 atag_illumos_status_t *aisp) 233 { 234 atag_illumos_mapping_t aim; 235 fakeloader_hdr_t *hdr; 236 Elf32_Ehdr *ehdr; 237 Elf32_Phdr *phdr; 238 int nhdrs, i; 239 uintptr_t ret; 240 uintptr_t text = 0, data = 0; 241 size_t textln = 0, dataln = 0; 242 243 hdr = (fakeloader_hdr_t *)addr; 244 245 if (hdr->fh_magic[0] != FH_MAGIC0) 246 fakeload_panic("fh_magic[0] is wrong!\n"); 247 if (hdr->fh_magic[1] != FH_MAGIC1) 248 fakeload_panic("fh_magic[1] is wrong!\n"); 249 if (hdr->fh_magic[2] != FH_MAGIC2) 250 fakeload_panic("fh_magic[2] is wrong!\n"); 251 if (hdr->fh_magic[3] != FH_MAGIC3) 252 fakeload_panic("fh_magic[3] is wrong!\n"); 253 254 if (hdr->fh_unix_size == 0) 255 fakeload_panic("hdr unix size is zero\n"); 256 if (hdr->fh_unix_offset == 0) 257 fakeload_panic("hdr unix offset is zero\n"); 258 if (hdr->fh_archive_size == 0) 259 fakeload_panic("hdr archive size is zero\n"); 260 if (hdr->fh_archive_offset == 0) 261 fakeload_panic("hdr archive_offset is zero\n"); 262 263 ehdr = (Elf32_Ehdr *)((uintptr_t)addr + hdr->fh_unix_offset); 264 265 if (ehdr->e_ident[EI_MAG0] != ELFMAG0) 266 fakeload_panic("magic[0] wrong"); 267 if (ehdr->e_ident[EI_MAG1] != ELFMAG1) 268 fakeload_panic("magic[1] wrong"); 269 if (ehdr->e_ident[EI_MAG2] != ELFMAG2) 270 fakeload_panic("magic[2] wrong"); 271 if (ehdr->e_ident[EI_MAG3] != ELFMAG3) 272 fakeload_panic("magic[3] wrong"); 273 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) 274 fakeload_panic("wrong elfclass"); 275 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) 276 fakeload_panic("wrong encoding"); 277 if (ehdr->e_ident[EI_OSABI] != ELFOSABI_SOLARIS) 278 fakeload_panic("wrong os abi"); 279 if (ehdr->e_ident[EI_ABIVERSION] != EAV_SUNW_CURRENT) 280 fakeload_panic("wrong abi version"); 281 if (ehdr->e_type != ET_EXEC) 282 fakeload_panic("unix is not an executable"); 283 if (ehdr->e_machine != EM_ARM) 284 fakeload_panic("unix is not an ARM Executible"); 285 if (ehdr->e_version != EV_CURRENT) 286 fakeload_panic("wrong version"); 287 if (ehdr->e_phnum == 0) 288 fakeload_panic("no program headers"); 289 ret = ehdr->e_entry; 290 291 FAKELOAD_DPRINTF("validated unix's headers\n"); 292 293 nhdrs = ehdr->e_phnum; 294 phdr = (Elf32_Phdr *)((uintptr_t)addr + hdr->fh_unix_offset + 295 ehdr->e_phoff); 296 for (i = 0; i < nhdrs; i++, phdr++) { 297 if (phdr->p_type != PT_LOAD) { 298 fakeload_puts("skipping non-PT_LOAD header\n"); 299 continue; 300 } 301 302 if (phdr->p_filesz == 0 || phdr->p_memsz == 0) { 303 fakeload_puts("skipping PT_LOAD with 0 file/mem\n"); 304 continue; 305 } 306 307 /* 308 * Create a mapping record for this in the atags. 309 */ 310 aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE; 311 aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING; 312 aim.aim_paddr = (uintptr_t)addr + hdr->fh_unix_offset + 313 phdr->p_offset; 314 aim.aim_plen = phdr->p_filesz; 315 aim.aim_vaddr = phdr->p_vaddr; 316 aim.aim_vlen = phdr->p_memsz; 317 /* Round up vlen to be a multiple of 4k */ 318 if (aim.aim_vlen & 0xfff) { 319 aim.aim_vlen &= ~0xfff; 320 aim.aim_vlen += 0x1000; 321 } 322 aim.aim_mapflags = phdr->p_flags; 323 atag_append(chain, &aim.aim_header); 324 325 /* 326 * When built with highvecs we need to account for the fact that 327 * _edata, _etext and _end are built assuming that the highvecs 328 * are normally part of our segments. ld is not doing anything 329 * wrong, but this breaks the assumptions that krtld currently 330 * has. As such, unix will use this information to overwrite the 331 * normal entry points that krtld uses in a similar style to 332 * SPARC. 333 */ 334 if (aim.aim_vaddr != 0xffff0000) { 335 if ((phdr->p_flags & PF_W) != 0) { 336 data = aim.aim_vaddr; 337 dataln = aim.aim_vlen; 338 } else { 339 text = aim.aim_vaddr; 340 textln = aim.aim_vlen; 341 } 342 } 343 } 344 345 aisp->ais_stext = text; 346 aisp->ais_etext = text + textln; 347 aisp->ais_sdata = data; 348 aisp->ais_edata = data + dataln; 349 350 /* 1:1 map the boot archive */ 351 aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE; 352 aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING; 353 aim.aim_paddr = (uintptr_t)addr + hdr->fh_archive_offset; 354 aim.aim_plen = hdr->fh_archive_size; 355 aim.aim_vaddr = aim.aim_paddr; 356 aim.aim_vlen = aim.aim_plen; 357 aim.aim_mapflags = PF_R | PF_W | PF_X; 358 atag_append(chain, &aim.aim_header); 359 aisp->ais_archive = aim.aim_paddr; 360 aisp->ais_archivelen = aim.aim_plen; 361 362 return (ret); 363 } 364 365 static void 366 fakeload_mkatags(atag_header_t *chain) 367 { 368 atag_illumos_status_t ais; 369 atag_illumos_mapping_t aim; 370 371 bzero(&ais, sizeof (ais)); 372 bzero(&aim, sizeof (aim)); 373 374 ais.ais_header.ah_size = ATAG_ILLUMOS_STATUS_SIZE; 375 ais.ais_header.ah_tag = ATAG_ILLUMOS_STATUS; 376 atag_append(chain, &ais.ais_header); 377 aim.aim_header.ah_size = ATAG_ILLUMOS_MAPPING_SIZE; 378 aim.aim_header.ah_tag = ATAG_ILLUMOS_MAPPING; 379 atag_append(chain, &aim.aim_header); 380 } 381 382 static uintptr_t 383 fakeload_alloc_l2pt(void) 384 { 385 uintptr_t ret; 386 387 if (pt_arena & ARMPT_L2_MASK) { 388 ret = pt_arena; 389 ret &= ~ARMPT_L2_MASK; 390 ret += ARMPT_L2_SIZE; 391 pt_arena = ret + ARMPT_L2_SIZE; 392 } else { 393 ret = pt_arena; 394 pt_arena = ret + ARMPT_L2_SIZE; 395 } 396 if (pt_arena >= pt_arena_max) { 397 fakeload_puts("pt_arena, max\n"); 398 fakeload_ultostr(pt_arena); 399 fakeload_puts("\n"); 400 fakeload_ultostr(pt_arena_max); 401 fakeload_puts("\n"); 402 fakeload_puts("l2pts alloced\n"); 403 fakeload_ultostr(nl2pages); 404 fakeload_puts("\n"); 405 fakeload_panic("ran out of page tables!"); 406 } 407 408 bzero((void *)ret, ARMPT_L2_SIZE); 409 nl2pages++; 410 return (ret); 411 } 412 413 /* 414 * Finally, do all the dirty work. Let's create some page tables. The L1 page 415 * table is full of 1 MB mappings by default. The L2 Page table is 1k in size 416 * and covers that 1 MB. We're going to always create L2 page tables for now 417 * which will use 4k and 64k pages. 418 */ 419 static void 420 fakeload_map(armpte_t *pt, uintptr_t pstart, uintptr_t vstart, size_t len, 421 uint32_t prot) 422 { 423 int entry, chunksize; 424 armpte_t *pte, *l2pt; 425 arm_l1pt_t *l1pt; 426 427 /* 428 * Make sure both pstart + vstart are 4k aligned, along with len. 429 */ 430 if (pstart & MMU_PAGEOFFSET) 431 fakeload_panic("pstart is not 4k aligned"); 432 if (vstart & MMU_PAGEOFFSET) 433 fakeload_panic("vstart is not 4k aligned"); 434 if (len & MMU_PAGEOFFSET) 435 fakeload_panic("len is not 4k aligned"); 436 437 /* 438 * We're going to logically deal with each 1 MB chunk at a time. 439 */ 440 while (len > 0) { 441 if (vstart & MMU_PAGEOFFSET1M) { 442 chunksize = MIN(len, MMU_PAGESIZE1M - 443 (vstart & MMU_PAGEOFFSET1M)); 444 } else { 445 chunksize = MIN(len, MMU_PAGESIZE1M); 446 } 447 448 entry = ARMPT_VADDR_TO_L1E(vstart); 449 pte = &pt[entry]; 450 451 if (!ARMPT_L1E_ISVALID(*pte)) { 452 uintptr_t l2table; 453 454 if (!(vstart & MMU_PAGEOFFSET1M) && 455 !(pstart & MMU_PAGEOFFSET1M) && 456 len >= MMU_PAGESIZE1M) { 457 fakeload_map_1mb(pstart, vstart, prot); 458 vstart += MMU_PAGESIZE1M; 459 pstart += MMU_PAGESIZE1M; 460 len -= MMU_PAGESIZE1M; 461 continue; 462 } 463 464 l2table = fakeload_alloc_l2pt(); 465 *pte = 0; 466 l1pt = (arm_l1pt_t *)pte; 467 l1pt->al_type = ARMPT_L1_TYPE_L2PT; 468 l1pt->al_ptaddr = ARMPT_ADDR_TO_L1PTADDR(l2table); 469 } else if ((*pte & ARMPT_L1_TYPE_MASK) != ARMPT_L1_TYPE_L2PT) { 470 fakeload_panic("encountered l1 entry that's not a " 471 "pointer to a level 2 table\n"); 472 } else { 473 l1pt = (arm_l1pt_t *)pte; 474 } 475 476 /* Now that we have the l1pt fill in l2 entries */ 477 l2pt = (void *)(l1pt->al_ptaddr << ARMPT_L1PT_TO_L2_SHIFT); 478 len -= chunksize; 479 while (chunksize > 0) { 480 arm_l2e_t *l2pte; 481 482 entry = ARMPT_VADDR_TO_L2E(vstart); 483 pte = &l2pt[entry]; 484 485 #ifdef MAP_DEBUG 486 fakeload_puts("4k page pa->va, l2root, entry\n"); 487 fakeload_ultostr(pstart); 488 fakeload_puts("->"); 489 fakeload_ultostr(vstart); 490 fakeload_puts(", "); 491 fakeload_ultostr((uintptr_t)l2pt); 492 fakeload_puts(", "); 493 fakeload_ultostr(entry); 494 fakeload_puts("\n"); 495 #endif 496 497 if ((*pte & ARMPT_L2_TYPE_MASK) != 498 ARMPT_L2_TYPE_INVALID) 499 fakeload_panic("found existing l2 page table, " 500 "overlap in requested mappings detected!"); 501 /* Map vaddr to our paddr! */ 502 l2pte = ((arm_l2e_t *)pte); 503 *pte = 0; 504 if (!(prot & PF_X)) 505 l2pte->ale_xn = 1; 506 l2pte->ale_ident = 1; 507 if (prot & PF_DEVICE) { 508 l2pte->ale_bbit = 1; 509 l2pte->ale_cbit = 0; 510 l2pte->ale_tex = 0; 511 l2pte->ale_sbit = 1; 512 } else { 513 l2pte->ale_bbit = 1; 514 l2pte->ale_cbit = 1; 515 l2pte->ale_tex = 1; 516 l2pte->ale_sbit = 1; 517 } 518 if (prot & PF_W) { 519 l2pte->ale_ap2 = 1; 520 l2pte->ale_ap = 1; 521 } else { 522 l2pte->ale_ap2 = 0; 523 l2pte->ale_ap = 1; 524 } 525 l2pte->ale_ngbit = 0; 526 l2pte->ale_addr = ARMPT_PADDR_TO_L2ADDR(pstart); 527 528 chunksize -= MMU_PAGESIZE; 529 vstart += MMU_PAGESIZE; 530 pstart += MMU_PAGESIZE; 531 } 532 } 533 } 534 535 static void 536 fakeload_create_map(armpte_t *pt, atag_illumos_mapping_t *aimp) 537 { 538 #ifdef MAP_DEBUG 539 fakeload_puts("paddr->vaddr\n"); 540 fakeload_ultostr(aimp->aim_paddr); 541 fakeload_puts("->"); 542 fakeload_ultostr(aimp->aim_vaddr); 543 fakeload_puts("\n"); 544 fakeload_puts("plen-vlen\n"); 545 fakeload_ultostr(aimp->aim_plen); 546 fakeload_puts("-"); 547 fakeload_ultostr(aimp->aim_vlen); 548 fakeload_puts("\n"); 549 #endif /* MAP_DEBUG */ 550 551 /* 552 * Can we map this in place or do we need to basically allocate a new 553 * region and bcopy everything into place for proper alignment? 554 * 555 * Criteria for this: we have a vlen > plen. plen is not page aligned. 556 */ 557 if (aimp->aim_vlen > aimp->aim_plen || 558 (aimp->aim_paddr & MMU_PAGEOFFSET) != 0) { 559 uintptr_t start; 560 561 if (aimp->aim_mapflags & PF_NORELOC) 562 fakeload_panic("tried to reloc unrelocatable mapping"); 563 #ifdef MAP_DEBUG 564 FAKELOAD_DPRINTF("reloacting paddr\n"); 565 #endif 566 start = freemem; 567 if (start & MMU_PAGEOFFSET) { 568 start &= MMU_PAGEMASK; 569 start += MMU_PAGESIZE; 570 } 571 bcopy((void *)aimp->aim_paddr, (void *)start, 572 aimp->aim_plen); 573 if (aimp->aim_vlen > aimp->aim_plen) { 574 bzero((void *)(start + aimp->aim_plen), 575 aimp->aim_vlen - aimp->aim_plen); 576 } 577 aimp->aim_paddr = start; 578 freemem = start + aimp->aim_vlen; 579 #ifdef MAP_DEBUG 580 fakeload_puts("new paddr: "); 581 fakeload_ultostr(start); 582 fakeload_puts("\n"); 583 #endif /* MAP_DEBUG */ 584 } 585 586 /* 587 * Now that everything has been set up, go ahead and map the new region. 588 */ 589 fakeload_map(pt, aimp->aim_paddr, aimp->aim_vaddr, aimp->aim_vlen, 590 aimp->aim_mapflags); 591 #ifdef MAP_DEBUG 592 FAKELOAD_DPRINTF("\n"); 593 #endif /* MAP_DEBUG */ 594 } 595 596 void 597 fakeload_init(void *ident, void *ident2, void *atag) 598 { 599 atag_header_t *hdr; 600 atag_header_t *chain = (atag_header_t *)atag; 601 const atag_initrd_t *initrd; 602 atag_illumos_status_t *aisp; 603 atag_illumos_mapping_t *aimp; 604 uintptr_t unix_start; 605 606 fakeload_backend_init(); 607 fakeload_puts("Hello from the loader\n"); 608 initrd = (atag_initrd_t *)atag_find(chain, ATAG_INITRD2); 609 if (initrd == NULL) 610 fakeload_panic("missing the initial ramdisk\n"); 611 612 /* 613 * Create the status atag header and the initial mapping record for the 614 * atags. We'll hold onto both of these. 615 */ 616 fakeload_mkatags(chain); 617 aisp = (atag_illumos_status_t *)atag_find(chain, ATAG_ILLUMOS_STATUS); 618 if (aisp == NULL) 619 fakeload_panic("can't find ATAG_ILLUMOS_STATUS"); 620 aimp = (atag_illumos_mapping_t *)atag_find(chain, ATAG_ILLUMOS_MAPPING); 621 if (aimp == NULL) 622 fakeload_panic("can't find ATAG_ILLUMOS_MAPPING"); 623 FAKELOAD_DPRINTF("created proto atags\n"); 624 625 fakeload_pt_arena_init(initrd); 626 627 fakeload_selfmap(chain); 628 629 /* 630 * Map the boot archive and all of unix 631 */ 632 unix_start = fakeload_archive_mappings(chain, 633 (const void *)(uintptr_t)initrd->ai_start, aisp); 634 FAKELOAD_DPRINTF("filled out unix and the archive's mappings\n"); 635 636 /* 637 * Fill in the atag mapping header for the atags themselves. 1:1 map it. 638 */ 639 aimp->aim_paddr = (uintptr_t)chain & ~0xfff; 640 aimp->aim_plen = atag_length(chain) & ~0xfff; 641 aimp->aim_plen += 0x1000; 642 aimp->aim_vaddr = aimp->aim_paddr; 643 aimp->aim_vlen = aimp->aim_plen; 644 aimp->aim_mapflags = PF_R | PF_W | PF_NORELOC; 645 646 /* 647 * Let the backend add mappings 648 */ 649 fakeload_backend_addmaps(chain); 650 651 /* 652 * Turn on unaligned access 653 */ 654 FAKELOAD_DPRINTF("turning on unaligned access\n"); 655 fakeload_unaligned_enable(); 656 FAKELOAD_DPRINTF("successfully enabled unaligned access\n"); 657 658 /* 659 * To turn on the MMU we need to do the following: 660 * o Program all relevant CP15 registers 661 * o Program 1st and 2nd level page tables 662 * o Invalidate and Disable the I/D-cache 663 * o Fill in the last bits of the ATAG_ILLUMOS_STATUS atag 664 * o Turn on the MMU in SCTLR 665 * o Jump to unix 666 */ 667 668 /* Last bits of the atag */ 669 aisp->ais_freemem = freemem; 670 aisp->ais_version = 1; 671 aisp->ais_ptbase = (uintptr_t)pt_addr; 672 673 /* 674 * Our initial page table is a series of 1 MB sections. While we really 675 * should map 4k pages, for the moment we're just going to map 1 MB 676 * regions, yay team! 677 */ 678 hdr = chain; 679 FAKELOAD_DPRINTF("creating mappings\n"); 680 while (hdr != NULL) { 681 if (hdr->ah_tag == ATAG_ILLUMOS_MAPPING) 682 fakeload_create_map(pt_addr, 683 (atag_illumos_mapping_t *)hdr); 684 hdr = atag_next(hdr); 685 } 686 687 /* 688 * Now that we've mapped everything, update the status atag. 689 */ 690 aisp->ais_freeused = freemem - aisp->ais_freemem; 691 aisp->ais_pt_arena = pt_arena; 692 aisp->ais_pt_arena_max = pt_arena_max; 693 694 /* Cache disable */ 695 FAKELOAD_DPRINTF("Flushing and disabling caches\n"); 696 armv6_dcache_flush(); 697 armv6_dcache_disable(); 698 armv6_dcache_inval(); 699 armv6_icache_disable(); 700 armv6_icache_inval(); 701 702 /* Program the page tables */ 703 FAKELOAD_DPRINTF("programming cp15 regs\n"); 704 fakeload_pt_setup((uintptr_t)pt_addr); 705 706 707 /* MMU Enable */ 708 FAKELOAD_DPRINTF("see you on the other side\n"); 709 fakeload_mmu_enable(); 710 711 FAKELOAD_DPRINTF("why helo thar\n"); 712 713 /* we should never come back */ 714 fakeload_exec(ident, ident2, chain, unix_start); 715 fakeload_panic("hit the end of the world\n"); 716 }