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 * 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 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 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 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 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 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 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