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 }
 |