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