1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Copyright (c) 2010, Intel Corporation.
27 * All rights reserved.
28 *
29 * Copyright 2013 Joyent, Inc. All rights reserved.
30 */
31
32 /*
33 * This file contains the functionality that mimics the boot operations
34 * on SPARC systems or the old boot.bin/multiboot programs on x86 systems.
35 * The x86 kernel now does everything on its own.
36 */
37
38 #include <sys/types.h>
39 #include <sys/bootconf.h>
40 #include <sys/bootsvcs.h>
41 #include <sys/bootinfo.h>
42 #include <sys/multiboot.h>
43 #include <sys/bootvfs.h>
44 #include <sys/bootprops.h>
45 #include <sys/varargs.h>
46 #include <sys/param.h>
47 #include <sys/machparam.h>
48 #include <sys/machsystm.h>
49 #include <sys/archsystm.h>
50 #include <sys/boot_console.h>
51 #include <sys/cmn_err.h>
52 #include <sys/systm.h>
53 #include <sys/promif.h>
54 #include <sys/archsystm.h>
55 #include <sys/x86_archext.h>
56 #include <sys/kobj.h>
57 #include <sys/privregs.h>
58 #include <sys/sysmacros.h>
59 #include <sys/ctype.h>
60 #include <sys/fastboot.h>
61 #ifdef __xpv
62 #include <sys/hypervisor.h>
63 #include <net/if.h>
64 #endif
65 #include <vm/kboot_mmu.h>
66 #include <vm/hat_pte.h>
67 #include <sys/kobj.h>
68 #include <sys/kobj_lex.h>
69 #include <sys/pci_cfgspace_impl.h>
70 #include <sys/fastboot_impl.h>
71 #include <sys/acpi/acconfig.h>
72 #include <sys/acpi/acpi.h>
73
74 static int have_console = 0; /* set once primitive console is initialized */
75 static char *boot_args = "";
76
77 /*
78 * Debugging macros
79 */
80 static uint_t kbm_debug = 0;
81 #define DBG_MSG(s) { if (kbm_debug) bop_printf(NULL, "%s", s); }
82 #define DBG(x) { if (kbm_debug) \
83 bop_printf(NULL, "%s is %" PRIx64 "\n", #x, (uint64_t)(x)); \
84 }
85
86 #define PUT_STRING(s) { \
87 char *cp; \
88 for (cp = (s); *cp; ++cp) \
89 bcons_putchar(*cp); \
90 }
91
92 bootops_t bootop; /* simple bootops we'll pass on to kernel */
93 struct bsys_mem bm;
94
95 /*
96 * Boot info from "glue" code in low memory. xbootp is used by:
97 * do_bop_phys_alloc(), do_bsys_alloc() and boot_prop_finish().
98 */
99 static struct xboot_info *xbootp;
100 static uintptr_t next_virt; /* next available virtual address */
101 static paddr_t next_phys; /* next available physical address from dboot */
102 static paddr_t high_phys = -(paddr_t)1; /* last used physical address */
103
104 /*
105 * buffer for vsnprintf for console I/O
106 */
107 #define BUFFERSIZE 512
108 static char buffer[BUFFERSIZE];
109
110 /*
111 * stuff to store/report/manipulate boot property settings.
112 */
113 typedef struct bootprop {
114 struct bootprop *bp_next;
115 char *bp_name;
116 uint_t bp_vlen;
117 char *bp_value;
118 } bootprop_t;
119
120 static bootprop_t *bprops = NULL;
121 static char *curr_page = NULL; /* ptr to avail bprop memory */
122 static int curr_space = 0; /* amount of memory at curr_page */
123
124 #ifdef __xpv
125 start_info_t *xen_info;
126 shared_info_t *HYPERVISOR_shared_info;
127 #endif
128
129 /*
130 * some allocator statistics
131 */
132 static ulong_t total_bop_alloc_scratch = 0;
133 static ulong_t total_bop_alloc_kernel = 0;
134
135 static void build_firmware_properties(void);
136
137 static int early_allocation = 1;
138
139 int force_fastreboot = 0;
140 volatile int fastreboot_onpanic = 0;
141 int post_fastreboot = 0;
142 #ifdef __xpv
143 volatile int fastreboot_capable = 0;
144 boolean_t bios_calls_available = B_FALSE;
145 #else
146 volatile int fastreboot_capable = 1;
147 boolean_t bios_calls_available = B_TRUE;
148 #endif
149
150 /*
151 * Information saved from current boot for fast reboot.
152 * If the information size exceeds what we have allocated, fast reboot
153 * will not be supported.
154 */
155 multiboot_info_t saved_mbi;
156 mb_memory_map_t saved_mmap[FASTBOOT_SAVED_MMAP_COUNT];
157 uint8_t saved_drives[FASTBOOT_SAVED_DRIVES_SIZE];
158 char saved_cmdline[FASTBOOT_SAVED_CMDLINE_LEN];
159 int saved_cmdline_len = 0;
160 size_t saved_file_size[FASTBOOT_MAX_FILES_MAP];
161
162 /*
163 * Turn off fastreboot_onpanic to avoid panic loop.
164 */
165 char fastreboot_onpanic_cmdline[FASTBOOT_SAVED_CMDLINE_LEN];
166 static const char fastreboot_onpanic_args[] = " -B fastreboot_onpanic=0";
167
168 /*
169 * Pointers to where System Resource Affinity Table (SRAT), System Locality
170 * Information Table (SLIT) and Maximum System Capability Table (MSCT)
171 * are mapped into virtual memory
172 */
173 ACPI_TABLE_SRAT *srat_ptr = NULL;
174 ACPI_TABLE_SLIT *slit_ptr = NULL;
175 ACPI_TABLE_MSCT *msct_ptr = NULL;
176
177 /*
178 * Arbitrary limit on number of localities we handle; if
179 * this limit is raised to more than UINT16_MAX, make sure
180 * process_slit() knows how to handle it.
181 */
182 #define SLIT_LOCALITIES_MAX (4096)
183
184 #define SLIT_NUM_PROPNAME "acpi-slit-localities"
185 #define SLIT_PROPNAME "acpi-slit"
186
187 /*
188 * Allocate aligned physical memory at boot time. This allocator allocates
189 * from the highest possible addresses. This avoids exhausting memory that
190 * would be useful for DMA buffers.
191 */
192 paddr_t
193 do_bop_phys_alloc(uint64_t size, uint64_t align)
194 {
195 paddr_t pa = 0;
196 paddr_t start;
197 paddr_t end;
198 struct memlist *ml = (struct memlist *)xbootp->bi_phys_install;
199
200 /*
201 * Be careful if high memory usage is limited in startup.c
202 * Since there are holes in the low part of the physical address
203 * space we can treat physmem as a pfn (not just a pgcnt) and
204 * get a conservative upper limit.
205 */
206 if (physmem != 0 && high_phys > pfn_to_pa(physmem))
207 high_phys = pfn_to_pa(physmem);
208
209 /*
210 * find the lowest or highest available memory in physinstalled
211 * On 32 bit avoid physmem above 4Gig if PAE isn't enabled
212 */
213 #if defined(__i386)
214 if (xbootp->bi_use_pae == 0 && high_phys > FOUR_GIG)
215 high_phys = FOUR_GIG;
216 #endif
217
218 /*
219 * find the highest available memory in physinstalled
220 */
221 size = P2ROUNDUP(size, align);
222 for (; ml; ml = ml->ml_next) {
223 start = P2ROUNDUP(ml->ml_address, align);
224 end = P2ALIGN(ml->ml_address + ml->ml_size, align);
225 if (start < next_phys)
226 start = P2ROUNDUP(next_phys, align);
227 if (end > high_phys)
228 end = P2ALIGN(high_phys, align);
229
230 if (end <= start)
231 continue;
232 if (end - start < size)
233 continue;
234
235 /*
236 * Early allocations need to use low memory, since
237 * physmem might be further limited by bootenv.rc
238 */
239 if (early_allocation) {
240 if (pa == 0 || start < pa)
241 pa = start;
242 } else {
243 if (end - size > pa)
244 pa = end - size;
245 }
246 }
247 if (pa != 0) {
248 if (early_allocation)
249 next_phys = pa + size;
250 else
251 high_phys = pa;
252 return (pa);
253 }
254 bop_panic("do_bop_phys_alloc(0x%" PRIx64 ", 0x%" PRIx64
255 ") Out of memory\n", size, align);
256 /*NOTREACHED*/
257 }
258
259 uintptr_t
260 alloc_vaddr(size_t size, paddr_t align)
261 {
262 uintptr_t rv;
263
264 next_virt = P2ROUNDUP(next_virt, (uintptr_t)align);
265 rv = (uintptr_t)next_virt;
266 next_virt += size;
267 return (rv);
268 }
269
270 /*
271 * Allocate virtual memory. The size is always rounded up to a multiple
272 * of base pagesize.
273 */
274
275 /*ARGSUSED*/
276 static caddr_t
277 do_bsys_alloc(bootops_t *bop, caddr_t virthint, size_t size, int align)
278 {
279 paddr_t a = align; /* same type as pa for masking */
280 uint_t pgsize;
281 paddr_t pa;
282 uintptr_t va;
283 ssize_t s; /* the aligned size */
284 uint_t level;
285 uint_t is_kernel = (virthint != 0);
286
287 if (a < MMU_PAGESIZE)
288 a = MMU_PAGESIZE;
289 else if (!ISP2(a))
290 prom_panic("do_bsys_alloc() incorrect alignment");
291 size = P2ROUNDUP(size, MMU_PAGESIZE);
292
293 /*
294 * Use the next aligned virtual address if we weren't given one.
295 */
296 if (virthint == NULL) {
297 virthint = (caddr_t)alloc_vaddr(size, a);
298 total_bop_alloc_scratch += size;
299 } else {
300 total_bop_alloc_kernel += size;
301 }
302
303 /*
304 * allocate the physical memory
305 */
306 pa = do_bop_phys_alloc(size, a);
307
308 /*
309 * Add the mappings to the page tables, try large pages first.
310 */
311 va = (uintptr_t)virthint;
312 s = size;
313 level = 1;
314 pgsize = xbootp->bi_use_pae ? TWO_MEG : FOUR_MEG;
315 if (xbootp->bi_use_largepage && a == pgsize) {
316 while (IS_P2ALIGNED(pa, pgsize) && IS_P2ALIGNED(va, pgsize) &&
317 s >= pgsize) {
318 kbm_map(va, pa, level, is_kernel);
319 va += pgsize;
320 pa += pgsize;
321 s -= pgsize;
322 }
323 }
324
325 /*
326 * Map remaining pages use small mappings
327 */
328 level = 0;
329 pgsize = MMU_PAGESIZE;
330 while (s > 0) {
331 kbm_map(va, pa, level, is_kernel);
332 va += pgsize;
333 pa += pgsize;
334 s -= pgsize;
335 }
336 return (virthint);
337 }
338
339 /*
340 * Free virtual memory - we'll just ignore these.
341 */
342 /*ARGSUSED*/
343 static void
344 do_bsys_free(bootops_t *bop, caddr_t virt, size_t size)
345 {
346 bop_printf(NULL, "do_bsys_free(virt=0x%p, size=0x%lx) ignored\n",
347 (void *)virt, size);
348 }
349
350 /*
351 * Old interface
352 */
353 /*ARGSUSED*/
354 static caddr_t
355 do_bsys_ealloc(bootops_t *bop, caddr_t virthint, size_t size,
356 int align, int flags)
357 {
358 prom_panic("unsupported call to BOP_EALLOC()\n");
359 return (0);
360 }
361
362
363 static void
364 bsetprop(char *name, int nlen, void *value, int vlen)
365 {
366 uint_t size;
367 uint_t need_size;
368 bootprop_t *b;
369
370 /*
371 * align the size to 16 byte boundary
372 */
373 size = sizeof (bootprop_t) + nlen + 1 + vlen;
374 size = (size + 0xf) & ~0xf;
375 if (size > curr_space) {
376 need_size = (size + (MMU_PAGEOFFSET)) & MMU_PAGEMASK;
377 curr_page = do_bsys_alloc(NULL, 0, need_size, MMU_PAGESIZE);
378 curr_space = need_size;
379 }
380
381 /*
382 * use a bootprop_t at curr_page and link into list
383 */
384 b = (bootprop_t *)curr_page;
385 curr_page += sizeof (bootprop_t);
386 curr_space -= sizeof (bootprop_t);
387 b->bp_next = bprops;
388 bprops = b;
389
390 /*
391 * follow by name and ending zero byte
392 */
393 b->bp_name = curr_page;
394 bcopy(name, curr_page, nlen);
395 curr_page += nlen;
396 *curr_page++ = 0;
397 curr_space -= nlen + 1;
398
399 /*
400 * copy in value, but no ending zero byte
401 */
402 b->bp_value = curr_page;
403 b->bp_vlen = vlen;
404 if (vlen > 0) {
405 bcopy(value, curr_page, vlen);
406 curr_page += vlen;
407 curr_space -= vlen;
408 }
409
410 /*
411 * align new values of curr_page, curr_space
412 */
413 while (curr_space & 0xf) {
414 ++curr_page;
415 --curr_space;
416 }
417 }
418
419 static void
420 bsetprops(char *name, char *value)
421 {
422 bsetprop(name, strlen(name), value, strlen(value) + 1);
423 }
424
425 static void
426 bsetprop64(char *name, uint64_t value)
427 {
428 bsetprop(name, strlen(name), (void *)&value, sizeof (value));
429 }
430
431 static void
432 bsetpropsi(char *name, int value)
433 {
434 char prop_val[32];
435
436 (void) snprintf(prop_val, sizeof (prop_val), "%d", value);
437 bsetprops(name, prop_val);
438 }
439
440 /*
441 * to find the size of the buffer to allocate
442 */
443 /*ARGSUSED*/
444 int
445 do_bsys_getproplen(bootops_t *bop, const char *name)
446 {
447 bootprop_t *b;
448
449 for (b = bprops; b; b = b->bp_next) {
450 if (strcmp(name, b->bp_name) != 0)
451 continue;
452 return (b->bp_vlen);
453 }
454 return (-1);
455 }
456
457 /*
458 * get the value associated with this name
459 */
460 /*ARGSUSED*/
461 int
462 do_bsys_getprop(bootops_t *bop, const char *name, void *value)
463 {
464 bootprop_t *b;
465
466 for (b = bprops; b; b = b->bp_next) {
467 if (strcmp(name, b->bp_name) != 0)
468 continue;
469 bcopy(b->bp_value, value, b->bp_vlen);
470 return (0);
471 }
472 return (-1);
473 }
474
475 /*
476 * get the name of the next property in succession from the standalone
477 */
478 /*ARGSUSED*/
479 static char *
480 do_bsys_nextprop(bootops_t *bop, char *name)
481 {
482 bootprop_t *b;
483
484 /*
485 * A null name is a special signal for the 1st boot property
486 */
487 if (name == NULL || strlen(name) == 0) {
488 if (bprops == NULL)
489 return (NULL);
490 return (bprops->bp_name);
491 }
492
493 for (b = bprops; b; b = b->bp_next) {
494 if (name != b->bp_name)
495 continue;
496 b = b->bp_next;
497 if (b == NULL)
498 return (NULL);
499 return (b->bp_name);
500 }
501 return (NULL);
502 }
503
504 /*
505 * Parse numeric value from a string. Understands decimal, hex, octal, - and ~
506 */
507 static int
508 parse_value(char *p, uint64_t *retval)
509 {
510 int adjust = 0;
511 uint64_t tmp = 0;
512 int digit;
513 int radix = 10;
514
515 *retval = 0;
516 if (*p == '-' || *p == '~')
517 adjust = *p++;
518
519 if (*p == '0') {
520 ++p;
521 if (*p == 0)
522 return (0);
523 if (*p == 'x' || *p == 'X') {
524 radix = 16;
525 ++p;
526 } else {
527 radix = 8;
528 ++p;
529 }
530 }
531 while (*p) {
532 if ('0' <= *p && *p <= '9')
533 digit = *p - '0';
534 else if ('a' <= *p && *p <= 'f')
535 digit = 10 + *p - 'a';
536 else if ('A' <= *p && *p <= 'F')
537 digit = 10 + *p - 'A';
538 else
539 return (-1);
540 if (digit >= radix)
541 return (-1);
542 tmp = tmp * radix + digit;
543 ++p;
544 }
545 if (adjust == '-')
546 tmp = -tmp;
547 else if (adjust == '~')
548 tmp = ~tmp;
549 *retval = tmp;
550 return (0);
551 }
552
553 static boolean_t
554 unprintable(char *value, int size)
555 {
556 int i;
557
558 if (size <= 0 || value[0] == '\0')
559 return (B_TRUE);
560
561 for (i = 0; i < size; i++) {
562 if (value[i] == '\0')
563 return (i != (size - 1));
564
565 if (!isprint(value[i]))
566 return (B_TRUE);
567 }
568 return (B_FALSE);
569 }
570
571 /*
572 * Print out information about all boot properties.
573 * buffer is pointer to pre-allocated space to be used as temporary
574 * space for property values.
575 */
576 static void
577 boot_prop_display(char *buffer)
578 {
579 char *name = "";
580 int i, len;
581
582 bop_printf(NULL, "\nBoot properties:\n");
583
584 while ((name = do_bsys_nextprop(NULL, name)) != NULL) {
585 bop_printf(NULL, "\t0x%p %s = ", (void *)name, name);
586 (void) do_bsys_getprop(NULL, name, buffer);
587 len = do_bsys_getproplen(NULL, name);
588 bop_printf(NULL, "len=%d ", len);
589 if (!unprintable(buffer, len)) {
590 buffer[len] = 0;
591 bop_printf(NULL, "%s\n", buffer);
592 continue;
593 }
594 for (i = 0; i < len; i++) {
595 bop_printf(NULL, "%02x", buffer[i] & 0xff);
596 if (i < len - 1)
597 bop_printf(NULL, ".");
598 }
599 bop_printf(NULL, "\n");
600 }
601 }
602
603 /*
604 * 2nd part of building the table of boot properties. This includes:
605 * - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values)
606 *
607 * lines look like one of:
608 * ^$
609 * ^# comment till end of line
610 * setprop name 'value'
611 * setprop name value
612 * setprop name "value"
613 *
614 * we do single character I/O since this is really just looking at memory
615 */
616 void
617 boot_prop_finish(void)
618 {
619 int fd;
620 char *line;
621 int c;
622 int bytes_read;
623 char *name;
624 int n_len;
625 char *value;
626 int v_len;
627 char *inputdev; /* these override the command line if serial ports */
628 char *outputdev;
629 char *consoledev;
630 uint64_t lvalue;
631 int use_xencons = 0;
632
633 #ifdef __xpv
634 if (!DOMAIN_IS_INITDOMAIN(xen_info))
635 use_xencons = 1;
636 #endif /* __xpv */
637
638 DBG_MSG("Opening /boot/solaris/bootenv.rc\n");
639 fd = BRD_OPEN(bfs_ops, "/boot/solaris/bootenv.rc", 0);
640 DBG(fd);
641
642 line = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
643 while (fd >= 0) {
644
645 /*
646 * get a line
647 */
648 for (c = 0; ; ++c) {
649 bytes_read = BRD_READ(bfs_ops, fd, line + c, 1);
650 if (bytes_read == 0) {
651 if (c == 0)
652 goto done;
653 break;
654 }
655 if (line[c] == '\n')
656 break;
657 }
658 line[c] = 0;
659
660 /*
661 * ignore comment lines
662 */
663 c = 0;
664 while (ISSPACE(line[c]))
665 ++c;
666 if (line[c] == '#' || line[c] == 0)
667 continue;
668
669 /*
670 * must have "setprop " or "setprop\t"
671 */
672 if (strncmp(line + c, "setprop ", 8) != 0 &&
673 strncmp(line + c, "setprop\t", 8) != 0)
674 continue;
675 c += 8;
676 while (ISSPACE(line[c]))
677 ++c;
678 if (line[c] == 0)
679 continue;
680
681 /*
682 * gather up the property name
683 */
684 name = line + c;
685 n_len = 0;
686 while (line[c] && !ISSPACE(line[c]))
687 ++n_len, ++c;
688
689 /*
690 * gather up the value, if any
691 */
692 value = "";
693 v_len = 0;
694 while (ISSPACE(line[c]))
695 ++c;
696 if (line[c] != 0) {
697 value = line + c;
698 while (line[c] && !ISSPACE(line[c]))
699 ++v_len, ++c;
700 }
701
702 if (v_len >= 2 && value[0] == value[v_len - 1] &&
703 (value[0] == '\'' || value[0] == '"')) {
704 ++value;
705 v_len -= 2;
706 }
707 name[n_len] = 0;
708 if (v_len > 0)
709 value[v_len] = 0;
710 else
711 continue;
712
713 /*
714 * ignore "boot-file" property, it's now meaningless
715 */
716 if (strcmp(name, "boot-file") == 0)
717 continue;
718 if (strcmp(name, "boot-args") == 0 &&
719 strlen(boot_args) > 0)
720 continue;
721
722 /*
723 * If a property was explicitly set on the command line
724 * it will override a setting in bootenv.rc
725 */
726 if (do_bsys_getproplen(NULL, name) > 0)
727 continue;
728
729 bsetprop(name, n_len, value, v_len + 1);
730 }
731 done:
732 if (fd >= 0)
733 (void) BRD_CLOSE(bfs_ops, fd);
734
735 /*
736 * Check if we have to limit the boot time allocator
737 */
738 if (do_bsys_getproplen(NULL, "physmem") != -1 &&
739 do_bsys_getprop(NULL, "physmem", line) >= 0 &&
740 parse_value(line, &lvalue) != -1) {
741 if (0 < lvalue && (lvalue < physmem || physmem == 0)) {
742 physmem = (pgcnt_t)lvalue;
743 DBG(physmem);
744 }
745 }
746 early_allocation = 0;
747
748 /*
749 * check to see if we have to override the default value of the console
750 */
751 if (!use_xencons) {
752 inputdev = line;
753 v_len = do_bsys_getproplen(NULL, "input-device");
754 if (v_len > 0)
755 (void) do_bsys_getprop(NULL, "input-device", inputdev);
756 else
757 v_len = 0;
758 inputdev[v_len] = 0;
759
760 outputdev = inputdev + v_len + 1;
761 v_len = do_bsys_getproplen(NULL, "output-device");
762 if (v_len > 0)
763 (void) do_bsys_getprop(NULL, "output-device",
764 outputdev);
765 else
766 v_len = 0;
767 outputdev[v_len] = 0;
768
769 consoledev = outputdev + v_len + 1;
770 v_len = do_bsys_getproplen(NULL, "console");
771 if (v_len > 0) {
772 (void) do_bsys_getprop(NULL, "console", consoledev);
773 if (post_fastreboot &&
774 strcmp(consoledev, "graphics") == 0) {
775 bsetprops("console", "text");
776 v_len = strlen("text");
777 bcopy("text", consoledev, v_len);
778 }
779 } else {
780 v_len = 0;
781 }
782 consoledev[v_len] = 0;
783 bcons_init2(inputdev, outputdev, consoledev);
784 } else {
785 /*
786 * Ensure console property exists
787 * If not create it as "hypervisor"
788 */
789 v_len = do_bsys_getproplen(NULL, "console");
790 if (v_len < 0)
791 bsetprops("console", "hypervisor");
792 inputdev = outputdev = consoledev = "hypervisor";
793 bcons_init2(inputdev, outputdev, consoledev);
794 }
795
796 if (strstr((char *)xbootp->bi_cmdline, "prom_debug") || kbm_debug)
797 boot_prop_display(line);
798 }
799
800 /*
801 * print formatted output
802 */
803 /*PRINTFLIKE2*/
804 /*ARGSUSED*/
805 void
806 bop_printf(bootops_t *bop, const char *fmt, ...)
807 {
808 va_list ap;
809
810 if (have_console == 0)
811 return;
812
813 va_start(ap, fmt);
814 (void) vsnprintf(buffer, BUFFERSIZE, fmt, ap);
815 va_end(ap);
816 PUT_STRING(buffer);
817 }
818
819 /*
820 * Another panic() variant; this one can be used even earlier during boot than
821 * prom_panic().
822 */
823 /*PRINTFLIKE1*/
824 void
825 bop_panic(const char *fmt, ...)
826 {
827 va_list ap;
828
829 va_start(ap, fmt);
830 bop_printf(NULL, fmt, ap);
831 va_end(ap);
832
833 bop_printf(NULL, "\nPress any key to reboot.\n");
834 (void) bcons_getchar();
835 bop_printf(NULL, "Resetting...\n");
836 pc_reset();
837 }
838
839 /*
840 * Do a real mode interrupt BIOS call
841 */
842 typedef struct bios_regs {
843 unsigned short ax, bx, cx, dx, si, di, bp, es, ds;
844 } bios_regs_t;
845 typedef int (*bios_func_t)(int, bios_regs_t *);
846
847 /*ARGSUSED*/
848 static void
849 do_bsys_doint(bootops_t *bop, int intnum, struct bop_regs *rp)
850 {
851 #if defined(__xpv)
852 prom_panic("unsupported call to BOP_DOINT()\n");
853 #else /* __xpv */
854 static int firsttime = 1;
855 bios_func_t bios_func = (bios_func_t)(void *)(uintptr_t)0x5000;
856 bios_regs_t br;
857
858 /*
859 * The first time we do this, we have to copy the pre-packaged
860 * low memory bios call code image into place.
861 */
862 if (firsttime) {
863 extern char bios_image[];
864 extern uint32_t bios_size;
865
866 bcopy(bios_image, (void *)bios_func, bios_size);
867 firsttime = 0;
868 }
869
870 br.ax = rp->eax.word.ax;
871 br.bx = rp->ebx.word.bx;
872 br.cx = rp->ecx.word.cx;
873 br.dx = rp->edx.word.dx;
874 br.bp = rp->ebp.word.bp;
875 br.si = rp->esi.word.si;
876 br.di = rp->edi.word.di;
877 br.ds = rp->ds;
878 br.es = rp->es;
879
880 DBG_MSG("Doing BIOS call...");
881 DBG(br.ax);
882 DBG(br.bx);
883 DBG(br.dx);
884 rp->eflags = bios_func(intnum, &br);
885 DBG_MSG("done\n");
886
887 rp->eax.word.ax = br.ax;
888 rp->ebx.word.bx = br.bx;
889 rp->ecx.word.cx = br.cx;
890 rp->edx.word.dx = br.dx;
891 rp->ebp.word.bp = br.bp;
892 rp->esi.word.si = br.si;
893 rp->edi.word.di = br.di;
894 rp->ds = br.ds;
895 rp->es = br.es;
896 #endif /* __xpv */
897 }
898
899 static struct boot_syscalls bop_sysp = {
900 bcons_getchar,
901 bcons_putchar,
902 bcons_ischar,
903 };
904
905 static char *whoami;
906
907 #define BUFLEN 64
908
909 #if defined(__xpv)
910
911 static char namebuf[32];
912
913 static void
914 xen_parse_props(char *s, char *prop_map[], int n_prop)
915 {
916 char **prop_name = prop_map;
917 char *cp = s, *scp;
918
919 do {
920 scp = cp;
921 while ((*cp != NULL) && (*cp != ':'))
922 cp++;
923
924 if ((scp != cp) && (*prop_name != NULL)) {
925 *cp = NULL;
926 bsetprops(*prop_name, scp);
927 }
928
929 cp++;
930 prop_name++;
931 n_prop--;
932 } while (n_prop > 0);
933 }
934
935 #define VBDPATHLEN 64
936
937 /*
938 * parse the 'xpv-root' property to create properties used by
939 * ufs_mountroot.
940 */
941 static void
942 xen_vbdroot_props(char *s)
943 {
944 char vbdpath[VBDPATHLEN] = "/xpvd/xdf@";
945 const char lnamefix[] = "/dev/dsk/c0d";
946 char *pnp;
947 char *prop_p;
948 char mi;
949 short minor;
950 long addr = 0;
951
952 pnp = vbdpath + strlen(vbdpath);
953 prop_p = s + strlen(lnamefix);
954 while ((*prop_p != '\0') && (*prop_p != 's') && (*prop_p != 'p'))
955 addr = addr * 10 + *prop_p++ - '0';
956 (void) snprintf(pnp, VBDPATHLEN, "%lx", addr);
957 pnp = vbdpath + strlen(vbdpath);
958 if (*prop_p == 's')
959 mi = 'a';
960 else if (*prop_p == 'p')
961 mi = 'q';
962 else
963 ASSERT(0); /* shouldn't be here */
964 prop_p++;
965 ASSERT(*prop_p != '\0');
966 if (ISDIGIT(*prop_p)) {
967 minor = *prop_p - '0';
968 prop_p++;
969 if (ISDIGIT(*prop_p)) {
970 minor = minor * 10 + *prop_p - '0';
971 }
972 } else {
973 /* malformed root path, use 0 as default */
974 minor = 0;
975 }
976 ASSERT(minor < 16); /* at most 16 partitions */
977 mi += minor;
978 *pnp++ = ':';
979 *pnp++ = mi;
980 *pnp++ = '\0';
981 bsetprops("fstype", "ufs");
982 bsetprops("bootpath", vbdpath);
983
984 DBG_MSG("VBD bootpath set to ");
985 DBG_MSG(vbdpath);
986 DBG_MSG("\n");
987 }
988
989 /*
990 * parse the xpv-nfsroot property to create properties used by
991 * nfs_mountroot.
992 */
993 static void
994 xen_nfsroot_props(char *s)
995 {
996 char *prop_map[] = {
997 BP_SERVER_IP, /* server IP address */
998 BP_SERVER_NAME, /* server hostname */
999 BP_SERVER_PATH, /* root path */
1000 };
1001 int n_prop = sizeof (prop_map) / sizeof (prop_map[0]);
1002
1003 bsetprop("fstype", 6, "nfs", 4);
1004
1005 xen_parse_props(s, prop_map, n_prop);
1006
1007 /*
1008 * If a server name wasn't specified, use a default.
1009 */
1010 if (do_bsys_getproplen(NULL, BP_SERVER_NAME) == -1)
1011 bsetprops(BP_SERVER_NAME, "unknown");
1012 }
1013
1014 /*
1015 * Extract our IP address, etc. from the "xpv-ip" property.
1016 */
1017 static void
1018 xen_ip_props(char *s)
1019 {
1020 char *prop_map[] = {
1021 BP_HOST_IP, /* IP address */
1022 NULL, /* NFS server IP address (ignored in */
1023 /* favour of xpv-nfsroot) */
1024 BP_ROUTER_IP, /* IP gateway */
1025 BP_SUBNET_MASK, /* IP subnet mask */
1026 "xpv-hostname", /* hostname (ignored) */
1027 BP_NETWORK_INTERFACE, /* interface name */
1028 "xpv-hcp", /* host configuration protocol */
1029 };
1030 int n_prop = sizeof (prop_map) / sizeof (prop_map[0]);
1031 char ifname[IFNAMSIZ];
1032
1033 xen_parse_props(s, prop_map, n_prop);
1034
1035 /*
1036 * A Linux dom0 administrator expects all interfaces to be
1037 * called "ethX", which is not the case here.
1038 *
1039 * If the interface name specified is "eth0", presume that
1040 * this is really intended to be "xnf0" (the first domU ->
1041 * dom0 interface for this domain).
1042 */
1043 if ((do_bsys_getprop(NULL, BP_NETWORK_INTERFACE, ifname) == 0) &&
1044 (strcmp("eth0", ifname) == 0)) {
1045 bsetprops(BP_NETWORK_INTERFACE, "xnf0");
1046 bop_printf(NULL,
1047 "network interface name 'eth0' replaced with 'xnf0'\n");
1048 }
1049 }
1050
1051 #else /* __xpv */
1052
1053 static void
1054 setup_rarp_props(struct sol_netinfo *sip)
1055 {
1056 char buf[BUFLEN]; /* to hold ip/mac addrs */
1057 uint8_t *val;
1058
1059 val = (uint8_t *)&sip->sn_ciaddr;
1060 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
1061 val[0], val[1], val[2], val[3]);
1062 bsetprops(BP_HOST_IP, buf);
1063
1064 val = (uint8_t *)&sip->sn_siaddr;
1065 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
1066 val[0], val[1], val[2], val[3]);
1067 bsetprops(BP_SERVER_IP, buf);
1068
1069 if (sip->sn_giaddr != 0) {
1070 val = (uint8_t *)&sip->sn_giaddr;
1071 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
1072 val[0], val[1], val[2], val[3]);
1073 bsetprops(BP_ROUTER_IP, buf);
1074 }
1075
1076 if (sip->sn_netmask != 0) {
1077 val = (uint8_t *)&sip->sn_netmask;
1078 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
1079 val[0], val[1], val[2], val[3]);
1080 bsetprops(BP_SUBNET_MASK, buf);
1081 }
1082
1083 if (sip->sn_mactype != 4 || sip->sn_maclen != 6) {
1084 bop_printf(NULL, "unsupported mac type %d, mac len %d\n",
1085 sip->sn_mactype, sip->sn_maclen);
1086 } else {
1087 val = sip->sn_macaddr;
1088 (void) snprintf(buf, BUFLEN, "%x:%x:%x:%x:%x:%x",
1089 val[0], val[1], val[2], val[3], val[4], val[5]);
1090 bsetprops(BP_BOOT_MAC, buf);
1091 }
1092 }
1093
1094 #endif /* __xpv */
1095
1096 static void
1097 build_panic_cmdline(const char *cmd, int cmdlen)
1098 {
1099 int proplen;
1100 size_t arglen;
1101
1102 arglen = sizeof (fastreboot_onpanic_args);
1103 /*
1104 * If we allready have fastreboot-onpanic set to zero,
1105 * don't add them again.
1106 */
1107 if ((proplen = do_bsys_getproplen(NULL, FASTREBOOT_ONPANIC)) > 0 &&
1108 proplen <= sizeof (fastreboot_onpanic_cmdline)) {
1109 (void) do_bsys_getprop(NULL, FASTREBOOT_ONPANIC,
1110 fastreboot_onpanic_cmdline);
1111 if (FASTREBOOT_ONPANIC_NOTSET(fastreboot_onpanic_cmdline))
1112 arglen = 1;
1113 }
1114
1115 /*
1116 * construct fastreboot_onpanic_cmdline
1117 */
1118 if (cmdlen + arglen > sizeof (fastreboot_onpanic_cmdline)) {
1119 DBG_MSG("Command line too long: clearing "
1120 FASTREBOOT_ONPANIC "\n");
1121 fastreboot_onpanic = 0;
1122 } else {
1123 bcopy(cmd, fastreboot_onpanic_cmdline, cmdlen);
1124 if (arglen != 1)
1125 bcopy(fastreboot_onpanic_args,
1126 fastreboot_onpanic_cmdline + cmdlen, arglen);
1127 else
1128 fastreboot_onpanic_cmdline[cmdlen] = 0;
1129 }
1130 }
1131
1132
1133 #ifndef __xpv
1134 /*
1135 * Construct boot command line for Fast Reboot
1136 */
1137 static void
1138 build_fastboot_cmdline(struct xboot_info *xbp)
1139 {
1140 saved_cmdline_len = strlen(xbp->bi_cmdline) + 1;
1141 if (saved_cmdline_len > FASTBOOT_SAVED_CMDLINE_LEN) {
1142 DBG(saved_cmdline_len);
1143 DBG_MSG("Command line too long: clearing fastreboot_capable\n");
1144 fastreboot_capable = 0;
1145 } else {
1146 bcopy((void *)(xbp->bi_cmdline), (void *)saved_cmdline,
1147 saved_cmdline_len);
1148 saved_cmdline[saved_cmdline_len - 1] = '\0';
1149 build_panic_cmdline(saved_cmdline, saved_cmdline_len - 1);
1150 }
1151 }
1152
1153 /*
1154 * Save memory layout, disk drive information, unix and boot archive sizes for
1155 * Fast Reboot.
1156 */
1157 static void
1158 save_boot_info(struct xboot_info *xbi)
1159 {
1160 multiboot_info_t *mbi = xbi->bi_mb_info;
1161 struct boot_modules *modp;
1162 int i;
1163
1164 bcopy(mbi, &saved_mbi, sizeof (multiboot_info_t));
1165 if (mbi->mmap_length > sizeof (saved_mmap)) {
1166 DBG_MSG("mbi->mmap_length too big: clearing "
1167 "fastreboot_capable\n");
1168 fastreboot_capable = 0;
1169 } else {
1170 bcopy((void *)(uintptr_t)mbi->mmap_addr, (void *)saved_mmap,
1171 mbi->mmap_length);
1172 }
1173
1174 if ((mbi->flags & MB_INFO_DRIVE_INFO) != 0) {
1175 if (mbi->drives_length > sizeof (saved_drives)) {
1176 DBG(mbi->drives_length);
1177 DBG_MSG("mbi->drives_length too big: clearing "
1178 "fastreboot_capable\n");
1179 fastreboot_capable = 0;
1180 } else {
1181 bcopy((void *)(uintptr_t)mbi->drives_addr,
1182 (void *)saved_drives, mbi->drives_length);
1183 }
1184 } else {
1185 saved_mbi.drives_length = 0;
1186 saved_mbi.drives_addr = NULL;
1187 }
1188
1189 /*
1190 * Current file sizes. Used by fastboot.c to figure out how much
1191 * memory to reserve for panic reboot.
1192 * Use the module list from the dboot-constructed xboot_info
1193 * instead of the list referenced by the multiboot structure
1194 * because that structure may not be addressable now.
1195 */
1196 saved_file_size[FASTBOOT_NAME_UNIX] = FOUR_MEG - PAGESIZE;
1197 for (i = 0, modp = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
1198 i < xbi->bi_module_cnt; i++, modp++) {
1199 saved_file_size[FASTBOOT_NAME_BOOTARCHIVE] += modp->bm_size;
1200 }
1201 }
1202 #endif /* __xpv */
1203
1204
1205 /*
1206 * 1st pass at building the table of boot properties. This includes:
1207 * - values set on the command line: -B a=x,b=y,c=z ....
1208 * - known values we just compute (ie. from xbp)
1209 * - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values)
1210 *
1211 * the grub command line looked like:
1212 * kernel boot-file [-B prop=value[,prop=value]...] [boot-args]
1213 *
1214 * whoami is the same as boot-file
1215 */
1216 static void
1217 build_boot_properties(struct xboot_info *xbp)
1218 {
1219 char *name;
1220 int name_len;
1221 char *value;
1222 int value_len;
1223 struct boot_modules *bm, *rdbm;
1224 char *propbuf;
1225 int quoted = 0;
1226 int boot_arg_len;
1227 uint_t i, midx;
1228 char modid[32];
1229 #ifndef __xpv
1230 static int stdout_val = 0;
1231 uchar_t boot_device;
1232 char str[3];
1233 multiboot_info_t *mbi;
1234 int netboot;
1235 struct sol_netinfo *sip;
1236 #endif
1237
1238 /*
1239 * These have to be done first, so that kobj_mount_root() works
1240 */
1241 DBG_MSG("Building boot properties\n");
1242 propbuf = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, 0);
1243 DBG((uintptr_t)propbuf);
1244 if (xbp->bi_module_cnt > 0) {
1245 bm = xbp->bi_modules;
1246 rdbm = NULL;
1247 for (midx = i = 0; i < xbp->bi_module_cnt; i++) {
1248 if (bm[i].bm_type == BMT_ROOTFS) {
1249 rdbm = &bm[i];
1250 continue;
1251 }
1252 if (bm[i].bm_type == BMT_HASH || bm[i].bm_name == NULL)
1253 continue;
1254
1255 (void) snprintf(modid, sizeof (modid),
1256 "module-name-%u", midx);
1257 bsetprops(modid, (char *)bm[i].bm_name);
1258 (void) snprintf(modid, sizeof (modid),
1259 "module-addr-%u", midx);
1260 bsetprop64(modid, (uint64_t)(uintptr_t)bm[i].bm_addr);
1261 (void) snprintf(modid, sizeof (modid),
1262 "module-size-%u", midx);
1263 bsetprop64(modid, (uint64_t)bm[i].bm_size);
1264 ++midx;
1265 }
1266 if (rdbm != NULL) {
1267 bsetprop64("ramdisk_start",
1268 (uint64_t)(uintptr_t)rdbm->bm_addr);
1269 bsetprop64("ramdisk_end",
1270 (uint64_t)(uintptr_t)rdbm->bm_addr + rdbm->bm_size);
1271 }
1272 }
1273
1274 /*
1275 * If there are any boot time modules or hashes present, then disable
1276 * fast reboot.
1277 */
1278 if (xbp->bi_module_cnt > 1) {
1279 fastreboot_disable(FBNS_BOOTMOD);
1280 }
1281
1282 DBG_MSG("Parsing command line for boot properties\n");
1283 value = xbp->bi_cmdline;
1284
1285 /*
1286 * allocate memory to collect boot_args into
1287 */
1288 boot_arg_len = strlen(xbp->bi_cmdline) + 1;
1289 boot_args = do_bsys_alloc(NULL, NULL, boot_arg_len, MMU_PAGESIZE);
1290 boot_args[0] = 0;
1291 boot_arg_len = 0;
1292
1293 #ifdef __xpv
1294 /*
1295 * Xen puts a lot of device information in front of the kernel name
1296 * let's grab them and make them boot properties. The first
1297 * string w/o an "=" in it will be the boot-file property.
1298 */
1299 (void) strcpy(namebuf, "xpv-");
1300 for (;;) {
1301 /*
1302 * get to next property
1303 */
1304 while (ISSPACE(*value))
1305 ++value;
1306 name = value;
1307 /*
1308 * look for an "="
1309 */
1310 while (*value && !ISSPACE(*value) && *value != '=') {
1311 value++;
1312 }
1313 if (*value != '=') { /* no "=" in the property */
1314 value = name;
1315 break;
1316 }
1317 name_len = value - name;
1318 value_len = 0;
1319 /*
1320 * skip over the "="
1321 */
1322 value++;
1323 while (value[value_len] && !ISSPACE(value[value_len])) {
1324 ++value_len;
1325 }
1326 /*
1327 * build property name with "xpv-" prefix
1328 */
1329 if (name_len + 4 > 32) { /* skip if name too long */
1330 value += value_len;
1331 continue;
1332 }
1333 bcopy(name, &namebuf[4], name_len);
1334 name_len += 4;
1335 namebuf[name_len] = 0;
1336 bcopy(value, propbuf, value_len);
1337 propbuf[value_len] = 0;
1338 bsetprops(namebuf, propbuf);
1339
1340 /*
1341 * xpv-root is set to the logical disk name of the xen
1342 * VBD when booting from a disk-based filesystem.
1343 */
1344 if (strcmp(namebuf, "xpv-root") == 0)
1345 xen_vbdroot_props(propbuf);
1346 /*
1347 * While we're here, if we have a "xpv-nfsroot" property
1348 * then we need to set "fstype" to "nfs" so we mount
1349 * our root from the nfs server. Also parse the xpv-nfsroot
1350 * property to create the properties that nfs_mountroot will
1351 * need to find the root and mount it.
1352 */
1353 if (strcmp(namebuf, "xpv-nfsroot") == 0)
1354 xen_nfsroot_props(propbuf);
1355
1356 if (strcmp(namebuf, "xpv-ip") == 0)
1357 xen_ip_props(propbuf);
1358 value += value_len;
1359 }
1360 #endif
1361
1362 while (ISSPACE(*value))
1363 ++value;
1364 /*
1365 * value now points at the boot-file
1366 */
1367 value_len = 0;
1368 while (value[value_len] && !ISSPACE(value[value_len]))
1369 ++value_len;
1370 if (value_len > 0) {
1371 whoami = propbuf;
1372 bcopy(value, whoami, value_len);
1373 whoami[value_len] = 0;
1374 bsetprops("boot-file", whoami);
1375 /*
1376 * strip leading path stuff from whoami, so running from
1377 * PXE/miniroot makes sense.
1378 */
1379 if (strstr(whoami, "/platform/") != NULL)
1380 whoami = strstr(whoami, "/platform/");
1381 bsetprops("whoami", whoami);
1382 }
1383
1384 /*
1385 * Values forcibly set boot properties on the command line via -B.
1386 * Allow use of quotes in values. Other stuff goes on kernel
1387 * command line.
1388 */
1389 name = value + value_len;
1390 while (*name != 0) {
1391 /*
1392 * anything not " -B" is copied to the command line
1393 */
1394 if (!ISSPACE(name[0]) || name[1] != '-' || name[2] != 'B') {
1395 boot_args[boot_arg_len++] = *name;
1396 boot_args[boot_arg_len] = 0;
1397 ++name;
1398 continue;
1399 }
1400
1401 /*
1402 * skip the " -B" and following white space
1403 */
1404 name += 3;
1405 while (ISSPACE(*name))
1406 ++name;
1407 while (*name && !ISSPACE(*name)) {
1408 value = strstr(name, "=");
1409 if (value == NULL)
1410 break;
1411 name_len = value - name;
1412 ++value;
1413 value_len = 0;
1414 quoted = 0;
1415 for (; ; ++value_len) {
1416 if (!value[value_len])
1417 break;
1418
1419 /*
1420 * is this value quoted?
1421 */
1422 if (value_len == 0 &&
1423 (value[0] == '\'' || value[0] == '"')) {
1424 quoted = value[0];
1425 ++value_len;
1426 }
1427
1428 /*
1429 * In the quote accept any character,
1430 * but look for ending quote.
1431 */
1432 if (quoted) {
1433 if (value[value_len] == quoted)
1434 quoted = 0;
1435 continue;
1436 }
1437
1438 /*
1439 * a comma or white space ends the value
1440 */
1441 if (value[value_len] == ',' ||
1442 ISSPACE(value[value_len]))
1443 break;
1444 }
1445
1446 if (value_len == 0) {
1447 bsetprop(name, name_len, "true", 5);
1448 } else {
1449 char *v = value;
1450 int l = value_len;
1451 if (v[0] == v[l - 1] &&
1452 (v[0] == '\'' || v[0] == '"')) {
1453 ++v;
1454 l -= 2;
1455 }
1456 bcopy(v, propbuf, l);
1457 propbuf[l] = '\0';
1458 bsetprop(name, name_len, propbuf,
1459 l + 1);
1460 }
1461 name = value + value_len;
1462 while (*name == ',')
1463 ++name;
1464 }
1465 }
1466
1467 /*
1468 * set boot-args property
1469 * 1275 name is bootargs, so set
1470 * that too
1471 */
1472 bsetprops("boot-args", boot_args);
1473 bsetprops("bootargs", boot_args);
1474
1475 #ifndef __xpv
1476 /*
1477 * set the BIOS boot device from GRUB
1478 */
1479 netboot = 0;
1480 mbi = xbp->bi_mb_info;
1481
1482 /*
1483 * Build boot command line for Fast Reboot
1484 */
1485 build_fastboot_cmdline(xbp);
1486
1487 /*
1488 * Save various boot information for Fast Reboot
1489 */
1490 save_boot_info(xbp);
1491
1492 if (mbi != NULL && mbi->flags & MB_INFO_BOOTDEV) {
1493 boot_device = mbi->boot_device >> 24;
1494 if (boot_device == 0x20)
1495 netboot++;
1496 str[0] = (boot_device >> 4) + '0';
1497 str[1] = (boot_device & 0xf) + '0';
1498 str[2] = 0;
1499 bsetprops("bios-boot-device", str);
1500 } else {
1501 netboot = 1;
1502 }
1503
1504 /*
1505 * In the netboot case, drives_info is overloaded with the dhcp ack.
1506 * This is not multiboot compliant and requires special pxegrub!
1507 */
1508 if (netboot && mbi->drives_length != 0) {
1509 sip = (struct sol_netinfo *)(uintptr_t)mbi->drives_addr;
1510 if (sip->sn_infotype == SN_TYPE_BOOTP)
1511 bsetprop("bootp-response", sizeof ("bootp-response"),
1512 (void *)(uintptr_t)mbi->drives_addr,
1513 mbi->drives_length);
1514 else if (sip->sn_infotype == SN_TYPE_RARP)
1515 setup_rarp_props(sip);
1516 }
1517 bsetprop("stdout", strlen("stdout"),
1518 &stdout_val, sizeof (stdout_val));
1519 #endif /* __xpv */
1520
1521 /*
1522 * more conjured up values for made up things....
1523 */
1524 #if defined(__xpv)
1525 bsetprops("mfg-name", "i86xpv");
1526 bsetprops("impl-arch-name", "i86xpv");
1527 #else
1528 bsetprops("mfg-name", "i86pc");
1529 bsetprops("impl-arch-name", "i86pc");
1530 #endif
1531
1532 /*
1533 * Build firmware-provided system properties
1534 */
1535 build_firmware_properties();
1536
1537 /*
1538 * XXPV
1539 *
1540 * Find out what these are:
1541 * - cpuid_feature_ecx_include
1542 * - cpuid_feature_ecx_exclude
1543 * - cpuid_feature_edx_include
1544 * - cpuid_feature_edx_exclude
1545 *
1546 * Find out what these are in multiboot:
1547 * - netdev-path
1548 * - fstype
1549 */
1550 }
1551
1552 #ifdef __xpv
1553 /*
1554 * Under the Hypervisor, memory usable for DMA may be scarce. One
1555 * very likely large pool of DMA friendly memory is occupied by
1556 * the boot_archive, as it was loaded by grub into low MFNs.
1557 *
1558 * Here we free up that memory by copying the boot archive to what are
1559 * likely higher MFN pages and then swapping the mfn/pfn mappings.
1560 */
1561 #define PFN_2GIG 0x80000
1562 static void
1563 relocate_boot_archive(struct xboot_info *xbp)
1564 {
1565 mfn_t max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
1566 struct boot_modules *bm = xbp->bi_modules;
1567 uintptr_t va;
1568 pfn_t va_pfn;
1569 mfn_t va_mfn;
1570 caddr_t copy;
1571 pfn_t copy_pfn;
1572 mfn_t copy_mfn;
1573 size_t len;
1574 int slop;
1575 int total = 0;
1576 int relocated = 0;
1577 int mmu_update_return;
1578 mmu_update_t t[2];
1579 x86pte_t pte;
1580
1581 /*
1582 * If all MFN's are below 2Gig, don't bother doing this.
1583 */
1584 if (max_mfn < PFN_2GIG)
1585 return;
1586 if (xbp->bi_module_cnt < 1) {
1587 DBG_MSG("no boot_archive!");
1588 return;
1589 }
1590
1591 DBG_MSG("moving boot_archive to high MFN memory\n");
1592 va = (uintptr_t)bm->bm_addr;
1593 len = bm->bm_size;
1594 slop = va & MMU_PAGEOFFSET;
1595 if (slop) {
1596 va += MMU_PAGESIZE - slop;
1597 len -= MMU_PAGESIZE - slop;
1598 }
1599 len = P2ALIGN(len, MMU_PAGESIZE);
1600
1601 /*
1602 * Go through all boot_archive pages, swapping any low MFN pages
1603 * with memory at next_phys.
1604 */
1605 while (len != 0) {
1606 ++total;
1607 va_pfn = mmu_btop(va - ONE_GIG);
1608 va_mfn = mfn_list[va_pfn];
1609 if (mfn_list[va_pfn] < PFN_2GIG) {
1610 copy = kbm_remap_window(next_phys, 1);
1611 bcopy((void *)va, copy, MMU_PAGESIZE);
1612 copy_pfn = mmu_btop(next_phys);
1613 copy_mfn = mfn_list[copy_pfn];
1614
1615 pte = mfn_to_ma(copy_mfn) | PT_NOCONSIST | PT_VALID;
1616 if (HYPERVISOR_update_va_mapping(va, pte,
1617 UVMF_INVLPG | UVMF_LOCAL))
1618 bop_panic("relocate_boot_archive(): "
1619 "HYPERVISOR_update_va_mapping() failed");
1620
1621 mfn_list[va_pfn] = copy_mfn;
1622 mfn_list[copy_pfn] = va_mfn;
1623
1624 t[0].ptr = mfn_to_ma(copy_mfn) | MMU_MACHPHYS_UPDATE;
1625 t[0].val = va_pfn;
1626 t[1].ptr = mfn_to_ma(va_mfn) | MMU_MACHPHYS_UPDATE;
1627 t[1].val = copy_pfn;
1628 if (HYPERVISOR_mmu_update(t, 2, &mmu_update_return,
1629 DOMID_SELF) != 0 || mmu_update_return != 2)
1630 bop_panic("relocate_boot_archive(): "
1631 "HYPERVISOR_mmu_update() failed");
1632
1633 next_phys += MMU_PAGESIZE;
1634 ++relocated;
1635 }
1636 len -= MMU_PAGESIZE;
1637 va += MMU_PAGESIZE;
1638 }
1639 DBG_MSG("Relocated pages:\n");
1640 DBG(relocated);
1641 DBG_MSG("Out of total pages:\n");
1642 DBG(total);
1643 }
1644 #endif /* __xpv */
1645
1646 #if !defined(__xpv)
1647 /*
1648 * Install a temporary IDT that lets us catch errors in the boot time code.
1649 * We shouldn't get any faults at all while this is installed, so we'll
1650 * just generate a traceback and exit.
1651 */
1652 #ifdef __amd64
1653 static const int bcode_sel = B64CODE_SEL;
1654 #else
1655 static const int bcode_sel = B32CODE_SEL;
1656 #endif
1657
1658 /*
1659 * simple description of a stack frame (args are 32 bit only currently)
1660 */
1661 typedef struct bop_frame {
1662 struct bop_frame *old_frame;
1663 pc_t retaddr;
1664 long arg[1];
1665 } bop_frame_t;
1666
1667 void
1668 bop_traceback(bop_frame_t *frame)
1669 {
1670 pc_t pc;
1671 int cnt;
1672 char *ksym;
1673 ulong_t off;
1674 #if defined(__i386)
1675 int a;
1676 #endif
1677
1678 bop_printf(NULL, "Stack traceback:\n");
1679 for (cnt = 0; cnt < 30; ++cnt) { /* up to 30 frames */
1680 pc = frame->retaddr;
1681 if (pc == 0)
1682 break;
1683 ksym = kobj_getsymname(pc, &off);
1684 if (ksym)
1685 bop_printf(NULL, " %s+%lx", ksym, off);
1686 else
1687 bop_printf(NULL, " 0x%lx", pc);
1688
1689 frame = frame->old_frame;
1690 if (frame == 0) {
1691 bop_printf(NULL, "\n");
1692 break;
1693 }
1694 #if defined(__i386)
1695 for (a = 0; a < 6; ++a) { /* try for 6 args */
1696 if ((void *)&frame->arg[a] == (void *)frame->old_frame)
1697 break;
1698 if (a == 0)
1699 bop_printf(NULL, "(");
1700 else
1701 bop_printf(NULL, ",");
1702 bop_printf(NULL, "0x%lx", frame->arg[a]);
1703 }
1704 bop_printf(NULL, ")");
1705 #endif
1706 bop_printf(NULL, "\n");
1707 }
1708 }
1709
1710 struct trapframe {
1711 ulong_t error_code; /* optional */
1712 ulong_t inst_ptr;
1713 ulong_t code_seg;
1714 ulong_t flags_reg;
1715 #ifdef __amd64
1716 ulong_t stk_ptr;
1717 ulong_t stk_seg;
1718 #endif
1719 };
1720
1721 void
1722 bop_trap(ulong_t *tfp)
1723 {
1724 struct trapframe *tf = (struct trapframe *)tfp;
1725 bop_frame_t fakeframe;
1726 static int depth = 0;
1727
1728 /*
1729 * Check for an infinite loop of traps.
1730 */
1731 if (++depth > 2)
1732 bop_panic("Nested trap");
1733
1734 bop_printf(NULL, "Unexpected trap\n");
1735
1736 /*
1737 * adjust the tf for optional error_code by detecting the code selector
1738 */
1739 if (tf->code_seg != bcode_sel)
1740 tf = (struct trapframe *)(tfp - 1);
1741 else
1742 bop_printf(NULL, "error code 0x%lx\n",
1743 tf->error_code & 0xffffffff);
1744
1745 bop_printf(NULL, "instruction pointer 0x%lx\n", tf->inst_ptr);
1746 bop_printf(NULL, "code segment 0x%lx\n", tf->code_seg & 0xffff);
1747 bop_printf(NULL, "flags register 0x%lx\n", tf->flags_reg);
1748 #ifdef __amd64
1749 bop_printf(NULL, "return %%rsp 0x%lx\n", tf->stk_ptr);
1750 bop_printf(NULL, "return %%ss 0x%lx\n", tf->stk_seg & 0xffff);
1751 #endif
1752
1753 /* grab %[er]bp pushed by our code from the stack */
1754 fakeframe.old_frame = (bop_frame_t *)*(tfp - 3);
1755 fakeframe.retaddr = (pc_t)tf->inst_ptr;
1756 bop_printf(NULL, "Attempting stack backtrace:\n");
1757 bop_traceback(&fakeframe);
1758 bop_panic("unexpected trap in early boot");
1759 }
1760
1761 extern void bop_trap_handler(void);
1762
1763 static gate_desc_t *bop_idt;
1764
1765 static desctbr_t bop_idt_info;
1766
1767 static void
1768 bop_idt_init(void)
1769 {
1770 int t;
1771
1772 bop_idt = (gate_desc_t *)
1773 do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
1774 bzero(bop_idt, MMU_PAGESIZE);
1775 for (t = 0; t < NIDT; ++t) {
1776 /*
1777 * Note that since boot runs without a TSS, the
1778 * double fault handler cannot use an alternate stack
1779 * (64-bit) or a task gate (32-bit).
1780 */
1781 set_gatesegd(&bop_idt[t], &bop_trap_handler, bcode_sel,
1782 SDT_SYSIGT, TRP_KPL, 0);
1783 }
1784 bop_idt_info.dtr_limit = (NIDT * sizeof (gate_desc_t)) - 1;
1785 bop_idt_info.dtr_base = (uintptr_t)bop_idt;
1786 wr_idtr(&bop_idt_info);
1787 }
1788 #endif /* !defined(__xpv) */
1789
1790 /*
1791 * This is where we enter the kernel. It dummies up the boot_ops and
1792 * boot_syscalls vectors and jumps off to _kobj_boot()
1793 */
1794 void
1795 _start(struct xboot_info *xbp)
1796 {
1797 bootops_t *bops = &bootop;
1798 extern void _kobj_boot();
1799
1800 /*
1801 * 1st off - initialize the console for any error messages
1802 */
1803 xbootp = xbp;
1804 #ifdef __xpv
1805 HYPERVISOR_shared_info = (void *)xbp->bi_shared_info;
1806 xen_info = xbp->bi_xen_start_info;
1807 #endif
1808
1809 #ifndef __xpv
1810 if (*((uint32_t *)(FASTBOOT_SWTCH_PA + FASTBOOT_STACK_OFFSET)) ==
1811 FASTBOOT_MAGIC) {
1812 post_fastreboot = 1;
1813 *((uint32_t *)(FASTBOOT_SWTCH_PA + FASTBOOT_STACK_OFFSET)) = 0;
1814 }
1815 #endif
1816
1817 bcons_init((void *)xbp->bi_cmdline);
1818 have_console = 1;
1819
1820 /*
1821 * enable debugging
1822 */
1823 if (strstr((char *)xbp->bi_cmdline, "kbm_debug"))
1824 kbm_debug = 1;
1825
1826 DBG_MSG("\n\n*** Entered Solaris in _start() cmdline is: ");
1827 DBG_MSG((char *)xbp->bi_cmdline);
1828 DBG_MSG("\n\n\n");
1829
1830 /*
1831 * physavail is no longer used by startup
1832 */
1833 bm.physinstalled = xbp->bi_phys_install;
1834 bm.pcimem = xbp->bi_pcimem;
1835 bm.rsvdmem = xbp->bi_rsvdmem;
1836 bm.physavail = NULL;
1837
1838 /*
1839 * initialize the boot time allocator
1840 */
1841 next_phys = xbp->bi_next_paddr;
1842 DBG(next_phys);
1843 next_virt = (uintptr_t)xbp->bi_next_vaddr;
1844 DBG(next_virt);
1845 DBG_MSG("Initializing boot time memory management...");
1846 #ifdef __xpv
1847 {
1848 xen_platform_parameters_t p;
1849
1850 /* This call shouldn't fail, dboot already did it once. */
1851 (void) HYPERVISOR_xen_version(XENVER_platform_parameters, &p);
1852 mfn_to_pfn_mapping = (pfn_t *)(xen_virt_start = p.virt_start);
1853 DBG(xen_virt_start);
1854 }
1855 #endif
1856 kbm_init(xbp);
1857 DBG_MSG("done\n");
1858
1859 /*
1860 * Fill in the bootops vector
1861 */
1862 bops->bsys_version = BO_VERSION;
1863 bops->boot_mem = &bm;
1864 bops->bsys_alloc = do_bsys_alloc;
1865 bops->bsys_free = do_bsys_free;
1866 bops->bsys_getproplen = do_bsys_getproplen;
1867 bops->bsys_getprop = do_bsys_getprop;
1868 bops->bsys_nextprop = do_bsys_nextprop;
1869 bops->bsys_printf = bop_printf;
1870 bops->bsys_doint = do_bsys_doint;
1871
1872 /*
1873 * BOP_EALLOC() is no longer needed
1874 */
1875 bops->bsys_ealloc = do_bsys_ealloc;
1876
1877 #ifdef __xpv
1878 /*
1879 * On domain 0 we need to free up some physical memory that is
1880 * usable for DMA. Since GRUB loaded the boot_archive, it is
1881 * sitting in low MFN memory. We'll relocated the boot archive
1882 * pages to high PFN memory.
1883 */
1884 if (DOMAIN_IS_INITDOMAIN(xen_info))
1885 relocate_boot_archive(xbp);
1886 #endif
1887
1888 #ifndef __xpv
1889 /*
1890 * Install an IDT to catch early pagefaults (shouldn't have any).
1891 * Also needed for kmdb.
1892 */
1893 bop_idt_init();
1894 #endif
1895
1896 /*
1897 * Start building the boot properties from the command line
1898 */
1899 DBG_MSG("Initializing boot properties:\n");
1900 build_boot_properties(xbp);
1901
1902 if (strstr((char *)xbp->bi_cmdline, "prom_debug") || kbm_debug) {
1903 char *value;
1904
1905 value = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
1906 boot_prop_display(value);
1907 }
1908
1909 /*
1910 * jump into krtld...
1911 */
1912 _kobj_boot(&bop_sysp, NULL, bops, NULL);
1913 }
1914
1915
1916 /*ARGSUSED*/
1917 static caddr_t
1918 no_more_alloc(bootops_t *bop, caddr_t virthint, size_t size, int align)
1919 {
1920 panic("Attempt to bsys_alloc() too late\n");
1921 return (NULL);
1922 }
1923
1924 /*ARGSUSED*/
1925 static void
1926 no_more_free(bootops_t *bop, caddr_t virt, size_t size)
1927 {
1928 panic("Attempt to bsys_free() too late\n");
1929 }
1930
1931 void
1932 bop_no_more_mem(void)
1933 {
1934 DBG(total_bop_alloc_scratch);
1935 DBG(total_bop_alloc_kernel);
1936 bootops->bsys_alloc = no_more_alloc;
1937 bootops->bsys_free = no_more_free;
1938 }
1939
1940
1941 /*
1942 * Set ACPI firmware properties
1943 */
1944
1945 static caddr_t
1946 vmap_phys(size_t length, paddr_t pa)
1947 {
1948 paddr_t start, end;
1949 caddr_t va;
1950 size_t len, page;
1951
1952 #ifdef __xpv
1953 pa = pfn_to_pa(xen_assign_pfn(mmu_btop(pa))) | (pa & MMU_PAGEOFFSET);
1954 #endif
1955 start = P2ALIGN(pa, MMU_PAGESIZE);
1956 end = P2ROUNDUP(pa + length, MMU_PAGESIZE);
1957 len = end - start;
1958 va = (caddr_t)alloc_vaddr(len, MMU_PAGESIZE);
1959 for (page = 0; page < len; page += MMU_PAGESIZE)
1960 kbm_map((uintptr_t)va + page, start + page, 0, 0);
1961 return (va + (pa & MMU_PAGEOFFSET));
1962 }
1963
1964 static uint8_t
1965 checksum_table(uint8_t *tp, size_t len)
1966 {
1967 uint8_t sum = 0;
1968
1969 while (len-- > 0)
1970 sum += *tp++;
1971
1972 return (sum);
1973 }
1974
1975 static int
1976 valid_rsdp(ACPI_TABLE_RSDP *rp)
1977 {
1978
1979 /* validate the V1.x checksum */
1980 if (checksum_table((uint8_t *)rp, ACPI_RSDP_CHECKSUM_LENGTH) != 0)
1981 return (0);
1982
1983 /* If pre-ACPI 2.0, this is a valid RSDP */
1984 if (rp->Revision < 2)
1985 return (1);
1986
1987 /* validate the V2.x checksum */
1988 if (checksum_table((uint8_t *)rp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)
1989 return (0);
1990
1991 return (1);
1992 }
1993
1994 /*
1995 * Scan memory range for an RSDP;
1996 * see ACPI 3.0 Spec, 5.2.5.1
1997 */
1998 static ACPI_TABLE_RSDP *
1999 scan_rsdp(paddr_t start, paddr_t end)
2000 {
2001 ssize_t len = end - start;
2002 caddr_t ptr;
2003
2004 ptr = vmap_phys(len, start);
2005 while (len > 0) {
2006 if (strncmp(ptr, ACPI_SIG_RSDP, strlen(ACPI_SIG_RSDP)) == 0 &&
2007 valid_rsdp((ACPI_TABLE_RSDP *)ptr))
2008 return ((ACPI_TABLE_RSDP *)ptr);
2009
2010 ptr += ACPI_RSDP_SCAN_STEP;
2011 len -= ACPI_RSDP_SCAN_STEP;
2012 }
2013
2014 return (NULL);
2015 }
2016
2017 /*
2018 * Refer to ACPI 3.0 Spec, section 5.2.5.1 to understand this function
2019 */
2020 static ACPI_TABLE_RSDP *
2021 find_rsdp()
2022 {
2023 ACPI_TABLE_RSDP *rsdp;
2024 uint16_t *ebda_seg;
2025 paddr_t ebda_addr;
2026
2027 /*
2028 * Get the EBDA segment and scan the first 1K
2029 */
2030 ebda_seg = (uint16_t *)vmap_phys(sizeof (uint16_t),
2031 ACPI_EBDA_PTR_LOCATION);
2032 ebda_addr = *ebda_seg << 4;
2033 rsdp = scan_rsdp(ebda_addr, ebda_addr + ACPI_EBDA_WINDOW_SIZE);
2034 if (rsdp == NULL)
2035 /* if EBDA doesn't contain RSDP, look in BIOS memory */
2036 rsdp = scan_rsdp(ACPI_HI_RSDP_WINDOW_BASE,
2037 ACPI_HI_RSDP_WINDOW_BASE + ACPI_HI_RSDP_WINDOW_SIZE);
2038 return (rsdp);
2039 }
2040
2041 static ACPI_TABLE_HEADER *
2042 map_fw_table(paddr_t table_addr)
2043 {
2044 ACPI_TABLE_HEADER *tp;
2045 size_t len = MAX(sizeof (*tp), MMU_PAGESIZE);
2046
2047 /*
2048 * Map at least a page; if the table is larger than this, remap it
2049 */
2050 tp = (ACPI_TABLE_HEADER *)vmap_phys(len, table_addr);
2051 if (tp->Length > len)
2052 tp = (ACPI_TABLE_HEADER *)vmap_phys(tp->Length, table_addr);
2053 return (tp);
2054 }
2055
2056 static ACPI_TABLE_HEADER *
2057 find_fw_table(char *signature)
2058 {
2059 static int revision = 0;
2060 static ACPI_TABLE_XSDT *xsdt;
2061 static int len;
2062 paddr_t xsdt_addr;
2063 ACPI_TABLE_RSDP *rsdp;
2064 ACPI_TABLE_HEADER *tp;
2065 paddr_t table_addr;
2066 int n;
2067
2068 if (strlen(signature) != ACPI_NAME_SIZE)
2069 return (NULL);
2070
2071 /*
2072 * Reading the ACPI 3.0 Spec, section 5.2.5.3 will help
2073 * understand this code. If we haven't already found the RSDT/XSDT,
2074 * revision will be 0. Find the RSDP and check the revision
2075 * to find out whether to use the RSDT or XSDT. If revision is
2076 * 0 or 1, use the RSDT and set internal revision to 1; if it is 2,
2077 * use the XSDT. If the XSDT address is 0, though, fall back to
2078 * revision 1 and use the RSDT.
2079 */
2080 if (revision == 0) {
2081 if ((rsdp = find_rsdp()) != NULL) {
2082 revision = rsdp->Revision;
2083 /*
2084 * ACPI 6.0 states that current revision is 2
2085 * from acpi_table_rsdp definition:
2086 * Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+
2087 */
2088 if (revision > 2)
2089 revision = 2;
2090 switch (revision) {
2091 case 2:
2092 /*
2093 * Use the XSDT unless BIOS is buggy and
2094 * claims to be rev 2 but has a null XSDT
2095 * address
2096 */
2097 xsdt_addr = rsdp->XsdtPhysicalAddress;
2098 if (xsdt_addr != 0)
2099 break;
2100 /* FALLTHROUGH */
2101 case 0:
2102 /* treat RSDP rev 0 as revision 1 internally */
2103 revision = 1;
2104 /* FALLTHROUGH */
2105 case 1:
2106 /* use the RSDT for rev 0/1 */
2107 xsdt_addr = rsdp->RsdtPhysicalAddress;
2108 break;
2109 default:
2110 /* unknown revision */
2111 revision = 0;
2112 break;
2113 }
2114 }
2115 if (revision == 0)
2116 return (NULL);
2117
2118 /* cache the XSDT info */
2119 xsdt = (ACPI_TABLE_XSDT *)map_fw_table(xsdt_addr);
2120 len = (xsdt->Header.Length - sizeof (xsdt->Header)) /
2121 ((revision == 1) ? sizeof (uint32_t) : sizeof (uint64_t));
2122 }
2123
2124 /*
2125 * Scan the table headers looking for a signature match
2126 */
2127 for (n = 0; n < len; n++) {
2128 ACPI_TABLE_RSDT *rsdt = (ACPI_TABLE_RSDT *)xsdt;
2129 table_addr = (revision == 1) ? rsdt->TableOffsetEntry[n] :
2130 xsdt->TableOffsetEntry[n];
2131
2132 if (table_addr == 0)
2133 continue;
2134 tp = map_fw_table(table_addr);
2135 if (strncmp(tp->Signature, signature, ACPI_NAME_SIZE) == 0) {
2136 return (tp);
2137 }
2138 }
2139 return (NULL);
2140 }
2141
2142 static void
2143 process_mcfg(ACPI_TABLE_MCFG *tp)
2144 {
2145 ACPI_MCFG_ALLOCATION *cfg_baap;
2146 char *cfg_baa_endp;
2147 int64_t ecfginfo[4];
2148
2149 cfg_baap = (ACPI_MCFG_ALLOCATION *)((uintptr_t)tp + sizeof (*tp));
2150 cfg_baa_endp = ((char *)tp) + tp->Header.Length;
2151 while ((char *)cfg_baap < cfg_baa_endp) {
2152 if (cfg_baap->Address != 0 && cfg_baap->PciSegment == 0) {
2153 ecfginfo[0] = cfg_baap->Address;
2154 ecfginfo[1] = cfg_baap->PciSegment;
2155 ecfginfo[2] = cfg_baap->StartBusNumber;
2156 ecfginfo[3] = cfg_baap->EndBusNumber;
2157 bsetprop(MCFG_PROPNAME, strlen(MCFG_PROPNAME),
2158 ecfginfo, sizeof (ecfginfo));
2159 break;
2160 }
2161 cfg_baap++;
2162 }
2163 }
2164
2165 #ifndef __xpv
2166 static void
2167 process_madt_entries(ACPI_TABLE_MADT *tp, uint32_t *cpu_countp,
2168 uint32_t *cpu_possible_countp, uint32_t *cpu_apicid_array)
2169 {
2170 ACPI_SUBTABLE_HEADER *item, *end;
2171 uint32_t cpu_count = 0;
2172 uint32_t cpu_possible_count = 0;
2173
2174 /*
2175 * Determine number of CPUs and keep track of "final" APIC ID
2176 * for each CPU by walking through ACPI MADT processor list
2177 */
2178 end = (ACPI_SUBTABLE_HEADER *)(tp->Header.Length + (uintptr_t)tp);
2179 item = (ACPI_SUBTABLE_HEADER *)((uintptr_t)tp + sizeof (*tp));
2180
2181 while (item < end) {
2182 switch (item->Type) {
2183 case ACPI_MADT_TYPE_LOCAL_APIC: {
2184 ACPI_MADT_LOCAL_APIC *cpu =
2185 (ACPI_MADT_LOCAL_APIC *) item;
2186
2187 if (cpu->LapicFlags & ACPI_MADT_ENABLED) {
2188 if (cpu_apicid_array != NULL)
2189 cpu_apicid_array[cpu_count] = cpu->Id;
2190 cpu_count++;
2191 }
2192 cpu_possible_count++;
2193 break;
2194 }
2195 case ACPI_MADT_TYPE_LOCAL_X2APIC: {
2196 ACPI_MADT_LOCAL_X2APIC *cpu =
2197 (ACPI_MADT_LOCAL_X2APIC *) item;
2198
2199 if (cpu->LapicFlags & ACPI_MADT_ENABLED) {
2200 if (cpu_apicid_array != NULL)
2201 cpu_apicid_array[cpu_count] =
2202 cpu->LocalApicId;
2203 cpu_count++;
2204 }
2205 cpu_possible_count++;
2206 break;
2207 }
2208 default:
2209 if (kbm_debug)
2210 bop_printf(NULL, "MADT type %d\n", item->Type);
2211 break;
2212 }
2213
2214 item = (ACPI_SUBTABLE_HEADER *)((uintptr_t)item + item->Length);
2215 }
2216 if (cpu_countp)
2217 *cpu_countp = cpu_count;
2218 if (cpu_possible_countp)
2219 *cpu_possible_countp = cpu_possible_count;
2220 }
2221
2222 static void
2223 process_madt(ACPI_TABLE_MADT *tp)
2224 {
2225 uint32_t cpu_count = 0;
2226 uint32_t cpu_possible_count = 0;
2227 uint32_t *cpu_apicid_array; /* x2APIC ID is 32bit! */
2228
2229 if (tp != NULL) {
2230 /* count cpu's */
2231 process_madt_entries(tp, &cpu_count, &cpu_possible_count, NULL);
2232
2233 cpu_apicid_array = (uint32_t *)do_bsys_alloc(NULL, NULL,
2234 cpu_count * sizeof (*cpu_apicid_array), MMU_PAGESIZE);
2235 if (cpu_apicid_array == NULL)
2236 bop_panic("Not enough memory for APIC ID array");
2237
2238 /* copy IDs */
2239 process_madt_entries(tp, NULL, NULL, cpu_apicid_array);
2240
2241 /*
2242 * Make boot property for array of "final" APIC IDs for each
2243 * CPU
2244 */
2245 bsetprop(BP_CPU_APICID_ARRAY, strlen(BP_CPU_APICID_ARRAY),
2246 cpu_apicid_array, cpu_count * sizeof (*cpu_apicid_array));
2247 }
2248
2249 /*
2250 * Check whether property plat-max-ncpus is already set.
2251 */
2252 if (do_bsys_getproplen(NULL, PLAT_MAX_NCPUS_NAME) < 0) {
2253 /*
2254 * Set plat-max-ncpus to number of maximum possible CPUs given
2255 * in MADT if it hasn't been set.
2256 * There's no formal way to detect max possible CPUs supported
2257 * by platform according to ACPI spec3.0b. So current CPU
2258 * hotplug implementation expects that all possible CPUs will
2259 * have an entry in MADT table and set plat-max-ncpus to number
2260 * of entries in MADT.
2261 * With introducing of ACPI4.0, Maximum System Capability Table
2262 * (MSCT) provides maximum number of CPUs supported by platform.
2263 * If MSCT is unavailable, fall back to old way.
2264 */
2265 if (tp != NULL)
2266 bsetpropsi(PLAT_MAX_NCPUS_NAME, cpu_possible_count);
2267 }
2268
2269 /*
2270 * Set boot property boot-max-ncpus to number of CPUs existing at
2271 * boot time. boot-max-ncpus is mainly used for optimization.
2272 */
2273 if (tp != NULL)
2274 bsetpropsi(BOOT_MAX_NCPUS_NAME, cpu_count);
2275
2276 /*
2277 * User-set boot-ncpus overrides firmware count
2278 */
2279 if (do_bsys_getproplen(NULL, BOOT_NCPUS_NAME) >= 0)
2280 return;
2281
2282 /*
2283 * Set boot property boot-ncpus to number of active CPUs given in MADT
2284 * if it hasn't been set yet.
2285 */
2286 if (tp != NULL)
2287 bsetpropsi(BOOT_NCPUS_NAME, cpu_count);
2288 }
2289
2290 static void
2291 process_srat(ACPI_TABLE_SRAT *tp)
2292 {
2293 ACPI_SUBTABLE_HEADER *item, *end;
2294 int i;
2295 int proc_num, mem_num;
2296 #pragma pack(1)
2297 struct {
2298 uint32_t domain;
2299 uint32_t apic_id;
2300 uint32_t sapic_id;
2301 } processor;
2302 struct {
2303 uint32_t domain;
2304 uint32_t x2apic_id;
2305 } x2apic;
2306 struct {
2307 uint32_t domain;
2308 uint64_t addr;
2309 uint64_t length;
2310 uint32_t flags;
2311 } memory;
2312 #pragma pack()
2313 char prop_name[30];
2314 uint64_t maxmem = 0;
2315
2316 if (tp == NULL)
2317 return;
2318
2319 proc_num = mem_num = 0;
2320 end = (ACPI_SUBTABLE_HEADER *)(tp->Header.Length + (uintptr_t)tp);
2321 item = (ACPI_SUBTABLE_HEADER *)((uintptr_t)tp + sizeof (*tp));
2322 while (item < end) {
2323 switch (item->Type) {
2324 case ACPI_SRAT_TYPE_CPU_AFFINITY: {
2325 ACPI_SRAT_CPU_AFFINITY *cpu =
2326 (ACPI_SRAT_CPU_AFFINITY *) item;
2327
2328 if (!(cpu->Flags & ACPI_SRAT_CPU_ENABLED))
2329 break;
2330 processor.domain = cpu->ProximityDomainLo;
2331 for (i = 0; i < 3; i++)
2332 processor.domain +=
2333 cpu->ProximityDomainHi[i] << ((i + 1) * 8);
2334 processor.apic_id = cpu->ApicId;
2335 processor.sapic_id = cpu->LocalSapicEid;
2336 (void) snprintf(prop_name, 30, "acpi-srat-processor-%d",
2337 proc_num);
2338 bsetprop(prop_name, strlen(prop_name), &processor,
2339 sizeof (processor));
2340 proc_num++;
2341 break;
2342 }
2343 case ACPI_SRAT_TYPE_MEMORY_AFFINITY: {
2344 ACPI_SRAT_MEM_AFFINITY *mem =
2345 (ACPI_SRAT_MEM_AFFINITY *)item;
2346
2347 if (!(mem->Flags & ACPI_SRAT_MEM_ENABLED))
2348 break;
2349 memory.domain = mem->ProximityDomain;
2350 memory.addr = mem->BaseAddress;
2351 memory.length = mem->Length;
2352 memory.flags = mem->Flags;
2353 (void) snprintf(prop_name, 30, "acpi-srat-memory-%d",
2354 mem_num);
2355 bsetprop(prop_name, strlen(prop_name), &memory,
2356 sizeof (memory));
2357 if ((mem->Flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) &&
2358 (memory.addr + memory.length > maxmem)) {
2359 maxmem = memory.addr + memory.length;
2360 }
2361 mem_num++;
2362 break;
2363 }
2364 case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: {
2365 ACPI_SRAT_X2APIC_CPU_AFFINITY *x2cpu =
2366 (ACPI_SRAT_X2APIC_CPU_AFFINITY *) item;
2367
2368 if (!(x2cpu->Flags & ACPI_SRAT_CPU_ENABLED))
2369 break;
2370 x2apic.domain = x2cpu->ProximityDomain;
2371 x2apic.x2apic_id = x2cpu->ApicId;
2372 (void) snprintf(prop_name, 30, "acpi-srat-processor-%d",
2373 proc_num);
2374 bsetprop(prop_name, strlen(prop_name), &x2apic,
2375 sizeof (x2apic));
2376 proc_num++;
2377 break;
2378 }
2379 default:
2380 if (kbm_debug)
2381 bop_printf(NULL, "SRAT type %d\n", item->Type);
2382 break;
2383 }
2384
2385 item = (ACPI_SUBTABLE_HEADER *)
2386 (item->Length + (uintptr_t)item);
2387 }
2388
2389 /*
2390 * The maximum physical address calculated from the SRAT table is more
2391 * accurate than that calculated from the MSCT table.
2392 */
2393 if (maxmem != 0) {
2394 plat_dr_physmax = btop(maxmem);
2395 }
2396 }
2397
2398 static void
2399 process_slit(ACPI_TABLE_SLIT *tp)
2400 {
2401
2402 /*
2403 * Check the number of localities; if it's too huge, we just
2404 * return and locality enumeration code will handle this later,
2405 * if possible.
2406 *
2407 * Note that the size of the table is the square of the
2408 * number of localities; if the number of localities exceeds
2409 * UINT16_MAX, the table size may overflow an int when being
2410 * passed to bsetprop() below.
2411 */
2412 if (tp->LocalityCount >= SLIT_LOCALITIES_MAX)
2413 return;
2414
2415 bsetprop(SLIT_NUM_PROPNAME, strlen(SLIT_NUM_PROPNAME),
2416 &tp->LocalityCount, sizeof (tp->LocalityCount));
2417 bsetprop(SLIT_PROPNAME, strlen(SLIT_PROPNAME), &tp->Entry,
2418 tp->LocalityCount * tp->LocalityCount);
2419 }
2420
2421 static ACPI_TABLE_MSCT *
2422 process_msct(ACPI_TABLE_MSCT *tp)
2423 {
2424 int last_seen = 0;
2425 int proc_num = 0;
2426 ACPI_MSCT_PROXIMITY *item, *end;
2427 extern uint64_t plat_dr_options;
2428
2429 ASSERT(tp != NULL);
2430
2431 end = (ACPI_MSCT_PROXIMITY *)(tp->Header.Length + (uintptr_t)tp);
2432 for (item = (void *)((uintptr_t)tp + tp->ProximityOffset);
2433 item < end;
2434 item = (void *)(item->Length + (uintptr_t)item)) {
2435 /*
2436 * Sanity check according to section 5.2.19.1 of ACPI 4.0.
2437 * Revision 1
2438 * Length 22
2439 */
2440 if (item->Revision != 1 || item->Length != 22) {
2441 cmn_err(CE_CONT,
2442 "?boot: unknown proximity domain structure in MSCT "
2443 "with Revision(%d), Length(%d).\n",
2444 (int)item->Revision, (int)item->Length);
2445 return (NULL);
2446 } else if (item->RangeStart > item->RangeEnd) {
2447 cmn_err(CE_CONT,
2448 "?boot: invalid proximity domain structure in MSCT "
2449 "with RangeStart(%u), RangeEnd(%u).\n",
2450 item->RangeStart, item->RangeEnd);
2451 return (NULL);
2452 } else if (item->RangeStart != last_seen) {
2453 /*
2454 * Items must be organized in ascending order of the
2455 * proximity domain enumerations.
2456 */
2457 cmn_err(CE_CONT,
2458 "?boot: invalid proximity domain structure in MSCT,"
2459 " items are not orginized in ascending order.\n");
2460 return (NULL);
2461 }
2462
2463 /*
2464 * If ProcessorCapacity is 0 then there would be no CPUs in this
2465 * domain.
2466 */
2467 if (item->ProcessorCapacity != 0) {
2468 proc_num += (item->RangeEnd - item->RangeStart + 1) *
2469 item->ProcessorCapacity;
2470 }
2471
2472 last_seen = item->RangeEnd - item->RangeStart + 1;
2473 /*
2474 * Break out if all proximity domains have been processed.
2475 * Some BIOSes may have unused items at the end of MSCT table.
2476 */
2477 if (last_seen > tp->MaxProximityDomains) {
2478 break;
2479 }
2480 }
2481 if (last_seen != tp->MaxProximityDomains + 1) {
2482 cmn_err(CE_CONT,
2483 "?boot: invalid proximity domain structure in MSCT, "
2484 "proximity domain count doesn't match.\n");
2485 return (NULL);
2486 }
2487
2488 /*
2489 * Set plat-max-ncpus property if it hasn't been set yet.
2490 */
2491 if (do_bsys_getproplen(NULL, PLAT_MAX_NCPUS_NAME) < 0) {
2492 if (proc_num != 0) {
2493 bsetpropsi(PLAT_MAX_NCPUS_NAME, proc_num);
2494 }
2495 }
2496
2497 /*
2498 * Use Maximum Physical Address from the MSCT table as upper limit for
2499 * memory hot-adding by default. It may be overridden by value from
2500 * the SRAT table or the "plat-dr-physmax" boot option.
2501 */
2502 plat_dr_physmax = btop(tp->MaxAddress + 1);
2503
2504 /*
2505 * Existence of MSCT implies CPU/memory hotplug-capability for the
2506 * platform.
2507 */
2508 plat_dr_options |= PLAT_DR_FEATURE_CPU;
2509 plat_dr_options |= PLAT_DR_FEATURE_MEMORY;
2510
2511 return (tp);
2512 }
2513
2514 /*
2515 * If this system has a PC-compatible BIOS, it will have handlers for
2516 * various well-known BIOS calls. These calls take the form of INT
2517 * instructions, revectoring to the nominated entry in the real mode
2518 * Interrupt Vector Table (IVT). If all of the commonly used entries (from
2519 * INT 10h up to INT 1Ah) are zero, we almost certainly don't want to make
2520 * use of BOP_DOINT() later.
2521 *
2522 * The IVT begins at linear address 0 on the 8086. Though later CPUs
2523 * allowed it to be moved, it seems that most BIOS implementations choose
2524 * not to do so for compatibility reasons. Our BIOS call trampoline (see
2525 * "idt_info" in "uts/i86pc/ml/bios_call_src.s") also assumes this address.
2526 */
2527 static int
2528 system_has_bios(void)
2529 {
2530 uint32_t all_ivts = 0;
2531
2532 DBG_MSG("\nBIOS IVT Entries:\n");
2533 for (uint32_t intnum = 0x10; intnum <= 0x1a; intnum++) {
2534 /*
2535 * The first software interrupt number (i.e. INT 0h) maps to
2536 * vector number 32 in the IVT. Each entry in the IVT is
2537 * four bytes, describing a 16 bit far call address.
2538 */
2539 uintptr_t slot = 4 * (32 + intnum);
2540 uint32_t ivte = *((uint32_t *)slot);
2541
2542 if (ivte != 0) {
2543 DBG(intnum);
2544 DBG(ivte);
2545 }
2546 all_ivts |= ivte;
2547 }
2548 if (all_ivts == 0) {
2549 DBG_MSG("System has no BIOS IVT entries\n");
2550 }
2551 DBG_MSG("\n");
2552
2553 return (all_ivts != 0);
2554 }
2555
2556 #else /* __xpv */
2557 static void
2558 enumerate_xen_cpus()
2559 {
2560 processorid_t id, max_id;
2561
2562 /*
2563 * User-set boot-ncpus overrides enumeration
2564 */
2565 if (do_bsys_getproplen(NULL, BOOT_NCPUS_NAME) >= 0)
2566 return;
2567
2568 /*
2569 * Probe every possible virtual CPU id and remember the
2570 * highest id present; the count of CPUs is one greater
2571 * than this. This tacitly assumes at least cpu 0 is present.
2572 */
2573 max_id = 0;
2574 for (id = 0; id < MAX_VIRT_CPUS; id++)
2575 if (HYPERVISOR_vcpu_op(VCPUOP_is_up, id, NULL) == 0)
2576 max_id = id;
2577
2578 bsetpropsi(BOOT_NCPUS_NAME, max_id+1);
2579
2580 }
2581 #endif /* __xpv */
2582
2583 static void
2584 build_firmware_properties(void)
2585 {
2586 ACPI_TABLE_HEADER *tp = NULL;
2587
2588 #ifndef __xpv
2589 if (do_bsys_getproplen(NULL, "no-bios") > 0 || !system_has_bios())
2590 bios_calls_available = B_FALSE;
2591
2592 if ((tp = find_fw_table(ACPI_SIG_MSCT)) != NULL)
2593 msct_ptr = process_msct((ACPI_TABLE_MSCT *)tp);
2594 else
2595 msct_ptr = NULL;
2596
2597 if ((tp = find_fw_table(ACPI_SIG_MADT)) != NULL)
2598 process_madt((ACPI_TABLE_MADT *)tp);
2599
2600 if ((srat_ptr = (ACPI_TABLE_SRAT *)
2601 find_fw_table(ACPI_SIG_SRAT)) != NULL)
2602 process_srat(srat_ptr);
2603
2604 if (slit_ptr = (ACPI_TABLE_SLIT *)find_fw_table(ACPI_SIG_SLIT))
2605 process_slit(slit_ptr);
2606
2607 tp = find_fw_table(ACPI_SIG_MCFG);
2608 #else /* __xpv */
2609 enumerate_xen_cpus();
2610 if (DOMAIN_IS_INITDOMAIN(xen_info))
2611 tp = find_fw_table(ACPI_SIG_MCFG);
2612 #endif /* __xpv */
2613 if (tp != NULL)
2614 process_mcfg((ACPI_TABLE_MCFG *)tp);
2615 }
2616
2617 /*
2618 * fake up a boot property for deferred early console output
2619 * this is used by both graphical boot and the (developer only)
2620 * USB serial console
2621 */
2622 void *
2623 defcons_init(size_t size)
2624 {
2625 static char *p = NULL;
2626
2627 p = do_bsys_alloc(NULL, NULL, size, MMU_PAGESIZE);
2628 *p = 0;
2629 bsetprop("deferred-console-buf", strlen("deferred-console-buf") + 1,
2630 &p, sizeof (p));
2631 return (p);
2632 }
2633
2634 /*ARGSUSED*/
2635 int
2636 boot_compinfo(int fd, struct compinfo *cbp)
2637 {
2638 cbp->iscmp = 0;
2639 cbp->blksize = MAXBSIZE;
2640 return (0);
2641 }
2642
2643 #define BP_MAX_STRLEN 32
2644
2645 /*
2646 * Get value for given boot property
2647 */
2648 int
2649 bootprop_getval(const char *prop_name, u_longlong_t *prop_value)
2650 {
2651 int boot_prop_len;
2652 char str[BP_MAX_STRLEN];
2653 u_longlong_t value;
2654
2655 boot_prop_len = BOP_GETPROPLEN(bootops, prop_name);
2656 if (boot_prop_len < 0 || boot_prop_len > sizeof (str) ||
2657 BOP_GETPROP(bootops, prop_name, str) < 0 ||
2658 kobj_getvalue(str, &value) == -1)
2659 return (-1);
2660
2661 if (prop_value)
2662 *prop_value = value;
2663
2664 return (0);
2665 }