4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/param.h>
27 #include <sys/promif.h>
28 #include <sys/salib.h>
31 #include <sys/param.h>
32 #include <sys/fcntl.h>
33 #include <sys/obpdefs.h>
34 #include <sys/reboot.h>
35 #include <sys/promif.h>
37 #include <sys/bootvfs.h>
38 #include <sys/platnames.h>
39 #include <sys/salib.h>
43 #include <sys/boot_policy.h>
44 #include <sys/boot_redirect.h>
45 #include <sys/bootconf.h>
47 #include "boot_plat.h"
50 static char ramdisk_preamble_fth
[] =
52 ": find-abort ( name$ -- ) "
53 " .\" Can't find \" type abort "
56 ": get-package ( pkg$ -- ph ) "
57 " 2dup find-package 0= if "
63 "\" /openprom/client-services\" get-package constant cif-ph "
65 "instance defer cif-open ( dev$ -- ihandle|0 ) "
66 "instance defer cif-close ( ihandle -- ) "
68 ": find-cif-method ( adr,len -- acf ) "
69 " 2dup cif-ph find-method 0= if ( adr,len ) "
71 " then ( adr,len acf ) "
75 "\" open\" find-cif-method to cif-open "
76 "\" close\" find-cif-method to cif-close "
80 "d# 100 buffer: open-cstr "
82 ": dev-open ( dev$ -- okay? ) "
83 /* copy to C string for open */
84 " 0 over open-cstr + c! "
85 " open-cstr swap move "
86 " open-cstr cif-open dup if "
96 ": open-abort ( file$ -- ) "
97 " .\" Can't open \" type abort "
101 static char ramdisk_fth
[] =
103 "\" /\" get-package push-package "
106 " \" %s\" device-name "
108 " \" block\" device-type "
109 " \" SUNW,ramdisk\" encode-string \" compatible\" property"
111 " 0 instance value current-offset "
113 " 0 value ramdisk-base-va "
114 " 0 value ramdisk-size "
115 " 0 value alloc-size "
118 " ramdisk-size encode-int \" size\" property "
119 " ramdisk-base-va encode-int \" address\" property "
120 " alloc-size encode-int \" alloc-size\" property "
124 " : current-va ( -- adr ) ramdisk-base-va current-offset + ; "
128 " : open ( -- okay? ) "
129 /* " .\" ramdisk-open\" cr " */
136 " : seek ( off.low off.high -- error? ) "
137 /* " 2dup .\" ramdisk-seek: \" .x .x " */
138 " drop dup ramdisk-size > if "
139 /* " .\" fail\" cr " */
140 " drop true exit ( failed ) "
142 " to current-offset false ( succeeded ) "
143 /* " .\" OK\" cr " */
146 " : read ( addr len -- actual-len ) "
147 /* " 2dup .\" ramdisk-read: \" .x .x " */
148 " dup current-offset + ( addr len new-off ) "
149 " dup ramdisk-size > if "
150 " ramdisk-size - - ( addr len' ) "
151 " ramdisk-size ( addr len new-off ) "
152 " then -rot ( new-off addr len ) "
153 " tuck current-va -rot move ( new-off len ) "
154 " swap to current-offset ( len ) "
158 " : create ( alloc-sz base size -- ) "
160 " to ramdisk-base-va "
168 "\" /%s\" 2dup dev-open 0= if "
172 /* %x %x %x will be replaced by alloc-sz, base, size respectively */
173 "h# %x h# %x h# %x ( alloc-sz base size ) "
174 "\" create\" dev-ih $call-method ( ) "
179 char ramdisk_bootable
[] =
181 "\" /chosen\" get-package push-package "
182 " \" nfs\" encode-string \" fstype\" property "
183 " \" /%s\" encode-string \" bootarchive\" property "
186 " h# %x d# 512 + to load-base init-program "
189 #define BOOT_ARCHIVE_ALLOC_SIZE (32 * 1024 * 1024) /* 32 MB */
190 #define BOOTFS_VIRT ((caddr_t)0x50f00000)
191 #define ROOTFS_VIRT ((caddr_t)0x52000000)
193 struct ramdisk_attr
{
198 RD_BOOTFS
, BOOTFS_VIRT
, 0,
199 RD_ROOTFS
, ROOTFS_VIRT
, 0,
203 static struct ramdisk_attr
*
204 ramdisk_lookup(char *ramdisk_name
)
208 for (i
= 0; ramdisk_attr
[i
].rd_name
!= 0; i
++) {
209 if (strcmp(ramdisk_name
, ramdisk_attr
[i
].rd_name
) == 0) {
210 return (&ramdisk_attr
[i
]);
217 ramdisk_free_mem(caddr_t addr
, size_t size
)
221 for (end_addr
= addr
+ size
; addr
< end_addr
;
222 addr
+= BOOT_ARCHIVE_ALLOC_SIZE
) {
223 prom_free(addr
, MIN(BOOT_ARCHIVE_ALLOC_SIZE
, end_addr
- addr
));
228 * Allocate memory for ramdisk image.
231 ramdisk_alloc_mem(caddr_t addr
, size_t size
)
236 for (end_addr
= virt
+ size
; virt
< end_addr
;
237 virt
+= BOOT_ARCHIVE_ALLOC_SIZE
) {
239 MIN(BOOT_ARCHIVE_ALLOC_SIZE
, end_addr
- virt
),
241 ramdisk_free_mem(addr
, virt
- addr
);
249 create_ramdisk(char *ramdisk_name
, size_t size
, char **devpath
)
253 struct ramdisk_attr
*rdp
;
256 static int need_preamble
= 1;
259 * lookup ramdisk name.
261 if ((rdp
= ramdisk_lookup(ramdisk_name
)) == NULL
)
262 prom_panic("invalid ramdisk name");
269 size
= roundup(size
, PAGESIZE
);
270 if (ramdisk_alloc_mem(virt
, size
) == NULL
)
271 prom_panic("can't alloc ramdisk memory");
276 prom_interpret(ramdisk_preamble_fth
, 0, 0, 0, 0, 0);
281 * add some space to the size to accommodate a few words in the
284 buf_size
= sizeof (ramdisk_fth
) + 80;
286 fth_buf
= bkmem_alloc(buf_size
);
288 prom_panic("unable to allocate Forth buffer for ramdisk");
290 (void) snprintf(fth_buf
, buf_size
, ramdisk_fth
,
291 ramdisk_name
, ramdisk_name
,
292 BOOT_ARCHIVE_ALLOC_SIZE
, virt
, size
);
294 prom_interpret(fth_buf
, 0, 0, 0, 0, 0);
295 bkmem_free(fth_buf
, buf_size
);
297 if (devpath
!= NULL
) {
298 (void) snprintf(tdevpath
, sizeof (tdevpath
), "/%s:nolabel",
300 *devpath
= strdup(tdevpath
);
307 destroy_ramdisk(char *ramdisk_name
)
309 struct ramdisk_attr
*rdp
;
312 * lookup ramdisk name.
314 if ((rdp
= ramdisk_lookup(ramdisk_name
)) == NULL
)
315 prom_panic("invalid ramdisk name");
317 ramdisk_free_mem(rdp
->rd_base
, rdp
->rd_size
);
322 * change cwp! to drop in the 2nd word of (init-program) - really
323 * init-c-stack, but that word has no header.
324 * (you are not expected to undertsnad this)
326 char obpfix
[] = "' drop ' cwp! ' (init-program) >body ta1+ token@ (patch";
327 char obpver
[OBP_MAXPROPNAME
];
328 const char badver
[] = "OBP 4.27.";
332 boot_ramdisk(char *ramdisk_name
)
336 struct ramdisk_attr
*rdp
;
340 * OBP revs 4.27.0 to 4.27.8 started using
341 * windowed regs for the forth kernel, but
342 * init-program still blindly 0'd %cwp, which
343 * causes predictably disaterous consequences
344 * when called with %cwp != 0.
346 * We detect and fix this here
348 if (prom_version_name(obpver
, OBP_MAXPROPNAME
) != -1 &&
349 strncmp(obpver
, badver
, sizeof (badver
) - 1) == 0) {
350 char ch
= obpver
[sizeof (badver
) - 1];
352 if (ch
>= '0' && ch
<= '8') {
353 prom_interpret(obpfix
, 0, 0, 0, 0, 0);
357 /* close all open devices */
361 * lookup ramdisk name.
363 if ((rdp
= ramdisk_lookup(ramdisk_name
)) == NULL
)
364 prom_panic("invalid ramdisk name");
367 * add some space to the size to accommodate a few words in the
370 buf_size
= sizeof (ramdisk_bootable
) + 80;
372 fth_buf
= bkmem_alloc(buf_size
);
374 prom_panic("unable to allocate Forth buffer for ramdisk");
376 (void) snprintf(fth_buf
, buf_size
, ramdisk_bootable
,
377 ramdisk_name
, rdp
->rd_base
);
379 prom_interpret(fth_buf
, 0, 0, 0, 0, 0);
382 * Ugh Serengeti proms don't execute C programs
383 * in init-program, and 'go' doesn't work when
384 * launching a second C program (inetboot itself
385 * was launched as the 1st C program). Nested fcode
386 * programs work, but that doesn't help the kernel.
394 pnode_t chosen
= prom_chosennode();
399 extern caddr_t sg_addr
;
400 extern size_t sg_len
;
403 prom_panic("do_sg_go");
406 * The ramdisk bootblk left a pointer to the elf image
407 * in 'elfheader-address' Use it to find the kernel's
410 if (prom_getprop(chosen
, "elfheader-address", (caddr_t
)&eadr
) == -1)
411 prom_panic("no elf header property");
412 ehdr
= (Elf64_Ehdr
*)(uintptr_t)eadr
;
413 if (ehdr
->e_machine
!= EM_SPARCV9
)
414 prom_panic("bad ELF header");
415 entry
= ehdr
->e_entry
;
420 prom_free(sg_addr
, sg_len
);
423 * Use pre-newboot's exitto64() to launch the kernel
425 exitto64((int (*)())entry
, NULL
);
426 prom_panic("exitto returned");