Print this page
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
loader: pxe receive cleanup
9475 libefi: Do not return only if ReceiveFilter
installboot: should support efi system partition
8931 boot1.efi: scan all display modes rather than
loader: spinconsole updates
loader: gfx experiment to try GOP Blt() function.
sha1 build test
loader: add sha1 hash calculation
common/sha1: update for loader build
loader: biosdisk rework
uts: 32-bit kernel FB needs mapping in low memory
uts: add diag-device
uts: boot console mirror with diag-device
uts: enable very early console on ttya
kmdb: add diag-device as input/output device
uts: test VGA memory exclusion from mapping
uts: clear boot mapping and protect boot pages test
uts: add dboot map debug printf
uts: need to release FB pages in release_bootstrap()
uts: add screenmap ioctl
uts: update sys/queue.h
loader: add illumos uts/common to include path
loader: tem/gfx font cleanup
loader: vbe checks
uts: gfx_private set KD_TEXT when KD_RESETTEXT is
uts: gfx 8-bit update
loader: gfx 8-bit fix
loader: always set media size from partition.
uts: MB2 support for 32-bit kernel
loader: x86 should have tem 80x25
uts: x86 should have tem 80x25
uts: font update
loader: font update
uts: tem attributes
loader: tem.c comment added
uts: use font module
loader: add font module
loader: build rules for new font setup
uts: gfx_private update for new font structure
uts: early boot update for new font structure
uts: font update
uts: font build rules update for new fonts
uts: tem update to new font structure
loader: module.c needs to include tem_impl.h
uts: gfx_private 8x16 font rework
uts: make font_lookup public
loader: font rework
uts: font rework
9259 libefi: efi_alloc_and_read should check for PMBR
uts: tem utf-8 support
loader: implement tem utf-8 support
loader: tem should be able to display UTF-8
7784 uts: console input should support utf-8
7796 uts: ldterm default to utf-8
uts: do not reset serial console
uts: set up colors even if tem is not console
uts: add type for early boot properties
uts: gfx_private experiment with drm and vga
uts: gfx_private should use setmode drm callback.
uts: identify FB types and set up gfx_private based
loader: replace gop and vesa with framebuffer
uts: boot needs simple tem to support mdb
uts: boot_keyboard should emit esc sequences for
uts: gfx_private FB showuld be written by line
kmdb: set terminal window size
uts: gfx_private needs to keep track of early boot FB
pnglite: move pnglite to usr/src/common
loader: gfx_fb
ficl-sys: add gfx primitives
loader: add illumos.png logo
ficl: add fb-putimage
loader: add png support
loader: add alpha blending for gfx_fb
loader: use term-drawrect for menu frame
ficl: add simple gfx words
uts: provide fb_info via fbgattr dev_specific array.
uts: gfx_private add alpha blending
uts: update sys/ascii.h
uts: tem OSC support (incomplete)
uts: implement env module support and use data from
uts: tem get colors from early boot data
loader: use crc32 from libstand (libz)
loader: optimize for size
loader: pass tem info to the environment
loader: import tem for loader console
loader: UEFI loader needs to set ISADIR based on
loader: need UEFI32 support
8918 loader.efi: add vesa edid support
uts: tem_safe_pix_clear_prom_output() should only
uts: tem_safe_pix_clear_entire_screen() should use
uts: tem_safe_check_first_time() should query cursor
uts: tem implement cls callback & visual_io v4
uts: gfx_vgatext use block cursor for vgatext
uts: gfx_private implement cls callback & visual_io
uts: gfx_private bitmap framebuffer implementation
uts: early start frame buffer console support
uts: font functions should check the input char
uts: font rendering should support 16/24/32bit depths
uts: use smallest font as fallback default.
uts: update terminal dimensions based on selected
7834 uts: vgatext should use gfx_private
uts: add spacing property to 8859-1.bdf
terminfo: add underline for sun-color
terminfo: sun-color has 16 colors
uts: add font load callback type
loader: do not repeat int13 calls with error 0x20 and
8905 loader: add skein/edonr support
8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Revert "NEX-16819 loader UEFI support"
This reverts commit ec06b9fc617b99234e538bf2e7e4d02a24993e0c.
Reverting due to failures in the zfs-tests and the sharefs-tests
NEX-16819 loader UEFI support
Includes work by Toomas Soome <tsoome@me.com>
Upstream commits:
loader: pxe receive cleanup
9475 libefi: Do not return only if ReceiveFilter
installboot: should support efi system partition
8931 boot1.efi: scan all display modes rather than
loader: spinconsole updates
loader: gfx experiment to try GOP Blt() function.
sha1 build test
loader: add sha1 hash calculation
common/sha1: update for loader build
loader: biosdisk rework
uts: 32-bit kernel FB needs mapping in low memory
uts: add diag-device
uts: boot console mirror with diag-device
uts: enable very early console on ttya
kmdb: add diag-device as input/output device
uts: test VGA memory exclusion from mapping
uts: clear boot mapping and protect boot pages test
uts: add dboot map debug printf
uts: need to release FB pages in release_bootstrap()
uts: add screenmap ioctl
uts: update sys/queue.h
loader: add illumos uts/common to include path
loader: tem/gfx font cleanup
loader: vbe checks
uts: gfx_private set KD_TEXT when KD_RESETTEXT is
uts: gfx 8-bit update
loader: gfx 8-bit fix
loader: always set media size from partition.
uts: MB2 support for 32-bit kernel
loader: x86 should have tem 80x25
uts: x86 should have tem 80x25
uts: font update
loader: font update
uts: tem attributes
loader: tem.c comment added
uts: use font module
loader: add font module
loader: build rules for new font setup
uts: gfx_private update for new font structure
uts: early boot update for new font structure
uts: font update
uts: font build rules update for new fonts
uts: tem update to new font structure
loader: module.c needs to include tem_impl.h
uts: gfx_private 8x16 font rework
uts: make font_lookup public
loader: font rework
uts: font rework
libefi: efi_alloc_and_read should check for PMBR
uts: tem utf-8 support
loader: implement tem utf-8 support
loader: tem should be able to display UTF-8
7784 uts: console input should support utf-8
7796 uts: ldterm default to utf-8
uts: do not reset serial console
uts: set up colors even if tem is not console
uts: add type for early boot properties
uts: gfx_private experiment with drm and vga
uts: gfx_private should use setmode drm callback.
uts: identify FB types and set up gfx_private based
loader: replace gop and vesa with framebuffer
uts: boot needs simple tem to support mdb
uts: boot_keyboard should emit esc sequences for
uts: gfx_private FB showuld be written by line
kmdb: set terminal window size
uts: gfx_private needs to keep track of early boot FB
pnglite: move pnglite to usr/src/common
loader: gfx_fb
ficl-sys: add gfx primitives
loader: add illumos.png logo
ficl: add fb-putimage
loader: add png support
loader: add alpha blending for gfx_fb
loader: use term-drawrect for menu frame
ficl: add simple gfx words
uts: provide fb_info via fbgattr dev_specific array.
uts: gfx_private add alpha blending
uts: update sys/ascii.h
uts: tem OSC support (incomplete)
uts: implement env module support and use data from
uts: tem get colors from early boot data
loader: use crc32 from libstand (libz)
loader: optimize for size
loader: pass tem info to the environment
loader: import tem for loader console
loader: UEFI loader needs to set ISADIR based on
loader: need UEFI32 support
8918 loader.efi: add vesa edid support
uts: tem_safe_pix_clear_prom_output() should only
uts: tem_safe_pix_clear_entire_screen() should use
uts: tem_safe_check_first_time() should query cursor
uts: tem implement cls callback & visual_io v4
uts: gfx_vgatext use block cursor for vgatext
uts: gfx_private implement cls callback & visual_io
uts: gfx_private bitmap framebuffer implementation
uts: early start frame buffer console support
uts: font functions should check the input char
uts: font rendering should support 16/24/32bit depths
uts: use smallest font as fallback default.
uts: update terminal dimensions based on selected
7834 uts: vgatext should use gfx_private
uts: add spacing property to 8859-1.bdf
terminfo: add underline for sun-color
terminfo: sun-color has 16 colors
uts: add font load callback type
loader: do not repeat int13 calls with error 0x20 and
8905 loader: add skein/edonr support
8904 common/crypto: make skein and edonr loader
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/i86pc/dboot/dboot_startkern.c
+++ new/usr/src/uts/i86pc/dboot/dboot_startkern.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 *
26 26 * Copyright 2013 Joyent, Inc. All rights reserved.
27 27 */
28 28
|
↓ open down ↓ |
28 lines elided |
↑ open up ↑ |
29 29
30 30 #include <sys/types.h>
31 31 #include <sys/machparam.h>
32 32 #include <sys/x86_archext.h>
33 33 #include <sys/systm.h>
34 34 #include <sys/mach_mmu.h>
35 35 #include <sys/multiboot.h>
36 36 #include <sys/multiboot2.h>
37 37 #include <sys/multiboot2_impl.h>
38 38 #include <sys/sysmacros.h>
39 +#include <sys/framebuffer.h>
39 40 #include <sys/sha1.h>
40 41 #include <util/string.h>
41 42 #include <util/strtolctype.h>
42 43 #include <sys/efi.h>
43 44
44 45 #if defined(__xpv)
45 46
46 47 #include <sys/hypervisor.h>
47 48 uintptr_t xen_virt_start;
48 49 pfn_t *mfn_to_pfn_mapping;
49 50
50 51 #else /* !__xpv */
51 52
52 53 extern multiboot_header_t mb_header;
53 54 extern uint32_t mb2_load_addr;
54 55 extern int have_cpuid(void);
55 56
56 57 #endif /* !__xpv */
57 58
58 59 #include <sys/inttypes.h>
59 60 #include <sys/bootinfo.h>
60 61 #include <sys/mach_mmu.h>
61 62 #include <sys/boot_console.h>
62 63
63 64 #include "dboot_asm.h"
64 65 #include "dboot_printf.h"
65 66 #include "dboot_xboot.h"
66 67 #include "dboot_elfload.h"
67 68
68 69 #define SHA1_ASCII_LENGTH (SHA1_DIGEST_LENGTH * 2)
69 70
70 71 /*
71 72 * This file contains code that runs to transition us from either a multiboot
72 73 * compliant loader (32 bit non-paging) or a XPV domain loader to
73 74 * regular kernel execution. Its task is to setup the kernel memory image
74 75 * and page tables.
75 76 *
76 77 * The code executes as:
77 78 * - 32 bits under GRUB (for 32 or 64 bit Solaris)
78 79 * - a 32 bit program for the 32-bit PV hypervisor
79 80 * - a 64 bit program for the 64-bit PV hypervisor (at least for now)
80 81 *
81 82 * Under the PV hypervisor, we must create mappings for any memory beyond the
82 83 * initial start of day allocation (such as the kernel itself).
83 84 *
84 85 * When on the metal, the mapping between maddr_t and paddr_t is 1:1.
85 86 * Since we are running in real mode, so all such memory is accessible.
86 87 */
87 88
88 89 /*
89 90 * Standard bits used in PTE (page level) and PTP (internal levels)
90 91 */
91 92 x86pte_t ptp_bits = PT_VALID | PT_REF | PT_WRITABLE | PT_USER;
92 93 x86pte_t pte_bits = PT_VALID | PT_REF | PT_WRITABLE | PT_MOD | PT_NOCONSIST;
93 94
94 95 /*
95 96 * This is the target addresses (physical) where the kernel text and data
96 97 * nucleus pages will be unpacked. On the hypervisor this is actually a
97 98 * virtual address.
98 99 */
99 100 paddr_t ktext_phys;
100 101 uint32_t ksize = 2 * FOUR_MEG; /* kernel nucleus is 8Meg */
101 102
102 103 static uint64_t target_kernel_text; /* value to use for KERNEL_TEXT */
103 104
104 105 /*
105 106 * The stack is setup in assembler before entering startup_kernel()
106 107 */
107 108 char stack_space[STACK_SIZE];
108 109
109 110 /*
110 111 * Used to track physical memory allocation
111 112 */
112 113 static paddr_t next_avail_addr = 0;
113 114
114 115 #if defined(__xpv)
115 116 /*
116 117 * Additional information needed for hypervisor memory allocation.
117 118 * Only memory up to scratch_end is mapped by page tables.
118 119 * mfn_base is the start of the hypervisor virtual image. It's ONE_GIG, so
119 120 * to derive a pfn from a pointer, you subtract mfn_base.
120 121 */
121 122
122 123 static paddr_t scratch_end = 0; /* we can't write all of mem here */
123 124 static paddr_t mfn_base; /* addr corresponding to mfn_list[0] */
124 125 start_info_t *xen_info;
125 126
126 127 #else /* __xpv */
127 128
128 129 /*
129 130 * If on the metal, then we have a multiboot loader.
|
↓ open down ↓ |
81 lines elided |
↑ open up ↑ |
130 131 */
131 132 uint32_t mb_magic; /* magic from boot loader */
132 133 uint32_t mb_addr; /* multiboot info package from loader */
133 134 int multiboot_version;
134 135 multiboot_info_t *mb_info;
135 136 multiboot2_info_header_t *mb2_info;
136 137 multiboot_tag_mmap_t *mb2_mmap_tagp;
137 138 int num_entries; /* mmap entry count */
138 139 boolean_t num_entries_set; /* is mmap entry count set */
139 140 uintptr_t load_addr;
141 +static boot_framebuffer_t framebuffer[2];
142 +static boot_framebuffer_t *fb;
140 143
141 144 /* can not be automatic variables because of alignment */
142 145 static efi_guid_t smbios3 = SMBIOS3_TABLE_GUID;
143 146 static efi_guid_t smbios = SMBIOS_TABLE_GUID;
144 147 static efi_guid_t acpi2 = EFI_ACPI_TABLE_GUID;
145 148 static efi_guid_t acpi1 = ACPI_10_TABLE_GUID;
146 149 #endif /* __xpv */
147 150
148 151 /*
149 152 * This contains information passed to the kernel
150 153 */
151 154 struct xboot_info boot_info[2]; /* extra space to fix alignement for amd64 */
152 155 struct xboot_info *bi;
153 156
154 157 /*
155 158 * Page table and memory stuff.
156 159 */
|
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
157 160 static paddr_t max_mem; /* maximum memory address */
158 161
159 162 /*
160 163 * Information about processor MMU
161 164 */
162 165 int amd64_support = 0;
163 166 int largepage_support = 0;
164 167 int pae_support = 0;
165 168 int pge_support = 0;
166 169 int NX_support = 0;
170 +int PAT_support = 0;
167 171
168 172 /*
169 173 * Low 32 bits of kernel entry address passed back to assembler.
170 174 * When running a 64 bit kernel, the high 32 bits are 0xffffffff.
171 175 */
172 176 uint32_t entry_addr_low;
173 177
174 178 /*
175 179 * Memlists for the kernel. We shouldn't need a lot of these.
176 180 */
177 181 #define MAX_MEMLIST (50)
178 182 struct boot_memlist memlists[MAX_MEMLIST];
179 183 uint_t memlists_used = 0;
180 184 struct boot_memlist pcimemlists[MAX_MEMLIST];
181 185 uint_t pcimemlists_used = 0;
182 186 struct boot_memlist rsvdmemlists[MAX_MEMLIST];
183 187 uint_t rsvdmemlists_used = 0;
184 188
185 189 /*
186 190 * This should match what's in the bootloader. It's arbitrary, but GRUB
187 191 * in particular has limitations on how much space it can use before it
188 192 * stops working properly. This should be enough.
189 193 */
190 194 struct boot_modules modules[MAX_BOOT_MODULES];
191 195 uint_t modules_used = 0;
192 196
193 197 #ifdef __xpv
194 198 /*
195 199 * Xen strips the size field out of the mb_memory_map_t, see struct e820entry
196 200 * definition in Xen source.
197 201 */
198 202 typedef struct {
199 203 uint32_t base_addr_low;
200 204 uint32_t base_addr_high;
201 205 uint32_t length_low;
202 206 uint32_t length_high;
203 207 uint32_t type;
204 208 } mmap_t;
205 209
206 210 /*
207 211 * There is 512KB of scratch area after the boot stack page.
208 212 * We'll use that for everything except the kernel nucleus pages which are too
209 213 * big to fit there and are allocated last anyway.
210 214 */
211 215 #define MAXMAPS 100
212 216 static mmap_t map_buffer[MAXMAPS];
213 217 #else
214 218 typedef mb_memory_map_t mmap_t;
215 219 #endif
216 220
217 221 /*
218 222 * Debugging macros
219 223 */
220 224 uint_t prom_debug = 0;
221 225 uint_t map_debug = 0;
222 226
223 227 static char noname[2] = "-";
224 228
225 229 /*
226 230 * Either hypervisor-specific or grub-specific code builds the initial
227 231 * memlists. This code does the sort/merge/link for final use.
228 232 */
229 233 static void
230 234 sort_physinstall(void)
231 235 {
232 236 int i;
233 237 #if !defined(__xpv)
234 238 int j;
235 239 struct boot_memlist tmp;
236 240
237 241 /*
238 242 * Now sort the memlists, in case they weren't in order.
239 243 * Yeah, this is a bubble sort; small, simple and easy to get right.
240 244 */
241 245 DBG_MSG("Sorting phys-installed list\n");
242 246 for (j = memlists_used - 1; j > 0; --j) {
243 247 for (i = 0; i < j; ++i) {
244 248 if (memlists[i].addr < memlists[i + 1].addr)
245 249 continue;
246 250 tmp = memlists[i];
247 251 memlists[i] = memlists[i + 1];
248 252 memlists[i + 1] = tmp;
249 253 }
250 254 }
251 255
252 256 /*
253 257 * Merge any memlists that don't have holes between them.
254 258 */
255 259 for (i = 0; i <= memlists_used - 1; ++i) {
256 260 if (memlists[i].addr + memlists[i].size != memlists[i + 1].addr)
257 261 continue;
258 262
259 263 if (prom_debug)
260 264 dboot_printf(
261 265 "merging mem segs %" PRIx64 "...%" PRIx64
262 266 " w/ %" PRIx64 "...%" PRIx64 "\n",
263 267 memlists[i].addr,
264 268 memlists[i].addr + memlists[i].size,
265 269 memlists[i + 1].addr,
266 270 memlists[i + 1].addr + memlists[i + 1].size);
267 271
268 272 memlists[i].size += memlists[i + 1].size;
269 273 for (j = i + 1; j < memlists_used - 1; ++j)
270 274 memlists[j] = memlists[j + 1];
271 275 --memlists_used;
272 276 DBG(memlists_used);
273 277 --i; /* after merging we need to reexamine, so do this */
274 278 }
275 279 #endif /* __xpv */
276 280
277 281 if (prom_debug) {
278 282 dboot_printf("\nFinal memlists:\n");
279 283 for (i = 0; i < memlists_used; ++i) {
280 284 dboot_printf("\t%d: addr=%" PRIx64 " size=%"
281 285 PRIx64 "\n", i, memlists[i].addr, memlists[i].size);
282 286 }
283 287 }
284 288
285 289 /*
286 290 * link together the memlists with native size pointers
287 291 */
288 292 memlists[0].next = 0;
289 293 memlists[0].prev = 0;
290 294 for (i = 1; i < memlists_used; ++i) {
291 295 memlists[i].prev = (native_ptr_t)(uintptr_t)(memlists + i - 1);
292 296 memlists[i].next = 0;
293 297 memlists[i - 1].next = (native_ptr_t)(uintptr_t)(memlists + i);
294 298 }
295 299 bi->bi_phys_install = (native_ptr_t)(uintptr_t)memlists;
296 300 DBG(bi->bi_phys_install);
297 301 }
298 302
299 303 /*
300 304 * build bios reserved memlists
301 305 */
302 306 static void
303 307 build_rsvdmemlists(void)
304 308 {
305 309 int i;
306 310
307 311 rsvdmemlists[0].next = 0;
308 312 rsvdmemlists[0].prev = 0;
309 313 for (i = 1; i < rsvdmemlists_used; ++i) {
310 314 rsvdmemlists[i].prev =
311 315 (native_ptr_t)(uintptr_t)(rsvdmemlists + i - 1);
312 316 rsvdmemlists[i].next = 0;
313 317 rsvdmemlists[i - 1].next =
314 318 (native_ptr_t)(uintptr_t)(rsvdmemlists + i);
315 319 }
316 320 bi->bi_rsvdmem = (native_ptr_t)(uintptr_t)rsvdmemlists;
317 321 DBG(bi->bi_rsvdmem);
318 322 }
319 323
320 324 #if defined(__xpv)
321 325
322 326 /*
323 327 * halt on the hypervisor after a delay to drain console output
324 328 */
325 329 void
326 330 dboot_halt(void)
327 331 {
328 332 uint_t i = 10000;
329 333
330 334 while (--i)
331 335 (void) HYPERVISOR_yield();
332 336 (void) HYPERVISOR_shutdown(SHUTDOWN_poweroff);
333 337 }
334 338
335 339 /*
336 340 * From a machine address, find the corresponding pseudo-physical address.
337 341 * Pseudo-physical address are contiguous and run from mfn_base in each VM.
338 342 * Machine addresses are the real underlying hardware addresses.
339 343 * These are needed for page table entries. Note that this routine is
340 344 * poorly protected. A bad value of "ma" will cause a page fault.
341 345 */
342 346 paddr_t
343 347 ma_to_pa(maddr_t ma)
344 348 {
345 349 ulong_t pgoff = ma & MMU_PAGEOFFSET;
346 350 ulong_t pfn = mfn_to_pfn_mapping[mmu_btop(ma)];
347 351 paddr_t pa;
348 352
349 353 if (pfn >= xen_info->nr_pages)
350 354 return (-(paddr_t)1);
351 355 pa = mfn_base + mmu_ptob((paddr_t)pfn) + pgoff;
352 356 #ifdef DEBUG
353 357 if (ma != pa_to_ma(pa))
354 358 dboot_printf("ma_to_pa(%" PRIx64 ") got %" PRIx64 ", "
355 359 "pa_to_ma() says %" PRIx64 "\n", ma, pa, pa_to_ma(pa));
356 360 #endif
357 361 return (pa);
358 362 }
359 363
360 364 /*
361 365 * From a pseudo-physical address, find the corresponding machine address.
362 366 */
363 367 maddr_t
364 368 pa_to_ma(paddr_t pa)
365 369 {
366 370 pfn_t pfn;
367 371 ulong_t mfn;
368 372
369 373 pfn = mmu_btop(pa - mfn_base);
370 374 if (pa < mfn_base || pfn >= xen_info->nr_pages)
371 375 dboot_panic("pa_to_ma(): illegal address 0x%lx", (ulong_t)pa);
372 376 mfn = ((ulong_t *)xen_info->mfn_list)[pfn];
373 377 #ifdef DEBUG
374 378 if (mfn_to_pfn_mapping[mfn] != pfn)
375 379 dboot_printf("pa_to_ma(pfn=%lx) got %lx ma_to_pa() says %lx\n",
376 380 pfn, mfn, mfn_to_pfn_mapping[mfn]);
377 381 #endif
378 382 return (mfn_to_ma(mfn) | (pa & MMU_PAGEOFFSET));
379 383 }
380 384
381 385 #endif /* __xpv */
382 386
383 387 x86pte_t
384 388 get_pteval(paddr_t table, uint_t index)
385 389 {
386 390 if (pae_support)
387 391 return (((x86pte_t *)(uintptr_t)table)[index]);
388 392 return (((x86pte32_t *)(uintptr_t)table)[index]);
389 393 }
390 394
391 395 /*ARGSUSED*/
392 396 void
393 397 set_pteval(paddr_t table, uint_t index, uint_t level, x86pte_t pteval)
394 398 {
395 399 #ifdef __xpv
396 400 mmu_update_t t;
397 401 maddr_t mtable = pa_to_ma(table);
398 402 int retcnt;
399 403
400 404 t.ptr = (mtable + index * pte_size) | MMU_NORMAL_PT_UPDATE;
401 405 t.val = pteval;
402 406 if (HYPERVISOR_mmu_update(&t, 1, &retcnt, DOMID_SELF) || retcnt != 1)
403 407 dboot_panic("HYPERVISOR_mmu_update() failed");
404 408 #else /* __xpv */
405 409 uintptr_t tab_addr = (uintptr_t)table;
406 410
407 411 if (pae_support)
408 412 ((x86pte_t *)tab_addr)[index] = pteval;
409 413 else
410 414 ((x86pte32_t *)tab_addr)[index] = (x86pte32_t)pteval;
411 415 if (level == top_level && level == 2)
412 416 reload_cr3();
413 417 #endif /* __xpv */
414 418 }
415 419
416 420 paddr_t
417 421 make_ptable(x86pte_t *pteval, uint_t level)
418 422 {
419 423 paddr_t new_table = (paddr_t)(uintptr_t)mem_alloc(MMU_PAGESIZE);
420 424
421 425 if (level == top_level && level == 2)
422 426 *pteval = pa_to_ma((uintptr_t)new_table) | PT_VALID;
423 427 else
424 428 *pteval = pa_to_ma((uintptr_t)new_table) | ptp_bits;
425 429
426 430 #ifdef __xpv
427 431 /* Remove write permission to the new page table. */
428 432 if (HYPERVISOR_update_va_mapping(new_table,
429 433 *pteval & ~(x86pte_t)PT_WRITABLE, UVMF_INVLPG | UVMF_LOCAL))
430 434 dboot_panic("HYP_update_va_mapping error");
431 435 #endif
432 436
433 437 if (map_debug)
434 438 dboot_printf("new page table lvl=%d paddr=0x%lx ptp=0x%"
435 439 PRIx64 "\n", level, (ulong_t)new_table, *pteval);
436 440 return (new_table);
437 441 }
438 442
439 443 x86pte_t *
440 444 map_pte(paddr_t table, uint_t index)
441 445 {
442 446 return ((x86pte_t *)(uintptr_t)(table + index * pte_size));
443 447 }
444 448
445 449 /*
446 450 * dump out the contents of page tables...
447 451 */
448 452 static void
449 453 dump_tables(void)
450 454 {
451 455 uint_t save_index[4]; /* for recursion */
452 456 char *save_table[4]; /* for recursion */
453 457 uint_t l;
454 458 uint64_t va;
455 459 uint64_t pgsize;
456 460 int index;
457 461 int i;
458 462 x86pte_t pteval;
459 463 char *table;
460 464 static char *tablist = "\t\t\t";
461 465 char *tabs = tablist + 3 - top_level;
462 466 uint_t pa, pa1;
463 467 #if !defined(__xpv)
464 468 #define maddr_t paddr_t
465 469 #endif /* !__xpv */
466 470
467 471 dboot_printf("Finished pagetables:\n");
468 472 table = (char *)(uintptr_t)top_page_table;
469 473 l = top_level;
470 474 va = 0;
471 475 for (index = 0; index < ptes_per_table; ++index) {
472 476 pgsize = 1ull << shift_amt[l];
473 477 if (pae_support)
474 478 pteval = ((x86pte_t *)table)[index];
475 479 else
476 480 pteval = ((x86pte32_t *)table)[index];
477 481 if (pteval == 0)
478 482 goto next_entry;
479 483
480 484 dboot_printf("%s %p[0x%x] = %" PRIx64 ", va=%" PRIx64,
481 485 tabs + l, (void *)table, index, (uint64_t)pteval, va);
482 486 pa = ma_to_pa(pteval & MMU_PAGEMASK);
483 487 dboot_printf(" physaddr=%x\n", pa);
484 488
485 489 /*
486 490 * Don't try to walk hypervisor private pagetables
487 491 */
488 492 if ((l > 1 || (l == 1 && (pteval & PT_PAGESIZE) == 0))) {
489 493 save_table[l] = table;
490 494 save_index[l] = index;
491 495 --l;
492 496 index = -1;
493 497 table = (char *)(uintptr_t)
494 498 ma_to_pa(pteval & MMU_PAGEMASK);
495 499 goto recursion;
496 500 }
497 501
498 502 /*
499 503 * shorten dump for consecutive mappings
500 504 */
501 505 for (i = 1; index + i < ptes_per_table; ++i) {
502 506 if (pae_support)
503 507 pteval = ((x86pte_t *)table)[index + i];
504 508 else
505 509 pteval = ((x86pte32_t *)table)[index + i];
506 510 if (pteval == 0)
507 511 break;
508 512 pa1 = ma_to_pa(pteval & MMU_PAGEMASK);
509 513 if (pa1 != pa + i * pgsize)
510 514 break;
511 515 }
512 516 if (i > 2) {
513 517 dboot_printf("%s...\n", tabs + l);
514 518 va += pgsize * (i - 2);
515 519 index += i - 2;
516 520 }
517 521 next_entry:
518 522 va += pgsize;
519 523 if (l == 3 && index == 256) /* VA hole */
520 524 va = 0xffff800000000000ull;
521 525 recursion:
522 526 ;
523 527 }
524 528 if (l < top_level) {
525 529 ++l;
526 530 index = save_index[l];
527 531 table = save_table[l];
528 532 goto recursion;
529 533 }
530 534 }
531 535
532 536 /*
533 537 * Add a mapping for the machine page at the given virtual address.
534 538 */
535 539 static void
536 540 map_ma_at_va(maddr_t ma, native_ptr_t va, uint_t level)
537 541 {
538 542 x86pte_t *ptep;
539 543 x86pte_t pteval;
540 544
541 545 pteval = ma | pte_bits;
542 546 if (level > 0)
543 547 pteval |= PT_PAGESIZE;
544 548 if (va >= target_kernel_text && pge_support)
545 549 pteval |= PT_GLOBAL;
546 550
547 551 if (map_debug && ma != va)
548 552 dboot_printf("mapping ma=0x%" PRIx64 " va=0x%" PRIx64
549 553 " pte=0x%" PRIx64 " l=%d\n",
550 554 (uint64_t)ma, (uint64_t)va, pteval, level);
551 555
552 556 #if defined(__xpv)
553 557 /*
554 558 * see if we can avoid find_pte() on the hypervisor
555 559 */
556 560 if (HYPERVISOR_update_va_mapping(va, pteval,
557 561 UVMF_INVLPG | UVMF_LOCAL) == 0)
558 562 return;
559 563 #endif
560 564
561 565 /*
562 566 * Find the pte that will map this address. This creates any
563 567 * missing intermediate level page tables
564 568 */
565 569 ptep = find_pte(va, NULL, level, 0);
566 570
567 571 /*
568 572 * When paravirtualized, we must use hypervisor calls to modify the
569 573 * PTE, since paging is active. On real hardware we just write to
570 574 * the pagetables which aren't in use yet.
571 575 */
572 576 #if defined(__xpv)
573 577 ptep = ptep; /* shut lint up */
574 578 if (HYPERVISOR_update_va_mapping(va, pteval, UVMF_INVLPG | UVMF_LOCAL))
575 579 dboot_panic("mmu_update failed-map_pa_at_va va=0x%" PRIx64
576 580 " l=%d ma=0x%" PRIx64 ", pte=0x%" PRIx64 "",
577 581 (uint64_t)va, level, (uint64_t)ma, pteval);
578 582 #else
579 583 if (va < 1024 * 1024)
580 584 pteval |= PT_NOCACHE; /* for video RAM */
581 585 if (pae_support)
582 586 *ptep = pteval;
583 587 else
584 588 *((x86pte32_t *)ptep) = (x86pte32_t)pteval;
585 589 #endif
586 590 }
587 591
588 592 /*
589 593 * Add a mapping for the physical page at the given virtual address.
590 594 */
591 595 static void
592 596 map_pa_at_va(paddr_t pa, native_ptr_t va, uint_t level)
593 597 {
594 598 map_ma_at_va(pa_to_ma(pa), va, level);
595 599 }
596 600
597 601 /*
598 602 * This is called to remove start..end from the
599 603 * possible range of PCI addresses.
600 604 */
601 605 const uint64_t pci_lo_limit = 0x00100000ul;
602 606 const uint64_t pci_hi_limit = 0xfff00000ul;
603 607 static void
604 608 exclude_from_pci(uint64_t start, uint64_t end)
605 609 {
606 610 int i;
607 611 int j;
608 612 struct boot_memlist *ml;
609 613
610 614 for (i = 0; i < pcimemlists_used; ++i) {
611 615 ml = &pcimemlists[i];
612 616
613 617 /* delete the entire range? */
614 618 if (start <= ml->addr && ml->addr + ml->size <= end) {
615 619 --pcimemlists_used;
616 620 for (j = i; j < pcimemlists_used; ++j)
617 621 pcimemlists[j] = pcimemlists[j + 1];
618 622 --i; /* to revisit the new one at this index */
619 623 }
620 624
621 625 /* split a range? */
622 626 else if (ml->addr < start && end < ml->addr + ml->size) {
623 627
624 628 ++pcimemlists_used;
625 629 if (pcimemlists_used > MAX_MEMLIST)
626 630 dboot_panic("too many pcimemlists");
627 631
628 632 for (j = pcimemlists_used - 1; j > i; --j)
629 633 pcimemlists[j] = pcimemlists[j - 1];
630 634 ml->size = start - ml->addr;
631 635
632 636 ++ml;
633 637 ml->size = (ml->addr + ml->size) - end;
634 638 ml->addr = end;
635 639 ++i; /* skip on to next one */
636 640 }
637 641
638 642 /* cut memory off the start? */
639 643 else if (ml->addr < end && end < ml->addr + ml->size) {
640 644 ml->size -= end - ml->addr;
641 645 ml->addr = end;
642 646 }
643 647
644 648 /* cut memory off the end? */
645 649 else if (ml->addr <= start && start < ml->addr + ml->size) {
646 650 ml->size = start - ml->addr;
647 651 }
648 652 }
649 653 }
650 654
651 655 /*
652 656 * During memory allocation, find the highest address not used yet.
653 657 */
654 658 static void
655 659 check_higher(paddr_t a)
656 660 {
657 661 if (a < next_avail_addr)
658 662 return;
659 663 next_avail_addr = RNDUP(a + 1, MMU_PAGESIZE);
660 664 DBG(next_avail_addr);
661 665 }
662 666
663 667 static int
664 668 dboot_loader_mmap_entries(void)
665 669 {
666 670 #if !defined(__xpv)
667 671 if (num_entries_set == B_TRUE)
668 672 return (num_entries);
669 673
670 674 switch (multiboot_version) {
671 675 case 1:
672 676 DBG(mb_info->flags);
673 677 if (mb_info->flags & 0x40) {
674 678 mb_memory_map_t *mmap;
675 679
676 680 DBG(mb_info->mmap_addr);
677 681 DBG(mb_info->mmap_length);
678 682 check_higher(mb_info->mmap_addr + mb_info->mmap_length);
679 683
680 684 for (mmap = (mb_memory_map_t *)mb_info->mmap_addr;
681 685 (uint32_t)mmap < mb_info->mmap_addr +
682 686 mb_info->mmap_length;
683 687 mmap = (mb_memory_map_t *)((uint32_t)mmap +
684 688 mmap->size + sizeof (mmap->size)))
685 689 ++num_entries;
686 690
687 691 num_entries_set = B_TRUE;
688 692 }
689 693 break;
690 694 case 2:
691 695 num_entries_set = B_TRUE;
692 696 num_entries = dboot_multiboot2_mmap_nentries(mb2_info,
693 697 mb2_mmap_tagp);
694 698 break;
695 699 default:
696 700 dboot_panic("Unknown multiboot version: %d\n",
697 701 multiboot_version);
698 702 break;
699 703 }
700 704 return (num_entries);
701 705 #else
702 706 return (MAXMAPS);
703 707 #endif
704 708 }
705 709
706 710 static uint32_t
707 711 dboot_loader_mmap_get_type(int index)
708 712 {
709 713 #if !defined(__xpv)
710 714 mb_memory_map_t *mp, *mpend;
711 715 int i;
712 716
713 717 switch (multiboot_version) {
714 718 case 1:
715 719 mp = (mb_memory_map_t *)mb_info->mmap_addr;
716 720 mpend = (mb_memory_map_t *)
717 721 (mb_info->mmap_addr + mb_info->mmap_length);
718 722
719 723 for (i = 0; mp < mpend && i != index; i++)
720 724 mp = (mb_memory_map_t *)((uint32_t)mp + mp->size +
721 725 sizeof (mp->size));
722 726 if (mp >= mpend) {
723 727 dboot_panic("dboot_loader_mmap_get_type(): index "
724 728 "out of bounds: %d\n", index);
725 729 }
726 730 return (mp->type);
727 731
728 732 case 2:
729 733 return (dboot_multiboot2_mmap_get_type(mb2_info,
730 734 mb2_mmap_tagp, index));
731 735
732 736 default:
733 737 dboot_panic("Unknown multiboot version: %d\n",
734 738 multiboot_version);
735 739 break;
736 740 }
737 741 return (0);
738 742 #else
739 743 return (map_buffer[index].type);
740 744 #endif
741 745 }
742 746
743 747 static uint64_t
744 748 dboot_loader_mmap_get_base(int index)
745 749 {
746 750 #if !defined(__xpv)
747 751 mb_memory_map_t *mp, *mpend;
748 752 int i;
749 753
750 754 switch (multiboot_version) {
751 755 case 1:
752 756 mp = (mb_memory_map_t *)mb_info->mmap_addr;
753 757 mpend = (mb_memory_map_t *)
754 758 (mb_info->mmap_addr + mb_info->mmap_length);
755 759
756 760 for (i = 0; mp < mpend && i != index; i++)
757 761 mp = (mb_memory_map_t *)((uint32_t)mp + mp->size +
758 762 sizeof (mp->size));
759 763 if (mp >= mpend) {
760 764 dboot_panic("dboot_loader_mmap_get_base(): index "
761 765 "out of bounds: %d\n", index);
762 766 }
763 767 return (((uint64_t)mp->base_addr_high << 32) +
764 768 (uint64_t)mp->base_addr_low);
765 769
766 770 case 2:
767 771 return (dboot_multiboot2_mmap_get_base(mb2_info,
768 772 mb2_mmap_tagp, index));
769 773
770 774 default:
771 775 dboot_panic("Unknown multiboot version: %d\n",
772 776 multiboot_version);
773 777 break;
774 778 }
775 779 return (0);
776 780 #else
777 781 return (((uint64_t)map_buffer[index].base_addr_high << 32) +
778 782 (uint64_t)map_buffer[index].base_addr_low);
779 783 #endif
780 784 }
781 785
782 786 static uint64_t
783 787 dboot_loader_mmap_get_length(int index)
784 788 {
785 789 #if !defined(__xpv)
786 790 mb_memory_map_t *mp, *mpend;
787 791 int i;
788 792
789 793 switch (multiboot_version) {
790 794 case 1:
791 795 mp = (mb_memory_map_t *)mb_info->mmap_addr;
792 796 mpend = (mb_memory_map_t *)
793 797 (mb_info->mmap_addr + mb_info->mmap_length);
794 798
795 799 for (i = 0; mp < mpend && i != index; i++)
796 800 mp = (mb_memory_map_t *)((uint32_t)mp + mp->size +
797 801 sizeof (mp->size));
798 802 if (mp >= mpend) {
799 803 dboot_panic("dboot_loader_mmap_get_length(): index "
800 804 "out of bounds: %d\n", index);
801 805 }
802 806 return (((uint64_t)mp->length_high << 32) +
803 807 (uint64_t)mp->length_low);
804 808
805 809 case 2:
806 810 return (dboot_multiboot2_mmap_get_length(mb2_info,
807 811 mb2_mmap_tagp, index));
808 812
809 813 default:
810 814 dboot_panic("Unknown multiboot version: %d\n",
811 815 multiboot_version);
812 816 break;
813 817 }
814 818 return (0);
815 819 #else
816 820 return (((uint64_t)map_buffer[index].length_high << 32) +
817 821 (uint64_t)map_buffer[index].length_low);
818 822 #endif
819 823 }
820 824
821 825 static void
822 826 build_pcimemlists(void)
823 827 {
824 828 uint64_t page_offset = MMU_PAGEOFFSET; /* needs to be 64 bits */
825 829 uint64_t start;
826 830 uint64_t end;
827 831 int i, num;
828 832
829 833 /*
830 834 * initialize
831 835 */
832 836 pcimemlists[0].addr = pci_lo_limit;
833 837 pcimemlists[0].size = pci_hi_limit - pci_lo_limit;
834 838 pcimemlists_used = 1;
835 839
836 840 num = dboot_loader_mmap_entries();
837 841 /*
838 842 * Fill in PCI memlists.
839 843 */
840 844 for (i = 0; i < num; ++i) {
841 845 start = dboot_loader_mmap_get_base(i);
842 846 end = start + dboot_loader_mmap_get_length(i);
843 847
844 848 if (prom_debug)
845 849 dboot_printf("\ttype: %d %" PRIx64 "..%"
846 850 PRIx64 "\n", dboot_loader_mmap_get_type(i),
847 851 start, end);
848 852
849 853 /*
850 854 * page align start and end
851 855 */
852 856 start = (start + page_offset) & ~page_offset;
853 857 end &= ~page_offset;
854 858 if (end <= start)
855 859 continue;
856 860
857 861 exclude_from_pci(start, end);
858 862 }
859 863
860 864 /*
861 865 * Finish off the pcimemlist
862 866 */
863 867 if (prom_debug) {
864 868 for (i = 0; i < pcimemlists_used; ++i) {
865 869 dboot_printf("pcimemlist entry 0x%" PRIx64 "..0x%"
866 870 PRIx64 "\n", pcimemlists[i].addr,
867 871 pcimemlists[i].addr + pcimemlists[i].size);
868 872 }
869 873 }
870 874 pcimemlists[0].next = 0;
871 875 pcimemlists[0].prev = 0;
872 876 for (i = 1; i < pcimemlists_used; ++i) {
873 877 pcimemlists[i].prev =
874 878 (native_ptr_t)(uintptr_t)(pcimemlists + i - 1);
875 879 pcimemlists[i].next = 0;
876 880 pcimemlists[i - 1].next =
877 881 (native_ptr_t)(uintptr_t)(pcimemlists + i);
878 882 }
879 883 bi->bi_pcimem = (native_ptr_t)(uintptr_t)pcimemlists;
880 884 DBG(bi->bi_pcimem);
881 885 }
882 886
883 887 #if defined(__xpv)
884 888 /*
885 889 * Initialize memory allocator stuff from hypervisor-supplied start info.
886 890 */
887 891 static void
888 892 init_mem_alloc(void)
889 893 {
890 894 int local; /* variables needed to find start region */
891 895 paddr_t scratch_start;
892 896 xen_memory_map_t map;
893 897
894 898 DBG_MSG("Entered init_mem_alloc()\n");
895 899
896 900 /*
897 901 * Free memory follows the stack. There's at least 512KB of scratch
898 902 * space, rounded up to at least 2Mb alignment. That should be enough
899 903 * for the page tables we'll need to build. The nucleus memory is
900 904 * allocated last and will be outside the addressible range. We'll
901 905 * switch to new page tables before we unpack the kernel
902 906 */
903 907 scratch_start = RNDUP((paddr_t)(uintptr_t)&local, MMU_PAGESIZE);
904 908 DBG(scratch_start);
905 909 scratch_end = RNDUP((paddr_t)scratch_start + 512 * 1024, TWO_MEG);
906 910 DBG(scratch_end);
907 911
908 912 /*
909 913 * For paranoia, leave some space between hypervisor data and ours.
910 914 * Use 500 instead of 512.
911 915 */
912 916 next_avail_addr = scratch_end - 500 * 1024;
913 917 DBG(next_avail_addr);
914 918
915 919 /*
916 920 * The domain builder gives us at most 1 module
917 921 */
918 922 DBG(xen_info->mod_len);
919 923 if (xen_info->mod_len > 0) {
920 924 DBG(xen_info->mod_start);
921 925 modules[0].bm_addr =
922 926 (native_ptr_t)(uintptr_t)xen_info->mod_start;
923 927 modules[0].bm_size = xen_info->mod_len;
924 928 bi->bi_module_cnt = 1;
925 929 bi->bi_modules = (native_ptr_t)(uintptr_t)modules;
926 930 } else {
927 931 bi->bi_module_cnt = 0;
928 932 bi->bi_modules = (native_ptr_t)(uintptr_t)NULL;
929 933 }
930 934 DBG(bi->bi_module_cnt);
931 935 DBG(bi->bi_modules);
932 936
933 937 DBG(xen_info->mfn_list);
934 938 DBG(xen_info->nr_pages);
935 939 max_mem = (paddr_t)xen_info->nr_pages << MMU_PAGESHIFT;
936 940 DBG(max_mem);
937 941
938 942 /*
939 943 * Using pseudo-physical addresses, so only 1 memlist element
940 944 */
941 945 memlists[0].addr = 0;
942 946 DBG(memlists[0].addr);
943 947 memlists[0].size = max_mem;
944 948 DBG(memlists[0].size);
945 949 memlists_used = 1;
946 950 DBG(memlists_used);
947 951
948 952 /*
949 953 * finish building physinstall list
950 954 */
951 955 sort_physinstall();
952 956
953 957 /*
954 958 * build bios reserved memlists
955 959 */
956 960 build_rsvdmemlists();
957 961
958 962 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
959 963 /*
960 964 * build PCI Memory list
961 965 */
962 966 map.nr_entries = MAXMAPS;
963 967 /*LINTED: constant in conditional context*/
964 968 set_xen_guest_handle(map.buffer, map_buffer);
965 969 if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &map) != 0)
|
↓ open down ↓ |
789 lines elided |
↑ open up ↑ |
966 970 dboot_panic("getting XENMEM_machine_memory_map failed");
967 971 build_pcimemlists();
968 972 }
969 973 }
970 974
971 975 #else /* !__xpv */
972 976
973 977 static void
974 978 dboot_multiboot1_xboot_consinfo(void)
975 979 {
976 - bi->bi_framebuffer = NULL;
980 + fb->framebuffer = 0;
977 981 }
978 982
979 983 static void
980 984 dboot_multiboot2_xboot_consinfo(void)
981 985 {
982 - multiboot_tag_framebuffer_t *fb;
983 - fb = dboot_multiboot2_find_tag(mb2_info,
986 + multiboot_tag_framebuffer_t *fbtag;
987 + fbtag = dboot_multiboot2_find_tag(mb2_info,
984 988 MULTIBOOT_TAG_TYPE_FRAMEBUFFER);
985 - bi->bi_framebuffer = (native_ptr_t)(uintptr_t)fb;
989 + fb->framebuffer = (uint64_t)(uintptr_t)fbtag;
990 + fb->boot_fb_virt = 0;
986 991 }
987 992
988 993 static int
989 994 dboot_multiboot_modcount(void)
990 995 {
991 996 switch (multiboot_version) {
992 997 case 1:
993 998 return (mb_info->mods_count);
994 999
995 1000 case 2:
996 1001 return (dboot_multiboot2_modcount(mb2_info));
997 1002
998 1003 default:
999 1004 dboot_panic("Unknown multiboot version: %d\n",
1000 1005 multiboot_version);
1001 1006 break;
1002 1007 }
1003 1008 return (0);
1004 1009 }
1005 1010
1006 1011 static uint32_t
1007 1012 dboot_multiboot_modstart(int index)
1008 1013 {
1009 1014 switch (multiboot_version) {
1010 1015 case 1:
1011 1016 return (((mb_module_t *)mb_info->mods_addr)[index].mod_start);
1012 1017
1013 1018 case 2:
1014 1019 return (dboot_multiboot2_modstart(mb2_info, index));
1015 1020
1016 1021 default:
1017 1022 dboot_panic("Unknown multiboot version: %d\n",
1018 1023 multiboot_version);
1019 1024 break;
1020 1025 }
1021 1026 return (0);
1022 1027 }
1023 1028
1024 1029 static uint32_t
1025 1030 dboot_multiboot_modend(int index)
1026 1031 {
1027 1032 switch (multiboot_version) {
1028 1033 case 1:
1029 1034 return (((mb_module_t *)mb_info->mods_addr)[index].mod_end);
1030 1035
1031 1036 case 2:
1032 1037 return (dboot_multiboot2_modend(mb2_info, index));
1033 1038
1034 1039 default:
1035 1040 dboot_panic("Unknown multiboot version: %d\n",
1036 1041 multiboot_version);
1037 1042 break;
1038 1043 }
1039 1044 return (0);
1040 1045 }
1041 1046
1042 1047 static char *
1043 1048 dboot_multiboot_modcmdline(int index)
1044 1049 {
1045 1050 switch (multiboot_version) {
1046 1051 case 1:
1047 1052 return ((char *)((mb_module_t *)
1048 1053 mb_info->mods_addr)[index].mod_name);
1049 1054
1050 1055 case 2:
1051 1056 return (dboot_multiboot2_modcmdline(mb2_info, index));
|
↓ open down ↓ |
56 lines elided |
↑ open up ↑ |
1052 1057
1053 1058 default:
1054 1059 dboot_panic("Unknown multiboot version: %d\n",
1055 1060 multiboot_version);
1056 1061 break;
1057 1062 }
1058 1063 return (0);
1059 1064 }
1060 1065
1061 1066 /*
1062 - * Find the environment module for console setup.
1067 + * Find the modules used by console setup.
1063 1068 * 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.
1069 + * before anything else and therefore we need to pick up the needed modules.
1066 1070 *
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.
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.
1069 1074 */
1070 1075 static void
1071 -dboot_find_env(void)
1076 +dboot_find_console_modules(void)
1072 1077 {
1073 1078 int i, modcount;
1074 1079 uint32_t mod_start, mod_end;
1075 1080 char *cmdline;
1076 1081
1077 1082 modcount = dboot_multiboot_modcount();
1078 -
1083 + bi->bi_module_cnt = 0;
1079 1084 for (i = 0; i < modcount; ++i) {
1080 1085 cmdline = dboot_multiboot_modcmdline(i);
1081 1086 if (cmdline == NULL)
1082 1087 continue;
1083 1088
1084 - if (strstr(cmdline, "type=environment") == NULL)
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
1085 1094 continue;
1086 1095
1087 1096 mod_start = dboot_multiboot_modstart(i);
1088 1097 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;
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++;
1097 1106 }
1107 + if (bi->bi_module_cnt != 0)
1108 + bi->bi_modules = (native_ptr_t)(uintptr_t)modules;
1098 1109 }
1099 1110
1100 1111 static boolean_t
1101 1112 dboot_multiboot_basicmeminfo(uint32_t *lower, uint32_t *upper)
1102 1113 {
1103 1114 boolean_t rv = B_FALSE;
1104 1115
1105 1116 switch (multiboot_version) {
1106 1117 case 1:
1107 1118 if (mb_info->flags & 0x01) {
1108 1119 *lower = mb_info->mem_lower;
1109 1120 *upper = mb_info->mem_upper;
1110 1121 rv = B_TRUE;
1111 1122 }
1112 1123 break;
1113 1124
1114 1125 case 2:
1115 1126 return (dboot_multiboot2_basicmeminfo(mb2_info, lower, upper));
1116 1127
1117 1128 default:
1118 1129 dboot_panic("Unknown multiboot version: %d\n",
1119 1130 multiboot_version);
1120 1131 break;
1121 1132 }
1122 1133 return (rv);
1123 1134 }
1124 1135
1125 1136 static uint8_t
1126 1137 dboot_a2h(char v)
1127 1138 {
1128 1139 if (v >= 'a')
1129 1140 return (v - 'a' + 0xa);
1130 1141 else if (v >= 'A')
1131 1142 return (v - 'A' + 0xa);
1132 1143 else if (v >= '0')
1133 1144 return (v - '0');
1134 1145 else
1135 1146 dboot_panic("bad ASCII hex character %c\n", v);
1136 1147
1137 1148 return (0);
1138 1149 }
1139 1150
1140 1151 static void
1141 1152 digest_a2h(const char *ascii, uint8_t *digest)
1142 1153 {
1143 1154 unsigned int i;
1144 1155
1145 1156 for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
1146 1157 digest[i] = dboot_a2h(ascii[i * 2]) << 4;
1147 1158 digest[i] |= dboot_a2h(ascii[i * 2 + 1]);
1148 1159 }
1149 1160 }
1150 1161
1151 1162 /*
1152 1163 * Generate a SHA-1 hash of the first len bytes of image, and compare it with
1153 1164 * the ASCII-format hash found in the 40-byte buffer at ascii. If they
1154 1165 * match, return 0, otherwise -1. This works only for images smaller than
1155 1166 * 4 GB, which should not be a problem.
1156 1167 */
1157 1168 static int
1158 1169 check_image_hash(uint_t midx)
1159 1170 {
1160 1171 const char *ascii;
1161 1172 const void *image;
1162 1173 size_t len;
1163 1174 SHA1_CTX ctx;
1164 1175 uint8_t digest[SHA1_DIGEST_LENGTH];
1165 1176 uint8_t baseline[SHA1_DIGEST_LENGTH];
1166 1177 unsigned int i;
1167 1178
1168 1179 ascii = (const char *)(uintptr_t)modules[midx].bm_hash;
1169 1180 image = (const void *)(uintptr_t)modules[midx].bm_addr;
1170 1181 len = (size_t)modules[midx].bm_size;
1171 1182
1172 1183 digest_a2h(ascii, baseline);
1173 1184
1174 1185 SHA1Init(&ctx);
1175 1186 SHA1Update(&ctx, image, len);
1176 1187 SHA1Final(digest, &ctx);
1177 1188
1178 1189 for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
1179 1190 if (digest[i] != baseline[i])
1180 1191 return (-1);
1181 1192 }
1182 1193
1183 1194 return (0);
1184 1195 }
1185 1196
1186 1197 static const char *
1187 1198 type_to_str(boot_module_type_t type)
|
↓ open down ↓ |
80 lines elided |
↑ open up ↑ |
1188 1199 {
1189 1200 switch (type) {
1190 1201 case BMT_ROOTFS:
1191 1202 return ("rootfs");
1192 1203 case BMT_FILE:
1193 1204 return ("file");
1194 1205 case BMT_HASH:
1195 1206 return ("hash");
1196 1207 case BMT_ENV:
1197 1208 return ("environment");
1209 + case BMT_FONT:
1210 + return ("console-font");
1198 1211 default:
1199 1212 return ("unknown");
1200 1213 }
1201 1214 }
1202 1215
1203 1216 static void
1204 1217 check_images(void)
1205 1218 {
1206 1219 uint_t i;
1207 1220 char displayhash[SHA1_ASCII_LENGTH + 1];
1208 1221
1209 1222 for (i = 0; i < modules_used; i++) {
1210 1223 if (prom_debug) {
1211 1224 dboot_printf("module #%d: name %s type %s "
1212 1225 "addr %lx size %lx\n",
1213 1226 i, (char *)(uintptr_t)modules[i].bm_name,
1214 1227 type_to_str(modules[i].bm_type),
1215 1228 (ulong_t)modules[i].bm_addr,
1216 1229 (ulong_t)modules[i].bm_size);
1217 1230 }
1218 1231
1219 1232 if (modules[i].bm_type == BMT_HASH ||
1220 1233 modules[i].bm_hash == (native_ptr_t)(uintptr_t)NULL) {
1221 1234 DBG_MSG("module has no hash; skipping check\n");
1222 1235 continue;
1223 1236 }
1224 1237 (void) memcpy(displayhash,
1225 1238 (void *)(uintptr_t)modules[i].bm_hash,
1226 1239 SHA1_ASCII_LENGTH);
1227 1240 displayhash[SHA1_ASCII_LENGTH] = '\0';
1228 1241 if (prom_debug) {
1229 1242 dboot_printf("checking expected hash [%s]: ",
1230 1243 displayhash);
1231 1244 }
1232 1245
1233 1246 if (check_image_hash(i) != 0)
1234 1247 dboot_panic("hash mismatch!\n");
1235 1248 else
1236 1249 DBG_MSG("OK\n");
1237 1250 }
1238 1251 }
1239 1252
1240 1253 /*
1241 1254 * Determine the module's starting address, size, name, and type, and fill the
1242 1255 * boot_modules structure. This structure is used by the bop code, except for
1243 1256 * hashes which are checked prior to transferring control to the kernel.
1244 1257 */
1245 1258 static void
1246 1259 process_module(int midx)
1247 1260 {
1248 1261 uint32_t mod_start = dboot_multiboot_modstart(midx);
1249 1262 uint32_t mod_end = dboot_multiboot_modend(midx);
1250 1263 char *cmdline = dboot_multiboot_modcmdline(midx);
1251 1264 char *p, *q;
1252 1265
1253 1266 check_higher(mod_end);
1254 1267 if (prom_debug) {
1255 1268 dboot_printf("\tmodule #%d: '%s' at 0x%lx, end 0x%lx\n",
1256 1269 midx, cmdline, (ulong_t)mod_start, (ulong_t)mod_end);
1257 1270 }
1258 1271
1259 1272 if (mod_start > mod_end) {
1260 1273 dboot_panic("module #%d: module start address 0x%lx greater "
1261 1274 "than end address 0x%lx", midx,
1262 1275 (ulong_t)mod_start, (ulong_t)mod_end);
1263 1276 }
1264 1277
1265 1278 /*
1266 1279 * A brief note on lengths and sizes: GRUB, for reasons unknown, passes
1267 1280 * the address of the last valid byte in a module plus 1 as mod_end.
1268 1281 * This is of course a bug; the multiboot specification simply states
1269 1282 * that mod_start and mod_end "contain the start and end addresses of
1270 1283 * the boot module itself" which is pretty obviously not what GRUB is
1271 1284 * doing. However, fixing it requires that not only this code be
1272 1285 * changed but also that other code consuming this value and values
1273 1286 * derived from it be fixed, and that the kernel and GRUB must either
1274 1287 * both have the bug or neither. While there are a lot of combinations
1275 1288 * that will work, there are also some that won't, so for simplicity
1276 1289 * we'll just cope with the bug. That means we won't actually hash the
1277 1290 * byte at mod_end, and we will expect that mod_end for the hash file
1278 1291 * itself is one greater than some multiple of 41 (40 bytes of ASCII
1279 1292 * hash plus a newline for each module). We set bm_size to the true
1280 1293 * correct number of bytes in each module, achieving exactly this.
1281 1294 */
1282 1295
1283 1296 modules[midx].bm_addr = (native_ptr_t)(uintptr_t)mod_start;
1284 1297 modules[midx].bm_size = mod_end - mod_start;
1285 1298 modules[midx].bm_name = (native_ptr_t)(uintptr_t)cmdline;
1286 1299 modules[midx].bm_hash = (native_ptr_t)(uintptr_t)NULL;
1287 1300 modules[midx].bm_type = BMT_FILE;
1288 1301
1289 1302 if (cmdline == NULL) {
1290 1303 modules[midx].bm_name = (native_ptr_t)(uintptr_t)noname;
1291 1304 return;
1292 1305 }
1293 1306
1294 1307 p = cmdline;
1295 1308 modules[midx].bm_name =
1296 1309 (native_ptr_t)(uintptr_t)strsep(&p, " \t\f\n\r");
1297 1310
1298 1311 while (p != NULL) {
1299 1312 q = strsep(&p, " \t\f\n\r");
1300 1313 if (strncmp(q, "name=", 5) == 0) {
1301 1314 if (q[5] != '\0' && !isspace(q[5])) {
1302 1315 modules[midx].bm_name =
1303 1316 (native_ptr_t)(uintptr_t)(q + 5);
1304 1317 }
1305 1318 continue;
1306 1319 }
1307 1320
|
↓ open down ↓ |
100 lines elided |
↑ open up ↑ |
1308 1321 if (strncmp(q, "type=", 5) == 0) {
1309 1322 if (q[5] == '\0' || isspace(q[5]))
1310 1323 continue;
1311 1324 q += 5;
1312 1325 if (strcmp(q, "rootfs") == 0) {
1313 1326 modules[midx].bm_type = BMT_ROOTFS;
1314 1327 } else if (strcmp(q, "hash") == 0) {
1315 1328 modules[midx].bm_type = BMT_HASH;
1316 1329 } else if (strcmp(q, "environment") == 0) {
1317 1330 modules[midx].bm_type = BMT_ENV;
1331 + } else if (strcmp(q, "console-font") == 0) {
1332 + modules[midx].bm_type = BMT_FONT;
1318 1333 } else if (strcmp(q, "file") != 0) {
1319 1334 dboot_printf("\tmodule #%d: unknown module "
1320 1335 "type '%s'; defaulting to 'file'",
1321 1336 midx, q);
1322 1337 }
1323 1338 continue;
1324 1339 }
1325 1340
1326 1341 if (strncmp(q, "hash=", 5) == 0) {
1327 1342 if (q[5] != '\0' && !isspace(q[5])) {
1328 1343 modules[midx].bm_hash =
1329 1344 (native_ptr_t)(uintptr_t)(q + 5);
1330 1345 }
1331 1346 continue;
1332 1347 }
1333 1348
1334 1349 dboot_printf("ignoring unknown option '%s'\n", q);
1335 1350 }
1336 1351 }
1337 1352
1338 1353 /*
1339 1354 * Backward compatibility: if there are exactly one or two modules, both
1340 1355 * of type 'file' and neither with an embedded hash value, we have been
1341 1356 * given the legacy style modules. In this case we need to treat the first
1342 1357 * module as a rootfs and the second as a hash referencing that module.
1343 1358 * Otherwise, even if the configuration is invalid, we assume that the
1344 1359 * operator knows what he's doing or at least isn't being bitten by this
1345 1360 * interface change.
1346 1361 */
1347 1362 static void
1348 1363 fixup_modules(void)
1349 1364 {
1350 1365 if (modules_used == 0 || modules_used > 2)
1351 1366 return;
1352 1367
1353 1368 if (modules[0].bm_type != BMT_FILE ||
1354 1369 modules_used > 1 && modules[1].bm_type != BMT_FILE) {
1355 1370 return;
1356 1371 }
1357 1372
1358 1373 if (modules[0].bm_hash != (native_ptr_t)(uintptr_t)NULL ||
1359 1374 modules_used > 1 &&
1360 1375 modules[1].bm_hash != (native_ptr_t)(uintptr_t)NULL) {
1361 1376 return;
1362 1377 }
1363 1378
1364 1379 modules[0].bm_type = BMT_ROOTFS;
1365 1380 if (modules_used > 1) {
1366 1381 modules[1].bm_type = BMT_HASH;
1367 1382 modules[1].bm_name = modules[0].bm_name;
1368 1383 }
1369 1384 }
1370 1385
1371 1386 /*
1372 1387 * For modules that do not have assigned hashes but have a separate hash module,
1373 1388 * find the assigned hash module and set the primary module's bm_hash to point
1374 1389 * to the hash data from that module. We will then ignore modules of type
1375 1390 * BMT_HASH from this point forward.
1376 1391 */
1377 1392 static void
1378 1393 assign_module_hashes(void)
1379 1394 {
1380 1395 uint_t i, j;
1381 1396
1382 1397 for (i = 0; i < modules_used; i++) {
1383 1398 if (modules[i].bm_type == BMT_HASH ||
1384 1399 modules[i].bm_hash != (native_ptr_t)(uintptr_t)NULL) {
1385 1400 continue;
1386 1401 }
1387 1402
1388 1403 for (j = 0; j < modules_used; j++) {
1389 1404 if (modules[j].bm_type != BMT_HASH ||
1390 1405 strcmp((char *)(uintptr_t)modules[j].bm_name,
1391 1406 (char *)(uintptr_t)modules[i].bm_name) != 0) {
1392 1407 continue;
1393 1408 }
1394 1409
1395 1410 if (modules[j].bm_size < SHA1_ASCII_LENGTH) {
1396 1411 dboot_printf("Short hash module of length "
1397 1412 "0x%lx bytes; ignoring\n",
1398 1413 (ulong_t)modules[j].bm_size);
1399 1414 } else {
1400 1415 modules[i].bm_hash = modules[j].bm_addr;
1401 1416 }
1402 1417 break;
1403 1418 }
1404 1419 }
1405 1420 }
1406 1421
1407 1422 /*
1408 1423 * Walk through the module information finding the last used address.
1409 1424 * The first available address will become the top level page table.
1410 1425 */
1411 1426 static void
1412 1427 dboot_process_modules(void)
1413 1428 {
1414 1429 int i, modcount;
1415 1430 extern char _end[];
1416 1431
1417 1432 DBG_MSG("\nFinding Modules\n");
1418 1433 modcount = dboot_multiboot_modcount();
1419 1434 if (modcount > MAX_BOOT_MODULES) {
1420 1435 dboot_panic("Too many modules (%d) -- the maximum is %d.",
1421 1436 modcount, MAX_BOOT_MODULES);
1422 1437 }
1423 1438 /*
1424 1439 * search the modules to find the last used address
1425 1440 * we'll build the module list while we're walking through here
1426 1441 */
1427 1442 check_higher((paddr_t)(uintptr_t)&_end);
1428 1443 for (i = 0; i < modcount; ++i) {
1429 1444 process_module(i);
1430 1445 modules_used++;
1431 1446 }
1432 1447 bi->bi_modules = (native_ptr_t)(uintptr_t)modules;
1433 1448 DBG(bi->bi_modules);
1434 1449 bi->bi_module_cnt = modcount;
1435 1450 DBG(bi->bi_module_cnt);
1436 1451
1437 1452 fixup_modules();
1438 1453 assign_module_hashes();
1439 1454 check_images();
1440 1455 }
1441 1456
1442 1457 /*
1443 1458 * We then build the phys_install memlist from the multiboot information.
1444 1459 */
1445 1460 static void
1446 1461 dboot_process_mmap(void)
1447 1462 {
1448 1463 uint64_t start;
1449 1464 uint64_t end;
1450 1465 uint64_t page_offset = MMU_PAGEOFFSET; /* needs to be 64 bits */
1451 1466 uint32_t lower, upper;
1452 1467 int i, mmap_entries;
1453 1468
1454 1469 /*
1455 1470 * Walk through the memory map from multiboot and build our memlist
1456 1471 * structures. Note these will have native format pointers.
1457 1472 */
1458 1473 DBG_MSG("\nFinding Memory Map\n");
1459 1474 num_entries = 0;
1460 1475 num_entries_set = B_FALSE;
1461 1476 max_mem = 0;
1462 1477 if ((mmap_entries = dboot_loader_mmap_entries()) > 0) {
1463 1478 for (i = 0; i < mmap_entries; i++) {
1464 1479 uint32_t type = dboot_loader_mmap_get_type(i);
1465 1480 start = dboot_loader_mmap_get_base(i);
1466 1481 end = start + dboot_loader_mmap_get_length(i);
1467 1482
1468 1483 if (prom_debug)
1469 1484 dboot_printf("\ttype: %d %" PRIx64 "..%"
1470 1485 PRIx64 "\n", type, start, end);
1471 1486
1472 1487 /*
1473 1488 * page align start and end
1474 1489 */
1475 1490 start = (start + page_offset) & ~page_offset;
1476 1491 end &= ~page_offset;
1477 1492 if (end <= start)
1478 1493 continue;
1479 1494
1480 1495 /*
1481 1496 * only type 1 is usable RAM
1482 1497 */
1483 1498 switch (type) {
1484 1499 case 1:
1485 1500 if (end > max_mem)
1486 1501 max_mem = end;
1487 1502 memlists[memlists_used].addr = start;
1488 1503 memlists[memlists_used].size = end - start;
1489 1504 ++memlists_used;
1490 1505 if (memlists_used > MAX_MEMLIST)
1491 1506 dboot_panic("too many memlists");
1492 1507 break;
1493 1508 case 2:
1494 1509 rsvdmemlists[rsvdmemlists_used].addr = start;
1495 1510 rsvdmemlists[rsvdmemlists_used].size =
1496 1511 end - start;
1497 1512 ++rsvdmemlists_used;
1498 1513 if (rsvdmemlists_used > MAX_MEMLIST)
1499 1514 dboot_panic("too many rsvdmemlists");
1500 1515 break;
1501 1516 default:
1502 1517 continue;
1503 1518 }
1504 1519 }
1505 1520 build_pcimemlists();
1506 1521 } else if (dboot_multiboot_basicmeminfo(&lower, &upper)) {
1507 1522 DBG(lower);
1508 1523 memlists[memlists_used].addr = 0;
1509 1524 memlists[memlists_used].size = lower * 1024;
1510 1525 ++memlists_used;
1511 1526 DBG(upper);
1512 1527 memlists[memlists_used].addr = 1024 * 1024;
1513 1528 memlists[memlists_used].size = upper * 1024;
1514 1529 ++memlists_used;
1515 1530
1516 1531 /*
1517 1532 * Old platform - assume I/O space at the end of memory.
1518 1533 */
1519 1534 pcimemlists[0].addr = (upper * 1024) + (1024 * 1024);
1520 1535 pcimemlists[0].size = pci_hi_limit - pcimemlists[0].addr;
1521 1536 pcimemlists[0].next = 0;
1522 1537 pcimemlists[0].prev = 0;
1523 1538 bi->bi_pcimem = (native_ptr_t)(uintptr_t)pcimemlists;
1524 1539 DBG(bi->bi_pcimem);
1525 1540 } else {
1526 1541 dboot_panic("No memory info from boot loader!!!");
1527 1542 }
1528 1543
1529 1544 /*
1530 1545 * finish processing the physinstall list
1531 1546 */
1532 1547 sort_physinstall();
1533 1548
1534 1549 /*
1535 1550 * build bios reserved mem lists
1536 1551 */
1537 1552 build_rsvdmemlists();
1538 1553 }
1539 1554
1540 1555 /*
1541 1556 * The highest address is used as the starting point for dboot's simple
1542 1557 * memory allocator.
1543 1558 *
1544 1559 * Finding the highest address in case of Multiboot 1 protocol is
1545 1560 * quite painful in the sense that some information provided by
1546 1561 * the multiboot info structure points to BIOS data, and some to RAM.
1547 1562 *
1548 1563 * The module list was processed and checked already by dboot_process_modules(),
1549 1564 * so we will check the command line string and the memory map.
1550 1565 *
1551 1566 * This list of to be checked items is based on our current knowledge of
1552 1567 * allocations made by grub1 and will need to be reviewed if there
1553 1568 * are updates about the information provided by Multiboot 1.
1554 1569 *
1555 1570 * In the case of the Multiboot 2, our life is much simpler, as the MB2
1556 1571 * information tag list is one contiguous chunk of memory.
1557 1572 */
1558 1573 static paddr_t
1559 1574 dboot_multiboot1_highest_addr(void)
1560 1575 {
1561 1576 paddr_t addr = (paddr_t)(uintptr_t)NULL;
1562 1577 char *cmdl = (char *)mb_info->cmdline;
1563 1578
1564 1579 if (mb_info->flags & MB_INFO_CMDLINE)
1565 1580 addr = ((paddr_t)((uintptr_t)cmdl + strlen(cmdl) + 1));
1566 1581
1567 1582 if (mb_info->flags & MB_INFO_MEM_MAP)
1568 1583 addr = MAX(addr,
1569 1584 ((paddr_t)(mb_info->mmap_addr + mb_info->mmap_length)));
1570 1585 return (addr);
1571 1586 }
1572 1587
1573 1588 static void
1574 1589 dboot_multiboot_highest_addr(void)
1575 1590 {
1576 1591 paddr_t addr;
1577 1592
1578 1593 switch (multiboot_version) {
1579 1594 case 1:
1580 1595 addr = dboot_multiboot1_highest_addr();
1581 1596 if (addr != (paddr_t)(uintptr_t)NULL)
1582 1597 check_higher(addr);
1583 1598 break;
1584 1599 case 2:
1585 1600 addr = dboot_multiboot2_highest_addr(mb2_info);
1586 1601 if (addr != (paddr_t)(uintptr_t)NULL)
1587 1602 check_higher(addr);
1588 1603 break;
1589 1604 default:
1590 1605 dboot_panic("Unknown multiboot version: %d\n",
1591 1606 multiboot_version);
1592 1607 break;
1593 1608 }
1594 1609 }
1595 1610
1596 1611 /*
1597 1612 * Walk the boot loader provided information and find the highest free address.
1598 1613 */
1599 1614 static void
1600 1615 init_mem_alloc(void)
1601 1616 {
1602 1617 DBG_MSG("Entered init_mem_alloc()\n");
1603 1618 dboot_process_modules();
1604 1619 dboot_process_mmap();
1605 1620 dboot_multiboot_highest_addr();
1606 1621 }
1607 1622
1608 1623 static int
1609 1624 dboot_same_guids(efi_guid_t *g1, efi_guid_t *g2)
1610 1625 {
1611 1626 int i;
1612 1627
1613 1628 if (g1->time_low != g2->time_low)
1614 1629 return (0);
1615 1630 if (g1->time_mid != g2->time_mid)
1616 1631 return (0);
1617 1632 if (g1->time_hi_and_version != g2->time_hi_and_version)
1618 1633 return (0);
1619 1634 if (g1->clock_seq_hi_and_reserved != g2->clock_seq_hi_and_reserved)
1620 1635 return (0);
1621 1636 if (g1->clock_seq_low != g2->clock_seq_low)
1622 1637 return (0);
1623 1638
1624 1639 for (i = 0; i < 6; i++) {
1625 1640 if (g1->node_addr[i] != g2->node_addr[i])
1626 1641 return (0);
1627 1642 }
1628 1643 return (1);
1629 1644 }
1630 1645
1631 1646 static void
1632 1647 process_efi32(EFI_SYSTEM_TABLE32 *efi)
1633 1648 {
1634 1649 uint32_t entries;
1635 1650 EFI_CONFIGURATION_TABLE32 *config;
1636 1651 int i;
1637 1652
1638 1653 entries = efi->NumberOfTableEntries;
1639 1654 config = (EFI_CONFIGURATION_TABLE32 *)(uintptr_t)
1640 1655 efi->ConfigurationTable;
1641 1656
1642 1657 for (i = 0; i < entries; i++) {
1643 1658 if (dboot_same_guids(&config[i].VendorGuid, &smbios3)) {
1644 1659 bi->bi_smbios = (native_ptr_t)(uintptr_t)
1645 1660 config[i].VendorTable;
1646 1661 }
1647 1662 if (bi->bi_smbios == NULL &&
1648 1663 dboot_same_guids(&config[i].VendorGuid, &smbios)) {
1649 1664 bi->bi_smbios = (native_ptr_t)(uintptr_t)
1650 1665 config[i].VendorTable;
1651 1666 }
1652 1667 if (dboot_same_guids(&config[i].VendorGuid, &acpi2)) {
1653 1668 bi->bi_acpi_rsdp = (native_ptr_t)(uintptr_t)
1654 1669 config[i].VendorTable;
1655 1670 }
1656 1671 if (bi->bi_acpi_rsdp == NULL &&
1657 1672 dboot_same_guids(&config[i].VendorGuid, &acpi1)) {
1658 1673 bi->bi_acpi_rsdp = (native_ptr_t)(uintptr_t)
1659 1674 config[i].VendorTable;
1660 1675 }
1661 1676 }
1662 1677 }
1663 1678
1664 1679 static void
1665 1680 process_efi64(EFI_SYSTEM_TABLE64 *efi)
1666 1681 {
1667 1682 uint64_t entries;
1668 1683 EFI_CONFIGURATION_TABLE64 *config;
1669 1684 int i;
1670 1685
1671 1686 entries = efi->NumberOfTableEntries;
1672 1687 config = (EFI_CONFIGURATION_TABLE64 *)(uintptr_t)
1673 1688 efi->ConfigurationTable;
1674 1689
1675 1690 for (i = 0; i < entries; i++) {
1676 1691 if (dboot_same_guids(&config[i].VendorGuid, &smbios3)) {
1677 1692 bi->bi_smbios = (native_ptr_t)(uintptr_t)
1678 1693 config[i].VendorTable;
1679 1694 }
1680 1695 if (bi->bi_smbios == NULL &&
1681 1696 dboot_same_guids(&config[i].VendorGuid, &smbios)) {
1682 1697 bi->bi_smbios = (native_ptr_t)(uintptr_t)
1683 1698 config[i].VendorTable;
1684 1699 }
1685 1700 /* Prefer acpi v2+ over v1. */
1686 1701 if (dboot_same_guids(&config[i].VendorGuid, &acpi2)) {
1687 1702 bi->bi_acpi_rsdp = (native_ptr_t)(uintptr_t)
1688 1703 config[i].VendorTable;
1689 1704 }
1690 1705 if (bi->bi_acpi_rsdp == NULL &&
1691 1706 dboot_same_guids(&config[i].VendorGuid, &acpi1)) {
1692 1707 bi->bi_acpi_rsdp = (native_ptr_t)(uintptr_t)
1693 1708 config[i].VendorTable;
1694 1709 }
1695 1710 }
1696 1711 }
1697 1712
1698 1713 static void
1699 1714 dboot_multiboot_get_fwtables(void)
1700 1715 {
1701 1716 multiboot_tag_new_acpi_t *nacpitagp;
1702 1717 multiboot_tag_old_acpi_t *oacpitagp;
1703 1718 multiboot_tag_efi64_t *efi64tagp = NULL;
1704 1719 multiboot_tag_efi32_t *efi32tagp = NULL;
1705 1720
1706 1721 /* no fw tables from multiboot 1 */
1707 1722 if (multiboot_version != 2)
1708 1723 return;
1709 1724
1710 1725 efi64tagp = (multiboot_tag_efi64_t *)
1711 1726 dboot_multiboot2_find_tag(mb2_info, MULTIBOOT_TAG_TYPE_EFI64);
1712 1727 if (efi64tagp != NULL) {
1713 1728 bi->bi_uefi_arch = XBI_UEFI_ARCH_64;
1714 1729 bi->bi_uefi_systab = (native_ptr_t)(uintptr_t)
1715 1730 efi64tagp->mb_pointer;
1716 1731 process_efi64((EFI_SYSTEM_TABLE64 *)(uintptr_t)
1717 1732 efi64tagp->mb_pointer);
1718 1733 } else {
1719 1734 efi32tagp = (multiboot_tag_efi32_t *)
1720 1735 dboot_multiboot2_find_tag(mb2_info,
1721 1736 MULTIBOOT_TAG_TYPE_EFI32);
1722 1737 if (efi32tagp != NULL) {
1723 1738 bi->bi_uefi_arch = XBI_UEFI_ARCH_32;
1724 1739 bi->bi_uefi_systab = (native_ptr_t)(uintptr_t)
1725 1740 efi32tagp->mb_pointer;
1726 1741 process_efi32((EFI_SYSTEM_TABLE32 *)(uintptr_t)
1727 1742 efi32tagp->mb_pointer);
1728 1743 }
1729 1744 }
1730 1745
1731 1746 /*
1732 1747 * The ACPI RSDP can be found by scanning the BIOS memory areas or
1733 1748 * from the EFI system table. The boot loader may pass in the address
1734 1749 * it found the ACPI tables at.
1735 1750 */
1736 1751 nacpitagp = (multiboot_tag_new_acpi_t *)
1737 1752 dboot_multiboot2_find_tag(mb2_info,
1738 1753 MULTIBOOT_TAG_TYPE_ACPI_NEW);
1739 1754 oacpitagp = (multiboot_tag_old_acpi_t *)
1740 1755 dboot_multiboot2_find_tag(mb2_info,
1741 1756 MULTIBOOT_TAG_TYPE_ACPI_OLD);
1742 1757
1743 1758 if (nacpitagp != NULL) {
1744 1759 bi->bi_acpi_rsdp = (native_ptr_t)(uintptr_t)
1745 1760 &nacpitagp->mb_rsdp[0];
1746 1761 } else if (oacpitagp != NULL) {
1747 1762 bi->bi_acpi_rsdp = (native_ptr_t)(uintptr_t)
1748 1763 &oacpitagp->mb_rsdp[0];
1749 1764 }
1750 1765 }
1751 1766
1752 1767 /* print out EFI version string with newline */
1753 1768 static void
1754 1769 dboot_print_efi_version(uint32_t ver)
1755 1770 {
1756 1771 int rev;
1757 1772
1758 1773 dboot_printf("%d.", EFI_REV_MAJOR(ver));
1759 1774
1760 1775 rev = EFI_REV_MINOR(ver);
1761 1776 if ((rev % 10) != 0) {
1762 1777 dboot_printf("%d.%d\n", rev / 10, rev % 10);
1763 1778 } else {
1764 1779 dboot_printf("%d\n", rev / 10);
1765 1780 }
1766 1781 }
1767 1782
1768 1783 static void
1769 1784 print_efi32(EFI_SYSTEM_TABLE32 *efi)
1770 1785 {
1771 1786 uint16_t *data;
1772 1787 EFI_CONFIGURATION_TABLE32 *conf;
1773 1788 int i;
1774 1789
1775 1790 dboot_printf("EFI32 signature: %llx\n",
1776 1791 (unsigned long long)efi->Hdr.Signature);
1777 1792 dboot_printf("EFI system version: ");
1778 1793 dboot_print_efi_version(efi->Hdr.Revision);
1779 1794 dboot_printf("EFI system vendor: ");
1780 1795 data = (uint16_t *)(uintptr_t)efi->FirmwareVendor;
1781 1796 for (i = 0; data[i] != 0; i++)
1782 1797 dboot_printf("%c", (char)data[i]);
1783 1798 dboot_printf("\nEFI firmware revision: ");
1784 1799 dboot_print_efi_version(efi->FirmwareRevision);
1785 1800 dboot_printf("EFI system table number of entries: %d\n",
1786 1801 efi->NumberOfTableEntries);
1787 1802 conf = (EFI_CONFIGURATION_TABLE32 *)(uintptr_t)
1788 1803 efi->ConfigurationTable;
1789 1804 for (i = 0; i < (int)efi->NumberOfTableEntries; i++) {
1790 1805 dboot_printf("%d: 0x%x 0x%x 0x%x 0x%x 0x%x", i,
1791 1806 conf[i].VendorGuid.time_low,
1792 1807 conf[i].VendorGuid.time_mid,
1793 1808 conf[i].VendorGuid.time_hi_and_version,
1794 1809 conf[i].VendorGuid.clock_seq_hi_and_reserved,
1795 1810 conf[i].VendorGuid.clock_seq_low);
1796 1811 dboot_printf(" 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
1797 1812 conf[i].VendorGuid.node_addr[0],
1798 1813 conf[i].VendorGuid.node_addr[1],
1799 1814 conf[i].VendorGuid.node_addr[2],
1800 1815 conf[i].VendorGuid.node_addr[3],
1801 1816 conf[i].VendorGuid.node_addr[4],
1802 1817 conf[i].VendorGuid.node_addr[5]);
1803 1818 }
1804 1819 }
1805 1820
1806 1821 static void
1807 1822 print_efi64(EFI_SYSTEM_TABLE64 *efi)
1808 1823 {
1809 1824 uint16_t *data;
1810 1825 EFI_CONFIGURATION_TABLE64 *conf;
1811 1826 int i;
1812 1827
1813 1828 dboot_printf("EFI64 signature: %llx\n",
1814 1829 (unsigned long long)efi->Hdr.Signature);
1815 1830 dboot_printf("EFI system version: ");
1816 1831 dboot_print_efi_version(efi->Hdr.Revision);
1817 1832 dboot_printf("EFI system vendor: ");
1818 1833 data = (uint16_t *)(uintptr_t)efi->FirmwareVendor;
1819 1834 for (i = 0; data[i] != 0; i++)
1820 1835 dboot_printf("%c", (char)data[i]);
1821 1836 dboot_printf("\nEFI firmware revision: ");
1822 1837 dboot_print_efi_version(efi->FirmwareRevision);
1823 1838 dboot_printf("EFI system table number of entries: %lld\n",
1824 1839 efi->NumberOfTableEntries);
1825 1840 conf = (EFI_CONFIGURATION_TABLE64 *)(uintptr_t)
1826 1841 efi->ConfigurationTable;
1827 1842 for (i = 0; i < (int)efi->NumberOfTableEntries; i++) {
1828 1843 dboot_printf("%d: 0x%x 0x%x 0x%x 0x%x 0x%x", i,
1829 1844 conf[i].VendorGuid.time_low,
1830 1845 conf[i].VendorGuid.time_mid,
1831 1846 conf[i].VendorGuid.time_hi_and_version,
1832 1847 conf[i].VendorGuid.clock_seq_hi_and_reserved,
1833 1848 conf[i].VendorGuid.clock_seq_low);
1834 1849 dboot_printf(" 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
1835 1850 conf[i].VendorGuid.node_addr[0],
1836 1851 conf[i].VendorGuid.node_addr[1],
1837 1852 conf[i].VendorGuid.node_addr[2],
1838 1853 conf[i].VendorGuid.node_addr[3],
1839 1854 conf[i].VendorGuid.node_addr[4],
1840 1855 conf[i].VendorGuid.node_addr[5]);
1841 1856 }
1842 1857 }
1843 1858 #endif /* !__xpv */
1844 1859
1845 1860 /*
1846 1861 * Simple memory allocator, allocates aligned physical memory.
1847 1862 * Note that startup_kernel() only allocates memory, never frees.
1848 1863 * Memory usage just grows in an upward direction.
1849 1864 */
1850 1865 static void *
1851 1866 do_mem_alloc(uint32_t size, uint32_t align)
1852 1867 {
1853 1868 uint_t i;
1854 1869 uint64_t best;
1855 1870 uint64_t start;
1856 1871 uint64_t end;
1857 1872
1858 1873 /*
1859 1874 * make sure size is a multiple of pagesize
1860 1875 */
1861 1876 size = RNDUP(size, MMU_PAGESIZE);
1862 1877 next_avail_addr = RNDUP(next_avail_addr, align);
1863 1878
1864 1879 /*
1865 1880 * XXPV fixme joe
1866 1881 *
1867 1882 * a really large bootarchive that causes you to run out of memory
1868 1883 * may cause this to blow up
1869 1884 */
1870 1885 /* LINTED E_UNEXPECTED_UINT_PROMOTION */
1871 1886 best = (uint64_t)-size;
1872 1887 for (i = 0; i < memlists_used; ++i) {
1873 1888 start = memlists[i].addr;
1874 1889 #if defined(__xpv)
1875 1890 start += mfn_base;
1876 1891 #endif
1877 1892 end = start + memlists[i].size;
1878 1893
1879 1894 /*
1880 1895 * did we find the desired address?
1881 1896 */
1882 1897 if (start <= next_avail_addr && next_avail_addr + size <= end) {
1883 1898 best = next_avail_addr;
1884 1899 goto done;
1885 1900 }
1886 1901
1887 1902 /*
1888 1903 * if not is this address the best so far?
1889 1904 */
1890 1905 if (start > next_avail_addr && start < best &&
1891 1906 RNDUP(start, align) + size <= end)
1892 1907 best = RNDUP(start, align);
1893 1908 }
1894 1909
1895 1910 /*
1896 1911 * We didn't find exactly the address we wanted, due to going off the
1897 1912 * end of a memory region. Return the best found memory address.
1898 1913 */
1899 1914 done:
1900 1915 next_avail_addr = best + size;
1901 1916 #if defined(__xpv)
1902 1917 if (next_avail_addr > scratch_end)
1903 1918 dboot_panic("Out of mem next_avail: 0x%lx, scratch_end: "
1904 1919 "0x%lx", (ulong_t)next_avail_addr,
1905 1920 (ulong_t)scratch_end);
1906 1921 #endif
1907 1922 (void) memset((void *)(uintptr_t)best, 0, size);
1908 1923 return ((void *)(uintptr_t)best);
1909 1924 }
1910 1925
1911 1926 void *
1912 1927 mem_alloc(uint32_t size)
1913 1928 {
1914 1929 return (do_mem_alloc(size, MMU_PAGESIZE));
1915 1930 }
1916 1931
1917 1932
1918 1933 /*
1919 1934 * Build page tables to map all of memory used so far as well as the kernel.
1920 1935 */
1921 1936 static void
1922 1937 build_page_tables(void)
1923 1938 {
1924 1939 uint32_t psize;
1925 1940 uint32_t level;
1926 1941 uint32_t off;
1927 1942 uint64_t start;
1928 1943 #if !defined(__xpv)
1929 1944 uint32_t i;
1930 1945 uint64_t end;
1931 1946 #endif /* __xpv */
1932 1947
1933 1948 /*
1934 1949 * If we're on metal, we need to create the top level pagetable.
1935 1950 */
1936 1951 #if defined(__xpv)
1937 1952 top_page_table = (paddr_t)(uintptr_t)xen_info->pt_base;
1938 1953 #else /* __xpv */
1939 1954 top_page_table = (paddr_t)(uintptr_t)mem_alloc(MMU_PAGESIZE);
1940 1955 #endif /* __xpv */
1941 1956 DBG((uintptr_t)top_page_table);
1942 1957
1943 1958 /*
1944 1959 * Determine if we'll use large mappings for kernel, then map it.
1945 1960 */
1946 1961 if (largepage_support) {
1947 1962 psize = lpagesize;
1948 1963 level = 1;
1949 1964 } else {
1950 1965 psize = MMU_PAGESIZE;
1951 1966 level = 0;
1952 1967 }
1953 1968
1954 1969 DBG_MSG("Mapping kernel\n");
1955 1970 DBG(ktext_phys);
1956 1971 DBG(target_kernel_text);
1957 1972 DBG(ksize);
1958 1973 DBG(psize);
1959 1974 for (off = 0; off < ksize; off += psize)
1960 1975 map_pa_at_va(ktext_phys + off, target_kernel_text + off, level);
1961 1976
1962 1977 /*
1963 1978 * The kernel will need a 1 page window to work with page tables
1964 1979 */
1965 1980 bi->bi_pt_window = (native_ptr_t)(uintptr_t)mem_alloc(MMU_PAGESIZE);
1966 1981 DBG(bi->bi_pt_window);
1967 1982 bi->bi_pte_to_pt_window =
1968 1983 (native_ptr_t)(uintptr_t)find_pte(bi->bi_pt_window, NULL, 0, 0);
1969 1984 DBG(bi->bi_pte_to_pt_window);
1970 1985
1971 1986 #if defined(__xpv)
1972 1987 if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
1973 1988 /* If this is a domU we're done. */
1974 1989 DBG_MSG("\nPage tables constructed\n");
1975 1990 return;
1976 1991 }
1977 1992 #endif /* __xpv */
1978 1993
1979 1994 /*
1980 1995 * We need 1:1 mappings for the lower 1M of memory to access
1981 1996 * BIOS tables used by a couple of drivers during boot.
1982 1997 *
1983 1998 * The following code works because our simple memory allocator
1984 1999 * only grows usage in an upwards direction.
1985 2000 *
1986 2001 * Note that by this point in boot some mappings for low memory
1987 2002 * may already exist because we've already accessed device in low
1988 2003 * memory. (Specifically the video frame buffer and keyboard
1989 2004 * status ports.) If we're booting on raw hardware then GRUB
1990 2005 * created these mappings for us. If we're booting under a
1991 2006 * hypervisor then we went ahead and remapped these devices into
1992 2007 * memory allocated within dboot itself.
1993 2008 */
1994 2009 if (map_debug)
1995 2010 dboot_printf("1:1 map pa=0..1Meg\n");
1996 2011 for (start = 0; start < 1024 * 1024; start += MMU_PAGESIZE) {
1997 2012 #if defined(__xpv)
1998 2013 map_ma_at_va(start, start, 0);
1999 2014 #else /* __xpv */
2000 2015 map_pa_at_va(start, start, 0);
2001 2016 #endif /* __xpv */
2002 2017 }
2003 2018
2004 2019 #if !defined(__xpv)
2005 2020
2006 2021 for (i = 0; i < memlists_used; ++i) {
2007 2022 start = memlists[i].addr;
2008 2023 end = start + memlists[i].size;
2009 2024
2010 2025 if (map_debug)
2011 2026 dboot_printf("1:1 map pa=%" PRIx64 "..%" PRIx64 "\n",
2012 2027 start, end);
2013 2028 while (start < end && start < next_avail_addr) {
2014 2029 map_pa_at_va(start, start, 0);
|
↓ open down ↓ |
687 lines elided |
↑ open up ↑ |
2015 2030 start += MMU_PAGESIZE;
2016 2031 }
2017 2032 if (start >= next_avail_addr)
2018 2033 break;
2019 2034 }
2020 2035
2021 2036 /*
2022 2037 * Map framebuffer memory as PT_NOCACHE as this is memory from a
2023 2038 * device and therefore must not be cached.
2024 2039 */
2025 - if (bi->bi_framebuffer != NULL) {
2026 - multiboot_tag_framebuffer_t *fb;
2027 - fb = (multiboot_tag_framebuffer_t *)(uintptr_t)
2028 - bi->bi_framebuffer;
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;
2029 2044
2030 - start = fb->framebuffer_common.framebuffer_addr;
2031 - end = start + fb->framebuffer_common.framebuffer_height *
2032 - fb->framebuffer_common.framebuffer_pitch;
2045 + start = fb_tagp->framebuffer_common.framebuffer_addr;
2046 + end = start + fb_tagp->framebuffer_common.framebuffer_height *
2047 + fb_tagp->framebuffer_common.framebuffer_pitch;
2033 2048
2034 - pte_bits |= PT_NOCACHE;
2035 - while (start < end) {
2036 - map_pa_at_va(start, start, 0);
2037 - start += MMU_PAGESIZE;
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;
2038 2077 }
2039 - pte_bits &= ~PT_NOCACHE;
2040 2078 }
2041 2079 #endif /* !__xpv */
2042 2080
2043 2081 DBG_MSG("\nPage tables constructed\n");
2044 2082 }
2045 2083
2046 2084 #define NO_MULTIBOOT \
2047 2085 "multiboot is no longer used to boot the Solaris Operating System.\n\
2048 2086 The grub entry should be changed to:\n\
2049 2087 kernel$ /platform/i86pc/kernel/$ISADIR/unix\n\
2050 2088 module$ /platform/i86pc/$ISADIR/boot_archive\n\
2051 2089 See http://illumos.org/msg/SUNOS-8000-AK for details.\n"
2052 2090
2053 2091 static void
2054 2092 dboot_init_xboot_consinfo(void)
|
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
2055 2093 {
2056 2094 uintptr_t addr;
2057 2095 /*
2058 2096 * boot info must be 16 byte aligned for 64 bit kernel ABI
2059 2097 */
2060 2098 addr = (uintptr_t)boot_info;
2061 2099 addr = (addr + 0xf) & ~0xf;
2062 2100 bi = (struct xboot_info *)addr;
2063 2101
2064 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 +
2065 2111 switch (multiboot_version) {
2066 2112 case 1:
2067 2113 dboot_multiboot1_xboot_consinfo();
2068 2114 break;
2069 2115 case 2:
2070 2116 dboot_multiboot2_xboot_consinfo();
2071 2117 break;
2072 2118 default:
2073 2119 dboot_panic("Unknown multiboot version: %d\n",
2074 2120 multiboot_version);
2075 2121 break;
2076 2122 }
2077 2123 /*
2078 2124 * Lookup environment module for the console. Complete module list
2079 2125 * will be built after console setup.
2080 2126 */
2081 - dboot_find_env();
2127 + dboot_find_console_modules();
2082 2128 #endif
2083 2129 }
2084 2130
2085 2131 /*
2086 2132 * Set up basic data from the boot loader.
2087 2133 * The load_addr is part of AOUT kludge setup in dboot_grub.s, to support
2088 2134 * 32-bit dboot code setup used to set up and start 64-bit kernel.
2089 2135 * AOUT kludge does allow 32-bit boot loader, such as grub1, to load and
2090 2136 * start 64-bit illumos kernel.
2091 2137 */
2092 2138 static void
2093 2139 dboot_loader_init(void)
2094 2140 {
2095 2141 #if !defined(__xpv)
2096 2142 mb_info = NULL;
2097 2143 mb2_info = NULL;
2098 2144
2099 2145 switch (mb_magic) {
2100 2146 case MB_BOOTLOADER_MAGIC:
2101 2147 multiboot_version = 1;
2102 2148 mb_info = (multiboot_info_t *)(uintptr_t)mb_addr;
2103 2149 #if defined(_BOOT_TARGET_amd64)
2104 2150 load_addr = mb_header.load_addr;
2105 2151 #endif
2106 2152 break;
2107 2153
2108 2154 case MULTIBOOT2_BOOTLOADER_MAGIC:
2109 2155 multiboot_version = 2;
2110 2156 mb2_info = (multiboot2_info_header_t *)(uintptr_t)mb_addr;
2111 2157 mb2_mmap_tagp = dboot_multiboot2_get_mmap_tagp(mb2_info);
2112 2158 #if defined(_BOOT_TARGET_amd64)
2113 2159 load_addr = mb2_load_addr;
2114 2160 #endif
2115 2161 break;
2116 2162
2117 2163 default:
2118 2164 dboot_panic("Unknown bootloader magic: 0x%x\n", mb_magic);
2119 2165 break;
2120 2166 }
2121 2167 #endif /* !defined(__xpv) */
2122 2168 }
2123 2169
2124 2170 /* Extract the kernel command line from [multi]boot information. */
2125 2171 static char *
2126 2172 dboot_loader_cmdline(void)
2127 2173 {
2128 2174 char *line = NULL;
2129 2175
2130 2176 #if defined(__xpv)
2131 2177 line = (char *)xen_info->cmd_line;
2132 2178 #else /* __xpv */
2133 2179
2134 2180 switch (multiboot_version) {
2135 2181 case 1:
2136 2182 if (mb_info->flags & MB_INFO_CMDLINE)
2137 2183 line = (char *)mb_info->cmdline;
2138 2184 break;
2139 2185
2140 2186 case 2:
2141 2187 line = dboot_multiboot2_cmdline(mb2_info);
2142 2188 break;
2143 2189
2144 2190 default:
2145 2191 dboot_panic("Unknown multiboot version: %d\n",
2146 2192 multiboot_version);
2147 2193 break;
2148 2194 }
2149 2195
2150 2196 #endif /* __xpv */
2151 2197
2152 2198 /*
2153 2199 * Make sure we have valid pointer so the string operations
2154 2200 * will not crash us.
2155 2201 */
2156 2202 if (line == NULL)
2157 2203 line = "";
2158 2204
2159 2205 return (line);
2160 2206 }
2161 2207
2162 2208 static char *
2163 2209 dboot_loader_name(void)
2164 2210 {
2165 2211 #if defined(__xpv)
2166 2212 return (NULL);
2167 2213 #else /* __xpv */
2168 2214 multiboot_tag_string_t *tag;
2169 2215
2170 2216 switch (multiboot_version) {
2171 2217 case 1:
2172 2218 return ((char *)mb_info->boot_loader_name);
2173 2219
2174 2220 case 2:
2175 2221 tag = dboot_multiboot2_find_tag(mb2_info,
2176 2222 MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME);
2177 2223 return (tag->mb_string);
2178 2224 default:
2179 2225 dboot_panic("Unknown multiboot version: %d\n",
2180 2226 multiboot_version);
2181 2227 break;
2182 2228 }
2183 2229
2184 2230 return (NULL);
2185 2231 #endif /* __xpv */
2186 2232 }
2187 2233
2188 2234 /*
2189 2235 * startup_kernel has a pretty simple job. It builds pagetables which reflect
2190 2236 * 1:1 mappings for all memory in use. It then also adds mappings for
2191 2237 * the kernel nucleus at virtual address of target_kernel_text using large page
2192 2238 * mappings. The page table pages are also accessible at 1:1 mapped
2193 2239 * virtual addresses.
2194 2240 */
|
↓ open down ↓ |
103 lines elided |
↑ open up ↑ |
2195 2241 /*ARGSUSED*/
2196 2242 void
2197 2243 startup_kernel(void)
2198 2244 {
2199 2245 char *cmdline;
2200 2246 char *bootloader;
2201 2247 #if defined(__xpv)
2202 2248 physdev_set_iopl_t set_iopl;
2203 2249 #endif /* __xpv */
2204 2250
2251 + bcons_init(NULL); /* Set very early console to ttya. */
2205 2252 dboot_loader_init();
2206 2253 /*
2207 2254 * At this point we are executing in a 32 bit real mode.
2208 2255 */
2209 2256
2210 2257 bootloader = dboot_loader_name();
2211 2258 cmdline = dboot_loader_cmdline();
2212 2259
2213 2260 #if defined(__xpv)
2214 2261 /*
2215 2262 * For dom0, before we initialize the console subsystem we'll
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
2216 2263 * need to enable io operations, so set I/O priveldge level to 1.
2217 2264 */
2218 2265 if (DOMAIN_IS_INITDOMAIN(xen_info)) {
2219 2266 set_iopl.iopl = 1;
2220 2267 (void) HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
2221 2268 }
2222 2269 #endif /* __xpv */
2223 2270
2224 2271 dboot_init_xboot_consinfo();
2225 2272 bi->bi_cmdline = (native_ptr_t)(uintptr_t)cmdline;
2226 - bcons_init(bi);
2273 + bcons_init(bi); /* Now we can set the real console. */
2227 2274
2228 2275 prom_debug = (find_boot_prop("prom_debug") != NULL);
2229 2276 map_debug = (find_boot_prop("map_debug") != NULL);
2230 2277
2231 2278 #if !defined(__xpv)
2232 2279 dboot_multiboot_get_fwtables();
2233 2280 #endif
2234 2281 DBG_MSG("\n\nillumos prekernel set: ");
2235 2282 DBG_MSG(cmdline);
2236 2283 DBG_MSG("\n");
2237 2284
2238 2285 if (bootloader != NULL && prom_debug) {
2239 2286 dboot_printf("Kernel loaded by: %s\n", bootloader);
2240 2287 #if !defined(__xpv)
2241 2288 dboot_printf("Using multiboot %d boot protocol.\n",
2242 2289 multiboot_version);
2243 2290 #endif
2244 2291 }
2245 2292
2246 2293 if (strstr(cmdline, "multiboot") != NULL) {
2247 2294 dboot_panic(NO_MULTIBOOT);
2248 2295 }
2249 2296
2250 2297 DBG((uintptr_t)bi);
2251 2298 #if !defined(__xpv)
2252 2299 DBG((uintptr_t)mb_info);
2253 2300 DBG((uintptr_t)mb2_info);
2254 2301 if (mb2_info != NULL)
2255 2302 DBG(mb2_info->mbi_total_size);
2256 2303 DBG(bi->bi_acpi_rsdp);
2257 2304 DBG(bi->bi_smbios);
2258 2305 DBG(bi->bi_uefi_arch);
2259 2306 DBG(bi->bi_uefi_systab);
2260 2307
2261 2308 if (bi->bi_uefi_systab && prom_debug) {
2262 2309 if (bi->bi_uefi_arch == XBI_UEFI_ARCH_64) {
2263 2310 print_efi64((EFI_SYSTEM_TABLE64 *)(uintptr_t)
2264 2311 bi->bi_uefi_systab);
2265 2312 } else {
2266 2313 print_efi32((EFI_SYSTEM_TABLE32 *)(uintptr_t)
2267 2314 bi->bi_uefi_systab);
2268 2315 }
2269 2316 }
2270 2317 #endif
2271 2318
2272 2319 /*
2273 2320 * Need correct target_kernel_text value
2274 2321 */
2275 2322 #if defined(_BOOT_TARGET_amd64)
2276 2323 target_kernel_text = KERNEL_TEXT_amd64;
2277 2324 #elif defined(__xpv)
2278 2325 target_kernel_text = KERNEL_TEXT_i386_xpv;
2279 2326 #else
2280 2327 target_kernel_text = KERNEL_TEXT_i386;
2281 2328 #endif
2282 2329 DBG(target_kernel_text);
2283 2330
2284 2331 #if defined(__xpv)
2285 2332
2286 2333 /*
2287 2334 * XXPV Derive this stuff from CPUID / what the hypervisor has enabled
2288 2335 */
2289 2336
2290 2337 #if defined(_BOOT_TARGET_amd64)
2291 2338 /*
2292 2339 * 64-bit hypervisor.
2293 2340 */
2294 2341 amd64_support = 1;
2295 2342 pae_support = 1;
2296 2343
2297 2344 #else /* _BOOT_TARGET_amd64 */
2298 2345
2299 2346 /*
2300 2347 * See if we are running on a PAE Hypervisor
2301 2348 */
2302 2349 {
2303 2350 xen_capabilities_info_t caps;
2304 2351
2305 2352 if (HYPERVISOR_xen_version(XENVER_capabilities, &caps) != 0)
2306 2353 dboot_panic("HYPERVISOR_xen_version(caps) failed");
2307 2354 caps[sizeof (caps) - 1] = 0;
2308 2355 if (prom_debug)
2309 2356 dboot_printf("xen capabilities %s\n", caps);
2310 2357 if (strstr(caps, "x86_32p") != NULL)
2311 2358 pae_support = 1;
2312 2359 }
2313 2360
2314 2361 #endif /* _BOOT_TARGET_amd64 */
2315 2362 {
2316 2363 xen_platform_parameters_t p;
2317 2364
2318 2365 if (HYPERVISOR_xen_version(XENVER_platform_parameters, &p) != 0)
2319 2366 dboot_panic("HYPERVISOR_xen_version(parms) failed");
2320 2367 DBG(p.virt_start);
2321 2368 mfn_to_pfn_mapping = (pfn_t *)(xen_virt_start = p.virt_start);
2322 2369 }
2323 2370
2324 2371 /*
2325 2372 * The hypervisor loads stuff starting at 1Gig
2326 2373 */
2327 2374 mfn_base = ONE_GIG;
2328 2375 DBG(mfn_base);
2329 2376
2330 2377 /*
2331 2378 * enable writable page table mode for the hypervisor
2332 2379 */
2333 2380 if (HYPERVISOR_vm_assist(VMASST_CMD_enable,
2334 2381 VMASST_TYPE_writable_pagetables) < 0)
2335 2382 dboot_panic("HYPERVISOR_vm_assist(writable_pagetables) failed");
2336 2383
2337 2384 /*
2338 2385 * check for NX support
2339 2386 */
2340 2387 if (pae_support) {
2341 2388 uint32_t eax = 0x80000000;
|
↓ open down ↓ |
105 lines elided |
↑ open up ↑ |
2342 2389 uint32_t edx = get_cpuid_edx(&eax);
2343 2390
2344 2391 if (eax >= 0x80000001) {
2345 2392 eax = 0x80000001;
2346 2393 edx = get_cpuid_edx(&eax);
2347 2394 if (edx & CPUID_AMD_EDX_NX)
2348 2395 NX_support = 1;
2349 2396 }
2350 2397 }
2351 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 + }
2352 2409 #if !defined(_BOOT_TARGET_amd64)
2353 2410
2354 2411 /*
2355 2412 * The 32-bit hypervisor uses segmentation to protect itself from
2356 2413 * guests. This means when a guest attempts to install a flat 4GB
2357 2414 * code or data descriptor the 32-bit hypervisor will protect itself
2358 2415 * by silently shrinking the segment such that if the guest attempts
2359 2416 * any access where the hypervisor lives a #gp fault is generated.
2360 2417 * The problem is that some applications expect a full 4GB flat
2361 2418 * segment for their current thread pointer and will use negative
2362 2419 * offset segment wrap around to access data. TLS support in linux
2363 2420 * brand is one example of this.
2364 2421 *
2365 2422 * The 32-bit hypervisor can catch the #gp fault in these cases
2366 2423 * and emulate the access without passing the #gp fault to the guest
2367 2424 * but only if VMASST_TYPE_4gb_segments is explicitly turned on.
2368 2425 * Seems like this should have been the default.
2369 2426 * Either way, we want the hypervisor -- and not Solaris -- to deal
2370 2427 * to deal with emulating these accesses.
2371 2428 */
2372 2429 if (HYPERVISOR_vm_assist(VMASST_CMD_enable,
2373 2430 VMASST_TYPE_4gb_segments) < 0)
2374 2431 dboot_panic("HYPERVISOR_vm_assist(4gb_segments) failed");
2375 2432 #endif /* !_BOOT_TARGET_amd64 */
2376 2433
2377 2434 #else /* __xpv */
2378 2435
2379 2436 /*
2380 2437 * use cpuid to enable MMU features
2381 2438 */
2382 2439 if (have_cpuid()) {
|
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
2383 2440 uint32_t eax, edx;
2384 2441
2385 2442 eax = 1;
2386 2443 edx = get_cpuid_edx(&eax);
2387 2444 if (edx & CPUID_INTC_EDX_PSE)
2388 2445 largepage_support = 1;
2389 2446 if (edx & CPUID_INTC_EDX_PGE)
2390 2447 pge_support = 1;
2391 2448 if (edx & CPUID_INTC_EDX_PAE)
2392 2449 pae_support = 1;
2450 + if (edx & CPUID_INTC_EDX_PAT)
2451 + PAT_support = 1;
2393 2452
2394 2453 eax = 0x80000000;
2395 2454 edx = get_cpuid_edx(&eax);
2396 2455 if (eax >= 0x80000001) {
2397 2456 eax = 0x80000001;
2398 2457 edx = get_cpuid_edx(&eax);
2399 2458 if (edx & CPUID_AMD_EDX_LM)
2400 2459 amd64_support = 1;
2401 2460 if (edx & CPUID_AMD_EDX_NX)
2402 2461 NX_support = 1;
2403 2462 }
2404 2463 } else {
2405 2464 dboot_printf("cpuid not supported\n");
2406 2465 }
2407 2466 #endif /* __xpv */
2408 2467
2409 2468
2410 2469 #if defined(_BOOT_TARGET_amd64)
2411 2470 if (amd64_support == 0)
2412 2471 dboot_panic("long mode not supported, rebooting");
2413 2472 else if (pae_support == 0)
2414 2473 dboot_panic("long mode, but no PAE; rebooting");
2415 2474 #else
2416 2475 /*
2417 2476 * Allow the command line to over-ride use of PAE for 32 bit.
2418 2477 */
2419 2478 if (strstr(cmdline, "disablePAE=true") != NULL) {
2420 2479 pae_support = 0;
2421 2480 NX_support = 0;
2422 2481 amd64_support = 0;
2423 2482 }
2424 2483 #endif
2425 2484
2426 2485 /*
2427 2486 * initialize the simple memory allocator
2428 2487 */
2429 2488 init_mem_alloc();
2430 2489
2431 2490 #if !defined(__xpv) && !defined(_BOOT_TARGET_amd64)
2432 2491 /*
2433 2492 * disable PAE on 32 bit h/w w/o NX and < 4Gig of memory
2434 2493 */
2435 2494 if (max_mem < FOUR_GIG && NX_support == 0)
2436 2495 pae_support = 0;
2437 2496 #endif
2438 2497
2439 2498 /*
2440 2499 * configure mmu information
2441 2500 */
2442 2501 if (pae_support) {
2443 2502 shift_amt = shift_amt_pae;
2444 2503 ptes_per_table = 512;
2445 2504 pte_size = 8;
2446 2505 lpagesize = TWO_MEG;
2447 2506 #if defined(_BOOT_TARGET_amd64)
2448 2507 top_level = 3;
2449 2508 #else
2450 2509 top_level = 2;
2451 2510 #endif
|
↓ open down ↓ |
49 lines elided |
↑ open up ↑ |
2452 2511 } else {
2453 2512 pae_support = 0;
2454 2513 NX_support = 0;
2455 2514 shift_amt = shift_amt_nopae;
2456 2515 ptes_per_table = 1024;
2457 2516 pte_size = 4;
2458 2517 lpagesize = FOUR_MEG;
2459 2518 top_level = 1;
2460 2519 }
2461 2520
2521 + DBG(PAT_support);
2462 2522 DBG(pge_support);
2463 2523 DBG(NX_support);
2464 2524 DBG(largepage_support);
2465 2525 DBG(amd64_support);
2466 2526 DBG(top_level);
2467 2527 DBG(pte_size);
2468 2528 DBG(ptes_per_table);
2469 2529 DBG(lpagesize);
2470 2530
2471 2531 #if defined(__xpv)
2472 2532 ktext_phys = ONE_GIG; /* from UNIX Mapfile */
2473 2533 #else
2474 2534 ktext_phys = FOUR_MEG; /* from UNIX Mapfile */
2475 2535 #endif
2476 2536
2477 2537 #if !defined(__xpv) && defined(_BOOT_TARGET_amd64)
2478 2538 /*
2479 2539 * For grub, copy kernel bits from the ELF64 file to final place.
2480 2540 */
2481 2541 DBG_MSG("\nAllocating nucleus pages.\n");
2482 2542 ktext_phys = (uintptr_t)do_mem_alloc(ksize, FOUR_MEG);
2483 2543
2484 2544 if (ktext_phys == 0)
2485 2545 dboot_panic("failed to allocate aligned kernel memory");
2486 2546 DBG(load_addr);
2487 2547 if (dboot_elfload64(load_addr) != 0)
2488 2548 dboot_panic("failed to parse kernel ELF image, rebooting");
2489 2549 #endif
2490 2550
2491 2551 DBG(ktext_phys);
2492 2552
2493 2553 /*
2494 2554 * Allocate page tables.
2495 2555 */
2496 2556 build_page_tables();
2497 2557
2498 2558 /*
2499 2559 * return to assembly code to switch to running kernel
2500 2560 */
2501 2561 entry_addr_low = (uint32_t)target_kernel_text;
2502 2562 DBG(entry_addr_low);
2503 2563 bi->bi_use_largepage = largepage_support;
2504 2564 bi->bi_use_pae = pae_support;
2505 2565 bi->bi_use_pge = pge_support;
2506 2566 bi->bi_use_nx = NX_support;
2507 2567
2508 2568 #if defined(__xpv)
2509 2569
2510 2570 bi->bi_next_paddr = next_avail_addr - mfn_base;
2511 2571 DBG(bi->bi_next_paddr);
2512 2572 bi->bi_next_vaddr = (native_ptr_t)(uintptr_t)next_avail_addr;
2513 2573 DBG(bi->bi_next_vaddr);
2514 2574
2515 2575 /*
2516 2576 * unmap unused pages in start area to make them available for DMA
2517 2577 */
2518 2578 while (next_avail_addr < scratch_end) {
2519 2579 (void) HYPERVISOR_update_va_mapping(next_avail_addr,
2520 2580 0, UVMF_INVLPG | UVMF_LOCAL);
2521 2581 next_avail_addr += MMU_PAGESIZE;
2522 2582 }
2523 2583
2524 2584 bi->bi_xen_start_info = (native_ptr_t)(uintptr_t)xen_info;
2525 2585 DBG((uintptr_t)HYPERVISOR_shared_info);
2526 2586 bi->bi_shared_info = (native_ptr_t)HYPERVISOR_shared_info;
2527 2587 bi->bi_top_page_table = (uintptr_t)top_page_table - mfn_base;
2528 2588
2529 2589 #else /* __xpv */
2530 2590
2531 2591 bi->bi_next_paddr = next_avail_addr;
2532 2592 DBG(bi->bi_next_paddr);
2533 2593 bi->bi_next_vaddr = (native_ptr_t)(uintptr_t)next_avail_addr;
2534 2594 DBG(bi->bi_next_vaddr);
2535 2595 bi->bi_mb_version = multiboot_version;
2536 2596
2537 2597 switch (multiboot_version) {
2538 2598 case 1:
2539 2599 bi->bi_mb_info = (native_ptr_t)(uintptr_t)mb_info;
2540 2600 break;
2541 2601 case 2:
2542 2602 bi->bi_mb_info = (native_ptr_t)(uintptr_t)mb2_info;
2543 2603 break;
2544 2604 default:
2545 2605 dboot_panic("Unknown multiboot version: %d\n",
2546 2606 multiboot_version);
2547 2607 break;
2548 2608 }
2549 2609 bi->bi_top_page_table = (uintptr_t)top_page_table;
2550 2610
|
↓ open down ↓ |
79 lines elided |
↑ open up ↑ |
2551 2611 #endif /* __xpv */
2552 2612
2553 2613 bi->bi_kseg_size = FOUR_MEG;
2554 2614 DBG(bi->bi_kseg_size);
2555 2615
2556 2616 #ifndef __xpv
2557 2617 if (map_debug)
2558 2618 dump_tables();
2559 2619 #endif
2560 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 +
2561 2630 DBG_MSG("\n\n*** DBOOT DONE -- back to asm to jump to kernel\n\n");
2562 2631 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX