1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/param.h> 29 #include <sys/promif.h> 30 #include <sys/salib.h> 31 /* EXPORT DELETE START */ 32 #include <bootlog.h> 33 /* EXPORT DELETE END */ 34 #include "ramdisk.h" 35 36 #include <sys/param.h> 37 #include <sys/fcntl.h> 38 #include <sys/obpdefs.h> 39 #include <sys/reboot.h> 40 #include <sys/promif.h> 41 #include <sys/stat.h> 42 #include <sys/bootvfs.h> 43 #include <sys/platnames.h> 44 #include <sys/salib.h> 45 #include <sys/elf.h> 46 #include <sys/link.h> 47 #include <sys/auxv.h> 48 #include <sys/boot_policy.h> 49 #include <sys/boot_redirect.h> 50 #include <sys/bootconf.h> 51 #include <sys/boot.h> 52 #include "boot_plat.h" 53 54 55 static char ramdisk_preamble_fth[] = 56 57 ": find-abort ( name$ -- ) " 58 " .\" Can't find \" type abort " 59 "; " 60 61 ": get-package ( pkg$ -- ph ) " 62 " 2dup find-package 0= if " 63 " find-abort " 64 " then ( pkg$ ph ) " 65 " nip nip ( ph ) " 66 "; " 67 68 "\" /openprom/client-services\" get-package constant cif-ph " 69 70 "instance defer cif-open ( dev$ -- ihandle|0 ) " 71 "instance defer cif-close ( ihandle -- ) " 72 73 ": find-cif-method ( adr,len -- acf ) " 74 " 2dup cif-ph find-method 0= if ( adr,len ) " 75 " find-abort " 76 " then ( adr,len acf ) " 77 " nip nip ( acf ) " 78 "; " 79 80 "\" open\" find-cif-method to cif-open " 81 "\" close\" find-cif-method to cif-close " 82 83 "0 value dev-ih " 84 85 "d# 100 buffer: open-cstr " 86 87 ": dev-open ( dev$ -- okay? ) " 88 /* copy to C string for open */ 89 " 0 over open-cstr + c! " 90 " open-cstr swap move " 91 " open-cstr cif-open dup if " 92 " dup to dev-ih " 93 " then " 94 "; " 95 96 ": dev-close ( -- ) " 97 " dev-ih cif-close " 98 " 0 to dev-ih " 99 "; " 100 101 ": open-abort ( file$ -- ) " 102 " .\" Can't open \" type abort " 103 "; " 104 ; 105 106 static char ramdisk_fth[] = 107 108 "\" /\" get-package push-package " 109 110 "new-device " 111 " \" %s\" device-name " 112 " " 113 " \" block\" device-type " 114 " \" SUNW,ramdisk\" encode-string \" compatible\" property" 115 116 " 0 instance value current-offset " 117 " " 118 " 0 value ramdisk-base-va " 119 " 0 value ramdisk-size " 120 " 0 value alloc-size " 121 " " 122 " : set-props " 123 " ramdisk-size encode-int \" size\" property " 124 " ramdisk-base-va encode-int \" address\" property " 125 " alloc-size encode-int \" alloc-size\" property " 126 " ; " 127 " set-props " 128 " " 129 " : current-va ( -- adr ) ramdisk-base-va current-offset + ; " 130 " " 131 " external " 132 " " 133 " : open ( -- okay? ) " 134 /* " .\" ramdisk-open\" cr " */ 135 " true " 136 " ; " 137 " " 138 " : close ( -- ) " 139 " ; " 140 " " 141 " : seek ( off.low off.high -- error? ) " 142 /* " 2dup .\" ramdisk-seek: \" .x .x " */ 143 " drop dup ramdisk-size > if " 144 /* " .\" fail\" cr " */ 145 " drop true exit ( failed ) " 146 " then " 147 " to current-offset false ( succeeded ) " 148 /* " .\" OK\" cr " */ 149 " ; " 150 " " 151 " : read ( addr len -- actual-len ) " 152 /* " 2dup .\" ramdisk-read: \" .x .x " */ 153 " dup current-offset + ( addr len new-off ) " 154 " dup ramdisk-size > if " 155 " ramdisk-size - - ( addr len' ) " 156 " ramdisk-size ( addr len new-off ) " 157 " then -rot ( new-off addr len ) " 158 " tuck current-va -rot move ( new-off len ) " 159 " swap to current-offset ( len ) " 160 /* " dup .x cr " */ 161 " ; " 162 " " 163 " : create ( alloc-sz base size -- ) " 164 " to ramdisk-size " 165 " to ramdisk-base-va " 166 " to alloc-size " 167 " set-props " 168 " ; " 169 " " 170 "finish-device " 171 "pop-package " 172 173 "\" /%s\" 2dup dev-open 0= if " 174 " open-abort " 175 "then 2drop " 176 177 /* %x %x %x will be replaced by alloc-sz, base, size respectively */ 178 "h# %x h# %x h# %x ( alloc-sz base size ) " 179 "\" create\" dev-ih $call-method ( ) " 180 "dev-close " 181 182 ; 183 184 char ramdisk_bootable[] = 185 186 "\" /chosen\" get-package push-package " 187 " \" nfs\" encode-string \" fstype\" property " 188 " \" /%s\" encode-string \" bootarchive\" property " 189 "pop-package " 190 191 " h# %x d# 512 + to load-base init-program " 192 ; 193 194 #define BOOT_ARCHIVE_ALLOC_SIZE (32 * 1024 * 1024) /* 32 MB */ 195 #define BOOTFS_VIRT ((caddr_t)0x50f00000) 196 #define ROOTFS_VIRT ((caddr_t)0x51000000) 197 198 struct ramdisk_attr { 199 char *rd_name; 200 caddr_t rd_base; 201 size_t rd_size; 202 } ramdisk_attr[] = { 203 RD_BOOTFS, BOOTFS_VIRT, 0, 204 RD_ROOTFS, ROOTFS_VIRT, 0, 205 0 206 }; 207 208 static struct ramdisk_attr * 209 ramdisk_lookup(char *ramdisk_name) 210 { 211 int i; 212 213 for (i = 0; ramdisk_attr[i].rd_name != 0; i++) { 214 if (strcmp(ramdisk_name, ramdisk_attr[i].rd_name) == 0) { 215 return (&ramdisk_attr[i]); 216 } 217 } 218 return (NULL); 219 } 220 221 static void 222 ramdisk_free_mem(caddr_t addr, size_t size) 223 { 224 caddr_t end_addr; 225 226 for (end_addr = addr + size; addr < end_addr; 227 addr += BOOT_ARCHIVE_ALLOC_SIZE) { 228 prom_free(addr, MIN(BOOT_ARCHIVE_ALLOC_SIZE, end_addr - addr)); 229 } 230 } 231 232 /* 233 * Allocate memory for ramdisk image. 234 */ 235 static caddr_t 236 ramdisk_alloc_mem(caddr_t addr, size_t size) 237 { 238 caddr_t virt = addr; 239 caddr_t end_addr; 240 241 for (end_addr = virt + size; virt < end_addr; 242 virt += BOOT_ARCHIVE_ALLOC_SIZE) { 243 if (prom_alloc(virt, 244 MIN(BOOT_ARCHIVE_ALLOC_SIZE, end_addr - virt), 245 1) == NULL) { 246 ramdisk_free_mem(addr, virt - addr); 247 return (NULL); 248 } 249 } 250 return (addr); 251 } 252 253 caddr_t 254 create_ramdisk(char *ramdisk_name, size_t size, char **devpath) 255 { 256 char *fth_buf; 257 size_t buf_size; 258 struct ramdisk_attr *rdp; 259 char tdevpath[80]; 260 caddr_t virt; 261 static int need_preamble = 1; 262 263 /* 264 * lookup ramdisk name. 265 */ 266 if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL) 267 prom_panic("invalid ramdisk name"); 268 269 virt = rdp->rd_base; 270 271 /* 272 * Allocate memory. 273 */ 274 size = roundup(size, PAGESIZE); 275 if (ramdisk_alloc_mem(virt, size) == NULL) 276 prom_panic("can't alloc ramdisk memory"); 277 278 rdp->rd_size = size; 279 280 if (need_preamble) { 281 prom_interpret(ramdisk_preamble_fth, 0, 0, 0, 0, 0); 282 need_preamble = 0; 283 } 284 285 /* 286 * add some space to the size to accommodate a few words in the 287 * snprintf() below. 288 */ 289 buf_size = sizeof (ramdisk_fth) + 80; 290 291 fth_buf = bkmem_alloc(buf_size); 292 if (fth_buf == NULL) 293 prom_panic("unable to allocate Forth buffer for ramdisk"); 294 295 (void) snprintf(fth_buf, buf_size, ramdisk_fth, 296 ramdisk_name, ramdisk_name, 297 BOOT_ARCHIVE_ALLOC_SIZE, virt, size); 298 299 prom_interpret(fth_buf, 0, 0, 0, 0, 0); 300 bkmem_free(fth_buf, buf_size); 301 302 if (devpath != NULL) { 303 (void) snprintf(tdevpath, sizeof (tdevpath), "/%s:nolabel", 304 ramdisk_name); 305 *devpath = strdup(tdevpath); 306 } 307 308 return (virt); 309 } 310 311 void 312 destroy_ramdisk(char *ramdisk_name) 313 { 314 struct ramdisk_attr *rdp; 315 316 /* 317 * lookup ramdisk name. 318 */ 319 if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL) 320 prom_panic("invalid ramdisk name"); 321 322 ramdisk_free_mem(rdp->rd_base, rdp->rd_size); 323 rdp->rd_size = 0; 324 } 325 326 /* 327 * change cwp! to drop in the 2nd word of (init-program) - really 328 * init-c-stack, but that word has no header. 329 * (you are not expected to undertsnad this) 330 */ 331 char obpfix[] = "' drop ' cwp! ' (init-program) >body ta1+ token@ (patch"; 332 char obpver[OBP_MAXPROPNAME]; 333 const char badver[] = "OBP 4.27."; 334 335 336 void 337 boot_ramdisk(char *ramdisk_name) 338 { 339 char *fth_buf; 340 size_t buf_size; 341 struct ramdisk_attr *rdp; 342 void do_sg_go(void); 343 344 /* 345 * OBP revs 4.27.0 to 4.27.8 started using 346 * windowed regs for the forth kernel, but 347 * init-program still blindly 0'd %cwp, which 348 * causes predictably disaterous consequences 349 * when called with %cwp != 0. 350 * 351 * We detect and fix this here 352 */ 353 if (prom_version_name(obpver, OBP_MAXPROPNAME) != -1 && 354 strncmp(obpver, badver, sizeof (badver) - 1) == 0) { 355 char ch = obpver[sizeof (badver) - 1]; 356 357 if (ch >= '0' && ch <= '8') { 358 prom_interpret(obpfix, 0, 0, 0, 0, 0); 359 } 360 } 361 362 /* close all open devices */ 363 closeall(1); 364 365 /* 366 * lookup ramdisk name. 367 */ 368 if ((rdp = ramdisk_lookup(ramdisk_name)) == NULL) 369 prom_panic("invalid ramdisk name"); 370 371 /* 372 * add some space to the size to accommodate a few words in the 373 * snprintf() below. 374 */ 375 buf_size = sizeof (ramdisk_bootable) + 80; 376 377 fth_buf = bkmem_alloc(buf_size); 378 if (fth_buf == NULL) 379 prom_panic("unable to allocate Forth buffer for ramdisk"); 380 381 (void) snprintf(fth_buf, buf_size, ramdisk_bootable, 382 ramdisk_name, rdp->rd_base); 383 384 prom_interpret(fth_buf, 0, 0, 0, 0, 0); 385 386 /* 387 * Ugh Serengeti proms don't execute C programs 388 * in init-program, and 'go' doesn't work when 389 * launching a second C program (inetboot itself 390 * was launched as the 1st C program). Nested fcode 391 * programs work, but that doesn't help the kernel. 392 */ 393 do_sg_go(); 394 } 395 396 void 397 do_sg_go() 398 { 399 pnode_t chosen = prom_chosennode(); 400 Elf64_Ehdr *ehdr; 401 Elf64_Addr entry; 402 uint32_t eadr; 403 extern int is_sg; 404 extern caddr_t sg_addr; 405 extern size_t sg_len; 406 407 if (!is_sg) 408 prom_panic("do_sg_go"); 409 410 /* 411 * The ramdisk bootblk left a pointer to the elf image 412 * in 'elfheader-address' Use it to find the kernel's 413 * entry point. 414 */ 415 if (prom_getprop(chosen, "elfheader-address", (caddr_t)&eadr) == -1) 416 prom_panic("no elf header property"); 417 ehdr = (Elf64_Ehdr *)(uintptr_t)eadr; 418 if (ehdr->e_machine != EM_SPARCV9) 419 prom_panic("bad ELF header"); 420 entry = ehdr->e_entry; 421 422 /* 423 * free extra bootmem 424 */ 425 prom_free(sg_addr, sg_len); 426 427 /* 428 * Use pre-newboot's exitto64() to launch the kernel 429 */ 430 exitto64((int (*)())entry, NULL); 431 prom_panic("exitto returned"); 432 } 433