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