xref: /titanic_44/usr/src/psm/stand/boot/sparc/common/ramdisk.c (revision 694c35faa87b858ecdadfe4fc592615f4eefbb07)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5986fd29aSsetje  * Common Development and Distribution License (the "License").
6986fd29aSsetje  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*c8551b44SJerry Gilliam  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/param.h>
277c478bd9Sstevel@tonic-gate #include <sys/promif.h>
287c478bd9Sstevel@tonic-gate #include <sys/salib.h>
297c478bd9Sstevel@tonic-gate #include <bootlog.h>
307c478bd9Sstevel@tonic-gate #include "ramdisk.h"
317c478bd9Sstevel@tonic-gate 
32986fd29aSsetje #include <sys/param.h>
33986fd29aSsetje #include <sys/fcntl.h>
34986fd29aSsetje #include <sys/obpdefs.h>
35986fd29aSsetje #include <sys/reboot.h>
36986fd29aSsetje #include <sys/promif.h>
37986fd29aSsetje #include <sys/stat.h>
38986fd29aSsetje #include <sys/bootvfs.h>
39986fd29aSsetje #include <sys/platnames.h>
40986fd29aSsetje #include <sys/salib.h>
41986fd29aSsetje #include <sys/elf.h>
42986fd29aSsetje #include <sys/link.h>
43986fd29aSsetje #include <sys/auxv.h>
44986fd29aSsetje #include <sys/boot_policy.h>
45986fd29aSsetje #include <sys/boot_redirect.h>
46986fd29aSsetje #include <sys/bootconf.h>
47986fd29aSsetje #include <sys/boot.h>
48986fd29aSsetje #include "boot_plat.h"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 
51986fd29aSsetje static char ramdisk_preamble_fth[] =
52986fd29aSsetje 
53986fd29aSsetje ": find-abort ( name$ -- ) "
54986fd29aSsetje "   .\" Can't find \" type abort "
55986fd29aSsetje "; "
56986fd29aSsetje 
57986fd29aSsetje ": get-package ( pkg$ -- ph ) "
58986fd29aSsetje "   2dup  find-package 0=  if "
59986fd29aSsetje "      find-abort "
60986fd29aSsetje "   then                       ( pkg$ ph ) "
61986fd29aSsetje "   nip nip                    ( ph ) "
62986fd29aSsetje "; "
63986fd29aSsetje 
64986fd29aSsetje "\" /openprom/client-services\" get-package  constant cif-ph "
65986fd29aSsetje 
66986fd29aSsetje "instance defer cif-open     ( dev$ -- ihandle|0 ) "
67986fd29aSsetje "instance defer cif-close    ( ihandle -- ) "
68986fd29aSsetje 
69986fd29aSsetje ": find-cif-method ( adr,len -- acf ) "
70986fd29aSsetje "   2dup  cif-ph find-method 0=  if    ( adr,len ) "
71986fd29aSsetje "      find-abort "
72986fd29aSsetje "   then                               ( adr,len acf ) "
73986fd29aSsetje "   nip nip                            ( acf ) "
74986fd29aSsetje "; "
75986fd29aSsetje 
76986fd29aSsetje "\" open\"     find-cif-method to cif-open "
77986fd29aSsetje "\" close\"    find-cif-method to cif-close "
78986fd29aSsetje 
79986fd29aSsetje "0 value dev-ih "
80986fd29aSsetje 
81986fd29aSsetje "d# 100 buffer: open-cstr "
82986fd29aSsetje 
83986fd29aSsetje ": dev-open ( dev$ -- okay? ) "
84986fd29aSsetje /* copy to C string for open  */
85986fd29aSsetje "   0  over open-cstr +  c! "
86986fd29aSsetje "   open-cstr swap  move "
87986fd29aSsetje "   open-cstr  cif-open dup  if "
88986fd29aSsetje "      dup to dev-ih "
89986fd29aSsetje "   then "
90986fd29aSsetje "; "
91986fd29aSsetje 
92986fd29aSsetje ": dev-close ( -- ) "
93986fd29aSsetje "   dev-ih cif-close "
94986fd29aSsetje "   0 to dev-ih "
95986fd29aSsetje "; "
96986fd29aSsetje 
97986fd29aSsetje ": open-abort  ( file$ -- ) "
98986fd29aSsetje "   .\" Can't open \"  type  abort "
99986fd29aSsetje "; "
100986fd29aSsetje ;
101986fd29aSsetje 
102986fd29aSsetje static char ramdisk_fth[] =
103986fd29aSsetje 
104986fd29aSsetje "\" /\" get-package  push-package "
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate "new-device "
1077c478bd9Sstevel@tonic-gate "   \" %s\" device-name "
108986fd29aSsetje "    "
109986fd29aSsetje "   \" block\"          device-type "
1107c478bd9Sstevel@tonic-gate "   \" SUNW,ramdisk\"	encode-string \" compatible\"  property"
1117c478bd9Sstevel@tonic-gate 
112986fd29aSsetje "   0 instance value current-offset "
113986fd29aSsetje "    "
114986fd29aSsetje "   0 value ramdisk-base-va "
115986fd29aSsetje "   0 value ramdisk-size "
116986fd29aSsetje "   0 value alloc-size "
117986fd29aSsetje "    "
118986fd29aSsetje "   : set-props "
119986fd29aSsetje "      ramdisk-size     encode-int  \" size\"        property "
120986fd29aSsetje "      ramdisk-base-va  encode-int  \" address\"     property "
121986fd29aSsetje "      alloc-size       encode-int  \" alloc-size\"  property "
1227c478bd9Sstevel@tonic-gate "   ; "
123986fd29aSsetje "   set-props "
124986fd29aSsetje "    "
125986fd29aSsetje "   : current-va  ( -- adr )  ramdisk-base-va current-offset +  ; "
126986fd29aSsetje "    "
1277c478bd9Sstevel@tonic-gate "   external "
128986fd29aSsetje "    "
129986fd29aSsetje "   : open  ( -- okay? ) "
130986fd29aSsetje /* " .\" ramdisk-open\" cr " */
131986fd29aSsetje "      true "
1327c478bd9Sstevel@tonic-gate "   ; "
133986fd29aSsetje "    "
134986fd29aSsetje "   : close  ( -- ) "
1357c478bd9Sstevel@tonic-gate "   ; "
136986fd29aSsetje "    "
137986fd29aSsetje "   : seek  ( off.low off.high -- error? ) "
138986fd29aSsetje /* " 2dup .\" ramdisk-seek: \" .x .x " */
139986fd29aSsetje "      drop  dup  ramdisk-size  >  if "
140986fd29aSsetje /* " .\" fail\" cr " */
141986fd29aSsetje "         drop true  exit         ( failed ) "
1427c478bd9Sstevel@tonic-gate "      then "
143986fd29aSsetje "      to current-offset  false   ( succeeded ) "
144986fd29aSsetje /* " .\" OK\" cr " */
1457c478bd9Sstevel@tonic-gate "   ; "
146986fd29aSsetje "    "
147986fd29aSsetje "   : read  ( addr len -- actual-len ) "
148986fd29aSsetje /* " 2dup .\" ramdisk-read: \" .x .x " */
149986fd29aSsetje "      dup  current-offset  +            ( addr len new-off ) "
150986fd29aSsetje "      dup  ramdisk-size  >  if "
151986fd29aSsetje "         ramdisk-size -  -              ( addr len' ) "
152986fd29aSsetje "         ramdisk-size                   ( addr len new-off ) "
153986fd29aSsetje "      then  -rot                        ( new-off addr len ) "
154986fd29aSsetje "      tuck  current-va  -rot  move      ( new-off len ) "
155986fd29aSsetje "      swap  to current-offset           ( len ) "
156986fd29aSsetje /* " dup .x cr " */
1577c478bd9Sstevel@tonic-gate "   ; "
158986fd29aSsetje "    "
159986fd29aSsetje "   : create ( alloc-sz base size -- ) "
160986fd29aSsetje "      to ramdisk-size "
161986fd29aSsetje "      to ramdisk-base-va "
162986fd29aSsetje "      to alloc-size "
163986fd29aSsetje "      set-props "
164986fd29aSsetje "   ; "
165986fd29aSsetje "    "
1667c478bd9Sstevel@tonic-gate "finish-device "
1677c478bd9Sstevel@tonic-gate "pop-package "
1687c478bd9Sstevel@tonic-gate 
169986fd29aSsetje "\" /%s\" 2dup  dev-open  0=  if "
170986fd29aSsetje "   open-abort "
171986fd29aSsetje "then 2drop "
1727c478bd9Sstevel@tonic-gate 
173986fd29aSsetje /* %x %x %x will be replaced by alloc-sz, base, size respectively */
174986fd29aSsetje "h# %x h# %x h# %x ( alloc-sz base size ) "
175986fd29aSsetje "\" create\" dev-ih  $call-method  (  ) "
176986fd29aSsetje "dev-close "
177986fd29aSsetje 
178986fd29aSsetje ;
179986fd29aSsetje 
180986fd29aSsetje char ramdisk_bootable[] =
181986fd29aSsetje 
182986fd29aSsetje "\" /chosen\" get-package  push-package "
183986fd29aSsetje "   \" nfs\"             encode-string  \" fstype\"  property "
184986fd29aSsetje "   \" /%s\"	  	 encode-string  \" bootarchive\"  property "
185986fd29aSsetje "pop-package "
186986fd29aSsetje 
187986fd29aSsetje "   h# %x d# 512 +  to load-base init-program "
188986fd29aSsetje ;
189986fd29aSsetje 
190986fd29aSsetje #define	BOOT_ARCHIVE_ALLOC_SIZE	(32 * 1024 * 1024)	/* 32 MB */
191986fd29aSsetje #define	BOOTFS_VIRT		((caddr_t)0x50f00000)
192*c8551b44SJerry Gilliam #define	ROOTFS_VIRT		((caddr_t)0x52000000)
193986fd29aSsetje 
194986fd29aSsetje struct ramdisk_attr {
195986fd29aSsetje 	char *rd_name;
196986fd29aSsetje 	caddr_t rd_base;
197986fd29aSsetje 	size_t rd_size;
198986fd29aSsetje } ramdisk_attr[] = {
199986fd29aSsetje 	RD_BOOTFS,	BOOTFS_VIRT,	0,
200986fd29aSsetje 	RD_ROOTFS,	ROOTFS_VIRT,	0,
201986fd29aSsetje 	0
202986fd29aSsetje };
203986fd29aSsetje 
204986fd29aSsetje static struct ramdisk_attr *
ramdisk_lookup(char * ramdisk_name)205986fd29aSsetje ramdisk_lookup(char *ramdisk_name)
206986fd29aSsetje {
207986fd29aSsetje 	int i;
208986fd29aSsetje 
209986fd29aSsetje 	for (i = 0; ramdisk_attr[i].rd_name != 0; i++) {
210986fd29aSsetje 		if (strcmp(ramdisk_name, ramdisk_attr[i].rd_name) == 0) {
211986fd29aSsetje 			return (&ramdisk_attr[i]);
212986fd29aSsetje 		}
213986fd29aSsetje 	}
214986fd29aSsetje 	return (NULL);
215986fd29aSsetje }
216986fd29aSsetje 
217986fd29aSsetje static void
ramdisk_free_mem(caddr_t addr,size_t size)218986fd29aSsetje ramdisk_free_mem(caddr_t addr, size_t size)
219986fd29aSsetje {
220986fd29aSsetje 	caddr_t	end_addr;
221986fd29aSsetje 
222986fd29aSsetje 	for (end_addr = addr + size; addr < end_addr;
223986fd29aSsetje 	    addr += BOOT_ARCHIVE_ALLOC_SIZE) {
224986fd29aSsetje 		prom_free(addr, MIN(BOOT_ARCHIVE_ALLOC_SIZE, end_addr - addr));
225986fd29aSsetje 	}
226986fd29aSsetje }
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate /*
229986fd29aSsetje  * Allocate memory for ramdisk image.
2307c478bd9Sstevel@tonic-gate  */
231986fd29aSsetje static caddr_t
ramdisk_alloc_mem(caddr_t addr,size_t size)232986fd29aSsetje ramdisk_alloc_mem(caddr_t addr, size_t size)
233986fd29aSsetje {
234986fd29aSsetje 	caddr_t virt = addr;
235986fd29aSsetje 	caddr_t	end_addr;
236986fd29aSsetje 
237986fd29aSsetje 	for (end_addr = virt + size; virt < end_addr;
238986fd29aSsetje 	    virt += BOOT_ARCHIVE_ALLOC_SIZE) {
239986fd29aSsetje 		if (prom_alloc(virt,
240986fd29aSsetje 		    MIN(BOOT_ARCHIVE_ALLOC_SIZE, end_addr - virt),
241986fd29aSsetje 		    1) == NULL) {
242986fd29aSsetje 			ramdisk_free_mem(addr, virt - addr);
243986fd29aSsetje 			return (NULL);
244986fd29aSsetje 		}
245986fd29aSsetje 	}
246986fd29aSsetje 	return (addr);
247986fd29aSsetje }
248986fd29aSsetje 
249986fd29aSsetje caddr_t
create_ramdisk(char * ramdisk_name,size_t size,char ** devpath)250986fd29aSsetje create_ramdisk(char *ramdisk_name, size_t size, char **devpath)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 	char	*fth_buf;
2537c478bd9Sstevel@tonic-gate 	size_t	buf_size;
254986fd29aSsetje 	struct ramdisk_attr *rdp;
255986fd29aSsetje 	char tdevpath[80];
256986fd29aSsetje 	caddr_t virt;
257986fd29aSsetje 	static int need_preamble = 1;
2587c478bd9Sstevel@tonic-gate 
259986fd29aSsetje 	/*
260986fd29aSsetje 	 * lookup ramdisk name.
261986fd29aSsetje 	 */
262986fd29aSsetje 	if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL)
263986fd29aSsetje 		prom_panic("invalid ramdisk name");
2647c478bd9Sstevel@tonic-gate 
265986fd29aSsetje 	virt = rdp->rd_base;
266986fd29aSsetje 
267986fd29aSsetje 	/*
268986fd29aSsetje 	 * Allocate memory.
269986fd29aSsetje 	 */
270986fd29aSsetje 	size = roundup(size, PAGESIZE);
271986fd29aSsetje 	if (ramdisk_alloc_mem(virt, size) == NULL)
272986fd29aSsetje 		prom_panic("can't alloc ramdisk memory");
273986fd29aSsetje 
274986fd29aSsetje 	rdp->rd_size = size;
275986fd29aSsetje 
276986fd29aSsetje 	if (need_preamble) {
277986fd29aSsetje 		prom_interpret(ramdisk_preamble_fth, 0, 0, 0, 0, 0);
278986fd29aSsetje 		need_preamble = 0;
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 
281986fd29aSsetje 	/*
282986fd29aSsetje 	 * add some space to the size to accommodate a few words in the
283986fd29aSsetje 	 * snprintf() below.
284986fd29aSsetje 	 */
285986fd29aSsetje 	buf_size = sizeof (ramdisk_fth) + 80;
286986fd29aSsetje 
287986fd29aSsetje 	fth_buf = bkmem_alloc(buf_size);
288986fd29aSsetje 	if (fth_buf == NULL)
289986fd29aSsetje 		prom_panic("unable to allocate Forth buffer for ramdisk");
290986fd29aSsetje 
291986fd29aSsetje 	(void) snprintf(fth_buf, buf_size, ramdisk_fth,
292986fd29aSsetje 	    ramdisk_name, ramdisk_name,
293986fd29aSsetje 	    BOOT_ARCHIVE_ALLOC_SIZE, virt, size);
294986fd29aSsetje 
295986fd29aSsetje 	prom_interpret(fth_buf, 0, 0, 0, 0, 0);
296986fd29aSsetje 	bkmem_free(fth_buf, buf_size);
297986fd29aSsetje 
298986fd29aSsetje 	if (devpath != NULL) {
299986fd29aSsetje 		(void) snprintf(tdevpath, sizeof (tdevpath), "/%s:nolabel",
300986fd29aSsetje 		    ramdisk_name);
301986fd29aSsetje 		*devpath = strdup(tdevpath);
302986fd29aSsetje 	}
303986fd29aSsetje 
304986fd29aSsetje 	return (virt);
305986fd29aSsetje }
306986fd29aSsetje 
307986fd29aSsetje void
destroy_ramdisk(char * ramdisk_name)308986fd29aSsetje destroy_ramdisk(char *ramdisk_name)
309986fd29aSsetje {
310986fd29aSsetje 	struct ramdisk_attr *rdp;
311986fd29aSsetje 
312986fd29aSsetje 	/*
313986fd29aSsetje 	 * lookup ramdisk name.
314986fd29aSsetje 	 */
315986fd29aSsetje 	if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL)
316986fd29aSsetje 		prom_panic("invalid ramdisk name");
317986fd29aSsetje 
318986fd29aSsetje 	ramdisk_free_mem(rdp->rd_base, rdp->rd_size);
319986fd29aSsetje 	rdp->rd_size = 0;
320986fd29aSsetje }
321986fd29aSsetje 
322986fd29aSsetje /*
323986fd29aSsetje  * change cwp! to drop in the 2nd word of (init-program) - really
324986fd29aSsetje  * init-c-stack, but that word has no header.
325986fd29aSsetje  * (you are not expected to undertsnad this)
326986fd29aSsetje  */
327986fd29aSsetje char obpfix[] = "' drop ' cwp!  ' (init-program) >body ta1+ token@ (patch";
328986fd29aSsetje char obpver[OBP_MAXPROPNAME];
329986fd29aSsetje const char badver[] = "OBP 4.27.";
330986fd29aSsetje 
331986fd29aSsetje 
332986fd29aSsetje void
boot_ramdisk(char * ramdisk_name)333986fd29aSsetje boot_ramdisk(char *ramdisk_name)
334986fd29aSsetje {
335986fd29aSsetje 	char	*fth_buf;
336986fd29aSsetje 	size_t	buf_size;
337986fd29aSsetje 	struct ramdisk_attr *rdp;
338986fd29aSsetje 	void do_sg_go(void);
339986fd29aSsetje 
340986fd29aSsetje 	/*
341986fd29aSsetje 	 * OBP revs 4.27.0 to 4.27.8 started using
342986fd29aSsetje 	 * windowed regs for the forth kernel, but
343986fd29aSsetje 	 * init-program still blindly 0'd %cwp, which
344986fd29aSsetje 	 * causes predictably disaterous consequences
345986fd29aSsetje 	 * when called with %cwp != 0.
346986fd29aSsetje 	 *
347986fd29aSsetje 	 * We detect and fix this here
348986fd29aSsetje 	 */
349986fd29aSsetje 	if (prom_version_name(obpver, OBP_MAXPROPNAME) != -1 &&
350986fd29aSsetje 	    strncmp(obpver, badver, sizeof (badver) - 1) == 0) {
351986fd29aSsetje 		char ch = obpver[sizeof (badver) - 1];
352986fd29aSsetje 
353986fd29aSsetje 		if (ch >= '0' && ch <= '8') {
354986fd29aSsetje 			prom_interpret(obpfix, 0, 0, 0, 0, 0);
355986fd29aSsetje 		}
356986fd29aSsetje 	}
357986fd29aSsetje 
358986fd29aSsetje 	/* close all open devices */
359986fd29aSsetje 	closeall(1);
360986fd29aSsetje 
361986fd29aSsetje 	/*
362986fd29aSsetje 	 * lookup ramdisk name.
363986fd29aSsetje 	 */
364986fd29aSsetje 	if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL)
365986fd29aSsetje 		prom_panic("invalid ramdisk name");
366986fd29aSsetje 
367986fd29aSsetje 	/*
368986fd29aSsetje 	 * add some space to the size to accommodate a few words in the
369986fd29aSsetje 	 * snprintf() below.
370986fd29aSsetje 	 */
371986fd29aSsetje 	buf_size = sizeof (ramdisk_bootable) + 80;
372986fd29aSsetje 
373986fd29aSsetje 	fth_buf = bkmem_alloc(buf_size);
374986fd29aSsetje 	if (fth_buf == NULL)
375986fd29aSsetje 		prom_panic("unable to allocate Forth buffer for ramdisk");
376986fd29aSsetje 
377986fd29aSsetje 	(void) snprintf(fth_buf, buf_size, ramdisk_bootable,
378986fd29aSsetje 	    ramdisk_name, rdp->rd_base);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	prom_interpret(fth_buf, 0, 0, 0, 0, 0);
3817c478bd9Sstevel@tonic-gate 
382986fd29aSsetje 	/*
383986fd29aSsetje 	 * Ugh  Serengeti proms don't execute C programs
384986fd29aSsetje 	 * in init-program, and 'go' doesn't work when
385986fd29aSsetje 	 * launching a second C program (inetboot itself
386986fd29aSsetje 	 * was launched as the 1st C program).  Nested fcode
387986fd29aSsetje 	 * programs work, but that doesn't help the kernel.
388986fd29aSsetje 	 */
389986fd29aSsetje 	do_sg_go();
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
392986fd29aSsetje void
do_sg_go()393986fd29aSsetje do_sg_go()
3947c478bd9Sstevel@tonic-gate {
395986fd29aSsetje 	pnode_t chosen = prom_chosennode();
396986fd29aSsetje 	Elf64_Ehdr *ehdr;
397986fd29aSsetje 	Elf64_Addr entry;
398986fd29aSsetje 	uint32_t eadr;
399986fd29aSsetje 	extern int is_sg;
400986fd29aSsetje 	extern caddr_t sg_addr;
401986fd29aSsetje 	extern size_t sg_len;
402986fd29aSsetje 
403986fd29aSsetje 	if (!is_sg)
404986fd29aSsetje 		prom_panic("do_sg_go");
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	/*
407986fd29aSsetje 	 * The ramdisk bootblk left a pointer to the elf image
408986fd29aSsetje 	 * in 'elfheader-address'  Use it to find the kernel's
409986fd29aSsetje 	 * entry point.
4107c478bd9Sstevel@tonic-gate 	 */
411986fd29aSsetje 	if (prom_getprop(chosen, "elfheader-address", (caddr_t)&eadr) == -1)
412986fd29aSsetje 		prom_panic("no elf header property");
413986fd29aSsetje 	ehdr = (Elf64_Ehdr *)(uintptr_t)eadr;
414986fd29aSsetje 	if (ehdr->e_machine != EM_SPARCV9)
415986fd29aSsetje 		prom_panic("bad ELF header");
416986fd29aSsetje 	entry = ehdr->e_entry;
4177c478bd9Sstevel@tonic-gate 
418986fd29aSsetje 	/*
419986fd29aSsetje 	 * free extra bootmem
420986fd29aSsetje 	 */
421986fd29aSsetje 	prom_free(sg_addr, sg_len);
4227c478bd9Sstevel@tonic-gate 
423986fd29aSsetje 	/*
424986fd29aSsetje 	 * Use pre-newboot's exitto64() to launch the kernel
425986fd29aSsetje 	 */
426986fd29aSsetje 	exitto64((int (*)())entry, NULL);
427986fd29aSsetje 	prom_panic("exitto returned");
4287c478bd9Sstevel@tonic-gate }
429