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 /* 18 * Just like in i86pc, we too get the joys of mimicking the SPARC boot system. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/param.h> 23 #include <sys/bootconf.h> 24 #include <sys/bootsvcs.h> 25 #include <sys/boot_console.h> 26 #include <sys/atag.h> 27 #include <sys/varargs.h> 28 #include <sys/cmn_err.h> 29 #include <sys/sysmacros.h> 30 #include <sys/systm.h> 31 #include <sys/ctype.h> 32 #include <sys/bootstat.h> 33 #include <sys/privregs.h> 34 #include <sys/cpu_asm.h> 35 #include <sys/boot_mmu.h> 36 #include <sys/elf.h> 37 38 static bootops_t bootop; 39 40 /* 41 * Debugging help 42 */ 43 static int fakebop_prop_debug = 0; 44 static int fakebop_alloc_debug = 0; 45 static int fakebop_atag_debug = 0; 46 47 static uint_t kbm_debug = 1; 48 #define DBG_MSG(x) { if (kbm_debug) bcons_puts(x); bcons_puts("\n"); } 49 #define BUFFERSIZE 256 50 static char buffer[BUFFERSIZE]; 51 52 /* 53 * fakebop memory allocations scheme 54 * 55 * It's a virtual world out there. The loader thankfully tells us all the areas 56 * that it has mapped for us and it also tells us about the page table arena -- 57 * a set of addresses that have already been set aside for us. We have two 58 * different kinds of allocations to worry about: 59 * 60 * o Those that specify a particular vaddr 61 * o Those that do not specify a particular vaddr 62 * 63 * Those that do not specify a particular vaddr will come out of our scratch 64 * space which is a fixed size arena of 16 MB (FAKEBOP_ALLOC_SIZE) that we set 65 * aside at the beginning of the allocator. If we end up running out of that 66 * then we'll go ahead and figure out a slightly larger area to worry about. 67 * 68 * Now, for those that do specify a particular vaddr we'll allocate more 69 * physical address space for it. The loader set aside enough L2 page tables for 70 * us that we'll go ahead and use the next 4k aligned address. 71 */ 72 #define FAKEBOP_ALLOC_SIZE (16 * 1024 * 1024) 73 74 static size_t bop_alloc_scratch_size; 75 static uintptr_t bop_alloc_scratch_next; /* Next scratch address */ 76 static uintptr_t bop_alloc_scratch_last; /* Last scratch address */ 77 78 static uintptr_t bop_alloc_pnext; /* Next paddr */ 79 static uintptr_t bop_alloc_plast; /* cross this paddr and panic */ 80 81 #define BI_HAS_RAMDISK 0x1 82 83 /* 84 * TODO Generalize this 85 * This is the set of information tha we want to gather from the various atag 86 * headers. This is simple and naive and will need to evolve as we have 87 * additional boards beyond just the RPi. 88 */ 89 typedef struct bootinfo { 90 uint_t bi_flags; 91 char *bi_cmdline; 92 uint32_t bi_ramdisk; 93 uint32_t bi_ramsize; 94 } bootinfo_t; 95 96 static bootinfo_t bootinfo; /* Simple set of boot information */ 97 98 static struct boot_syscalls bop_sysp = { 99 bcons_getchar, 100 bcons_putchar, 101 bcons_ischar, 102 }; 103 104 /* 105 * stuff to store/report/manipulate boot property settings. 106 */ 107 typedef struct bootprop { 108 struct bootprop *bp_next; 109 char *bp_name; 110 uint_t bp_vlen; 111 char *bp_value; 112 } bootprop_t; 113 114 static bootprop_t *bprops = NULL; 115 116 void 117 bop_panic(const char *msg) 118 { 119 bop_printf(NULL, "ARM bop_panic:\n%s\nSpinning Forever...", msg); 120 for (;;) 121 ; 122 } 123 124 /* 125 * XXX This is just a hack to let us see a bit more about what's going on. 126 * Normally we'd use vsnprintf, but that includes sys/systm.h which requires 127 * almost every header platform header in the world. Also, we're using hex, 128 * because hex is cool. Actually, we're really using it because it means we can 129 * bitshift instead of divide. There is no integer division in ARMv6 natively. 130 * Oops. 131 */ 132 static char * 133 fakebop_hack_ultostr(unsigned long value, char *ptr) 134 { 135 ulong_t t, val = (ulong_t)value; 136 char c; 137 138 do { 139 c = (char)('0' + val - 16 * (t = (val >> 4))); 140 if (c > '9') 141 c += 'A' - '9' - 1; 142 *--ptr = c; 143 } while ((val = t) != 0); 144 145 *--ptr = 'x'; 146 *--ptr = '0'; 147 148 return (ptr); 149 } 150 151 /* 152 * We need to map and reserve the scratch arena. As a part of this we'll go 153 * through and set up the right place for other paddrs. 154 */ 155 static void 156 fakebop_alloc_init(atag_header_t *chain) 157 { 158 uintptr_t pstart, vstart, pmax; 159 size_t len; 160 atag_illumos_mapping_t *aimp; 161 atag_illumos_status_t *aisp; 162 163 aisp = (atag_illumos_status_t *)atag_find(chain, ATAG_ILLUMOS_STATUS); 164 if (aisp == NULL) 165 bop_panic("missing ATAG_ILLUMOS_STATUS!\n"); 166 pstart = aisp->ais_freemem + aisp->ais_freeused; 167 /* Align to next 1 MB boundary */ 168 if (pstart & MMU_PAGEOFFSET1M) { 169 pstart &= MMU_PAGEMASK1M; 170 pstart += MMU_PAGESIZE1M; 171 } 172 len = FAKEBOP_ALLOC_SIZE; 173 vstart = pstart; 174 175 pmax = 0xffffffff; 176 /* Make sure the paddrs and vaddrs don't overlap at all */ 177 for (aimp = 178 (atag_illumos_mapping_t *)atag_find(chain, ATAG_ILLUMOS_MAPPING); 179 aimp != NULL; aimp = 180 (atag_illumos_mapping_t *)atag_find(atag_next(&aimp->aim_header), 181 ATAG_ILLUMOS_MAPPING)) { 182 if (aimp->aim_paddr < pstart && 183 aimp->aim_paddr + aimp->aim_vlen > pstart) 184 bop_panic("phys addresses overlap\n"); 185 if (pstart < aimp->aim_paddr && pstart + len > aimp->aim_paddr) 186 bop_panic("phys addresses overlap\n"); 187 if (aimp->aim_vaddr < vstart && aimp->aim_vaddr + 188 aimp->aim_vlen > vstart) 189 bop_panic("virt addreses overlap\n"); 190 if (vstart < aimp->aim_vaddr && vstart + len > aimp->aim_vaddr) 191 bop_panic("virt addresses overlap\n"); 192 193 if (aimp->aim_paddr > pstart && aimp->aim_paddr < pmax) 194 pmax = aimp->aim_paddr; 195 } 196 197 armboot_mmu_map(pstart, vstart, len, PF_R | PF_W | PF_X); 198 bop_alloc_scratch_next = vstart; 199 bop_alloc_scratch_last = vstart + len; 200 bop_alloc_scratch_size = len; 201 202 bop_alloc_pnext = pstart + len; 203 bop_alloc_plast = pmax; 204 } 205 206 #define DUMP_ATAG_VAL(name, val) \ 207 do { \ 208 DBG_MSG("\t" name ":"); \ 209 bcons_puts("\t"); \ 210 DBG_MSG(fakebop_hack_ultostr((val), \ 211 &buffer[BUFFERSIZE-1])); \ 212 } while (0) 213 214 static void 215 fakebop_dump_tags(void *tagstart) 216 { 217 atag_header_t *h = tagstart; 218 atag_core_t *acp; 219 atag_mem_t *amp; 220 atag_cmdline_t *alp; 221 atag_initrd_t *aip; 222 atag_illumos_status_t *aisp; 223 atag_illumos_mapping_t *aimp; 224 const char *tname; 225 int i; 226 char *c; 227 228 DBG_MSG("starting point:"); 229 DBG_MSG(fakebop_hack_ultostr((uintptr_t)h, &buffer[BUFFERSIZE-1])); 230 DBG_MSG("first atag size:"); 231 DBG_MSG(fakebop_hack_ultostr(h->ah_size, &buffer[BUFFERSIZE-1])); 232 DBG_MSG("first atag tag:"); 233 DBG_MSG(fakebop_hack_ultostr(h->ah_tag, &buffer[BUFFERSIZE-1])); 234 while (h != NULL) { 235 switch (h->ah_tag) { 236 case ATAG_CORE: 237 tname = "ATAG_CORE"; 238 break; 239 case ATAG_MEM: 240 tname = "ATAG_MEM"; 241 break; 242 case ATAG_VIDEOTEXT: 243 tname = "ATAG_VIDEOTEXT"; 244 break; 245 case ATAG_RAMDISK: 246 tname = "ATAG_RAMDISK"; 247 break; 248 case ATAG_INITRD2: 249 tname = "ATAG_INITRD2"; 250 break; 251 case ATAG_SERIAL: 252 tname = "ATAG_SERIAL"; 253 break; 254 case ATAG_REVISION: 255 tname = "ATAG_REVISION"; 256 break; 257 case ATAG_VIDEOLFB: 258 tname = "ATAG_VIDEOLFB"; 259 break; 260 case ATAG_CMDLINE: 261 tname = "ATAG_CMDLINE"; 262 break; 263 case ATAG_ILLUMOS_STATUS: 264 tname = "ATAG_ILLUMOS_STATUS"; 265 break; 266 case ATAG_ILLUMOS_MAPPING: 267 tname = "ATAG_ILLUMOS_MAPPING"; 268 break; 269 default: 270 tname = fakebop_hack_ultostr(h->ah_tag, 271 &buffer[BUFFERSIZE-1]); 272 break; 273 } 274 DBG_MSG("tag:"); 275 DBG_MSG(tname); 276 DBG_MSG("size:"); 277 DBG_MSG(fakebop_hack_ultostr(h->ah_size, 278 &buffer[BUFFERSIZE-1])); 279 /* Extended information */ 280 switch (h->ah_tag) { 281 case ATAG_CORE: 282 if (h->ah_size == 2) { 283 DBG_MSG("ATAG_CORE has no extra information"); 284 } else { 285 acp = (atag_core_t *)h; 286 DUMP_ATAG_VAL("flags", acp->ac_flags); 287 DUMP_ATAG_VAL("pagesize", acp->ac_pagesize); 288 DUMP_ATAG_VAL("rootdev", acp->ac_rootdev); 289 } 290 break; 291 case ATAG_MEM: 292 amp = (atag_mem_t *)h; 293 DUMP_ATAG_VAL("size", amp->am_size); 294 DUMP_ATAG_VAL("start", amp->am_start); 295 break; 296 case ATAG_INITRD2: 297 aip = (atag_initrd_t *)h; 298 DUMP_ATAG_VAL("size", aip->ai_size); 299 DUMP_ATAG_VAL("start", aip->ai_start); 300 break; 301 case ATAG_CMDLINE: 302 alp = (atag_cmdline_t *)h; 303 DBG_MSG("\tcmdline:"); 304 /* 305 * We have no intelligent thing to wrap our tty at 80 306 * chars so we just do this a bit more manually for now. 307 */ 308 i = 0; 309 c = alp->al_cmdline; 310 while (*c != '\0') { 311 bcons_putchar(*c++); 312 if (++i == 72) { 313 bcons_puts("\n"); 314 i = 0; 315 } 316 } 317 bcons_puts("\n"); 318 break; 319 case ATAG_ILLUMOS_STATUS: 320 aisp = (atag_illumos_status_t *)h; 321 DUMP_ATAG_VAL("version", aisp->ais_version); 322 DUMP_ATAG_VAL("ptbase", aisp->ais_ptbase); 323 DUMP_ATAG_VAL("freemem", aisp->ais_freemem); 324 DUMP_ATAG_VAL("freeused", aisp->ais_freeused); 325 DUMP_ATAG_VAL("archive", aisp->ais_archive); 326 DUMP_ATAG_VAL("archivelen", aisp->ais_archivelen); 327 DUMP_ATAG_VAL("pt_arena", aisp->ais_pt_arena); 328 DUMP_ATAG_VAL("pt_arena_max", aisp->ais_pt_arena_max); 329 DUMP_ATAG_VAL("stext", aisp->ais_stext); 330 DUMP_ATAG_VAL("etext", aisp->ais_etext); 331 DUMP_ATAG_VAL("sdata", aisp->ais_sdata); 332 DUMP_ATAG_VAL("edata", aisp->ais_edata); 333 break; 334 case ATAG_ILLUMOS_MAPPING: 335 aimp = (atag_illumos_mapping_t *)h; 336 DUMP_ATAG_VAL("paddr", aimp->aim_paddr); 337 DUMP_ATAG_VAL("plen", aimp->aim_plen); 338 DUMP_ATAG_VAL("vaddr", aimp->aim_vaddr); 339 DUMP_ATAG_VAL("vlen", aimp->aim_vlen); 340 DUMP_ATAG_VAL("mapflags", aimp->aim_mapflags); 341 break; 342 default: 343 break; 344 } 345 h = atag_next(h); 346 } 347 } 348 349 static void 350 fakebop_getatags(void *tagstart) 351 { 352 atag_mem_t *amp; 353 atag_cmdline_t *alp; 354 atag_header_t *ahp = tagstart; 355 atag_illumos_status_t *aisp; 356 bootinfo_t *bp = &bootinfo; 357 boolean_t got_mem = B_FALSE; 358 359 bp->bi_flags = 0; 360 while (ahp != NULL) { 361 switch (ahp->ah_tag) { 362 case ATAG_MEM: 363 amp = (atag_mem_t *)ahp; 364 /* 365 * We may actually get more than one ATAG_MEM if the 366 * system has discontiguous physical memory 367 */ 368 if (got_mem) { 369 bop_printf(NULL, "found multiple ATAG_MEM\n"); 370 bop_printf(NULL, "ignoring: %#x - %#x\n", 371 amp->am_start, amp->am_start + 372 amp->am_size - 1); 373 break; 374 } 375 376 bootop.boot_mem.physinstalled.ml_address = amp->am_start; 377 bootop.boot_mem.physinstalled.ml_size = amp->am_size; 378 bootop.boot_mem.physinstalled.ml_prev = NULL; 379 bootop.boot_mem.physinstalled.ml_next = NULL; 380 got_mem = B_TRUE; 381 break; 382 case ATAG_CMDLINE: 383 alp = (atag_cmdline_t *)ahp; 384 bp->bi_cmdline = alp->al_cmdline; 385 break; 386 case ATAG_ILLUMOS_STATUS: 387 aisp = (atag_illumos_status_t *)ahp; 388 bp->bi_ramdisk = aisp->ais_archive; 389 bp->bi_ramsize = aisp->ais_archivelen; 390 bp->bi_flags |= BI_HAS_RAMDISK; 391 break; 392 default: 393 break; 394 } 395 ahp = atag_next(ahp); 396 } 397 } 398 399 /* 400 * We've been asked to allocate at a specific VA. Allocate the next ragne of 401 * physical addresses and go from there. 402 */ 403 static caddr_t 404 fakebop_alloc_hint(caddr_t virt, size_t size, int align) 405 { 406 uintptr_t start = P2ROUNDUP(bop_alloc_pnext, align); 407 if (fakebop_alloc_debug != 0) 408 bop_printf(NULL, "asked to allocate %d bytes at v/p %p/%p\n", 409 size, virt, start); 410 if (start + size > bop_alloc_plast) 411 bop_panic("fakebop_alloc_hint: No more physical address -_-\n"); 412 413 armboot_mmu_map(start, (uintptr_t)virt, size, PF_R | PF_W | PF_X); 414 bop_alloc_pnext = start + size; 415 return (virt); 416 } 417 418 static caddr_t 419 fakebop_alloc(struct bootops *bops, caddr_t virthint, size_t size, int align) 420 { 421 caddr_t start; 422 423 if (virthint != NULL) 424 return (fakebop_alloc_hint(virthint, size, align)); 425 if (fakebop_alloc_debug != 0) 426 bop_printf(bops, "asked to allocate %d bytes\n", size); 427 if (bop_alloc_scratch_next == 0) 428 bop_panic("fakebop_alloc_init not called"); 429 430 if (align == BO_ALIGN_DONTCARE || align == 0) 431 align = 4; 432 433 start = (caddr_t)P2ROUNDUP(bop_alloc_scratch_next, align); 434 if ((uintptr_t)start + size > bop_alloc_scratch_last) 435 bop_panic("fakebop_alloc: ran out of scratch space!\n"); 436 if (fakebop_alloc_debug != 0) 437 bop_printf(bops, "returning address: %p\n", start); 438 bop_alloc_scratch_next = (uintptr_t)start + size; 439 440 return (start); 441 } 442 443 static void 444 fakebop_free(struct bootops *bops, caddr_t virt, size_t size) 445 { 446 bop_panic("Called into fakebop_free"); 447 } 448 449 static int 450 fakebop_getproplen(struct bootops *bops, const char *pname) 451 { 452 bootprop_t *p; 453 454 if (fakebop_prop_debug) 455 bop_printf(NULL, "fakebop_getproplen: asked for %s\n", pname); 456 for (p = bprops; p != NULL; p = p->bp_next) { 457 if (strcmp(pname, p->bp_name) == 0) 458 return (p->bp_vlen); 459 } 460 if (fakebop_prop_debug != 0) 461 bop_printf(NULL, "prop %s not found\n", pname); 462 return (-1); 463 } 464 465 static int 466 fakebop_getprop(struct bootops *bops, const char *pname, void *value) 467 { 468 bootprop_t *p; 469 470 if (fakebop_prop_debug) 471 bop_printf(NULL, "fakebop_getprop: asked for %s\n", pname); 472 for (p = bprops; p != NULL; p = p->bp_next) { 473 if (strcmp(pname, p->bp_name) == 0) 474 break; 475 } 476 if (p == NULL) { 477 if (fakebop_prop_debug) 478 bop_printf(NULL, "fakebop_getprop: ENOPROP %s\n", 479 pname); 480 return (-1); 481 } 482 if (fakebop_prop_debug) 483 bop_printf(NULL, "fakebop_getprop: copying %d bytes to 0x%x\n", 484 p->bp_vlen, value); 485 bcopy(p->bp_value, value, p->bp_vlen); 486 return (0); 487 } 488 489 void 490 bop_printf(bootops_t *bop, const char *fmt, ...) 491 { 492 va_list ap; 493 494 va_start(ap, fmt); 495 (void) vsnprintf(buffer, BUFFERSIZE, fmt, ap); 496 va_end(ap); 497 bcons_puts(buffer); 498 } 499 500 static void 501 fakebop_setprop(char *name, int nlen, void *value, int vlen) 502 { 503 size_t size; 504 bootprop_t *bp; 505 caddr_t cur; 506 507 size = sizeof (bootprop_t) + nlen + 1 + vlen; 508 cur = fakebop_alloc(NULL, NULL, size, BO_ALIGN_DONTCARE); 509 bp = (bootprop_t *)cur; 510 if (bprops == NULL) { 511 bprops = bp; 512 bp->bp_next = NULL; 513 } else { 514 bp->bp_next = bprops; 515 bprops = bp; 516 } 517 cur += sizeof (bootprop_t); 518 bp->bp_name = cur; 519 bcopy(name, cur, nlen); 520 cur += nlen; 521 *cur = '\0'; 522 cur++; 523 bp->bp_vlen = vlen; 524 bp->bp_value = cur; 525 if (vlen > 0) 526 bcopy(value, cur, vlen); 527 528 if (fakebop_prop_debug) 529 bop_printf(NULL, "setprop - name: %s, nlen: %d, vlen: %d\n", 530 bp->bp_name, nlen, bp->bp_vlen); 531 } 532 533 static void 534 fakebop_setprop_string(char *name, char *value) 535 { 536 if (fakebop_prop_debug) 537 bop_printf(NULL, "setprop_string: %s->[%s]\n", name, value); 538 fakebop_setprop(name, strlen(name), value, strlen(value) + 1); 539 } 540 541 static void 542 fakebop_setprop_32(char *name, uint32_t value) 543 { 544 if (fakebop_prop_debug) 545 bop_printf(NULL, "setprop_32: %s->[%d]\n", name, value); 546 fakebop_setprop(name, strlen(name), (void *)&value, sizeof (value)); 547 } 548 549 static void 550 fakebop_setprop_64(char *name, uint64_t value) 551 { 552 if (fakebop_prop_debug) 553 bop_printf(NULL, "setprop_64: %s->[%lld]\n", name, value); 554 fakebop_setprop(name, strlen(name), (void *)&value, sizeof (value)); 555 } 556 557 /* 558 * Here we create a bunch of the initial boot properties. This includes what 559 * we've been passed in via the command line. It also includes a few values that 560 * we compute ourselves. 561 */ 562 static void 563 fakebop_bootprops_init(void) 564 { 565 int i = 0, proplen = 0, cmdline_len = 0, quote, cont; 566 static int stdout_val = 0; 567 char *c, *prop, *cmdline, *pname; 568 bootinfo_t *bp = &bootinfo; 569 570 /* 571 * Set the ramdisk properties for kobj_boot_mountroot() can succeed. 572 */ 573 if ((bp->bi_flags & BI_HAS_RAMDISK) != 0) { 574 fakebop_setprop_64("ramdisk_start", 575 (uint64_t)(uintptr_t)bp->bi_ramdisk); 576 fakebop_setprop_64("ramdisk_end", 577 (uint64_t)(uintptr_t)bp->bi_ramdisk + bp->bi_ramsize); 578 } 579 580 /* 581 * TODO Various arm devices may spit properties at the front just like 582 * i86xpv. We should do something about them at some point. 583 */ 584 585 /* 586 * Our boot parameters always wil start with kernel /platform/..., but 587 * the bootloader may in fact stick other properties in front of us. To 588 * deal with that we go ahead and we include them. We'll find the kernel 589 * and our properties set via -B when we finally find something without 590 * an equals sign, mainly kernel. 591 */ 592 c = bp->bi_cmdline; 593 prop = strstr(c, "kernel"); 594 if (prop == NULL) 595 bop_panic("failed to find kernel string in boot params!"); 596 /* Get us past the first kernel string */ 597 prop += 6; 598 while (ISSPACE(prop[0])) 599 prop++; 600 proplen = 0; 601 while (prop[proplen] != '\0' && !ISSPACE(prop[proplen])) 602 proplen++; 603 c = prop + proplen + 1; 604 if (proplen > 0) { 605 prop[proplen] = '\0'; 606 fakebop_setprop_string("boot-file", prop); 607 /* 608 * We strip the leading path from whoami so no matter what 609 * environment we enter into here from it is consistent and 610 * makes some amount of sense. 611 */ 612 if (strstr(prop, "/platform") != NULL) 613 prop = strstr(prop, "/platform"); 614 fakebop_setprop_string("whoami", prop); 615 } else { 616 bop_panic("no kernel string in boot params!"); 617 } 618 619 /* 620 * At this point we have two different sets of properties. Anything that 621 * involves -B is a boot property, otherwise it becomes part of the 622 * kernel command line and must be saved in its own property. 623 */ 624 cmdline = fakebop_alloc(NULL, NULL, strlen(c), BO_ALIGN_DONTCARE); 625 cmdline[0] = '\0'; 626 while (*c != '\0') { 627 628 /* 629 * Just blindly copy it to the commadline if we don't find it. 630 */ 631 if (c[0] != '-' || c[1] != 'B') { 632 cmdline[cmdline_len++] = *c; 633 cmdline[cmdline_len] = '\0'; 634 c++; 635 continue; 636 } 637 638 /* Get past "-B" */ 639 c += 2; 640 while (ISSPACE(*c)) 641 c++; 642 643 /* 644 * We have a series of comma separated key-value pairs to sift 645 * through here. The key and value are separated by an equals 646 * sign. The value may quoted with either a ' or ". Note, white 647 * space will also end the value (as it indicates that we have 648 * moved on from the -B argument. 649 */ 650 for (;;) { 651 if (*c == '\0' || ISSPACE(*c)) 652 break; 653 prop = strchr(c, '='); 654 if (prop == NULL) 655 break; 656 pname = c; 657 *prop = '\0'; 658 prop++; 659 proplen = 0; 660 quote = '\0'; 661 for (;;) { 662 if (prop[proplen] == '\0') 663 break; 664 665 if (proplen == 0 && (prop[0] == '\'' || 666 prop[0] == '"')) { 667 quote = prop[0]; 668 proplen++; 669 continue; 670 } 671 672 if (quote != '\0') { 673 if (prop[proplen] == quote) 674 quote = '\0'; 675 proplen++; 676 continue; 677 } 678 679 if (prop[proplen] == ',' || 680 ISSPACE(prop[proplen])) 681 break; 682 683 /* We just have a normal character */ 684 proplen++; 685 } 686 687 /* 688 * Save whether we should continue or not and update 'c' 689 * now as we will most likely clobber the string when we 690 * are done. 691 */ 692 cont = (prop[proplen] == ','); 693 if (prop[proplen] != '\0') 694 c = prop + proplen + 1; 695 else 696 c = prop + proplen; 697 698 if (proplen == 0) { 699 fakebop_setprop_string(pname, "true"); 700 } else { 701 /* 702 * When we copy the prop, do not include the 703 * quote. 704 */ 705 if (prop[0] == prop[proplen - 1] && 706 (prop[0] == '\'' || prop[0] == '"')) { 707 prop++; 708 proplen -= 2; 709 } 710 prop[proplen] = '\0'; 711 fakebop_setprop_string(pname, prop); 712 } 713 714 if (cont == 0) 715 break; 716 } 717 } 718 719 /* 720 * Yes, we actually set both names here. The latter is set because of 721 * 1275. 722 */ 723 fakebop_setprop_string("boot-args", cmdline); 724 fakebop_setprop_string("bootargs", cmdline); 725 726 /* 727 * Here are some things that we make up, just like our i86pc brethren. 728 */ 729 fakebop_setprop_32("stdout", 0); 730 fakebop_setprop_string("mfg-name", "ARMv6"); 731 fakebop_setprop_string("impl-arch-name", "ARMv6"); 732 } 733 734 /* 735 * Nominally this should try and look for bootenv.rc, but seriously, let's not. 736 * Instead for now all we're going to to do is look and make sure that console 737 * is set. We *should* do something with it, but we're not. 738 */ 739 void 740 boot_prop_finish(void) 741 { 742 int ret; 743 744 if (fakebop_getproplen(NULL, "console") <= 0) 745 bop_panic("console not set"); 746 } 747 748 /*ARGSUSED*/ 749 int 750 boot_compinfo(int fd, struct compinfo *cbp) 751 { 752 cbp->iscmp = 0; 753 cbp->blksize = MAXBSIZE; 754 return (0); 755 } 756 757 extern void (*exception_table[])(void); 758 759 void 760 primordial_handler(void) 761 { 762 bop_panic("TRAP"); 763 } 764 765 void 766 primordial_svc(void *arg) 767 { 768 struct regs *r = (struct regs *)arg; 769 uint32_t *insaddr = (uint32_t *)(r->r_lr - 4); 770 771 bop_printf(NULL, "TRAP: svc #%d from %p\n", *insaddr & 0x00ffffff, 772 insaddr); 773 } 774 775 void 776 primordial_undef(void *arg) 777 { 778 struct regs *r = (struct regs *)arg; 779 uint32_t *insaddr = (uint32_t *)(r->r_lr - 4); 780 781 bop_printf(NULL, "TRAP: undefined instruction %x at %p\n", 782 *insaddr, insaddr); 783 } 784 785 void 786 primordial_reset(void *arg) 787 { 788 struct regs *r = (struct regs *)arg; 789 uint32_t *insaddr = (uint32_t *)(r->r_lr - 4); 790 791 bop_printf(NULL, "TRAP: reset from %p\n", 792 insaddr); 793 bop_panic("cannot recover from reset\n"); 794 } 795 796 void 797 primordial_prefetchabt(void *arg) 798 { 799 struct regs *r = (struct regs *)arg; 800 uint32_t *insaddr = (uint32_t *)(r->r_lr - 4); 801 uint32_t bkptno = ((*insaddr & 0xfff00) >> 4) | (*insaddr & 0xf); 802 803 bop_printf(NULL, "TRAP: prefetch (or bkpt #%d) at %p\n", 804 bkptno, insaddr); 805 } 806 807 /* 808 * XXX: This can't be tested without the MMU on, I don't think 809 * 810 * So while I'm sure (surely) we can decode this into a useful "what went 811 * wrong and why", I have no idea how, and couldn't test it if I did. 812 * 813 * I will say that I currently have the awful feeling that it would require an 814 * instruction decoder to decode *insaddr and find the memory refs... 815 */ 816 void 817 primordial_dataabt(void *arg) 818 { 819 struct regs *r = (struct regs *)arg; 820 /* XXX: Yes, really +8 see ARM A2.6.6 */ 821 uint32_t *insaddr = (uint32_t *)(r->r_lr - 8); 822 823 bop_printf(NULL, "TRAP: data abort at (insn) %p\n", insaddr); 824 bop_printf(NULL, "r0: %08x\tr1: %08x\n", r->r_r0, r->r_r1); 825 bop_printf(NULL, "r2: %08x\tr3: %08x\n", r->r_r2, r->r_r3); 826 bop_printf(NULL, "r4: %08x\tr5: %08x\n", r->r_r4, r->r_r5); 827 bop_printf(NULL, "r6: %08x\tr7: %08x\n", r->r_r6, r->r_r7); 828 bop_printf(NULL, "r8: %08x\tr9: %08x\n", r->r_r8, r->r_fp); 829 bop_panic("Page Fault! Go fix it\n"); 830 } 831 832 void 833 bad_interrupt(void *arg) 834 { 835 bop_panic("Interrupt with VE == 0 (non-vectored)\n"); 836 } 837 838 /* XXX: This should probably be somewhere else */ 839 void (*trap_table[ARM_EXCPT_NUM])(void *) = { 840 NULL, 841 NULL, 842 NULL, 843 NULL, 844 NULL, 845 NULL, 846 NULL, 847 NULL 848 }; 849 850 /* 851 * Welcome to the kernel. We need to make a fake version of the boot_ops and the 852 * boot_syscalls and then jump our way to _kobj_boot(). Here, we're borrowing 853 * the Linux bootloader expectations, mostly because a lot of bootloaders and 854 * boards already do this. If it turns out that we want to abstract this in the 855 * future, then we should have locore.s do that before we get here. 856 */ 857 void 858 _fakebop_start(void *zeros, uint32_t machid, void *tagstart) 859 { 860 atag_illumos_status_t *aisp; 861 bootinfo_t *bip = &bootinfo; 862 bootops_t *bops = &bootop; 863 extern void _kobj_boot(); 864 865 fakebop_getatags(tagstart); 866 bcons_init(bip->bi_cmdline); 867 868 /* Now that we have a console, we can usefully handle traps */ 869 trap_table[ARM_EXCPT_RESET] = primordial_reset; 870 trap_table[ARM_EXCPT_UNDINS] = primordial_undef; 871 trap_table[ARM_EXCPT_SVC] = primordial_svc; 872 trap_table[ARM_EXCPT_PREFETCH] = primordial_prefetchabt; 873 trap_table[ARM_EXCPT_DATA] = primordial_dataabt; 874 trap_table[ARM_EXCPT_IRQ] = bad_interrupt; 875 trap_table[ARM_EXCPT_FIQ] = bad_interrupt; 876 877 bop_printf(NULL, "Testing some exceptions\n"); 878 __asm__ __volatile__(".word 0xffffffff"); 879 __asm__ __volatile__("svc #14"); 880 /* the high and low bit in each field, so we can check the decode */ 881 __asm__ __volatile__("bkpt #32793"); 882 883 /* Clear some lines from the bootloader */ 884 bop_printf(NULL, "\nWelcome to fakebop -- ARM edition\n"); 885 if (fakebop_atag_debug != 0) 886 fakebop_dump_tags(tagstart); 887 888 aisp = (atag_illumos_status_t *)atag_find(tagstart, 889 ATAG_ILLUMOS_STATUS); 890 if (aisp == NULL) 891 bop_panic("missing ATAG_ILLUMOS_STATUS!\n"); 892 893 /* 894 * Fill in the bootops vector 895 */ 896 bops->bsys_version = BO_VERSION; 897 bops->bsys_alloc = fakebop_alloc; 898 bops->bsys_free = fakebop_free; 899 bops->bsys_getproplen = fakebop_getproplen; 900 bops->bsys_getprop = fakebop_getprop; 901 bops->bsys_printf = bop_printf; 902 903 armboot_mmu_init(tagstart); 904 fakebop_alloc_init(tagstart); 905 fakebop_bootprops_init(); 906 bop_printf(NULL, "booting into _kobj\n"); 907 908 /* 909 * krtld uses _stext, _etext, _sdata, and _edata as part of its segment 910 * brks. ARM is a bit different from other versions of unix because we 911 * have our exception vector in the binary at the top of our address 912 * space. As such, we basically pass in values to krtld that represent 913 * what our _etext and _edata would have looked like if not for the 914 * exception vector. 915 */ 916 _kobj_boot(&bop_sysp, NULL, bops, aisp->ais_stext, aisp->ais_etext, 917 aisp->ais_sdata, aisp->ais_edata, EXCEPTION_ADDRESS); 918 919 bop_panic("Returned from kobj_init\n"); 920 } 921 922 void 923 _fakebop_locore_start(struct boot_syscalls *sysp, struct bootops *bops) 924 { 925 bop_panic("Somehow made it back to fakebop_locore_start..."); 926 }