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