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