xref: /onnv-gate/usr/src/psm/stand/boot/sparc/common/ramdisk.c (revision 9034:00e1de19228d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55648Ssetje  * Common Development and Distribution License (the "License").
65648Ssetje  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*9034SJerry.Gilliam@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/param.h>
270Sstevel@tonic-gate #include <sys/promif.h>
280Sstevel@tonic-gate #include <sys/salib.h>
290Sstevel@tonic-gate /* EXPORT DELETE START */
300Sstevel@tonic-gate #include <bootlog.h>
310Sstevel@tonic-gate /* EXPORT DELETE END */
320Sstevel@tonic-gate #include "ramdisk.h"
330Sstevel@tonic-gate 
345648Ssetje #include <sys/param.h>
355648Ssetje #include <sys/fcntl.h>
365648Ssetje #include <sys/obpdefs.h>
375648Ssetje #include <sys/reboot.h>
385648Ssetje #include <sys/promif.h>
395648Ssetje #include <sys/stat.h>
405648Ssetje #include <sys/bootvfs.h>
415648Ssetje #include <sys/platnames.h>
425648Ssetje #include <sys/salib.h>
435648Ssetje #include <sys/elf.h>
445648Ssetje #include <sys/link.h>
455648Ssetje #include <sys/auxv.h>
465648Ssetje #include <sys/boot_policy.h>
475648Ssetje #include <sys/boot_redirect.h>
485648Ssetje #include <sys/bootconf.h>
495648Ssetje #include <sys/boot.h>
505648Ssetje #include "boot_plat.h"
515648Ssetje 
525648Ssetje 
535648Ssetje static char ramdisk_preamble_fth[] =
545648Ssetje 
555648Ssetje ": find-abort ( name$ -- ) "
565648Ssetje "   .\" Can't find \" type abort "
575648Ssetje "; "
585648Ssetje 
595648Ssetje ": get-package ( pkg$ -- ph ) "
605648Ssetje "   2dup  find-package 0=  if "
615648Ssetje "      find-abort "
625648Ssetje "   then                       ( pkg$ ph ) "
635648Ssetje "   nip nip                    ( ph ) "
645648Ssetje "; "
655648Ssetje 
665648Ssetje "\" /openprom/client-services\" get-package  constant cif-ph "
675648Ssetje 
685648Ssetje "instance defer cif-open     ( dev$ -- ihandle|0 ) "
695648Ssetje "instance defer cif-close    ( ihandle -- ) "
700Sstevel@tonic-gate 
715648Ssetje ": find-cif-method ( adr,len -- acf ) "
725648Ssetje "   2dup  cif-ph find-method 0=  if    ( adr,len ) "
735648Ssetje "      find-abort "
745648Ssetje "   then                               ( adr,len acf ) "
755648Ssetje "   nip nip                            ( acf ) "
765648Ssetje "; "
775648Ssetje 
785648Ssetje "\" open\"     find-cif-method to cif-open "
795648Ssetje "\" close\"    find-cif-method to cif-close "
805648Ssetje 
815648Ssetje "0 value dev-ih "
825648Ssetje 
835648Ssetje "d# 100 buffer: open-cstr "
840Sstevel@tonic-gate 
855648Ssetje ": dev-open ( dev$ -- okay? ) "
865648Ssetje /* copy to C string for open  */
875648Ssetje "   0  over open-cstr +  c! "
885648Ssetje "   open-cstr swap  move "
895648Ssetje "   open-cstr  cif-open dup  if "
905648Ssetje "      dup to dev-ih "
915648Ssetje "   then "
925648Ssetje "; "
935648Ssetje 
945648Ssetje ": dev-close ( -- ) "
955648Ssetje "   dev-ih cif-close "
965648Ssetje "   0 to dev-ih "
975648Ssetje "; "
980Sstevel@tonic-gate 
995648Ssetje ": open-abort  ( file$ -- ) "
1005648Ssetje "   .\" Can't open \"  type  abort "
1015648Ssetje "; "
1025648Ssetje ;
1035648Ssetje 
1045648Ssetje static char ramdisk_fth[] =
1055648Ssetje 
1065648Ssetje "\" /\" get-package  push-package "
1075648Ssetje 
1085648Ssetje "new-device "
1095648Ssetje "   \" %s\" device-name "
1105648Ssetje "    "
1115648Ssetje "   \" block\"          device-type "
1120Sstevel@tonic-gate "   \" SUNW,ramdisk\"	encode-string \" compatible\"  property"
1130Sstevel@tonic-gate 
1145648Ssetje "   0 instance value current-offset "
1155648Ssetje "    "
1165648Ssetje "   0 value ramdisk-base-va "
1175648Ssetje "   0 value ramdisk-size "
1185648Ssetje "   0 value alloc-size "
1195648Ssetje "    "
1205648Ssetje "   : set-props "
1215648Ssetje "      ramdisk-size     encode-int  \" size\"        property "
1225648Ssetje "      ramdisk-base-va  encode-int  \" address\"     property "
1235648Ssetje "      alloc-size       encode-int  \" alloc-size\"  property "
1245648Ssetje "   ; "
1255648Ssetje "   set-props "
1265648Ssetje "    "
1275648Ssetje "   : current-va  ( -- adr )  ramdisk-base-va current-offset +  ; "
1285648Ssetje "    "
1295648Ssetje "   external "
1305648Ssetje "    "
1315648Ssetje "   : open  ( -- okay? ) "
1325648Ssetje /* " .\" ramdisk-open\" cr " */
1335648Ssetje "      true "
1345648Ssetje "   ; "
1355648Ssetje "    "
1365648Ssetje "   : close  ( -- ) "
1375648Ssetje "   ; "
1385648Ssetje "    "
1395648Ssetje "   : seek  ( off.low off.high -- error? ) "
1405648Ssetje /* " 2dup .\" ramdisk-seek: \" .x .x " */
1415648Ssetje "      drop  dup  ramdisk-size  >  if "
1425648Ssetje /* " .\" fail\" cr " */
1435648Ssetje "         drop true  exit         ( failed ) "
1445648Ssetje "      then "
1455648Ssetje "      to current-offset  false   ( succeeded ) "
1465648Ssetje /* " .\" OK\" cr " */
1475648Ssetje "   ; "
1485648Ssetje "    "
1495648Ssetje "   : read  ( addr len -- actual-len ) "
1505648Ssetje /* " 2dup .\" ramdisk-read: \" .x .x " */
1515648Ssetje "      dup  current-offset  +            ( addr len new-off ) "
1525648Ssetje "      dup  ramdisk-size  >  if "
1535648Ssetje "         ramdisk-size -  -              ( addr len' ) "
1545648Ssetje "         ramdisk-size                   ( addr len new-off ) "
1555648Ssetje "      then  -rot                        ( new-off addr len ) "
1565648Ssetje "      tuck  current-va  -rot  move      ( new-off len ) "
1575648Ssetje "      swap  to current-offset           ( len ) "
1585648Ssetje /* " dup .x cr " */
1595648Ssetje "   ; "
1605648Ssetje "    "
1615648Ssetje "   : create ( alloc-sz base size -- ) "
1625648Ssetje "      to ramdisk-size "
1635648Ssetje "      to ramdisk-base-va "
1645648Ssetje "      to alloc-size "
1655648Ssetje "      set-props "
1665648Ssetje "   ; "
1675648Ssetje "    "
1685648Ssetje "finish-device "
1695648Ssetje "pop-package "
1700Sstevel@tonic-gate 
1715648Ssetje "\" /%s\" 2dup  dev-open  0=  if "
1725648Ssetje "   open-abort "
1735648Ssetje "then 2drop "
1740Sstevel@tonic-gate 
1755648Ssetje /* %x %x %x will be replaced by alloc-sz, base, size respectively */
1765648Ssetje "h# %x h# %x h# %x ( alloc-sz base size ) "
1775648Ssetje "\" create\" dev-ih  $call-method  (  ) "
1785648Ssetje "dev-close "
1790Sstevel@tonic-gate 
1805648Ssetje ;
1810Sstevel@tonic-gate 
1825648Ssetje char ramdisk_bootable[] =
1830Sstevel@tonic-gate 
1845648Ssetje "\" /chosen\" get-package  push-package "
1855648Ssetje "   \" nfs\"             encode-string  \" fstype\"  property "
1865648Ssetje "   \" /%s\"	  	 encode-string  \" bootarchive\"  property "
1875648Ssetje "pop-package "
1880Sstevel@tonic-gate 
1895648Ssetje "   h# %x d# 512 +  to load-base init-program "
1905648Ssetje ;
1910Sstevel@tonic-gate 
1925648Ssetje #define	BOOT_ARCHIVE_ALLOC_SIZE	(32 * 1024 * 1024)	/* 32 MB */
1935648Ssetje #define	BOOTFS_VIRT		((caddr_t)0x50f00000)
194*9034SJerry.Gilliam@Sun.COM #define	ROOTFS_VIRT		((caddr_t)0x52000000)
1950Sstevel@tonic-gate 
1965648Ssetje struct ramdisk_attr {
1975648Ssetje 	char *rd_name;
1985648Ssetje 	caddr_t rd_base;
1995648Ssetje 	size_t rd_size;
2005648Ssetje } ramdisk_attr[] = {
2015648Ssetje 	RD_BOOTFS,	BOOTFS_VIRT,	0,
2025648Ssetje 	RD_ROOTFS,	ROOTFS_VIRT,	0,
2035648Ssetje 	0
2045648Ssetje };
2050Sstevel@tonic-gate 
2065648Ssetje static struct ramdisk_attr *
ramdisk_lookup(char * ramdisk_name)2075648Ssetje ramdisk_lookup(char *ramdisk_name)
2085648Ssetje {
2095648Ssetje 	int i;
2100Sstevel@tonic-gate 
2115648Ssetje 	for (i = 0; ramdisk_attr[i].rd_name != 0; i++) {
2125648Ssetje 		if (strcmp(ramdisk_name, ramdisk_attr[i].rd_name) == 0) {
2135648Ssetje 			return (&ramdisk_attr[i]);
2145648Ssetje 		}
2155648Ssetje 	}
2165648Ssetje 	return (NULL);
2175648Ssetje }
2180Sstevel@tonic-gate 
2195648Ssetje static void
ramdisk_free_mem(caddr_t addr,size_t size)2205648Ssetje ramdisk_free_mem(caddr_t addr, size_t size)
2215648Ssetje {
2225648Ssetje 	caddr_t	end_addr;
2230Sstevel@tonic-gate 
2245648Ssetje 	for (end_addr = addr + size; addr < end_addr;
2255648Ssetje 	    addr += BOOT_ARCHIVE_ALLOC_SIZE) {
2265648Ssetje 		prom_free(addr, MIN(BOOT_ARCHIVE_ALLOC_SIZE, end_addr - addr));
2275648Ssetje 	}
2285648Ssetje }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate /*
2315648Ssetje  * Allocate memory for ramdisk image.
2320Sstevel@tonic-gate  */
2335648Ssetje static caddr_t
ramdisk_alloc_mem(caddr_t addr,size_t size)2345648Ssetje ramdisk_alloc_mem(caddr_t addr, size_t size)
2355648Ssetje {
2365648Ssetje 	caddr_t virt = addr;
2375648Ssetje 	caddr_t	end_addr;
2385648Ssetje 
2395648Ssetje 	for (end_addr = virt + size; virt < end_addr;
2405648Ssetje 	    virt += BOOT_ARCHIVE_ALLOC_SIZE) {
2415648Ssetje 		if (prom_alloc(virt,
2425648Ssetje 		    MIN(BOOT_ARCHIVE_ALLOC_SIZE, end_addr - virt),
2435648Ssetje 		    1) == NULL) {
2445648Ssetje 			ramdisk_free_mem(addr, virt - addr);
2455648Ssetje 			return (NULL);
2465648Ssetje 		}
2475648Ssetje 	}
2485648Ssetje 	return (addr);
2495648Ssetje }
2505648Ssetje 
2515648Ssetje caddr_t
create_ramdisk(char * ramdisk_name,size_t size,char ** devpath)2525648Ssetje create_ramdisk(char *ramdisk_name, size_t size, char **devpath)
2530Sstevel@tonic-gate {
2540Sstevel@tonic-gate 	char	*fth_buf;
2550Sstevel@tonic-gate 	size_t	buf_size;
2565648Ssetje 	struct ramdisk_attr *rdp;
2575648Ssetje 	char tdevpath[80];
2585648Ssetje 	caddr_t virt;
2595648Ssetje 	static int need_preamble = 1;
2600Sstevel@tonic-gate 
2615648Ssetje 	/*
2625648Ssetje 	 * lookup ramdisk name.
2635648Ssetje 	 */
2645648Ssetje 	if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL)
2655648Ssetje 		prom_panic("invalid ramdisk name");
2665648Ssetje 
2675648Ssetje 	virt = rdp->rd_base;
2685648Ssetje 
2695648Ssetje 	/*
2705648Ssetje 	 * Allocate memory.
2715648Ssetje 	 */
2725648Ssetje 	size = roundup(size, PAGESIZE);
2735648Ssetje 	if (ramdisk_alloc_mem(virt, size) == NULL)
2745648Ssetje 		prom_panic("can't alloc ramdisk memory");
2755648Ssetje 
2765648Ssetje 	rdp->rd_size = size;
2775648Ssetje 
2785648Ssetje 	if (need_preamble) {
2795648Ssetje 		prom_interpret(ramdisk_preamble_fth, 0, 0, 0, 0, 0);
2805648Ssetje 		need_preamble = 0;
2815648Ssetje 	}
2825648Ssetje 
2835648Ssetje 	/*
2845648Ssetje 	 * add some space to the size to accommodate a few words in the
2855648Ssetje 	 * snprintf() below.
2865648Ssetje 	 */
2875648Ssetje 	buf_size = sizeof (ramdisk_fth) + 80;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	fth_buf = bkmem_alloc(buf_size);
2905648Ssetje 	if (fth_buf == NULL)
2910Sstevel@tonic-gate 		prom_panic("unable to allocate Forth buffer for ramdisk");
2925648Ssetje 
2935648Ssetje 	(void) snprintf(fth_buf, buf_size, ramdisk_fth,
2945648Ssetje 	    ramdisk_name, ramdisk_name,
2955648Ssetje 	    BOOT_ARCHIVE_ALLOC_SIZE, virt, size);
2965648Ssetje 
2975648Ssetje 	prom_interpret(fth_buf, 0, 0, 0, 0, 0);
2985648Ssetje 	bkmem_free(fth_buf, buf_size);
2995648Ssetje 
3005648Ssetje 	if (devpath != NULL) {
3015648Ssetje 		(void) snprintf(tdevpath, sizeof (tdevpath), "/%s:nolabel",
3025648Ssetje 		    ramdisk_name);
3035648Ssetje 		*devpath = strdup(tdevpath);
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 
3065648Ssetje 	return (virt);
3075648Ssetje }
3085648Ssetje 
3095648Ssetje void
destroy_ramdisk(char * ramdisk_name)3105648Ssetje destroy_ramdisk(char *ramdisk_name)
3115648Ssetje {
3125648Ssetje 	struct ramdisk_attr *rdp;
3135648Ssetje 
3145648Ssetje 	/*
3155648Ssetje 	 * lookup ramdisk name.
3165648Ssetje 	 */
3175648Ssetje 	if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL)
3185648Ssetje 		prom_panic("invalid ramdisk name");
3195648Ssetje 
3205648Ssetje 	ramdisk_free_mem(rdp->rd_base, rdp->rd_size);
3215648Ssetje 	rdp->rd_size = 0;
3225648Ssetje }
3235648Ssetje 
3245648Ssetje /*
3255648Ssetje  * change cwp! to drop in the 2nd word of (init-program) - really
3265648Ssetje  * init-c-stack, but that word has no header.
3275648Ssetje  * (you are not expected to undertsnad this)
3285648Ssetje  */
3295648Ssetje char obpfix[] = "' drop ' cwp!  ' (init-program) >body ta1+ token@ (patch";
3305648Ssetje char obpver[OBP_MAXPROPNAME];
3315648Ssetje const char badver[] = "OBP 4.27.";
3325648Ssetje 
3335648Ssetje 
3345648Ssetje void
boot_ramdisk(char * ramdisk_name)3355648Ssetje boot_ramdisk(char *ramdisk_name)
3365648Ssetje {
3375648Ssetje 	char	*fth_buf;
3385648Ssetje 	size_t	buf_size;
3395648Ssetje 	struct ramdisk_attr *rdp;
3405648Ssetje 	void do_sg_go(void);
3415648Ssetje 
3425648Ssetje 	/*
3435648Ssetje 	 * OBP revs 4.27.0 to 4.27.8 started using
3445648Ssetje 	 * windowed regs for the forth kernel, but
3455648Ssetje 	 * init-program still blindly 0'd %cwp, which
3465648Ssetje 	 * causes predictably disaterous consequences
3475648Ssetje 	 * when called with %cwp != 0.
3485648Ssetje 	 *
3495648Ssetje 	 * We detect and fix this here
3505648Ssetje 	 */
3515648Ssetje 	if (prom_version_name(obpver, OBP_MAXPROPNAME) != -1 &&
3525648Ssetje 	    strncmp(obpver, badver, sizeof (badver) - 1) == 0) {
3535648Ssetje 		char ch = obpver[sizeof (badver) - 1];
3545648Ssetje 
3555648Ssetje 		if (ch >= '0' && ch <= '8') {
3565648Ssetje 			prom_interpret(obpfix, 0, 0, 0, 0, 0);
3575648Ssetje 		}
3585648Ssetje 	}
3595648Ssetje 
3605648Ssetje 	/* close all open devices */
3615648Ssetje 	closeall(1);
3625648Ssetje 
3635648Ssetje 	/*
3645648Ssetje 	 * lookup ramdisk name.
3655648Ssetje 	 */
3665648Ssetje 	if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL)
3675648Ssetje 		prom_panic("invalid ramdisk name");
3685648Ssetje 
3695648Ssetje 	/*
3705648Ssetje 	 * add some space to the size to accommodate a few words in the
3715648Ssetje 	 * snprintf() below.
3725648Ssetje 	 */
3735648Ssetje 	buf_size = sizeof (ramdisk_bootable) + 80;
3745648Ssetje 
3755648Ssetje 	fth_buf = bkmem_alloc(buf_size);
3765648Ssetje 	if (fth_buf == NULL)
3775648Ssetje 		prom_panic("unable to allocate Forth buffer for ramdisk");
3785648Ssetje 
3795648Ssetje 	(void) snprintf(fth_buf, buf_size, ramdisk_bootable,
3805648Ssetje 	    ramdisk_name, rdp->rd_base);
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	prom_interpret(fth_buf, 0, 0, 0, 0, 0);
3830Sstevel@tonic-gate 
3845648Ssetje 	/*
3855648Ssetje 	 * Ugh  Serengeti proms don't execute C programs
3865648Ssetje 	 * in init-program, and 'go' doesn't work when
3875648Ssetje 	 * launching a second C program (inetboot itself
3885648Ssetje 	 * was launched as the 1st C program).  Nested fcode
3895648Ssetje 	 * programs work, but that doesn't help the kernel.
3905648Ssetje 	 */
3915648Ssetje 	do_sg_go();
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate 
3945648Ssetje void
do_sg_go()3955648Ssetje do_sg_go()
3960Sstevel@tonic-gate {
3975648Ssetje 	pnode_t chosen = prom_chosennode();
3985648Ssetje 	Elf64_Ehdr *ehdr;
3995648Ssetje 	Elf64_Addr entry;
4005648Ssetje 	uint32_t eadr;
4015648Ssetje 	extern int is_sg;
4025648Ssetje 	extern caddr_t sg_addr;
4035648Ssetje 	extern size_t sg_len;
4045648Ssetje 
4055648Ssetje 	if (!is_sg)
4065648Ssetje 		prom_panic("do_sg_go");
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/*
4095648Ssetje 	 * The ramdisk bootblk left a pointer to the elf image
4105648Ssetje 	 * in 'elfheader-address'  Use it to find the kernel's
4115648Ssetje 	 * entry point.
4120Sstevel@tonic-gate 	 */
4135648Ssetje 	if (prom_getprop(chosen, "elfheader-address", (caddr_t)&eadr) == -1)
4145648Ssetje 		prom_panic("no elf header property");
4155648Ssetje 	ehdr = (Elf64_Ehdr *)(uintptr_t)eadr;
4165648Ssetje 	if (ehdr->e_machine != EM_SPARCV9)
4175648Ssetje 		prom_panic("bad ELF header");
4185648Ssetje 	entry = ehdr->e_entry;
4190Sstevel@tonic-gate 
4205648Ssetje 	/*
4215648Ssetje 	 * free extra bootmem
4225648Ssetje 	 */
4235648Ssetje 	prom_free(sg_addr, sg_len);
4240Sstevel@tonic-gate 
4255648Ssetje 	/*
4265648Ssetje 	 * Use pre-newboot's exitto64() to launch the kernel
4275648Ssetje 	 */
4285648Ssetje 	exitto64((int (*)())entry, NULL);
4295648Ssetje 	prom_panic("exitto returned");
4300Sstevel@tonic-gate }
431