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