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