xref: /titanic_50/usr/src/uts/i86pc/os/fastboot.c (revision 193974072f41a843678abf5f61979c748687e66b)
1*19397407SSherry Moore /*
2*19397407SSherry Moore  * CDDL HEADER START
3*19397407SSherry Moore  *
4*19397407SSherry Moore  * The contents of this file are subject to the terms of the
5*19397407SSherry Moore  * Common Development and Distribution License (the "License").
6*19397407SSherry Moore  * You may not use this file except in compliance with the License.
7*19397407SSherry Moore  *
8*19397407SSherry Moore  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*19397407SSherry Moore  * or http://www.opensolaris.org/os/licensing.
10*19397407SSherry Moore  * See the License for the specific language governing permissions
11*19397407SSherry Moore  * and limitations under the License.
12*19397407SSherry Moore  *
13*19397407SSherry Moore  * When distributing Covered Code, include this CDDL HEADER in each
14*19397407SSherry Moore  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*19397407SSherry Moore  * If applicable, add the following below this CDDL HEADER, with the
16*19397407SSherry Moore  * fields enclosed by brackets "[]" replaced with your own identifying
17*19397407SSherry Moore  * information: Portions Copyright [yyyy] [name of copyright owner]
18*19397407SSherry Moore  *
19*19397407SSherry Moore  * CDDL HEADER END
20*19397407SSherry Moore  */
21*19397407SSherry Moore 
22*19397407SSherry Moore /*
23*19397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*19397407SSherry Moore  * Use is subject to license terms.
25*19397407SSherry Moore  */
26*19397407SSherry Moore 
27*19397407SSherry Moore 
28*19397407SSherry Moore #include <sys/types.h>
29*19397407SSherry Moore #include <sys/param.h>
30*19397407SSherry Moore #include <sys/segments.h>
31*19397407SSherry Moore #include <sys/sysmacros.h>
32*19397407SSherry Moore #include <sys/vm.h>
33*19397407SSherry Moore 
34*19397407SSherry Moore #include <sys/proc.h>
35*19397407SSherry Moore #include <sys/buf.h>
36*19397407SSherry Moore #include <sys/kmem.h>
37*19397407SSherry Moore 
38*19397407SSherry Moore #include <sys/reboot.h>
39*19397407SSherry Moore #include <sys/uadmin.h>
40*19397407SSherry Moore 
41*19397407SSherry Moore #include <sys/cred.h>
42*19397407SSherry Moore #include <sys/vnode.h>
43*19397407SSherry Moore #include <sys/file.h>
44*19397407SSherry Moore 
45*19397407SSherry Moore #include <sys/cmn_err.h>
46*19397407SSherry Moore #include <sys/dumphdr.h>
47*19397407SSherry Moore #include <sys/bootconf.h>
48*19397407SSherry Moore #include <sys/ddidmareq.h>
49*19397407SSherry Moore #include <sys/varargs.h>
50*19397407SSherry Moore #include <sys/promif.h>
51*19397407SSherry Moore #include <sys/modctl.h>
52*19397407SSherry Moore 
53*19397407SSherry Moore #include <vm/hat.h>
54*19397407SSherry Moore #include <vm/as.h>
55*19397407SSherry Moore #include <vm/page.h>
56*19397407SSherry Moore #include <vm/seg.h>
57*19397407SSherry Moore #include <vm/hat_i86.h>
58*19397407SSherry Moore #include <sys/vm_machparam.h>
59*19397407SSherry Moore #include <sys/archsystm.h>
60*19397407SSherry Moore #include <sys/machsystm.h>
61*19397407SSherry Moore #include <sys/mman.h>
62*19397407SSherry Moore #include <sys/x86_archext.h>
63*19397407SSherry Moore 
64*19397407SSherry Moore #include <sys/fastboot.h>
65*19397407SSherry Moore #include <sys/machelf.h>
66*19397407SSherry Moore #include <sys/kobj.h>
67*19397407SSherry Moore #include <sys/multiboot.h>
68*19397407SSherry Moore 
69*19397407SSherry Moore fastboot_info_t newkernel = { 0 };
70*19397407SSherry Moore static char fastboot_filename[2][OBP_MAXPATHLEN] = { { 0 }, { 0 }};
71*19397407SSherry Moore static x86pte_t ptp_bits = PT_VALID | PT_REF | PT_USER | PT_WRITABLE;
72*19397407SSherry Moore static x86pte_t pte_bits =
73*19397407SSherry Moore     PT_VALID | PT_REF | PT_MOD | PT_NOCONSIST | PT_WRITABLE;
74*19397407SSherry Moore static uint_t fastboot_shift_amt_pae[] = {12, 21, 30, 39};
75*19397407SSherry Moore 
76*19397407SSherry Moore 
77*19397407SSherry Moore int fastboot_debug = 0;
78*19397407SSherry Moore int fastboot_contig = 0;
79*19397407SSherry Moore 
80*19397407SSherry Moore /*
81*19397407SSherry Moore  * Fake starting va for new kernel and boot archive.
82*19397407SSherry Moore  */
83*19397407SSherry Moore static uintptr_t fake_va = FASTBOOT_FAKE_VA;
84*19397407SSherry Moore 
85*19397407SSherry Moore /*
86*19397407SSherry Moore  * Below 1G for page tables as we are using 2G as the fake virtual address for
87*19397407SSherry Moore  * the new kernel and boot archive.
88*19397407SSherry Moore  */
89*19397407SSherry Moore static ddi_dma_attr_t fastboot_below_1G_dma_attr = {
90*19397407SSherry Moore 	DMA_ATTR_V0,
91*19397407SSherry Moore 	0x0000000008000000ULL,	/* dma_attr_addr_lo: 128MB */
92*19397407SSherry Moore 	0x000000003FFFFFFFULL,	/* dma_attr_addr_hi: 1G */
93*19397407SSherry Moore 	0x00000000FFFFFFFFULL,	/* dma_attr_count_max */
94*19397407SSherry Moore 	0x0000000000001000ULL,	/* dma_attr_align: 4KB */
95*19397407SSherry Moore 	1,			/* dma_attr_burstsize */
96*19397407SSherry Moore 	1,			/* dma_attr_minxfer */
97*19397407SSherry Moore 	0x00000000FFFFFFFFULL,	/* dma_attr_maxxfer */
98*19397407SSherry Moore 	0x00000000FFFFFFFFULL,	/* dma_attr_seg */
99*19397407SSherry Moore 	1,			/* dma_attr_sgllen */
100*19397407SSherry Moore 	0x1000ULL,		/* dma_attr_granular */
101*19397407SSherry Moore 	0,			/* dma_attr_flags */
102*19397407SSherry Moore };
103*19397407SSherry Moore 
104*19397407SSherry Moore static ddi_dma_attr_t fastboot_dma_attr = {
105*19397407SSherry Moore 	DMA_ATTR_V0,
106*19397407SSherry Moore 	0x0000000008000000ULL,	/* dma_attr_addr_lo: 128MB */
107*19397407SSherry Moore 	0x0000000FFFFFFFFFULL,	/* dma_attr_addr_hi: 64GB */
108*19397407SSherry Moore 	0x00000000FFFFFFFFULL,	/* dma_attr_count_max */
109*19397407SSherry Moore 	0x0000000000001000ULL,	/* dma_attr_align: 4KB */
110*19397407SSherry Moore 	1,			/* dma_attr_burstsize */
111*19397407SSherry Moore 	1,			/* dma_attr_minxfer */
112*19397407SSherry Moore 	0x00000000FFFFFFFFULL,	/* dma_attr_maxxfer */
113*19397407SSherry Moore 	0x00000000FFFFFFFFULL,	/* dma_attr_seg */
114*19397407SSherry Moore 	1,			/* dma_attr_sgllen */
115*19397407SSherry Moore 	0x1000ULL,		/* dma_attr_granular */
116*19397407SSherry Moore 	0,			/* dma_attr_flags */
117*19397407SSherry Moore };
118*19397407SSherry Moore 
119*19397407SSherry Moore /*
120*19397407SSherry Moore  * Various information saved from the previous boot to reconstruct
121*19397407SSherry Moore  * multiboot_info.
122*19397407SSherry Moore  */
123*19397407SSherry Moore extern multiboot_info_t saved_mbi;
124*19397407SSherry Moore extern mb_memory_map_t saved_mmap[FASTBOOT_SAVED_MMAP_COUNT];
125*19397407SSherry Moore extern struct sol_netinfo saved_drives[FASTBOOT_SAVED_DRIVES_COUNT];
126*19397407SSherry Moore extern char saved_cmdline[FASTBOOT_SAVED_CMDLINE_LEN];
127*19397407SSherry Moore extern int saved_cmdline_len;
128*19397407SSherry Moore 
129*19397407SSherry Moore extern void* contig_alloc(size_t size, ddi_dma_attr_t *attr,
130*19397407SSherry Moore     uintptr_t align, int cansleep);
131*19397407SSherry Moore 
132*19397407SSherry Moore /* PRINTLIKE */
133*19397407SSherry Moore extern void vprintf(const char *, va_list);
134*19397407SSherry Moore 
135*19397407SSherry Moore 
136*19397407SSherry Moore /*
137*19397407SSherry Moore  * Need to be able to get boot_archives from other places
138*19397407SSherry Moore  */
139*19397407SSherry Moore #define	BOOTARCHIVE64	"/platform/i86pc/amd64/boot_archive"
140*19397407SSherry Moore #define	BOOTARCHIVE32	"/platform/i86pc/boot_archive"
141*19397407SSherry Moore #define	BOOTARCHIVE_FAILSAFE	"/boot/x86.miniroot-safe"
142*19397407SSherry Moore #define	FAILSAFE_BOOTFILE	"/boot/platform/i86pc/kernel/unix"
143*19397407SSherry Moore 
144*19397407SSherry Moore static uint_t fastboot_vatoindex(fastboot_info_t *, uintptr_t, int);
145*19397407SSherry Moore static void fastboot_map_with_size(fastboot_info_t *, uintptr_t,
146*19397407SSherry Moore     paddr_t, size_t, int);
147*19397407SSherry Moore static void fastboot_build_pagetables(fastboot_info_t *);
148*19397407SSherry Moore static int fastboot_build_mbi(char *, fastboot_info_t *);
149*19397407SSherry Moore 
150*19397407SSherry Moore static const char fastboot_enomem_msg[] = "Fastboot: Couldn't allocate 0x%"
151*19397407SSherry Moore 	PRIx64" bytes below %s to do fast reboot";
152*19397407SSherry Moore 
153*19397407SSherry Moore static void
154*19397407SSherry Moore dprintf(char *fmt, ...)
155*19397407SSherry Moore {
156*19397407SSherry Moore 	va_list adx;
157*19397407SSherry Moore 
158*19397407SSherry Moore 	if (!fastboot_debug)
159*19397407SSherry Moore 		return;
160*19397407SSherry Moore 
161*19397407SSherry Moore 	va_start(adx, fmt);
162*19397407SSherry Moore 	vprintf(fmt, adx);
163*19397407SSherry Moore 	va_end(adx);
164*19397407SSherry Moore }
165*19397407SSherry Moore 
166*19397407SSherry Moore 
167*19397407SSherry Moore /*
168*19397407SSherry Moore  * Return the index corresponding to a virt address at a given page table level.
169*19397407SSherry Moore  */
170*19397407SSherry Moore static uint_t
171*19397407SSherry Moore fastboot_vatoindex(fastboot_info_t *nk, uintptr_t va, int level)
172*19397407SSherry Moore {
173*19397407SSherry Moore 	return ((va >> nk->fi_shift_amt[level]) & (nk->fi_ptes_per_table - 1));
174*19397407SSherry Moore }
175*19397407SSherry Moore 
176*19397407SSherry Moore 
177*19397407SSherry Moore /*
178*19397407SSherry Moore  * Add mapping from vstart to pstart for the specified size.
179*19397407SSherry Moore  * Only handles 2 level.  Must use 2M pages.  vstart, pstart
180*19397407SSherry Moore  * and size should all have been aligned at 2M boundaries.
181*19397407SSherry Moore  */
182*19397407SSherry Moore static void
183*19397407SSherry Moore fastboot_map_with_size(fastboot_info_t *nk, uintptr_t vstart, paddr_t pstart,
184*19397407SSherry Moore     size_t size, int level)
185*19397407SSherry Moore {
186*19397407SSherry Moore 	x86pte_t	pteval, *table;
187*19397407SSherry Moore 	uintptr_t	vaddr;
188*19397407SSherry Moore 	paddr_t		paddr;
189*19397407SSherry Moore 	int		index, l;
190*19397407SSherry Moore 
191*19397407SSherry Moore 	table = (x86pte_t *)(nk->fi_pagetable_va);
192*19397407SSherry Moore 
193*19397407SSherry Moore 	for (l = nk->fi_top_level; l >= level; l--) {
194*19397407SSherry Moore 
195*19397407SSherry Moore 		index = fastboot_vatoindex(nk, vstart, l);
196*19397407SSherry Moore 
197*19397407SSherry Moore 		if (l == level) {
198*19397407SSherry Moore 			/*
199*19397407SSherry Moore 			 * Last level.  Program the page table entries.
200*19397407SSherry Moore 			 */
201*19397407SSherry Moore 			for (vaddr = vstart, paddr = pstart;
202*19397407SSherry Moore 			    vaddr < vstart + size;
203*19397407SSherry Moore 			    vaddr += (1ULL << nk->fi_shift_amt[l]),
204*19397407SSherry Moore 			    paddr += (1ULL << nk->fi_shift_amt[l])) {
205*19397407SSherry Moore 
206*19397407SSherry Moore 				uint_t index = fastboot_vatoindex(nk, vaddr, l);
207*19397407SSherry Moore 
208*19397407SSherry Moore 				if (l > 0)
209*19397407SSherry Moore 					pteval = paddr | pte_bits | PT_PAGESIZE;
210*19397407SSherry Moore 				else
211*19397407SSherry Moore 					pteval = paddr | pte_bits;
212*19397407SSherry Moore 
213*19397407SSherry Moore 				table[index] = pteval;
214*19397407SSherry Moore 			}
215*19397407SSherry Moore 		} else if (table[index] & PT_VALID) {
216*19397407SSherry Moore 			if (l == level)
217*19397407SSherry Moore 				break;
218*19397407SSherry Moore 
219*19397407SSherry Moore 			table = (x86pte_t *)
220*19397407SSherry Moore 			    ((uintptr_t)(((paddr_t)table[index] & MMU_PAGEMASK)
221*19397407SSherry Moore 			    - nk->fi_pagetable_pa) + nk->fi_pagetable_va);
222*19397407SSherry Moore 		} else {
223*19397407SSherry Moore 			/*
224*19397407SSherry Moore 			 * Intermediate levels.  Program with either valid
225*19397407SSherry Moore 			 * bit or PTP bits.
226*19397407SSherry Moore 			 */
227*19397407SSherry Moore 			if (l == nk->fi_top_level) {
228*19397407SSherry Moore 				table[index] = nk->fi_next_table_pa | PT_VALID;
229*19397407SSherry Moore 			} else {
230*19397407SSherry Moore 				table[index] = nk->fi_next_table_pa | ptp_bits;
231*19397407SSherry Moore 			}
232*19397407SSherry Moore 			table = (x86pte_t *)(nk->fi_next_table_va);
233*19397407SSherry Moore 			nk->fi_next_table_va += MMU_PAGESIZE;
234*19397407SSherry Moore 			nk->fi_next_table_pa += MMU_PAGESIZE;
235*19397407SSherry Moore 		}
236*19397407SSherry Moore 	}
237*19397407SSherry Moore }
238*19397407SSherry Moore 
239*19397407SSherry Moore /*
240*19397407SSherry Moore  * Build page tables for the lower 1G of physical memory using 2M
241*19397407SSherry Moore  * pages, and prepare page tables for mapping new kernel and boot
242*19397407SSherry Moore  * archive pages using 4K pages.
243*19397407SSherry Moore  */
244*19397407SSherry Moore static void
245*19397407SSherry Moore fastboot_build_pagetables(fastboot_info_t *nk)
246*19397407SSherry Moore {
247*19397407SSherry Moore 	/*
248*19397407SSherry Moore 	 * Map lower 1G physical memory.  Use large pages.
249*19397407SSherry Moore 	 */
250*19397407SSherry Moore 	fastboot_map_with_size(nk, 0, 0, ONE_GIG, 1);
251*19397407SSherry Moore 
252*19397407SSherry Moore 	/*
253*19397407SSherry Moore 	 * Map one 4K page to get the middle page tables set up.
254*19397407SSherry Moore 	 */
255*19397407SSherry Moore 	fake_va = P2ALIGN_TYPED(fake_va, nk->fi_lpagesize, uintptr_t);
256*19397407SSherry Moore 	fastboot_map_with_size(nk, fake_va,
257*19397407SSherry Moore 	    nk->fi_files[0].fb_pte_list_va[0] & MMU_PAGEMASK, PAGESIZE, 0);
258*19397407SSherry Moore }
259*19397407SSherry Moore 
260*19397407SSherry Moore 
261*19397407SSherry Moore /*
262*19397407SSherry Moore  * Sanity check.  Look for dboot offset.
263*19397407SSherry Moore  */
264*19397407SSherry Moore static int
265*19397407SSherry Moore fastboot_elf64_find_dboot_load_offset(void *img, off_t imgsz, uint32_t *offp)
266*19397407SSherry Moore {
267*19397407SSherry Moore 	Elf64_Ehdr	*ehdr = (Elf64_Ehdr *)img;
268*19397407SSherry Moore 	Elf64_Phdr	*phdr;
269*19397407SSherry Moore 	uint8_t		*phdrbase;
270*19397407SSherry Moore 	int		i;
271*19397407SSherry Moore 
272*19397407SSherry Moore 	if ((ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize) >= imgsz)
273*19397407SSherry Moore 		return (-1);
274*19397407SSherry Moore 
275*19397407SSherry Moore 	phdrbase = (uint8_t *)img + ehdr->e_phoff;
276*19397407SSherry Moore 
277*19397407SSherry Moore 	for (i = 0; i < ehdr->e_phnum; i++) {
278*19397407SSherry Moore 		phdr = (Elf64_Phdr *)(phdrbase + ehdr->e_phentsize * i);
279*19397407SSherry Moore 
280*19397407SSherry Moore 		if (phdr->p_type == PT_LOAD) {
281*19397407SSherry Moore 			if (phdr->p_vaddr == phdr->p_paddr &&
282*19397407SSherry Moore 			    phdr->p_vaddr == DBOOT_ENTRY_ADDRESS) {
283*19397407SSherry Moore 				ASSERT(phdr->p_offset <= UINT32_MAX);
284*19397407SSherry Moore 				*offp = (uint32_t)phdr->p_offset;
285*19397407SSherry Moore 				return (0);
286*19397407SSherry Moore 			}
287*19397407SSherry Moore 		}
288*19397407SSherry Moore 	}
289*19397407SSherry Moore 
290*19397407SSherry Moore 	return (-1);
291*19397407SSherry Moore }
292*19397407SSherry Moore 
293*19397407SSherry Moore 
294*19397407SSherry Moore /*
295*19397407SSherry Moore  * Initialize text and data section information for 32-bit kernel.
296*19397407SSherry Moore  */
297*19397407SSherry Moore static int
298*19397407SSherry Moore fastboot_elf32_find_loadables(void *img, off_t imgsz, fastboot_section_t *sectp,
299*19397407SSherry Moore     int *sectcntp, uint32_t *offp)
300*19397407SSherry Moore {
301*19397407SSherry Moore 	Elf32_Ehdr	*ehdr = (Elf32_Ehdr *)img;
302*19397407SSherry Moore 	Elf32_Phdr	*phdr;
303*19397407SSherry Moore 	uint8_t		*phdrbase;
304*19397407SSherry Moore 	int		i;
305*19397407SSherry Moore 	int		used_sections = 0;
306*19397407SSherry Moore 
307*19397407SSherry Moore 
308*19397407SSherry Moore 	if ((ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize) >= imgsz)
309*19397407SSherry Moore 		return (-1);
310*19397407SSherry Moore 
311*19397407SSherry Moore 	phdrbase = (uint8_t *)img + ehdr->e_phoff;
312*19397407SSherry Moore 
313*19397407SSherry Moore 	for (i = 0; i < ehdr->e_phnum; i++) {
314*19397407SSherry Moore 		phdr = (Elf32_Phdr *)(phdrbase + ehdr->e_phentsize * i);
315*19397407SSherry Moore 
316*19397407SSherry Moore 		if (phdr->p_type == PT_INTERP)
317*19397407SSherry Moore 			return (-1);
318*19397407SSherry Moore 
319*19397407SSherry Moore 		if (phdr->p_type != PT_LOAD)
320*19397407SSherry Moore 			continue;
321*19397407SSherry Moore 
322*19397407SSherry Moore 		if (phdr->p_vaddr == phdr->p_paddr &&
323*19397407SSherry Moore 		    phdr->p_paddr == DBOOT_ENTRY_ADDRESS) {
324*19397407SSherry Moore 			*offp = (uint32_t)phdr->p_offset;
325*19397407SSherry Moore 		} else {
326*19397407SSherry Moore 			sectp[used_sections].fb_sec_offset = phdr->p_offset;
327*19397407SSherry Moore 			sectp[used_sections].fb_sec_paddr = phdr->p_paddr;
328*19397407SSherry Moore 			sectp[used_sections].fb_sec_size = phdr->p_filesz;
329*19397407SSherry Moore 			sectp[used_sections].fb_sec_bss_size =
330*19397407SSherry Moore 			    (phdr->p_filesz < phdr->p_memsz) ?
331*19397407SSherry Moore 			    (phdr->p_memsz - phdr->p_filesz) : 0;
332*19397407SSherry Moore 
333*19397407SSherry Moore 			used_sections++;
334*19397407SSherry Moore 		}
335*19397407SSherry Moore 
336*19397407SSherry Moore 	}
337*19397407SSherry Moore 
338*19397407SSherry Moore 	*sectcntp = used_sections;
339*19397407SSherry Moore 	return (0);
340*19397407SSherry Moore }
341*19397407SSherry Moore 
342*19397407SSherry Moore /*
343*19397407SSherry Moore  * Create multiboot info structure
344*19397407SSherry Moore  */
345*19397407SSherry Moore static int
346*19397407SSherry Moore fastboot_build_mbi(char *mdep, fastboot_info_t *nk)
347*19397407SSherry Moore {
348*19397407SSherry Moore 	mb_module_t	*mbp;
349*19397407SSherry Moore 	uintptr_t	next_addr;
350*19397407SSherry Moore 	uintptr_t	new_mbi_pa;
351*19397407SSherry Moore 	size_t		size;
352*19397407SSherry Moore 	void		*buf = NULL;
353*19397407SSherry Moore 	size_t		arglen;
354*19397407SSherry Moore 	char		bootargs[OBP_MAXPATHLEN];
355*19397407SSherry Moore 
356*19397407SSherry Moore 	bzero(bootargs, OBP_MAXPATHLEN);
357*19397407SSherry Moore 
358*19397407SSherry Moore 	if (mdep != NULL) {
359*19397407SSherry Moore 		arglen = strlen(mdep) + 1;
360*19397407SSherry Moore 	} else {
361*19397407SSherry Moore 		arglen = saved_cmdline_len;
362*19397407SSherry Moore 	}
363*19397407SSherry Moore 
364*19397407SSherry Moore 	size = PAGESIZE + P2ROUNDUP(arglen, PAGESIZE);
365*19397407SSherry Moore 	buf = contig_alloc(size, &fastboot_below_1G_dma_attr, PAGESIZE, 0);
366*19397407SSherry Moore 	if (buf == NULL) {
367*19397407SSherry Moore 		cmn_err(CE_WARN, fastboot_enomem_msg, (uint64_t)size, "1G");
368*19397407SSherry Moore 		return (-1);
369*19397407SSherry Moore 	}
370*19397407SSherry Moore 
371*19397407SSherry Moore 	bzero(buf, size);
372*19397407SSherry Moore 
373*19397407SSherry Moore 	new_mbi_pa = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat, (caddr_t)buf));
374*19397407SSherry Moore 
375*19397407SSherry Moore 	hat_devload(kas.a_hat, (caddr_t)new_mbi_pa, size,
376*19397407SSherry Moore 	    mmu_btop(new_mbi_pa), PROT_READ | PROT_WRITE, HAT_LOAD_NOCONSIST);
377*19397407SSherry Moore 
378*19397407SSherry Moore 	nk->fi_new_mbi_pa = (paddr_t)new_mbi_pa;
379*19397407SSherry Moore 
380*19397407SSherry Moore 	bcopy(&saved_mbi, (void *)new_mbi_pa, sizeof (multiboot_info_t));
381*19397407SSherry Moore 
382*19397407SSherry Moore 	next_addr = new_mbi_pa + sizeof (multiboot_info_t);
383*19397407SSherry Moore 	((multiboot_info_t *)new_mbi_pa)->mods_addr = next_addr;
384*19397407SSherry Moore 	mbp = (mb_module_t *)(uintptr_t)next_addr;
385*19397407SSherry Moore 	mbp->mod_start = newkernel.fi_files[FASTBOOT_BOOTARCHIVE].fb_dest_pa;
386*19397407SSherry Moore 	mbp->mod_end = newkernel.fi_files[FASTBOOT_BOOTARCHIVE].fb_next_pa;
387*19397407SSherry Moore 
388*19397407SSherry Moore 	next_addr += sizeof (mb_module_t);
389*19397407SSherry Moore 	bcopy(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE], (void *)next_addr,
390*19397407SSherry Moore 	    strlen(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE]));
391*19397407SSherry Moore 
392*19397407SSherry Moore 	mbp->mod_name = next_addr;
393*19397407SSherry Moore 	mbp->reserved = 0;
394*19397407SSherry Moore 	next_addr += strlen(fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE]);
395*19397407SSherry Moore 	*(char *)next_addr = '\0';
396*19397407SSherry Moore 	next_addr++;
397*19397407SSherry Moore 	next_addr = P2ROUNDUP_TYPED(next_addr, 16, uintptr_t);
398*19397407SSherry Moore 
399*19397407SSherry Moore 	((multiboot_info_t *)new_mbi_pa)->mmap_addr = next_addr;
400*19397407SSherry Moore 	bcopy((void *)(uintptr_t)saved_mmap, (void *)next_addr,
401*19397407SSherry Moore 	    saved_mbi.mmap_length);
402*19397407SSherry Moore 	next_addr += saved_mbi.mmap_length;
403*19397407SSherry Moore 
404*19397407SSherry Moore 	((multiboot_info_t *)new_mbi_pa)->drives_addr = next_addr;
405*19397407SSherry Moore 	bcopy((void *)(uintptr_t)saved_drives, (void *)next_addr,
406*19397407SSherry Moore 	    saved_mbi.drives_length);
407*19397407SSherry Moore 	next_addr += saved_mbi.drives_length;
408*19397407SSherry Moore 
409*19397407SSherry Moore 	((multiboot_info_t *)new_mbi_pa)->cmdline = next_addr;
410*19397407SSherry Moore 
411*19397407SSherry Moore 	if (mdep != NULL) {
412*19397407SSherry Moore 		bcopy(mdep, (void *)(uintptr_t)
413*19397407SSherry Moore 		    (((multiboot_info_t *)new_mbi_pa)->cmdline), (arglen - 1));
414*19397407SSherry Moore 	} else {
415*19397407SSherry Moore 		bcopy((void *)saved_cmdline, (void *)next_addr, (arglen - 1));
416*19397407SSherry Moore 	}
417*19397407SSherry Moore 	/* Terminate the string */
418*19397407SSherry Moore 	((char *)(intptr_t)next_addr)[arglen - 1] = '\0';
419*19397407SSherry Moore 
420*19397407SSherry Moore 	return (0);
421*19397407SSherry Moore }
422*19397407SSherry Moore 
423*19397407SSherry Moore 
424*19397407SSherry Moore void
425*19397407SSherry Moore load_kernel(char *mdep)
426*19397407SSherry Moore {
427*19397407SSherry Moore 	struct _buf	*file;
428*19397407SSherry Moore 	void		*buf = NULL;
429*19397407SSherry Moore 	uintptr_t	va;
430*19397407SSherry Moore 	int		i, j;
431*19397407SSherry Moore 	fastboot_file_t	*fb;
432*19397407SSherry Moore 	uint32_t	dboot_start_offset;
433*19397407SSherry Moore 	Ehdr		*ehdr;
434*19397407SSherry Moore 	char		kern_bootpath[OBP_MAXPATHLEN];
435*19397407SSherry Moore 	char		bootargs[OBP_MAXPATHLEN];
436*19397407SSherry Moore 	extern uintptr_t postbootkernelbase;
437*19397407SSherry Moore 	extern char	fb_swtch_image[];
438*19397407SSherry Moore 	int bootpath_len = 0;
439*19397407SSherry Moore 	int is_failsafe = 0;
440*19397407SSherry Moore 	uintptr_t next_pa = 0;	/* next available physical addr */
441*19397407SSherry Moore 
442*19397407SSherry Moore 	ASSERT(fastreboot_capable);
443*19397407SSherry Moore 
444*19397407SSherry Moore 	postbootkernelbase = 0;
445*19397407SSherry Moore 
446*19397407SSherry Moore 	if (x86_feature & X86_PAE) {
447*19397407SSherry Moore 		newkernel.fi_has_pae = 1;
448*19397407SSherry Moore 		newkernel.fi_shift_amt = fastboot_shift_amt_pae;
449*19397407SSherry Moore 		newkernel.fi_ptes_per_table = 512;
450*19397407SSherry Moore 		newkernel.fi_lpagesize = (2 << 20);	/* 2M */
451*19397407SSherry Moore 		newkernel.fi_top_level = 2;
452*19397407SSherry Moore 	}
453*19397407SSherry Moore 
454*19397407SSherry Moore 	bzero(kern_bootpath, OBP_MAXPATHLEN);
455*19397407SSherry Moore 	bzero(bootargs, OBP_MAXPATHLEN);
456*19397407SSherry Moore 
457*19397407SSherry Moore 	/*
458*19397407SSherry Moore 	 * If mdep is not NULL, it comes in the format of
459*19397407SSherry Moore 	 *	mountpoint unix args
460*19397407SSherry Moore 	 */
461*19397407SSherry Moore 	if (mdep != NULL) {
462*19397407SSherry Moore 		if (mdep[0] != '-') {
463*19397407SSherry Moore 			/* First get the root argument */
464*19397407SSherry Moore 			i = 0;
465*19397407SSherry Moore 			while (mdep[i] != '\0' && mdep[i] != ' ') {
466*19397407SSherry Moore 				i++;
467*19397407SSherry Moore 			}
468*19397407SSherry Moore 
469*19397407SSherry Moore 			if (i < 4 || strncmp(&mdep[i-4], "unix", 4) != 0) {
470*19397407SSherry Moore 				/* mount point */
471*19397407SSherry Moore 				bcopy(mdep, kern_bootpath, i);
472*19397407SSherry Moore 				kern_bootpath[i] = '\0';
473*19397407SSherry Moore 				bootpath_len = i;
474*19397407SSherry Moore 
475*19397407SSherry Moore 				/*
476*19397407SSherry Moore 				 * Get the next argument. It should be unix as
477*19397407SSherry Moore 				 * we have validated in in halt.c.
478*19397407SSherry Moore 				 */
479*19397407SSherry Moore 				if (strlen(mdep) > i) {
480*19397407SSherry Moore 					mdep += (i + 1);
481*19397407SSherry Moore 					i = 0;
482*19397407SSherry Moore 					while (mdep[i] != '\0' &&
483*19397407SSherry Moore 					    mdep[i] != ' ') {
484*19397407SSherry Moore 						i++;
485*19397407SSherry Moore 					}
486*19397407SSherry Moore 				}
487*19397407SSherry Moore 
488*19397407SSherry Moore 			}
489*19397407SSherry Moore 			bcopy(mdep, kern_bootfile, i);
490*19397407SSherry Moore 			kern_bootfile[i] = '\0';
491*19397407SSherry Moore 		} else {
492*19397407SSherry Moore 			int off = strlen(kern_bootfile);
493*19397407SSherry Moore 			bcopy(kern_bootfile, bootargs, off);
494*19397407SSherry Moore 			bcopy(" ", &bootargs[off++], 1);
495*19397407SSherry Moore 			bcopy(mdep, &bootargs[off], strlen(mdep));
496*19397407SSherry Moore 			off += strlen(mdep);
497*19397407SSherry Moore 			bootargs[off] = '\0';
498*19397407SSherry Moore 			mdep = bootargs;
499*19397407SSherry Moore 		}
500*19397407SSherry Moore 	}
501*19397407SSherry Moore 
502*19397407SSherry Moore 	/*
503*19397407SSherry Moore 	 * Make sure we get the null character
504*19397407SSherry Moore 	 */
505*19397407SSherry Moore 	bcopy(kern_bootpath, fastboot_filename[FASTBOOT_NAME_UNIX],
506*19397407SSherry Moore 	    bootpath_len);
507*19397407SSherry Moore 	bcopy(kern_bootfile,
508*19397407SSherry Moore 	    &fastboot_filename[FASTBOOT_NAME_UNIX][bootpath_len],
509*19397407SSherry Moore 	    strlen(kern_bootfile) + 1);
510*19397407SSherry Moore 
511*19397407SSherry Moore 	bcopy(kern_bootpath, fastboot_filename[FASTBOOT_NAME_BOOTARCHIVE],
512*19397407SSherry Moore 	    bootpath_len);
513*19397407SSherry Moore 
514*19397407SSherry Moore 	if (bcmp(kern_bootfile, FAILSAFE_BOOTFILE,
515*19397407SSherry Moore 	    (sizeof (FAILSAFE_BOOTFILE) - 1)) == 0) {
516*19397407SSherry Moore 		is_failsafe = 1;
517*19397407SSherry Moore 	}
518*19397407SSherry Moore 
519*19397407SSherry Moore 	/*
520*19397407SSherry Moore 	 * Read in unix and boot_archive
521*19397407SSherry Moore 	 */
522*19397407SSherry Moore 	for (i = 0; i < FASTBOOT_MAX_FILES_MAP; i++) {
523*19397407SSherry Moore 		uint64_t fsize;
524*19397407SSherry Moore 		size_t fsize_roundup, pt_size;
525*19397407SSherry Moore 		int page_index;
526*19397407SSherry Moore 		uintptr_t offset;
527*19397407SSherry Moore 		int pt_entry_count;
528*19397407SSherry Moore 		ddi_dma_attr_t dma_attr = fastboot_dma_attr;
529*19397407SSherry Moore 
530*19397407SSherry Moore 		dprintf("fastboot_filename[%d] = %s\n",
531*19397407SSherry Moore 		    i, fastboot_filename[i]);
532*19397407SSherry Moore 
533*19397407SSherry Moore 		if ((file = kobj_open_file(fastboot_filename[i])) ==
534*19397407SSherry Moore 		    (struct _buf *)-1) {
535*19397407SSherry Moore 			cmn_err(CE_WARN, "Fastboot: Couldn't open %s",
536*19397407SSherry Moore 			    fastboot_filename[i]);
537*19397407SSherry Moore 			goto err_out;
538*19397407SSherry Moore 		}
539*19397407SSherry Moore 
540*19397407SSherry Moore 		if (kobj_get_filesize(file, &fsize) != 0) {
541*19397407SSherry Moore 			cmn_err(CE_WARN,
542*19397407SSherry Moore 			    "Fastboot: Couldn't get filesize for %s",
543*19397407SSherry Moore 			    fastboot_filename[i]);
544*19397407SSherry Moore 			goto err_out;
545*19397407SSherry Moore 		}
546*19397407SSherry Moore 
547*19397407SSherry Moore 		if (i == FASTBOOT_BOOTARCHIVE && is_failsafe) {
548*19397407SSherry Moore 			/* Adjust low memory for failsafe mode */
549*19397407SSherry Moore 			fastboot_below_1G_dma_attr.dma_attr_addr_lo =
550*19397407SSherry Moore 			    dma_attr.dma_attr_addr_lo =
551*19397407SSherry Moore 			    P2ROUNDUP_TYPED(fsize, PAGESIZE, uint64_t) +
552*19397407SSherry Moore 			    next_pa;
553*19397407SSherry Moore 		}
554*19397407SSherry Moore 
555*19397407SSherry Moore 		if (!fastboot_contig)
556*19397407SSherry Moore 			dma_attr.dma_attr_sgllen = (fsize / PAGESIZE) +
557*19397407SSherry Moore 			    (((fsize % PAGESIZE) == 0) ? 0 : 1);
558*19397407SSherry Moore 
559*19397407SSherry Moore 		if ((buf = contig_alloc(fsize, &dma_attr, PAGESIZE, 0))
560*19397407SSherry Moore 		    == NULL) {
561*19397407SSherry Moore 			cmn_err(CE_WARN, fastboot_enomem_msg, fsize,
562*19397407SSherry Moore 			    "64G");
563*19397407SSherry Moore 			goto err_out;
564*19397407SSherry Moore 		}
565*19397407SSherry Moore 
566*19397407SSherry Moore 		va = P2ROUNDUP_TYPED((uintptr_t)buf, PAGESIZE, uintptr_t);
567*19397407SSherry Moore 
568*19397407SSherry Moore 		if (kobj_read_file(file, (char *)va, fsize, 0) < 0) {
569*19397407SSherry Moore 			cmn_err(CE_WARN, "Fastboot: Couldn't read %s",
570*19397407SSherry Moore 			    fastboot_filename[i]);
571*19397407SSherry Moore 			goto err_out;
572*19397407SSherry Moore 		}
573*19397407SSherry Moore 
574*19397407SSherry Moore 		fb = &newkernel.fi_files[i];
575*19397407SSherry Moore 		fb->fb_va = va;
576*19397407SSherry Moore 		fb->fb_size = fsize;
577*19397407SSherry Moore 		fb->fb_sectcnt = 0;
578*19397407SSherry Moore 
579*19397407SSherry Moore 		fsize_roundup = P2ROUNDUP_TYPED(fb->fb_size, PAGESIZE, size_t);
580*19397407SSherry Moore 
581*19397407SSherry Moore 		/*
582*19397407SSherry Moore 		 * Allocate one extra page table entry for terminating
583*19397407SSherry Moore 		 * the list.
584*19397407SSherry Moore 		 */
585*19397407SSherry Moore 		pt_entry_count = (fsize_roundup >> PAGESHIFT) + 1;
586*19397407SSherry Moore 		pt_size = P2ROUNDUP(pt_entry_count * 8, PAGESIZE);
587*19397407SSherry Moore 
588*19397407SSherry Moore 		if ((fb->fb_pte_list_va =
589*19397407SSherry Moore 		    (x86pte_t *)contig_alloc(pt_size,
590*19397407SSherry Moore 		    &fastboot_below_1G_dma_attr, PAGESIZE, 0)) == NULL) {
591*19397407SSherry Moore 			cmn_err(CE_WARN, fastboot_enomem_msg,
592*19397407SSherry Moore 			    (uint64_t)pt_size, "1G");
593*19397407SSherry Moore 			goto err_out;
594*19397407SSherry Moore 		}
595*19397407SSherry Moore 
596*19397407SSherry Moore 		bzero((void *)(fb->fb_pte_list_va), pt_size);
597*19397407SSherry Moore 
598*19397407SSherry Moore 		fb->fb_pte_list_pa = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat,
599*19397407SSherry Moore 		    (caddr_t)fb->fb_pte_list_va));
600*19397407SSherry Moore 
601*19397407SSherry Moore 		for (page_index = 0, offset = 0; offset < fb->fb_size;
602*19397407SSherry Moore 		    offset += PAGESIZE) {
603*19397407SSherry Moore 			uint64_t paddr;
604*19397407SSherry Moore 
605*19397407SSherry Moore 			paddr = mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat,
606*19397407SSherry Moore 			    (caddr_t)fb->fb_va + offset));
607*19397407SSherry Moore 
608*19397407SSherry Moore 			ASSERT(paddr >= fastboot_dma_attr.dma_attr_addr_lo);
609*19397407SSherry Moore 
610*19397407SSherry Moore 			/*
611*19397407SSherry Moore 			 * Include the pte_bits so we don't have to make
612*19397407SSherry Moore 			 * it in assembly.
613*19397407SSherry Moore 			 */
614*19397407SSherry Moore 			fb->fb_pte_list_va[page_index++] = (x86pte_t)
615*19397407SSherry Moore 			    (paddr | pte_bits);
616*19397407SSherry Moore 		}
617*19397407SSherry Moore 
618*19397407SSherry Moore 		fb->fb_pte_list_va[page_index] = FASTBOOT_TERMINATE;
619*19397407SSherry Moore 
620*19397407SSherry Moore 		if (i == FASTBOOT_UNIX) {
621*19397407SSherry Moore 			ehdr = (Ehdr *)va;
622*19397407SSherry Moore 
623*19397407SSherry Moore 			/*
624*19397407SSherry Moore 			 * Sanity checks:
625*19397407SSherry Moore 			 */
626*19397407SSherry Moore 			for (j = 0; j < SELFMAG; j++) {
627*19397407SSherry Moore 				if (ehdr->e_ident[j] != ELFMAG[j]) {
628*19397407SSherry Moore 					cmn_err(CE_WARN, "Fastboot: Bad ELF "
629*19397407SSherry Moore 					    "signature");
630*19397407SSherry Moore 					goto err_out;
631*19397407SSherry Moore 				}
632*19397407SSherry Moore 			}
633*19397407SSherry Moore 
634*19397407SSherry Moore 			if (ehdr->e_ident[EI_CLASS] == ELFCLASS32 &&
635*19397407SSherry Moore 			    ehdr->e_ident[EI_DATA] == ELFDATA2LSB &&
636*19397407SSherry Moore 			    ehdr->e_machine == EM_386) {
637*19397407SSherry Moore 
638*19397407SSherry Moore 				if (fastboot_elf32_find_loadables((void *)va,
639*19397407SSherry Moore 				    fsize, &fb->fb_sections[0],
640*19397407SSherry Moore 				    &fb->fb_sectcnt, &dboot_start_offset) < 0) {
641*19397407SSherry Moore 					cmn_err(CE_WARN, "Fastboot: ELF32 "
642*19397407SSherry Moore 					    "program section failure");
643*19397407SSherry Moore 					goto err_out;
644*19397407SSherry Moore 				}
645*19397407SSherry Moore 
646*19397407SSherry Moore 				if (fb->fb_sectcnt == 0) {
647*19397407SSherry Moore 					cmn_err(CE_WARN, "Fastboot: No ELF32 "
648*19397407SSherry Moore 					    "program sections found");
649*19397407SSherry Moore 					goto err_out;
650*19397407SSherry Moore 				}
651*19397407SSherry Moore 
652*19397407SSherry Moore 				if (is_failsafe) {
653*19397407SSherry Moore 					/* Failsafe boot_archive */
654*19397407SSherry Moore 					bcopy(BOOTARCHIVE_FAILSAFE,
655*19397407SSherry Moore 					    &fastboot_filename
656*19397407SSherry Moore 					    [FASTBOOT_NAME_BOOTARCHIVE]
657*19397407SSherry Moore 					    [bootpath_len],
658*19397407SSherry Moore 					    sizeof (BOOTARCHIVE_FAILSAFE));
659*19397407SSherry Moore 				} else {
660*19397407SSherry Moore 					bcopy(BOOTARCHIVE32,
661*19397407SSherry Moore 					    &fastboot_filename
662*19397407SSherry Moore 					    [FASTBOOT_NAME_BOOTARCHIVE]
663*19397407SSherry Moore 					    [bootpath_len],
664*19397407SSherry Moore 					    sizeof (BOOTARCHIVE32));
665*19397407SSherry Moore 				}
666*19397407SSherry Moore 
667*19397407SSherry Moore 			} else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64 &&
668*19397407SSherry Moore 			    ehdr->e_ident[EI_DATA] == ELFDATA2LSB &&
669*19397407SSherry Moore 			    ehdr->e_machine == EM_AMD64) {
670*19397407SSherry Moore 
671*19397407SSherry Moore 				if (fastboot_elf64_find_dboot_load_offset(
672*19397407SSherry Moore 				    (void *)va, fsize, &dboot_start_offset)
673*19397407SSherry Moore 				    != 0) {
674*19397407SSherry Moore 					cmn_err(CE_WARN, "Fastboot: Couldn't "
675*19397407SSherry Moore 					    "find ELF64 dboot entry offset");
676*19397407SSherry Moore 					goto err_out;
677*19397407SSherry Moore 				}
678*19397407SSherry Moore 
679*19397407SSherry Moore 				if ((x86_feature & X86_64) == 0 ||
680*19397407SSherry Moore 				    newkernel.fi_has_pae == 0) {
681*19397407SSherry Moore 					cmn_err(CE_WARN, "Fastboot: Cannot "
682*19397407SSherry Moore 					    "reboot to %s: "
683*19397407SSherry Moore 					    "not a 64-bit capable system",
684*19397407SSherry Moore 					    kern_bootfile);
685*19397407SSherry Moore 					goto err_out;
686*19397407SSherry Moore 				}
687*19397407SSherry Moore 
688*19397407SSherry Moore 				bcopy(BOOTARCHIVE64,
689*19397407SSherry Moore 				    &fastboot_filename
690*19397407SSherry Moore 				    [FASTBOOT_NAME_BOOTARCHIVE][bootpath_len],
691*19397407SSherry Moore 				    sizeof (BOOTARCHIVE64));
692*19397407SSherry Moore 			} else {
693*19397407SSherry Moore 				cmn_err(CE_WARN, "Fastboot: Unknown ELF type");
694*19397407SSherry Moore 				goto err_out;
695*19397407SSherry Moore 			}
696*19397407SSherry Moore 
697*19397407SSherry Moore 			fb->fb_dest_pa = DBOOT_ENTRY_ADDRESS -
698*19397407SSherry Moore 			    dboot_start_offset;
699*19397407SSherry Moore 
700*19397407SSherry Moore 			fb->fb_next_pa = DBOOT_ENTRY_ADDRESS + fsize_roundup;
701*19397407SSherry Moore 		} else {
702*19397407SSherry Moore 			fb->fb_dest_pa = newkernel.fi_files[i - 1].fb_next_pa;
703*19397407SSherry Moore 			fb->fb_next_pa = fb->fb_dest_pa + fsize_roundup;
704*19397407SSherry Moore 		}
705*19397407SSherry Moore 
706*19397407SSherry Moore 		next_pa = fb->fb_next_pa;
707*19397407SSherry Moore 
708*19397407SSherry Moore 		kobj_close_file(file);
709*19397407SSherry Moore 
710*19397407SSherry Moore 		/*
711*19397407SSherry Moore 		 * Set fb_va to fake_va
712*19397407SSherry Moore 		 */
713*19397407SSherry Moore 		fb->fb_va = fake_va;
714*19397407SSherry Moore 	}
715*19397407SSherry Moore 
716*19397407SSherry Moore 
717*19397407SSherry Moore 	/*
718*19397407SSherry Moore 	 * Add the function that will switch us to 32-bit protected mode
719*19397407SSherry Moore 	 */
720*19397407SSherry Moore 	fb = &newkernel.fi_files[FASTBOOT_SWTCH];
721*19397407SSherry Moore 	fb->fb_va = fb->fb_dest_pa = FASTBOOT_SWTCH_PA;
722*19397407SSherry Moore 	fb->fb_size = PAGESIZE;
723*19397407SSherry Moore 
724*19397407SSherry Moore 	/*
725*19397407SSherry Moore 	 * Map in FASTBOOT_SWTCH_PA
726*19397407SSherry Moore 	 */
727*19397407SSherry Moore 	hat_devload(kas.a_hat, (caddr_t)fb->fb_va, MMU_PAGESIZE,
728*19397407SSherry Moore 	    mmu_btop(fb->fb_dest_pa),
729*19397407SSherry Moore 	    PROT_READ | PROT_WRITE | PROT_EXEC, HAT_LOAD_NOCONSIST);
730*19397407SSherry Moore 
731*19397407SSherry Moore 	bcopy((void *)fb_swtch_image, (void *)fb->fb_va, fb->fb_size);
732*19397407SSherry Moore 
733*19397407SSherry Moore 	/*
734*19397407SSherry Moore 	 * Build the new multiboot_info structure
735*19397407SSherry Moore 	 */
736*19397407SSherry Moore 	if (fastboot_build_mbi(mdep, &newkernel) != 0) {
737*19397407SSherry Moore 		goto err_out;
738*19397407SSherry Moore 	}
739*19397407SSherry Moore 
740*19397407SSherry Moore 	/*
741*19397407SSherry Moore 	 * Build page table for low 1G physical memory. Use big pages.
742*19397407SSherry Moore 	 * Allocate 4 pages for the page tables.
743*19397407SSherry Moore 	 *    1 page for Page-Directory-Pointer Table
744*19397407SSherry Moore 	 *    2 page for Page Directory
745*19397407SSherry Moore 	 *    1 page for Page Table.
746*19397407SSherry Moore 	 * The page table entry will be rewritten to map the physical
747*19397407SSherry Moore 	 * address as we do the copying.
748*19397407SSherry Moore 	 */
749*19397407SSherry Moore 	if (newkernel.fi_has_pae) {
750*19397407SSherry Moore 		size_t size = MMU_PAGESIZE * 4;
751*19397407SSherry Moore 
752*19397407SSherry Moore 		if ((newkernel.fi_pagetable_va = (uintptr_t)
753*19397407SSherry Moore 		    contig_alloc(size, &fastboot_below_1G_dma_attr,
754*19397407SSherry Moore 		    PAGESIZE, 0)) == NULL) {
755*19397407SSherry Moore 			cmn_err(CE_WARN, fastboot_enomem_msg,
756*19397407SSherry Moore 			    (uint64_t)size, "1G");
757*19397407SSherry Moore 			goto err_out;
758*19397407SSherry Moore 		}
759*19397407SSherry Moore 
760*19397407SSherry Moore 		bzero((void *)(newkernel.fi_pagetable_va), size);
761*19397407SSherry Moore 
762*19397407SSherry Moore 		newkernel.fi_pagetable_pa =
763*19397407SSherry Moore 		    mmu_ptob((uint64_t)hat_getpfnum(kas.a_hat,
764*19397407SSherry Moore 		    (caddr_t)newkernel.fi_pagetable_va));
765*19397407SSherry Moore 
766*19397407SSherry Moore 		newkernel.fi_last_table_pa = newkernel.fi_pagetable_pa +
767*19397407SSherry Moore 		    MMU_PAGESIZE * 3;
768*19397407SSherry Moore 
769*19397407SSherry Moore 		newkernel.fi_next_table_va = newkernel.fi_pagetable_va +
770*19397407SSherry Moore 		    MMU_PAGESIZE;
771*19397407SSherry Moore 		newkernel.fi_next_table_pa = newkernel.fi_pagetable_pa +
772*19397407SSherry Moore 		    MMU_PAGESIZE;
773*19397407SSherry Moore 
774*19397407SSherry Moore 		fastboot_build_pagetables(&newkernel);
775*19397407SSherry Moore 	}
776*19397407SSherry Moore 
777*19397407SSherry Moore 
778*19397407SSherry Moore 	/* Mark it as valid */
779*19397407SSherry Moore 	newkernel.fi_valid = 1;
780*19397407SSherry Moore 	newkernel.fi_magic = FASTBOOT_MAGIC;
781*19397407SSherry Moore 
782*19397407SSherry Moore 	return;
783*19397407SSherry Moore 
784*19397407SSherry Moore err_out:
785*19397407SSherry Moore 	/* XXX Do we need to free up the memory we allocated? */
786*19397407SSherry Moore 
787*19397407SSherry Moore 	newkernel.fi_valid = 0;
788*19397407SSherry Moore }
789*19397407SSherry Moore 
790*19397407SSherry Moore 
791*19397407SSherry Moore void
792*19397407SSherry Moore fast_reboot()
793*19397407SSherry Moore {
794*19397407SSherry Moore 	void (*fastboot_func)(fastboot_info_t *);
795*19397407SSherry Moore 
796*19397407SSherry Moore 	fastboot_func = (void (*)())(newkernel.fi_files[FASTBOOT_SWTCH].fb_va);
797*19397407SSherry Moore 	(*fastboot_func)(&newkernel);
798*19397407SSherry Moore }
799