19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Copyright 2013 Joyent, Inc. All rights reserved.
27 */
28
29
30 #include <sys/types.h>
31 #include <sys/machparam.h>
32 #include <sys/x86_archext.h>
33 #include <sys/systm.h>
34 #include <sys/mach_mmu.h>
35 #include <sys/multiboot.h>
36 #include <sys/multiboot2.h>
37 #include <sys/multiboot2_impl.h>
38 #include <sys/sysmacros.h>
39 #include <sys/sha1.h>
40 #include <util/string.h>
41 #include <util/strtolctype.h>
42 #include <sys/efi.h>
43
44 #if defined(__xpv)
45
46 #include <sys/hypervisor.h>
47 uintptr_t xen_virt_start;
48 pfn_t *mfn_to_pfn_mapping;
49
50 #else /* !__xpv */
51
52 extern multiboot_header_t mb_header;
53 extern uint32_t mb2_load_addr;
54 extern int have_cpuid(void);
55
56 #endif /* !__xpv */
57
58 #include <sys/inttypes.h>
120 */
121
122 static paddr_t scratch_end = 0; /* we can't write all of mem here */
123 static paddr_t mfn_base; /* addr corresponding to mfn_list[0] */
124 start_info_t *xen_info;
125
126 #else /* __xpv */
127
128 /*
129 * If on the metal, then we have a multiboot loader.
130 */
131 uint32_t mb_magic; /* magic from boot loader */
132 uint32_t mb_addr; /* multiboot info package from loader */
133 int multiboot_version;
134 multiboot_info_t *mb_info;
135 multiboot2_info_header_t *mb2_info;
136 multiboot_tag_mmap_t *mb2_mmap_tagp;
137 int num_entries; /* mmap entry count */
138 boolean_t num_entries_set; /* is mmap entry count set */
139 uintptr_t load_addr;
140
141 /* can not be automatic variables because of alignment */
142 static efi_guid_t smbios3 = SMBIOS3_TABLE_GUID;
143 static efi_guid_t smbios = SMBIOS_TABLE_GUID;
144 static efi_guid_t acpi2 = EFI_ACPI_TABLE_GUID;
145 static efi_guid_t acpi1 = ACPI_10_TABLE_GUID;
146 #endif /* __xpv */
147
148 /*
149 * This contains information passed to the kernel
150 */
151 struct xboot_info boot_info[2]; /* extra space to fix alignement for amd64 */
152 struct xboot_info *bi;
153
154 /*
155 * Page table and memory stuff.
156 */
157 static paddr_t max_mem; /* maximum memory address */
158
159 /*
160 * Information about processor MMU
161 */
162 int amd64_support = 0;
163 int largepage_support = 0;
164 int pae_support = 0;
165 int pge_support = 0;
166 int NX_support = 0;
167
168 /*
169 * Low 32 bits of kernel entry address passed back to assembler.
170 * When running a 64 bit kernel, the high 32 bits are 0xffffffff.
171 */
172 uint32_t entry_addr_low;
173
174 /*
175 * Memlists for the kernel. We shouldn't need a lot of these.
176 */
177 #define MAX_MEMLIST (50)
178 struct boot_memlist memlists[MAX_MEMLIST];
179 uint_t memlists_used = 0;
180 struct boot_memlist pcimemlists[MAX_MEMLIST];
181 uint_t pcimemlists_used = 0;
182 struct boot_memlist rsvdmemlists[MAX_MEMLIST];
183 uint_t rsvdmemlists_used = 0;
184
185 /*
186 * This should match what's in the bootloader. It's arbitrary, but GRUB
956 build_rsvdmemlists();
957
958 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
959 /*
960 * build PCI Memory list
961 */
962 map.nr_entries = MAXMAPS;
963 /*LINTED: constant in conditional context*/
964 set_xen_guest_handle(map.buffer, map_buffer);
965 if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &map) != 0)
966 dboot_panic("getting XENMEM_machine_memory_map failed");
967 build_pcimemlists();
968 }
969 }
970
971 #else /* !__xpv */
972
973 static void
974 dboot_multiboot1_xboot_consinfo(void)
975 {
976 bi->bi_framebuffer = NULL;
977 }
978
979 static void
980 dboot_multiboot2_xboot_consinfo(void)
981 {
982 multiboot_tag_framebuffer_t *fb;
983 fb = dboot_multiboot2_find_tag(mb2_info,
984 MULTIBOOT_TAG_TYPE_FRAMEBUFFER);
985 bi->bi_framebuffer = (native_ptr_t)(uintptr_t)fb;
986 }
987
988 static int
989 dboot_multiboot_modcount(void)
990 {
991 switch (multiboot_version) {
992 case 1:
993 return (mb_info->mods_count);
994
995 case 2:
996 return (dboot_multiboot2_modcount(mb2_info));
997
998 default:
999 dboot_panic("Unknown multiboot version: %d\n",
1000 multiboot_version);
1001 break;
1002 }
1003 return (0);
1004 }
1005
1042 static char *
1043 dboot_multiboot_modcmdline(int index)
1044 {
1045 switch (multiboot_version) {
1046 case 1:
1047 return ((char *)((mb_module_t *)
1048 mb_info->mods_addr)[index].mod_name);
1049
1050 case 2:
1051 return (dboot_multiboot2_modcmdline(mb2_info, index));
1052
1053 default:
1054 dboot_panic("Unknown multiboot version: %d\n",
1055 multiboot_version);
1056 break;
1057 }
1058 return (0);
1059 }
1060
1061 /*
1062 * Find the environment module for console setup.
1063 * Since we need the console to print early boot messages, the console is set up
1064 * before anything else and therefore we need to pick up the environment module
1065 * early too.
1066 *
1067 * Note, we just will search for and if found, will pass the env
1068 * module to console setup, the proper module list processing will happen later.
1069 */
1070 static void
1071 dboot_find_env(void)
1072 {
1073 int i, modcount;
1074 uint32_t mod_start, mod_end;
1075 char *cmdline;
1076
1077 modcount = dboot_multiboot_modcount();
1078
1079 for (i = 0; i < modcount; ++i) {
1080 cmdline = dboot_multiboot_modcmdline(i);
1081 if (cmdline == NULL)
1082 continue;
1083
1084 if (strstr(cmdline, "type=environment") == NULL)
1085 continue;
1086
1087 mod_start = dboot_multiboot_modstart(i);
1088 mod_end = dboot_multiboot_modend(i);
1089 modules[0].bm_addr = (native_ptr_t)(uintptr_t)mod_start;
1090 modules[0].bm_size = mod_end - mod_start;
1091 modules[0].bm_name = (native_ptr_t)(uintptr_t)NULL;
1092 modules[0].bm_hash = (native_ptr_t)(uintptr_t)NULL;
1093 modules[0].bm_type = BMT_ENV;
1094 bi->bi_modules = (native_ptr_t)(uintptr_t)modules;
1095 bi->bi_module_cnt = 1;
1096 return;
1097 }
1098 }
1099
1100 static boolean_t
1101 dboot_multiboot_basicmeminfo(uint32_t *lower, uint32_t *upper)
1102 {
1103 boolean_t rv = B_FALSE;
1104
1105 switch (multiboot_version) {
1106 case 1:
1107 if (mb_info->flags & 0x01) {
1108 *lower = mb_info->mem_lower;
1109 *upper = mb_info->mem_upper;
1110 rv = B_TRUE;
1111 }
1112 break;
1113
1114 case 2:
1115 return (dboot_multiboot2_basicmeminfo(mb2_info, lower, upper));
1116
1117 default:
1178 for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
1179 if (digest[i] != baseline[i])
1180 return (-1);
1181 }
1182
1183 return (0);
1184 }
1185
1186 static const char *
1187 type_to_str(boot_module_type_t type)
1188 {
1189 switch (type) {
1190 case BMT_ROOTFS:
1191 return ("rootfs");
1192 case BMT_FILE:
1193 return ("file");
1194 case BMT_HASH:
1195 return ("hash");
1196 case BMT_ENV:
1197 return ("environment");
1198 default:
1199 return ("unknown");
1200 }
1201 }
1202
1203 static void
1204 check_images(void)
1205 {
1206 uint_t i;
1207 char displayhash[SHA1_ASCII_LENGTH + 1];
1208
1209 for (i = 0; i < modules_used; i++) {
1210 if (prom_debug) {
1211 dboot_printf("module #%d: name %s type %s "
1212 "addr %lx size %lx\n",
1213 i, (char *)(uintptr_t)modules[i].bm_name,
1214 type_to_str(modules[i].bm_type),
1215 (ulong_t)modules[i].bm_addr,
1216 (ulong_t)modules[i].bm_size);
1217 }
1298 while (p != NULL) {
1299 q = strsep(&p, " \t\f\n\r");
1300 if (strncmp(q, "name=", 5) == 0) {
1301 if (q[5] != '\0' && !isspace(q[5])) {
1302 modules[midx].bm_name =
1303 (native_ptr_t)(uintptr_t)(q + 5);
1304 }
1305 continue;
1306 }
1307
1308 if (strncmp(q, "type=", 5) == 0) {
1309 if (q[5] == '\0' || isspace(q[5]))
1310 continue;
1311 q += 5;
1312 if (strcmp(q, "rootfs") == 0) {
1313 modules[midx].bm_type = BMT_ROOTFS;
1314 } else if (strcmp(q, "hash") == 0) {
1315 modules[midx].bm_type = BMT_HASH;
1316 } else if (strcmp(q, "environment") == 0) {
1317 modules[midx].bm_type = BMT_ENV;
1318 } else if (strcmp(q, "file") != 0) {
1319 dboot_printf("\tmodule #%d: unknown module "
1320 "type '%s'; defaulting to 'file'",
1321 midx, q);
1322 }
1323 continue;
1324 }
1325
1326 if (strncmp(q, "hash=", 5) == 0) {
1327 if (q[5] != '\0' && !isspace(q[5])) {
1328 modules[midx].bm_hash =
1329 (native_ptr_t)(uintptr_t)(q + 5);
1330 }
1331 continue;
1332 }
1333
1334 dboot_printf("ignoring unknown option '%s'\n", q);
1335 }
1336 }
1337
2005
2006 for (i = 0; i < memlists_used; ++i) {
2007 start = memlists[i].addr;
2008 end = start + memlists[i].size;
2009
2010 if (map_debug)
2011 dboot_printf("1:1 map pa=%" PRIx64 "..%" PRIx64 "\n",
2012 start, end);
2013 while (start < end && start < next_avail_addr) {
2014 map_pa_at_va(start, start, 0);
2015 start += MMU_PAGESIZE;
2016 }
2017 if (start >= next_avail_addr)
2018 break;
2019 }
2020
2021 /*
2022 * Map framebuffer memory as PT_NOCACHE as this is memory from a
2023 * device and therefore must not be cached.
2024 */
2025 if (bi->bi_framebuffer != NULL) {
2026 multiboot_tag_framebuffer_t *fb;
2027 fb = (multiboot_tag_framebuffer_t *)(uintptr_t)
2028 bi->bi_framebuffer;
2029
2030 start = fb->framebuffer_common.framebuffer_addr;
2031 end = start + fb->framebuffer_common.framebuffer_height *
2032 fb->framebuffer_common.framebuffer_pitch;
2033
2034 pte_bits |= PT_NOCACHE;
2035 while (start < end) {
2036 map_pa_at_va(start, start, 0);
2037 start += MMU_PAGESIZE;
2038 }
2039 pte_bits &= ~PT_NOCACHE;
2040 }
2041 #endif /* !__xpv */
2042
2043 DBG_MSG("\nPage tables constructed\n");
2044 }
2045
2046 #define NO_MULTIBOOT \
2047 "multiboot is no longer used to boot the Solaris Operating System.\n\
2048 The grub entry should be changed to:\n\
2049 kernel$ /platform/i86pc/kernel/$ISADIR/unix\n\
2050 module$ /platform/i86pc/$ISADIR/boot_archive\n\
2051 See http://illumos.org/msg/SUNOS-8000-AK for details.\n"
2052
2053 static void
2054 dboot_init_xboot_consinfo(void)
2055 {
2056 uintptr_t addr;
2057 /*
2058 * boot info must be 16 byte aligned for 64 bit kernel ABI
2059 */
2060 addr = (uintptr_t)boot_info;
2061 addr = (addr + 0xf) & ~0xf;
2062 bi = (struct xboot_info *)addr;
2063
2064 #if !defined(__xpv)
2065 switch (multiboot_version) {
2066 case 1:
2067 dboot_multiboot1_xboot_consinfo();
2068 break;
2069 case 2:
2070 dboot_multiboot2_xboot_consinfo();
2071 break;
2072 default:
2073 dboot_panic("Unknown multiboot version: %d\n",
2074 multiboot_version);
2075 break;
2076 }
2077 /*
2078 * Lookup environment module for the console. Complete module list
2079 * will be built after console setup.
2080 */
2081 dboot_find_env();
2082 #endif
2083 }
2084
2085 /*
2086 * Set up basic data from the boot loader.
2087 * The load_addr is part of AOUT kludge setup in dboot_grub.s, to support
2088 * 32-bit dboot code setup used to set up and start 64-bit kernel.
2089 * AOUT kludge does allow 32-bit boot loader, such as grub1, to load and
2090 * start 64-bit illumos kernel.
2091 */
2092 static void
2093 dboot_loader_init(void)
2094 {
2095 #if !defined(__xpv)
2096 mb_info = NULL;
2097 mb2_info = NULL;
2098
2099 switch (mb_magic) {
2100 case MB_BOOTLOADER_MAGIC:
2101 multiboot_version = 1;
2185 #endif /* __xpv */
2186 }
2187
2188 /*
2189 * startup_kernel has a pretty simple job. It builds pagetables which reflect
2190 * 1:1 mappings for all memory in use. It then also adds mappings for
2191 * the kernel nucleus at virtual address of target_kernel_text using large page
2192 * mappings. The page table pages are also accessible at 1:1 mapped
2193 * virtual addresses.
2194 */
2195 /*ARGSUSED*/
2196 void
2197 startup_kernel(void)
2198 {
2199 char *cmdline;
2200 char *bootloader;
2201 #if defined(__xpv)
2202 physdev_set_iopl_t set_iopl;
2203 #endif /* __xpv */
2204
2205 dboot_loader_init();
2206 /*
2207 * At this point we are executing in a 32 bit real mode.
2208 */
2209
2210 bootloader = dboot_loader_name();
2211 cmdline = dboot_loader_cmdline();
2212
2213 #if defined(__xpv)
2214 /*
2215 * For dom0, before we initialize the console subsystem we'll
2216 * need to enable io operations, so set I/O priveldge level to 1.
2217 */
2218 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
2219 set_iopl.iopl = 1;
2220 (void) HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
2221 }
2222 #endif /* __xpv */
2223
2224 dboot_init_xboot_consinfo();
2225 bi->bi_cmdline = (native_ptr_t)(uintptr_t)cmdline;
2226 bcons_init(bi);
2227
2228 prom_debug = (find_boot_prop("prom_debug") != NULL);
2229 map_debug = (find_boot_prop("map_debug") != NULL);
2230
2231 #if !defined(__xpv)
2232 dboot_multiboot_get_fwtables();
2233 #endif
2234 DBG_MSG("\n\nillumos prekernel set: ");
2235 DBG_MSG(cmdline);
2236 DBG_MSG("\n");
2237
2238 if (bootloader != NULL && prom_debug) {
2239 dboot_printf("Kernel loaded by: %s\n", bootloader);
2240 #if !defined(__xpv)
2241 dboot_printf("Using multiboot %d boot protocol.\n",
2242 multiboot_version);
2243 #endif
2244 }
2245
2246 if (strstr(cmdline, "multiboot") != NULL) {
2332 */
2333 if (HYPERVISOR_vm_assist(VMASST_CMD_enable,
2334 VMASST_TYPE_writable_pagetables) < 0)
2335 dboot_panic("HYPERVISOR_vm_assist(writable_pagetables) failed");
2336
2337 /*
2338 * check for NX support
2339 */
2340 if (pae_support) {
2341 uint32_t eax = 0x80000000;
2342 uint32_t edx = get_cpuid_edx(&eax);
2343
2344 if (eax >= 0x80000001) {
2345 eax = 0x80000001;
2346 edx = get_cpuid_edx(&eax);
2347 if (edx & CPUID_AMD_EDX_NX)
2348 NX_support = 1;
2349 }
2350 }
2351
2352 #if !defined(_BOOT_TARGET_amd64)
2353
2354 /*
2355 * The 32-bit hypervisor uses segmentation to protect itself from
2356 * guests. This means when a guest attempts to install a flat 4GB
2357 * code or data descriptor the 32-bit hypervisor will protect itself
2358 * by silently shrinking the segment such that if the guest attempts
2359 * any access where the hypervisor lives a #gp fault is generated.
2360 * The problem is that some applications expect a full 4GB flat
2361 * segment for their current thread pointer and will use negative
2362 * offset segment wrap around to access data. TLS support in linux
2363 * brand is one example of this.
2364 *
2365 * The 32-bit hypervisor can catch the #gp fault in these cases
2366 * and emulate the access without passing the #gp fault to the guest
2367 * but only if VMASST_TYPE_4gb_segments is explicitly turned on.
2368 * Seems like this should have been the default.
2369 * Either way, we want the hypervisor -- and not Solaris -- to deal
2370 * to deal with emulating these accesses.
2371 */
2373 VMASST_TYPE_4gb_segments) < 0)
2374 dboot_panic("HYPERVISOR_vm_assist(4gb_segments) failed");
2375 #endif /* !_BOOT_TARGET_amd64 */
2376
2377 #else /* __xpv */
2378
2379 /*
2380 * use cpuid to enable MMU features
2381 */
2382 if (have_cpuid()) {
2383 uint32_t eax, edx;
2384
2385 eax = 1;
2386 edx = get_cpuid_edx(&eax);
2387 if (edx & CPUID_INTC_EDX_PSE)
2388 largepage_support = 1;
2389 if (edx & CPUID_INTC_EDX_PGE)
2390 pge_support = 1;
2391 if (edx & CPUID_INTC_EDX_PAE)
2392 pae_support = 1;
2393
2394 eax = 0x80000000;
2395 edx = get_cpuid_edx(&eax);
2396 if (eax >= 0x80000001) {
2397 eax = 0x80000001;
2398 edx = get_cpuid_edx(&eax);
2399 if (edx & CPUID_AMD_EDX_LM)
2400 amd64_support = 1;
2401 if (edx & CPUID_AMD_EDX_NX)
2402 NX_support = 1;
2403 }
2404 } else {
2405 dboot_printf("cpuid not supported\n");
2406 }
2407 #endif /* __xpv */
2408
2409
2410 #if defined(_BOOT_TARGET_amd64)
2411 if (amd64_support == 0)
2412 dboot_panic("long mode not supported, rebooting");
2442 if (pae_support) {
2443 shift_amt = shift_amt_pae;
2444 ptes_per_table = 512;
2445 pte_size = 8;
2446 lpagesize = TWO_MEG;
2447 #if defined(_BOOT_TARGET_amd64)
2448 top_level = 3;
2449 #else
2450 top_level = 2;
2451 #endif
2452 } else {
2453 pae_support = 0;
2454 NX_support = 0;
2455 shift_amt = shift_amt_nopae;
2456 ptes_per_table = 1024;
2457 pte_size = 4;
2458 lpagesize = FOUR_MEG;
2459 top_level = 1;
2460 }
2461
2462 DBG(pge_support);
2463 DBG(NX_support);
2464 DBG(largepage_support);
2465 DBG(amd64_support);
2466 DBG(top_level);
2467 DBG(pte_size);
2468 DBG(ptes_per_table);
2469 DBG(lpagesize);
2470
2471 #if defined(__xpv)
2472 ktext_phys = ONE_GIG; /* from UNIX Mapfile */
2473 #else
2474 ktext_phys = FOUR_MEG; /* from UNIX Mapfile */
2475 #endif
2476
2477 #if !defined(__xpv) && defined(_BOOT_TARGET_amd64)
2478 /*
2479 * For grub, copy kernel bits from the ELF64 file to final place.
2480 */
2481 DBG_MSG("\nAllocating nucleus pages.\n");
2541 case 2:
2542 bi->bi_mb_info = (native_ptr_t)(uintptr_t)mb2_info;
2543 break;
2544 default:
2545 dboot_panic("Unknown multiboot version: %d\n",
2546 multiboot_version);
2547 break;
2548 }
2549 bi->bi_top_page_table = (uintptr_t)top_page_table;
2550
2551 #endif /* __xpv */
2552
2553 bi->bi_kseg_size = FOUR_MEG;
2554 DBG(bi->bi_kseg_size);
2555
2556 #ifndef __xpv
2557 if (map_debug)
2558 dump_tables();
2559 #endif
2560
2561 DBG_MSG("\n\n*** DBOOT DONE -- back to asm to jump to kernel\n\n");
2562 }
|
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Copyright 2013 Joyent, Inc. All rights reserved.
27 */
28
29
30 #include <sys/types.h>
31 #include <sys/machparam.h>
32 #include <sys/x86_archext.h>
33 #include <sys/systm.h>
34 #include <sys/mach_mmu.h>
35 #include <sys/multiboot.h>
36 #include <sys/multiboot2.h>
37 #include <sys/multiboot2_impl.h>
38 #include <sys/sysmacros.h>
39 #include <sys/framebuffer.h>
40 #include <sys/sha1.h>
41 #include <util/string.h>
42 #include <util/strtolctype.h>
43 #include <sys/efi.h>
44
45 #if defined(__xpv)
46
47 #include <sys/hypervisor.h>
48 uintptr_t xen_virt_start;
49 pfn_t *mfn_to_pfn_mapping;
50
51 #else /* !__xpv */
52
53 extern multiboot_header_t mb_header;
54 extern uint32_t mb2_load_addr;
55 extern int have_cpuid(void);
56
57 #endif /* !__xpv */
58
59 #include <sys/inttypes.h>
121 */
122
123 static paddr_t scratch_end = 0; /* we can't write all of mem here */
124 static paddr_t mfn_base; /* addr corresponding to mfn_list[0] */
125 start_info_t *xen_info;
126
127 #else /* __xpv */
128
129 /*
130 * If on the metal, then we have a multiboot loader.
131 */
132 uint32_t mb_magic; /* magic from boot loader */
133 uint32_t mb_addr; /* multiboot info package from loader */
134 int multiboot_version;
135 multiboot_info_t *mb_info;
136 multiboot2_info_header_t *mb2_info;
137 multiboot_tag_mmap_t *mb2_mmap_tagp;
138 int num_entries; /* mmap entry count */
139 boolean_t num_entries_set; /* is mmap entry count set */
140 uintptr_t load_addr;
141 static boot_framebuffer_t framebuffer[2];
142 static boot_framebuffer_t *fb;
143
144 /* can not be automatic variables because of alignment */
145 static efi_guid_t smbios3 = SMBIOS3_TABLE_GUID;
146 static efi_guid_t smbios = SMBIOS_TABLE_GUID;
147 static efi_guid_t acpi2 = EFI_ACPI_TABLE_GUID;
148 static efi_guid_t acpi1 = ACPI_10_TABLE_GUID;
149 #endif /* __xpv */
150
151 /*
152 * This contains information passed to the kernel
153 */
154 struct xboot_info boot_info[2]; /* extra space to fix alignement for amd64 */
155 struct xboot_info *bi;
156
157 /*
158 * Page table and memory stuff.
159 */
160 static paddr_t max_mem; /* maximum memory address */
161
162 /*
163 * Information about processor MMU
164 */
165 int amd64_support = 0;
166 int largepage_support = 0;
167 int pae_support = 0;
168 int pge_support = 0;
169 int NX_support = 0;
170 int PAT_support = 0;
171
172 /*
173 * Low 32 bits of kernel entry address passed back to assembler.
174 * When running a 64 bit kernel, the high 32 bits are 0xffffffff.
175 */
176 uint32_t entry_addr_low;
177
178 /*
179 * Memlists for the kernel. We shouldn't need a lot of these.
180 */
181 #define MAX_MEMLIST (50)
182 struct boot_memlist memlists[MAX_MEMLIST];
183 uint_t memlists_used = 0;
184 struct boot_memlist pcimemlists[MAX_MEMLIST];
185 uint_t pcimemlists_used = 0;
186 struct boot_memlist rsvdmemlists[MAX_MEMLIST];
187 uint_t rsvdmemlists_used = 0;
188
189 /*
190 * This should match what's in the bootloader. It's arbitrary, but GRUB
960 build_rsvdmemlists();
961
962 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
963 /*
964 * build PCI Memory list
965 */
966 map.nr_entries = MAXMAPS;
967 /*LINTED: constant in conditional context*/
968 set_xen_guest_handle(map.buffer, map_buffer);
969 if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &map) != 0)
970 dboot_panic("getting XENMEM_machine_memory_map failed");
971 build_pcimemlists();
972 }
973 }
974
975 #else /* !__xpv */
976
977 static void
978 dboot_multiboot1_xboot_consinfo(void)
979 {
980 fb->framebuffer = 0;
981 }
982
983 static void
984 dboot_multiboot2_xboot_consinfo(void)
985 {
986 multiboot_tag_framebuffer_t *fbtag;
987 fbtag = dboot_multiboot2_find_tag(mb2_info,
988 MULTIBOOT_TAG_TYPE_FRAMEBUFFER);
989 fb->framebuffer = (uint64_t)(uintptr_t)fbtag;
990 fb->boot_fb_virt = 0;
991 }
992
993 static int
994 dboot_multiboot_modcount(void)
995 {
996 switch (multiboot_version) {
997 case 1:
998 return (mb_info->mods_count);
999
1000 case 2:
1001 return (dboot_multiboot2_modcount(mb2_info));
1002
1003 default:
1004 dboot_panic("Unknown multiboot version: %d\n",
1005 multiboot_version);
1006 break;
1007 }
1008 return (0);
1009 }
1010
1047 static char *
1048 dboot_multiboot_modcmdline(int index)
1049 {
1050 switch (multiboot_version) {
1051 case 1:
1052 return ((char *)((mb_module_t *)
1053 mb_info->mods_addr)[index].mod_name);
1054
1055 case 2:
1056 return (dboot_multiboot2_modcmdline(mb2_info, index));
1057
1058 default:
1059 dboot_panic("Unknown multiboot version: %d\n",
1060 multiboot_version);
1061 break;
1062 }
1063 return (0);
1064 }
1065
1066 /*
1067 * Find the modules used by console setup.
1068 * Since we need the console to print early boot messages, the console is set up
1069 * before anything else and therefore we need to pick up the needed modules.
1070 *
1071 * Note, we just will search for and if found, will pass the modules
1072 * to console setup, the proper module list processing will happen later.
1073 * Currenly used modules are boot environment and consoler font.
1074 */
1075 static void
1076 dboot_find_console_modules(void)
1077 {
1078 int i, modcount;
1079 uint32_t mod_start, mod_end;
1080 char *cmdline;
1081
1082 modcount = dboot_multiboot_modcount();
1083 bi->bi_module_cnt = 0;
1084 for (i = 0; i < modcount; ++i) {
1085 cmdline = dboot_multiboot_modcmdline(i);
1086 if (cmdline == NULL)
1087 continue;
1088
1089 if (strstr(cmdline, "type=console-font") != NULL)
1090 modules[bi->bi_module_cnt].bm_type = BMT_FONT;
1091 else if (strstr(cmdline, "type=environment") != NULL)
1092 modules[bi->bi_module_cnt].bm_type = BMT_ENV;
1093 else
1094 continue;
1095
1096 mod_start = dboot_multiboot_modstart(i);
1097 mod_end = dboot_multiboot_modend(i);
1098 modules[bi->bi_module_cnt].bm_addr =
1099 (native_ptr_t)(uintptr_t)mod_start;
1100 modules[bi->bi_module_cnt].bm_size = mod_end - mod_start;
1101 modules[bi->bi_module_cnt].bm_name =
1102 (native_ptr_t)(uintptr_t)NULL;
1103 modules[bi->bi_module_cnt].bm_hash =
1104 (native_ptr_t)(uintptr_t)NULL;
1105 bi->bi_module_cnt++;
1106 }
1107 if (bi->bi_module_cnt != 0)
1108 bi->bi_modules = (native_ptr_t)(uintptr_t)modules;
1109 }
1110
1111 static boolean_t
1112 dboot_multiboot_basicmeminfo(uint32_t *lower, uint32_t *upper)
1113 {
1114 boolean_t rv = B_FALSE;
1115
1116 switch (multiboot_version) {
1117 case 1:
1118 if (mb_info->flags & 0x01) {
1119 *lower = mb_info->mem_lower;
1120 *upper = mb_info->mem_upper;
1121 rv = B_TRUE;
1122 }
1123 break;
1124
1125 case 2:
1126 return (dboot_multiboot2_basicmeminfo(mb2_info, lower, upper));
1127
1128 default:
1189 for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
1190 if (digest[i] != baseline[i])
1191 return (-1);
1192 }
1193
1194 return (0);
1195 }
1196
1197 static const char *
1198 type_to_str(boot_module_type_t type)
1199 {
1200 switch (type) {
1201 case BMT_ROOTFS:
1202 return ("rootfs");
1203 case BMT_FILE:
1204 return ("file");
1205 case BMT_HASH:
1206 return ("hash");
1207 case BMT_ENV:
1208 return ("environment");
1209 case BMT_FONT:
1210 return ("console-font");
1211 default:
1212 return ("unknown");
1213 }
1214 }
1215
1216 static void
1217 check_images(void)
1218 {
1219 uint_t i;
1220 char displayhash[SHA1_ASCII_LENGTH + 1];
1221
1222 for (i = 0; i < modules_used; i++) {
1223 if (prom_debug) {
1224 dboot_printf("module #%d: name %s type %s "
1225 "addr %lx size %lx\n",
1226 i, (char *)(uintptr_t)modules[i].bm_name,
1227 type_to_str(modules[i].bm_type),
1228 (ulong_t)modules[i].bm_addr,
1229 (ulong_t)modules[i].bm_size);
1230 }
1311 while (p != NULL) {
1312 q = strsep(&p, " \t\f\n\r");
1313 if (strncmp(q, "name=", 5) == 0) {
1314 if (q[5] != '\0' && !isspace(q[5])) {
1315 modules[midx].bm_name =
1316 (native_ptr_t)(uintptr_t)(q + 5);
1317 }
1318 continue;
1319 }
1320
1321 if (strncmp(q, "type=", 5) == 0) {
1322 if (q[5] == '\0' || isspace(q[5]))
1323 continue;
1324 q += 5;
1325 if (strcmp(q, "rootfs") == 0) {
1326 modules[midx].bm_type = BMT_ROOTFS;
1327 } else if (strcmp(q, "hash") == 0) {
1328 modules[midx].bm_type = BMT_HASH;
1329 } else if (strcmp(q, "environment") == 0) {
1330 modules[midx].bm_type = BMT_ENV;
1331 } else if (strcmp(q, "console-font") == 0) {
1332 modules[midx].bm_type = BMT_FONT;
1333 } else if (strcmp(q, "file") != 0) {
1334 dboot_printf("\tmodule #%d: unknown module "
1335 "type '%s'; defaulting to 'file'",
1336 midx, q);
1337 }
1338 continue;
1339 }
1340
1341 if (strncmp(q, "hash=", 5) == 0) {
1342 if (q[5] != '\0' && !isspace(q[5])) {
1343 modules[midx].bm_hash =
1344 (native_ptr_t)(uintptr_t)(q + 5);
1345 }
1346 continue;
1347 }
1348
1349 dboot_printf("ignoring unknown option '%s'\n", q);
1350 }
1351 }
1352
2020
2021 for (i = 0; i < memlists_used; ++i) {
2022 start = memlists[i].addr;
2023 end = start + memlists[i].size;
2024
2025 if (map_debug)
2026 dboot_printf("1:1 map pa=%" PRIx64 "..%" PRIx64 "\n",
2027 start, end);
2028 while (start < end && start < next_avail_addr) {
2029 map_pa_at_va(start, start, 0);
2030 start += MMU_PAGESIZE;
2031 }
2032 if (start >= next_avail_addr)
2033 break;
2034 }
2035
2036 /*
2037 * Map framebuffer memory as PT_NOCACHE as this is memory from a
2038 * device and therefore must not be cached.
2039 */
2040 if (fb != NULL && fb->framebuffer != 0) {
2041 multiboot_tag_framebuffer_t *fb_tagp;
2042 fb_tagp = (multiboot_tag_framebuffer_t *)(uintptr_t)
2043 fb->framebuffer;
2044
2045 start = fb_tagp->framebuffer_common.framebuffer_addr;
2046 end = start + fb_tagp->framebuffer_common.framebuffer_height *
2047 fb_tagp->framebuffer_common.framebuffer_pitch;
2048
2049 /* VGA text memory is already mapped. */
2050 if (fb_tagp->framebuffer_common.framebuffer_type !=
2051 MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT) {
2052 uint64_t vaddr;
2053
2054 #if defined(_BOOT_TARGET_amd64)
2055 vaddr = start;
2056 #else
2057 vaddr = (uintptr_t)mem_alloc(end - start);
2058 #endif
2059 fb->boot_fb_virt = vaddr;
2060 if (map_debug) {
2061 dboot_printf("FB map pa=%" PRIx64 "..%"
2062 PRIx64 "\n", start, end);
2063 }
2064
2065 pte_bits |= PT_NOCACHE;
2066 if (PAT_support != 0)
2067 pte_bits |= PT_PAT_4K;
2068
2069 while (start < end) {
2070 map_pa_at_va(start, vaddr, 0);
2071 start += MMU_PAGESIZE;
2072 vaddr += MMU_PAGESIZE;
2073 }
2074 pte_bits &= ~PT_NOCACHE;
2075 if (PAT_support != 0)
2076 pte_bits &= ~PT_PAT_4K;
2077 }
2078 }
2079 #endif /* !__xpv */
2080
2081 DBG_MSG("\nPage tables constructed\n");
2082 }
2083
2084 #define NO_MULTIBOOT \
2085 "multiboot is no longer used to boot the Solaris Operating System.\n\
2086 The grub entry should be changed to:\n\
2087 kernel$ /platform/i86pc/kernel/$ISADIR/unix\n\
2088 module$ /platform/i86pc/$ISADIR/boot_archive\n\
2089 See http://illumos.org/msg/SUNOS-8000-AK for details.\n"
2090
2091 static void
2092 dboot_init_xboot_consinfo(void)
2093 {
2094 uintptr_t addr;
2095 /*
2096 * boot info must be 16 byte aligned for 64 bit kernel ABI
2097 */
2098 addr = (uintptr_t)boot_info;
2099 addr = (addr + 0xf) & ~0xf;
2100 bi = (struct xboot_info *)addr;
2101
2102 #if !defined(__xpv)
2103 /*
2104 * fb info must be 16 byte aligned for 64 bit kernel ABI
2105 */
2106 addr = (uintptr_t)framebuffer;
2107 addr = (addr + 0xf) & ~0xf;
2108 fb = (boot_framebuffer_t *)addr;
2109 bi->bi_framebuffer = (native_ptr_t)(uintptr_t)fb;
2110
2111 switch (multiboot_version) {
2112 case 1:
2113 dboot_multiboot1_xboot_consinfo();
2114 break;
2115 case 2:
2116 dboot_multiboot2_xboot_consinfo();
2117 break;
2118 default:
2119 dboot_panic("Unknown multiboot version: %d\n",
2120 multiboot_version);
2121 break;
2122 }
2123 /*
2124 * Lookup environment module for the console. Complete module list
2125 * will be built after console setup.
2126 */
2127 dboot_find_console_modules();
2128 #endif
2129 }
2130
2131 /*
2132 * Set up basic data from the boot loader.
2133 * The load_addr is part of AOUT kludge setup in dboot_grub.s, to support
2134 * 32-bit dboot code setup used to set up and start 64-bit kernel.
2135 * AOUT kludge does allow 32-bit boot loader, such as grub1, to load and
2136 * start 64-bit illumos kernel.
2137 */
2138 static void
2139 dboot_loader_init(void)
2140 {
2141 #if !defined(__xpv)
2142 mb_info = NULL;
2143 mb2_info = NULL;
2144
2145 switch (mb_magic) {
2146 case MB_BOOTLOADER_MAGIC:
2147 multiboot_version = 1;
2231 #endif /* __xpv */
2232 }
2233
2234 /*
2235 * startup_kernel has a pretty simple job. It builds pagetables which reflect
2236 * 1:1 mappings for all memory in use. It then also adds mappings for
2237 * the kernel nucleus at virtual address of target_kernel_text using large page
2238 * mappings. The page table pages are also accessible at 1:1 mapped
2239 * virtual addresses.
2240 */
2241 /*ARGSUSED*/
2242 void
2243 startup_kernel(void)
2244 {
2245 char *cmdline;
2246 char *bootloader;
2247 #if defined(__xpv)
2248 physdev_set_iopl_t set_iopl;
2249 #endif /* __xpv */
2250
2251 bcons_init(NULL); /* Set very early console to ttya. */
2252 dboot_loader_init();
2253 /*
2254 * At this point we are executing in a 32 bit real mode.
2255 */
2256
2257 bootloader = dboot_loader_name();
2258 cmdline = dboot_loader_cmdline();
2259
2260 #if defined(__xpv)
2261 /*
2262 * For dom0, before we initialize the console subsystem we'll
2263 * need to enable io operations, so set I/O priveldge level to 1.
2264 */
2265 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
2266 set_iopl.iopl = 1;
2267 (void) HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
2268 }
2269 #endif /* __xpv */
2270
2271 dboot_init_xboot_consinfo();
2272 bi->bi_cmdline = (native_ptr_t)(uintptr_t)cmdline;
2273 bcons_init(bi); /* Now we can set the real console. */
2274
2275 prom_debug = (find_boot_prop("prom_debug") != NULL);
2276 map_debug = (find_boot_prop("map_debug") != NULL);
2277
2278 #if !defined(__xpv)
2279 dboot_multiboot_get_fwtables();
2280 #endif
2281 DBG_MSG("\n\nillumos prekernel set: ");
2282 DBG_MSG(cmdline);
2283 DBG_MSG("\n");
2284
2285 if (bootloader != NULL && prom_debug) {
2286 dboot_printf("Kernel loaded by: %s\n", bootloader);
2287 #if !defined(__xpv)
2288 dboot_printf("Using multiboot %d boot protocol.\n",
2289 multiboot_version);
2290 #endif
2291 }
2292
2293 if (strstr(cmdline, "multiboot") != NULL) {
2379 */
2380 if (HYPERVISOR_vm_assist(VMASST_CMD_enable,
2381 VMASST_TYPE_writable_pagetables) < 0)
2382 dboot_panic("HYPERVISOR_vm_assist(writable_pagetables) failed");
2383
2384 /*
2385 * check for NX support
2386 */
2387 if (pae_support) {
2388 uint32_t eax = 0x80000000;
2389 uint32_t edx = get_cpuid_edx(&eax);
2390
2391 if (eax >= 0x80000001) {
2392 eax = 0x80000001;
2393 edx = get_cpuid_edx(&eax);
2394 if (edx & CPUID_AMD_EDX_NX)
2395 NX_support = 1;
2396 }
2397 }
2398
2399 /*
2400 * check for PAT support
2401 */
2402 {
2403 uint32_t eax = 1;
2404 uint32_t edx = get_cpuid_edx(&eax);
2405
2406 if (edx & CPUID_INTC_EDX_PAT)
2407 PAT_support = 1;
2408 }
2409 #if !defined(_BOOT_TARGET_amd64)
2410
2411 /*
2412 * The 32-bit hypervisor uses segmentation to protect itself from
2413 * guests. This means when a guest attempts to install a flat 4GB
2414 * code or data descriptor the 32-bit hypervisor will protect itself
2415 * by silently shrinking the segment such that if the guest attempts
2416 * any access where the hypervisor lives a #gp fault is generated.
2417 * The problem is that some applications expect a full 4GB flat
2418 * segment for their current thread pointer and will use negative
2419 * offset segment wrap around to access data. TLS support in linux
2420 * brand is one example of this.
2421 *
2422 * The 32-bit hypervisor can catch the #gp fault in these cases
2423 * and emulate the access without passing the #gp fault to the guest
2424 * but only if VMASST_TYPE_4gb_segments is explicitly turned on.
2425 * Seems like this should have been the default.
2426 * Either way, we want the hypervisor -- and not Solaris -- to deal
2427 * to deal with emulating these accesses.
2428 */
2430 VMASST_TYPE_4gb_segments) < 0)
2431 dboot_panic("HYPERVISOR_vm_assist(4gb_segments) failed");
2432 #endif /* !_BOOT_TARGET_amd64 */
2433
2434 #else /* __xpv */
2435
2436 /*
2437 * use cpuid to enable MMU features
2438 */
2439 if (have_cpuid()) {
2440 uint32_t eax, edx;
2441
2442 eax = 1;
2443 edx = get_cpuid_edx(&eax);
2444 if (edx & CPUID_INTC_EDX_PSE)
2445 largepage_support = 1;
2446 if (edx & CPUID_INTC_EDX_PGE)
2447 pge_support = 1;
2448 if (edx & CPUID_INTC_EDX_PAE)
2449 pae_support = 1;
2450 if (edx & CPUID_INTC_EDX_PAT)
2451 PAT_support = 1;
2452
2453 eax = 0x80000000;
2454 edx = get_cpuid_edx(&eax);
2455 if (eax >= 0x80000001) {
2456 eax = 0x80000001;
2457 edx = get_cpuid_edx(&eax);
2458 if (edx & CPUID_AMD_EDX_LM)
2459 amd64_support = 1;
2460 if (edx & CPUID_AMD_EDX_NX)
2461 NX_support = 1;
2462 }
2463 } else {
2464 dboot_printf("cpuid not supported\n");
2465 }
2466 #endif /* __xpv */
2467
2468
2469 #if defined(_BOOT_TARGET_amd64)
2470 if (amd64_support == 0)
2471 dboot_panic("long mode not supported, rebooting");
2501 if (pae_support) {
2502 shift_amt = shift_amt_pae;
2503 ptes_per_table = 512;
2504 pte_size = 8;
2505 lpagesize = TWO_MEG;
2506 #if defined(_BOOT_TARGET_amd64)
2507 top_level = 3;
2508 #else
2509 top_level = 2;
2510 #endif
2511 } else {
2512 pae_support = 0;
2513 NX_support = 0;
2514 shift_amt = shift_amt_nopae;
2515 ptes_per_table = 1024;
2516 pte_size = 4;
2517 lpagesize = FOUR_MEG;
2518 top_level = 1;
2519 }
2520
2521 DBG(PAT_support);
2522 DBG(pge_support);
2523 DBG(NX_support);
2524 DBG(largepage_support);
2525 DBG(amd64_support);
2526 DBG(top_level);
2527 DBG(pte_size);
2528 DBG(ptes_per_table);
2529 DBG(lpagesize);
2530
2531 #if defined(__xpv)
2532 ktext_phys = ONE_GIG; /* from UNIX Mapfile */
2533 #else
2534 ktext_phys = FOUR_MEG; /* from UNIX Mapfile */
2535 #endif
2536
2537 #if !defined(__xpv) && defined(_BOOT_TARGET_amd64)
2538 /*
2539 * For grub, copy kernel bits from the ELF64 file to final place.
2540 */
2541 DBG_MSG("\nAllocating nucleus pages.\n");
2601 case 2:
2602 bi->bi_mb_info = (native_ptr_t)(uintptr_t)mb2_info;
2603 break;
2604 default:
2605 dboot_panic("Unknown multiboot version: %d\n",
2606 multiboot_version);
2607 break;
2608 }
2609 bi->bi_top_page_table = (uintptr_t)top_page_table;
2610
2611 #endif /* __xpv */
2612
2613 bi->bi_kseg_size = FOUR_MEG;
2614 DBG(bi->bi_kseg_size);
2615
2616 #ifndef __xpv
2617 if (map_debug)
2618 dump_tables();
2619 #endif
2620
2621 #ifndef __xpv
2622 /* Update boot info with FB data */
2623 fb->cursor.origin.x = fb_info.cursor.origin.x;
2624 fb->cursor.origin.y = fb_info.cursor.origin.y;
2625 fb->cursor.pos.x = fb_info.cursor.pos.x;
2626 fb->cursor.pos.y = fb_info.cursor.pos.y;
2627 fb->cursor.visible = fb_info.cursor.visible;
2628 #endif
2629
2630 DBG_MSG("\n\n*** DBOOT DONE -- back to asm to jump to kernel\n\n");
2631 }
|