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