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 "ramdisk.h"
307c478bd9Sstevel@tonic-gate
31986fd29aSsetje #include <sys/param.h>
32986fd29aSsetje #include <sys/fcntl.h>
33986fd29aSsetje #include <sys/obpdefs.h>
34986fd29aSsetje #include <sys/reboot.h>
35986fd29aSsetje #include <sys/promif.h>
36986fd29aSsetje #include <sys/stat.h>
37986fd29aSsetje #include <sys/bootvfs.h>
38986fd29aSsetje #include <sys/platnames.h>
39986fd29aSsetje #include <sys/salib.h>
40986fd29aSsetje #include <sys/elf.h>
41986fd29aSsetje #include <sys/link.h>
42986fd29aSsetje #include <sys/auxv.h>
43986fd29aSsetje #include <sys/boot_policy.h>
44986fd29aSsetje #include <sys/boot_redirect.h>
45986fd29aSsetje #include <sys/bootconf.h>
46986fd29aSsetje #include <sys/boot.h>
47986fd29aSsetje #include "boot_plat.h"
48986fd29aSsetje
49986fd29aSsetje
50986fd29aSsetje static char ramdisk_preamble_fth[] =
51986fd29aSsetje
52986fd29aSsetje ": find-abort ( name$ -- ) "
53986fd29aSsetje " .\" Can't find \" type abort "
54986fd29aSsetje "; "
55986fd29aSsetje
56986fd29aSsetje ": get-package ( pkg$ -- ph ) "
57986fd29aSsetje " 2dup find-package 0= if "
58986fd29aSsetje " find-abort "
59986fd29aSsetje " then ( pkg$ ph ) "
60986fd29aSsetje " nip nip ( ph ) "
61986fd29aSsetje "; "
62986fd29aSsetje
63986fd29aSsetje "\" /openprom/client-services\" get-package constant cif-ph "
64986fd29aSsetje
65986fd29aSsetje "instance defer cif-open ( dev$ -- ihandle|0 ) "
66986fd29aSsetje "instance defer cif-close ( ihandle -- ) "
67986fd29aSsetje
68986fd29aSsetje ": find-cif-method ( adr,len -- acf ) "
69986fd29aSsetje " 2dup cif-ph find-method 0= if ( adr,len ) "
70986fd29aSsetje " find-abort "
71986fd29aSsetje " then ( adr,len acf ) "
72986fd29aSsetje " nip nip ( acf ) "
73986fd29aSsetje "; "
74986fd29aSsetje
75986fd29aSsetje "\" open\" find-cif-method to cif-open "
76986fd29aSsetje "\" close\" find-cif-method to cif-close "
77986fd29aSsetje
78986fd29aSsetje "0 value dev-ih "
79986fd29aSsetje
80986fd29aSsetje "d# 100 buffer: open-cstr "
81986fd29aSsetje
82986fd29aSsetje ": dev-open ( dev$ -- okay? ) "
83986fd29aSsetje /* copy to C string for open */
84986fd29aSsetje " 0 over open-cstr + c! "
85986fd29aSsetje " open-cstr swap move "
86986fd29aSsetje " open-cstr cif-open dup if "
87986fd29aSsetje " dup to dev-ih "
88986fd29aSsetje " then "
89986fd29aSsetje "; "
90986fd29aSsetje
91986fd29aSsetje ": dev-close ( -- ) "
92986fd29aSsetje " dev-ih cif-close "
93986fd29aSsetje " 0 to dev-ih "
94986fd29aSsetje "; "
95986fd29aSsetje
96986fd29aSsetje ": open-abort ( file$ -- ) "
97986fd29aSsetje " .\" Can't open \" type abort "
98986fd29aSsetje "; "
99986fd29aSsetje ;
100986fd29aSsetje
101986fd29aSsetje static char ramdisk_fth[] =
102986fd29aSsetje
103986fd29aSsetje "\" /\" get-package push-package "
104986fd29aSsetje
105986fd29aSsetje "new-device "
106986fd29aSsetje " \" %s\" device-name "
107986fd29aSsetje " "
108986fd29aSsetje " \" block\" device-type "
1097c478bd9Sstevel@tonic-gate " \" SUNW,ramdisk\" encode-string \" compatible\" property"
1107c478bd9Sstevel@tonic-gate
111986fd29aSsetje " 0 instance value current-offset "
112986fd29aSsetje " "
113986fd29aSsetje " 0 value ramdisk-base-va "
114986fd29aSsetje " 0 value ramdisk-size "
115986fd29aSsetje " 0 value alloc-size "
116986fd29aSsetje " "
117986fd29aSsetje " : set-props "
118986fd29aSsetje " ramdisk-size encode-int \" size\" property "
119986fd29aSsetje " ramdisk-base-va encode-int \" address\" property "
120986fd29aSsetje " alloc-size encode-int \" alloc-size\" property "
121986fd29aSsetje " ; "
122986fd29aSsetje " set-props "
123986fd29aSsetje " "
124986fd29aSsetje " : current-va ( -- adr ) ramdisk-base-va current-offset + ; "
125986fd29aSsetje " "
126986fd29aSsetje " external "
127986fd29aSsetje " "
128986fd29aSsetje " : open ( -- okay? ) "
129986fd29aSsetje /* " .\" ramdisk-open\" cr " */
130986fd29aSsetje " true "
131986fd29aSsetje " ; "
132986fd29aSsetje " "
133986fd29aSsetje " : close ( -- ) "
134986fd29aSsetje " ; "
135986fd29aSsetje " "
136986fd29aSsetje " : seek ( off.low off.high -- error? ) "
137986fd29aSsetje /* " 2dup .\" ramdisk-seek: \" .x .x " */
138986fd29aSsetje " drop dup ramdisk-size > if "
139986fd29aSsetje /* " .\" fail\" cr " */
140986fd29aSsetje " drop true exit ( failed ) "
141986fd29aSsetje " then "
142986fd29aSsetje " to current-offset false ( succeeded ) "
143986fd29aSsetje /* " .\" OK\" cr " */
1447c478bd9Sstevel@tonic-gate " ; "
145986fd29aSsetje " "
146986fd29aSsetje " : read ( addr len -- actual-len ) "
147986fd29aSsetje /* " 2dup .\" ramdisk-read: \" .x .x " */
148986fd29aSsetje " dup current-offset + ( addr len new-off ) "
149986fd29aSsetje " dup ramdisk-size > if "
150986fd29aSsetje " ramdisk-size - - ( addr len' ) "
151986fd29aSsetje " ramdisk-size ( addr len new-off ) "
152986fd29aSsetje " then -rot ( new-off addr len ) "
153986fd29aSsetje " tuck current-va -rot move ( new-off len ) "
154986fd29aSsetje " swap to current-offset ( len ) "
155986fd29aSsetje /* " dup .x cr " */
156986fd29aSsetje " ; "
157986fd29aSsetje " "
158986fd29aSsetje " : create ( alloc-sz base size -- ) "
159986fd29aSsetje " to ramdisk-size "
160986fd29aSsetje " to ramdisk-base-va "
161986fd29aSsetje " to alloc-size "
162986fd29aSsetje " set-props "
163986fd29aSsetje " ; "
164986fd29aSsetje " "
1657c478bd9Sstevel@tonic-gate "finish-device "
166986fd29aSsetje "pop-package "
167986fd29aSsetje
168986fd29aSsetje "\" /%s\" 2dup dev-open 0= if "
169986fd29aSsetje " open-abort "
170986fd29aSsetje "then 2drop "
171986fd29aSsetje
172986fd29aSsetje /* %x %x %x will be replaced by alloc-sz, base, size respectively */
173986fd29aSsetje "h# %x h# %x h# %x ( alloc-sz base size ) "
174986fd29aSsetje "\" create\" dev-ih $call-method ( ) "
175986fd29aSsetje "dev-close "
176986fd29aSsetje
177986fd29aSsetje ;
178986fd29aSsetje
179986fd29aSsetje char ramdisk_bootable[] =
180986fd29aSsetje
181986fd29aSsetje "\" /chosen\" get-package push-package "
182986fd29aSsetje " \" nfs\" encode-string \" fstype\" property "
183986fd29aSsetje " \" /%s\" encode-string \" bootarchive\" property "
184986fd29aSsetje "pop-package "
185986fd29aSsetje
186986fd29aSsetje " h# %x d# 512 + to load-base init-program "
187986fd29aSsetje ;
188986fd29aSsetje
189986fd29aSsetje #define BOOT_ARCHIVE_ALLOC_SIZE (32 * 1024 * 1024) /* 32 MB */
190986fd29aSsetje #define BOOTFS_VIRT ((caddr_t)0x50f00000)
191*c8551b44SJerry Gilliam #define ROOTFS_VIRT ((caddr_t)0x52000000)
192986fd29aSsetje
193986fd29aSsetje struct ramdisk_attr {
194986fd29aSsetje char *rd_name;
195986fd29aSsetje caddr_t rd_base;
196986fd29aSsetje size_t rd_size;
197986fd29aSsetje } ramdisk_attr[] = {
198986fd29aSsetje RD_BOOTFS, BOOTFS_VIRT, 0,
199986fd29aSsetje RD_ROOTFS, ROOTFS_VIRT, 0,
200986fd29aSsetje 0
201986fd29aSsetje };
202986fd29aSsetje
203986fd29aSsetje static struct ramdisk_attr *
ramdisk_lookup(char * ramdisk_name)204986fd29aSsetje ramdisk_lookup(char *ramdisk_name)
205986fd29aSsetje {
206986fd29aSsetje int i;
2077c478bd9Sstevel@tonic-gate
208986fd29aSsetje for (i = 0; ramdisk_attr[i].rd_name != 0; i++) {
209986fd29aSsetje if (strcmp(ramdisk_name, ramdisk_attr[i].rd_name) == 0) {
210986fd29aSsetje return (&ramdisk_attr[i]);
211986fd29aSsetje }
212986fd29aSsetje }
213986fd29aSsetje return (NULL);
214986fd29aSsetje }
2157c478bd9Sstevel@tonic-gate
216986fd29aSsetje static void
ramdisk_free_mem(caddr_t addr,size_t size)217986fd29aSsetje ramdisk_free_mem(caddr_t addr, size_t size)
218986fd29aSsetje {
219986fd29aSsetje caddr_t end_addr;
2207c478bd9Sstevel@tonic-gate
221986fd29aSsetje for (end_addr = addr + size; addr < end_addr;
222986fd29aSsetje addr += BOOT_ARCHIVE_ALLOC_SIZE) {
223986fd29aSsetje prom_free(addr, MIN(BOOT_ARCHIVE_ALLOC_SIZE, end_addr - addr));
224986fd29aSsetje }
225986fd29aSsetje }
2267c478bd9Sstevel@tonic-gate
2277c478bd9Sstevel@tonic-gate /*
228986fd29aSsetje * Allocate memory for ramdisk image.
2297c478bd9Sstevel@tonic-gate */
230986fd29aSsetje static caddr_t
ramdisk_alloc_mem(caddr_t addr,size_t size)231986fd29aSsetje ramdisk_alloc_mem(caddr_t addr, size_t size)
232986fd29aSsetje {
233986fd29aSsetje caddr_t virt = addr;
234986fd29aSsetje caddr_t end_addr;
235986fd29aSsetje
236986fd29aSsetje for (end_addr = virt + size; virt < end_addr;
237986fd29aSsetje virt += BOOT_ARCHIVE_ALLOC_SIZE) {
238986fd29aSsetje if (prom_alloc(virt,
239986fd29aSsetje MIN(BOOT_ARCHIVE_ALLOC_SIZE, end_addr - virt),
240986fd29aSsetje 1) == NULL) {
241986fd29aSsetje ramdisk_free_mem(addr, virt - addr);
242986fd29aSsetje return (NULL);
243986fd29aSsetje }
244986fd29aSsetje }
245986fd29aSsetje return (addr);
246986fd29aSsetje }
247986fd29aSsetje
248986fd29aSsetje caddr_t
create_ramdisk(char * ramdisk_name,size_t size,char ** devpath)249986fd29aSsetje create_ramdisk(char *ramdisk_name, size_t size, char **devpath)
2507c478bd9Sstevel@tonic-gate {
2517c478bd9Sstevel@tonic-gate char *fth_buf;
2527c478bd9Sstevel@tonic-gate size_t buf_size;
253986fd29aSsetje struct ramdisk_attr *rdp;
254986fd29aSsetje char tdevpath[80];
255986fd29aSsetje caddr_t virt;
256986fd29aSsetje static int need_preamble = 1;
257986fd29aSsetje
258986fd29aSsetje /*
259986fd29aSsetje * lookup ramdisk name.
260986fd29aSsetje */
261986fd29aSsetje if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL)
262986fd29aSsetje prom_panic("invalid ramdisk name");
263986fd29aSsetje
264986fd29aSsetje virt = rdp->rd_base;
265986fd29aSsetje
266986fd29aSsetje /*
267986fd29aSsetje * Allocate memory.
268986fd29aSsetje */
269986fd29aSsetje size = roundup(size, PAGESIZE);
270986fd29aSsetje if (ramdisk_alloc_mem(virt, size) == NULL)
271986fd29aSsetje prom_panic("can't alloc ramdisk memory");
272986fd29aSsetje
273986fd29aSsetje rdp->rd_size = size;
2747c478bd9Sstevel@tonic-gate
275986fd29aSsetje if (need_preamble) {
276986fd29aSsetje prom_interpret(ramdisk_preamble_fth, 0, 0, 0, 0, 0);
277986fd29aSsetje need_preamble = 0;
278986fd29aSsetje }
279986fd29aSsetje
280986fd29aSsetje /*
281986fd29aSsetje * add some space to the size to accommodate a few words in the
282986fd29aSsetje * snprintf() below.
283986fd29aSsetje */
284986fd29aSsetje buf_size = sizeof (ramdisk_fth) + 80;
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate fth_buf = bkmem_alloc(buf_size);
287986fd29aSsetje if (fth_buf == NULL)
2887c478bd9Sstevel@tonic-gate prom_panic("unable to allocate Forth buffer for ramdisk");
2897c478bd9Sstevel@tonic-gate
290986fd29aSsetje (void) snprintf(fth_buf, buf_size, ramdisk_fth,
291986fd29aSsetje ramdisk_name, ramdisk_name,
292986fd29aSsetje BOOT_ARCHIVE_ALLOC_SIZE, virt, size);
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate prom_interpret(fth_buf, 0, 0, 0, 0, 0);
2957c478bd9Sstevel@tonic-gate bkmem_free(fth_buf, buf_size);
296986fd29aSsetje
297986fd29aSsetje if (devpath != NULL) {
298986fd29aSsetje (void) snprintf(tdevpath, sizeof (tdevpath), "/%s:nolabel",
299986fd29aSsetje ramdisk_name);
300986fd29aSsetje *devpath = strdup(tdevpath);
301986fd29aSsetje }
302986fd29aSsetje
303986fd29aSsetje return (virt);
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate
306986fd29aSsetje void
destroy_ramdisk(char * ramdisk_name)307986fd29aSsetje destroy_ramdisk(char *ramdisk_name)
3087c478bd9Sstevel@tonic-gate {
309986fd29aSsetje struct ramdisk_attr *rdp;
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate /*
312986fd29aSsetje * lookup ramdisk name.
3137c478bd9Sstevel@tonic-gate */
314986fd29aSsetje if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL)
315986fd29aSsetje prom_panic("invalid ramdisk name");
3167c478bd9Sstevel@tonic-gate
317986fd29aSsetje ramdisk_free_mem(rdp->rd_base, rdp->rd_size);
318986fd29aSsetje rdp->rd_size = 0;
319986fd29aSsetje }
3207c478bd9Sstevel@tonic-gate
321986fd29aSsetje /*
322986fd29aSsetje * change cwp! to drop in the 2nd word of (init-program) - really
323986fd29aSsetje * init-c-stack, but that word has no header.
324986fd29aSsetje * (you are not expected to undertsnad this)
325986fd29aSsetje */
326986fd29aSsetje char obpfix[] = "' drop ' cwp! ' (init-program) >body ta1+ token@ (patch";
327986fd29aSsetje char obpver[OBP_MAXPROPNAME];
328986fd29aSsetje const char badver[] = "OBP 4.27.";
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate
331986fd29aSsetje void
boot_ramdisk(char * ramdisk_name)332986fd29aSsetje boot_ramdisk(char *ramdisk_name)
333986fd29aSsetje {
334986fd29aSsetje char *fth_buf;
335986fd29aSsetje size_t buf_size;
336986fd29aSsetje struct ramdisk_attr *rdp;
337986fd29aSsetje void do_sg_go(void);
3387c478bd9Sstevel@tonic-gate
339986fd29aSsetje /*
340986fd29aSsetje * OBP revs 4.27.0 to 4.27.8 started using
341986fd29aSsetje * windowed regs for the forth kernel, but
342986fd29aSsetje * init-program still blindly 0'd %cwp, which
343986fd29aSsetje * causes predictably disaterous consequences
344986fd29aSsetje * when called with %cwp != 0.
345986fd29aSsetje *
346986fd29aSsetje * We detect and fix this here
347986fd29aSsetje */
348986fd29aSsetje if (prom_version_name(obpver, OBP_MAXPROPNAME) != -1 &&
349986fd29aSsetje strncmp(obpver, badver, sizeof (badver) - 1) == 0) {
350986fd29aSsetje char ch = obpver[sizeof (badver) - 1];
3517c478bd9Sstevel@tonic-gate
352986fd29aSsetje if (ch >= '0' && ch <= '8') {
353986fd29aSsetje prom_interpret(obpfix, 0, 0, 0, 0, 0);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate
357986fd29aSsetje /* close all open devices */
358986fd29aSsetje closeall(1);
359986fd29aSsetje
360986fd29aSsetje /*
361986fd29aSsetje * lookup ramdisk name.
362986fd29aSsetje */
363986fd29aSsetje if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL)
364986fd29aSsetje prom_panic("invalid ramdisk name");
365986fd29aSsetje
366986fd29aSsetje /*
367986fd29aSsetje * add some space to the size to accommodate a few words in the
368986fd29aSsetje * snprintf() below.
369986fd29aSsetje */
370986fd29aSsetje buf_size = sizeof (ramdisk_bootable) + 80;
371986fd29aSsetje
372986fd29aSsetje fth_buf = bkmem_alloc(buf_size);
373986fd29aSsetje if (fth_buf == NULL)
374986fd29aSsetje prom_panic("unable to allocate Forth buffer for ramdisk");
375986fd29aSsetje
376986fd29aSsetje (void) snprintf(fth_buf, buf_size, ramdisk_bootable,
377986fd29aSsetje ramdisk_name, rdp->rd_base);
378986fd29aSsetje
379986fd29aSsetje prom_interpret(fth_buf, 0, 0, 0, 0, 0);
380986fd29aSsetje
381986fd29aSsetje /*
382986fd29aSsetje * Ugh Serengeti proms don't execute C programs
383986fd29aSsetje * in init-program, and 'go' doesn't work when
384986fd29aSsetje * launching a second C program (inetboot itself
385986fd29aSsetje * was launched as the 1st C program). Nested fcode
386986fd29aSsetje * programs work, but that doesn't help the kernel.
387986fd29aSsetje */
388986fd29aSsetje do_sg_go();
389986fd29aSsetje }
390986fd29aSsetje
391986fd29aSsetje void
do_sg_go()392986fd29aSsetje do_sg_go()
393986fd29aSsetje {
394986fd29aSsetje pnode_t chosen = prom_chosennode();
395986fd29aSsetje Elf64_Ehdr *ehdr;
396986fd29aSsetje Elf64_Addr entry;
397986fd29aSsetje uint32_t eadr;
398986fd29aSsetje extern int is_sg;
399986fd29aSsetje extern caddr_t sg_addr;
400986fd29aSsetje extern size_t sg_len;
401986fd29aSsetje
402986fd29aSsetje if (!is_sg)
403986fd29aSsetje prom_panic("do_sg_go");
404986fd29aSsetje
405986fd29aSsetje /*
406986fd29aSsetje * The ramdisk bootblk left a pointer to the elf image
407986fd29aSsetje * in 'elfheader-address' Use it to find the kernel's
408986fd29aSsetje * entry point.
409986fd29aSsetje */
410986fd29aSsetje if (prom_getprop(chosen, "elfheader-address", (caddr_t)&eadr) == -1)
411986fd29aSsetje prom_panic("no elf header property");
412986fd29aSsetje ehdr = (Elf64_Ehdr *)(uintptr_t)eadr;
413986fd29aSsetje if (ehdr->e_machine != EM_SPARCV9)
414986fd29aSsetje prom_panic("bad ELF header");
415986fd29aSsetje entry = ehdr->e_entry;
416986fd29aSsetje
417986fd29aSsetje /*
418986fd29aSsetje * free extra bootmem
419986fd29aSsetje */
420986fd29aSsetje prom_free(sg_addr, sg_len);
421986fd29aSsetje
422986fd29aSsetje /*
423986fd29aSsetje * Use pre-newboot's exitto64() to launch the kernel
424986fd29aSsetje */
425986fd29aSsetje exitto64((int (*)())entry, NULL);
426986fd29aSsetje prom_panic("exitto returned");
4277c478bd9Sstevel@tonic-gate }
428