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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/param.h> 30 #include <sys/promif.h> 31 #include <sys/salib.h> 32 /* EXPORT DELETE START */ 33 #include <bootlog.h> 34 /* EXPORT DELETE END */ 35 #include "ramdisk.h" 36 37 /* 38 * This is a chunk of Forth delivered by the OBP group. When loaded 39 * into OBP it creates a ramdisk device node whose functionality is 40 * defined in FWARC 2002/299. 41 * 42 * Note the %s in the line following " new-device" - this is where we 43 * plug the name of the node in. 44 */ 45 static const char ramdisk_fth[] = 46 47 "headerless " 48 49 "\" /\" find-package 0= if" 50 " .\" Can't find /\" abort " 51 "then push-package " 52 53 "new-device" 54 " \" %s\" device-name" 55 " \" block\" encode-string \" device_type\" property" 56 /* CSTYLED */ 57 " \" SUNW,ramdisk\" encode-string \" compatible\" property" 58 59 " hex" 60 61 " headerless" 62 63 " 0 value mmu-ihandle" 64 " 0 value mem-ihandle" 65 66 " : get-memory-ihandles" /* ( -- ) */ 67 " \" /chosen\" find-package drop dup \" mmu\" rot" 68 " get-package-property if" 69 " .\" Can't find chosen mmu property\" cr abort" 70 " then" 71 " decode-int to mmu-ihandle 2drop" 72 " \" memory\" rot get-package-property if" 73 " .\" Can't find chosen memory property\" cr abort" 74 " then" 75 " decode-int to mem-ihandle 2drop" 76 " ;" 77 78 " : get-page-size" /* ( -- page-size ) */ 79 " mmu-ihandle ihandle>phandle \" page-size\" rot get-package-property" 80 " if h# 2000 else decode-int nip nip then " 81 " ;" 82 83 " : get-mode" /* ( -- rw-mode ) */ 84 " here \" translate\" mmu-ihandle $call-method if" 85 " nip nip" 86 " else" 87 " h# 27" 88 " then" 89 " ;" 90 91 " : 64>32bit-phys" /* ( 64bit.lo 64bit.hi -- 32bit.lo 32bit.hi ) */ 92 " drop xlsplit" 93 " ;" 94 95 " : 32>64bit-phys" /* ( 32bit.lo 32bit.hi -- 64bit.lo 64bit.hi ) */ 96 " lxjoin 0" 97 " ;" 98 99 " : phy-claim" /* ( size align -- base.lo base.hi 0 | error ) */ 100 " \" claim\" mem-ihandle ['] $call-method catch if" 101 " drop 2drop 2drop -1" 102 " else" 103 " 64>32bit-phys 0" 104 " then" 105 " ;" 106 107 " : phy-release" /* ( phys.lo phys.hi size -- ) */ 108 " >r 32>64bit-phys r> \" release\" mem-ihandle $call-method" 109 " ;" 110 111 " : vir-claim" /* ( [ virt ] size align -- base ) */ 112 " \" claim\" mmu-ihandle $call-method" 113 " ;" 114 115 " : vir-release" /* ( virt size -- ) */ 116 " \" release\" mmu-ihandle $call-method" 117 " ;" 118 119 " : vir-map" /* ( phys-lo phys-hi virt size mode -- ) */ 120 " >r >r >r 32>64bit-phys r> r> r>" 121 " \" map\" mmu-ihandle $call-method" 122 " ;" 123 124 " : vir-unmap" /* ( virt size -- ) */ 125 " \" unmap\" mmu-ihandle $call-method" 126 " ;" 127 " headers" 128 129 /* \ This structure represents a physical "chunk" of ramdisk memory */ 130 " struct" 131 " /l field >res-pa.lo" /* \ lower 32bits of physical address */ 132 " /l field >res-pa.hi" /* \ upper 32bits of physical address */ 133 " /l field >res-len.lo" /* \ lower 32bits of chunk size */ 134 " /l field >res-len.hi" /* \ upper 32bits of chunk size */ 135 " constant /res-entry" 136 137 " 4 value max-res-entries" /* \ Max # of non-contig phys chunks */ 138 139 " max-res-entries /res-entry *" /* \ size of resource buffer */ 140 " ( value ) buffer: my-resources" /* \ resource buffer label */ 141 " 0 value num-res-entries" /* \ current # of chunks allocated */ 142 " h# 10 constant label-size" /* \ size of disk-label buffer */ 143 " label-size instance buffer: my-label" /* \ for disk-label argument string */ 144 145 " get-memory-ihandles" /* \ So we can claim/map/free memory */ 146 " get-page-size value pagesize" /* \ get virt pagesize from vmem node */ 147 " get-mode value mode" /* \ get mode to map virt memory with */ 148 149 " 0 instance value window-mapped?" /* \ just in case for pa's near 0 */ 150 " 0 instance value window-pa" /* \ physical base of virtual window */ 151 " 0 instance value window-base" /* \ virtual window base */ 152 " h# 10000 constant window-size" /* \ virtual window size */ 153 154 " 0 instance value filepos" /* \ file position marker */ 155 " -1 value new-disk?" /* \ need to alloc new resources? */ 156 157 " 0 instance value offset-low" /* \ Offset to start of partition */ 158 " 0 instance value offset-high" /* \ For partition relative seeks */ 159 " 0 instance value label-package" /* \ ihandle for disk-label package */ 160 161 " external" /* \ Because device_type = block */ 162 163 " 0 value size" /* \ size of disk */ 164 " 0 value #blocks" /* \ size of disk / decimal 512 */ 165 166 " headerless" 167 168 " : round-up" /* ( n -- n' ) */ 169 " 1- tuck + swap invert and" 170 " ;" 171 172 " : init-label-package" /* ( adr len -- okay? ) */ 173 " 0 to offset-high 0 to offset-low" 174 " \" disk-label\" $open-package to label-package" 175 " label-package if" 176 " 0 0 \" offset\" label-package $call-method" 177 " to offset-high to offset-low" 178 " true" 179 " else" 180 " .\" Can't open disk label package\" cr false" 181 " then" 182 " ;" 183 184 " : res-entry-len" /* ( n -- 64bit-len | 0 ) \ Get length of chunk n */ 185 " dup num-res-entries > if" 186 " drop 0" 187 " else" 188 " /res-entry * my-resources +" 189 " dup >res-len.lo l@ swap >res-len.hi l@" 190 " lxjoin" 191 " then" 192 " ;" 193 194 " : res-entry-pa" /* ( n -- 64bit-pa | 0 ) \ Get phys address of chunk n */ 195 " dup num-res-entries > if" /* ( n ) */ 196 " drop 0" /* ( 0 ) */ 197 " else" /* ( n ) */ 198 " /res-entry * my-resources +" /* ( chunk-adr ) */ 199 " dup >res-pa.lo l@ swap >res-pa.hi l@" /* ( pa.lo pa.hi ) */ 200 " lxjoin" /* ( 64bit-pa ) */ 201 " then" /* ( 64bit-pa ) */ 202 " ;" 203 204 " : claim-window" /* ( -- ) \ Claim mem for virt window */ 205 " window-size pagesize vir-claim to window-base" 206 " ;" 207 208 " : release-window" /* ( -- ) \ Free virt window memory */ 209 " window-base window-size" 210 " 2dup vir-unmap" 211 " vir-release" 212 " ;" 213 214 " : map-window" /* ( 64bit-pa -- ) \ Map a physical address to the v-window */ 215 " dup to window-pa" 216 " xlsplit window-base window-size mode vir-map" 217 " -1 to window-mapped?" 218 " ;" 219 220 " : unmap-window" /* ( -- ) \ Unmap the virtual window */ 221 " window-base window-size vir-unmap" 222 " 0 to window-mapped?" 223 " ;" 224 225 " : in-window?" /* ( pa -- in-window? ) */ 226 " window-mapped? if" 227 " window-pa dup window-size + 1- between" 228 " else" 229 " drop 0" 230 " then" 231 " ;" 232 233 " : window-left" /* ( offset -- space-left-in-window ) */ 234 " window-size mod" 235 " window-size swap -" 236 " ;" 237 238 " : release-resources" /* ( -- ) \ release previously claimed phys addrs */ 239 " num-res-entries 0 2dup = if" /* ( res-entries 0 ) */ 240 " 2drop exit" /* ( ) */ 241 " then" /* ( res-entries 0 ) */ 242 " do" /* ( ) */ 243 " i res-entry-pa xlsplit" /* ( pa.lo pa.hi ) */ 244 " i res-entry-len phy-release" /* ( ) */ 245 " loop" /* ( ) */ 246 " 0 to num-res-entries" /* ( ) */ 247 " my-resources max-res-entries /res-entry * erase" /* ( ) */ 248 " ;" 249 250 " : fill-entry" /* ( pa.lo pa.hi size.lo size.hi -- ) \ fill chunk buf */ 251 " num-res-entries /res-entry * my-resources +" 252 " tuck >res-len.hi l!" 253 " tuck >res-len.lo l!" 254 " tuck >res-pa.hi l!" 255 " >res-pa.lo l!" 256 " num-res-entries 1+ to num-res-entries" 257 " ;" 258 259 /* \ First attempt to claim the whole ramdisk contiguously. */ 260 /* \ If that doesn't work, try to claim it in smaller chunks */ 261 262 " : attempt-claim" /* ( size -- error? ) */ 263 " size 0 begin" /* ( next totcl ) */ 264 " over pagesize phy-claim if" /* ( next totcl ) */ 265 " swap 2 / window-size" /* ( totcl next' ) */ 266 " round-up swap" /* ( next' totcl ) */ 267 " else" /* ( next totcl pa.lo,hi ) */ 268 " 2over drop xlsplit" /* ( next totcl pa.lo,hi len.lo,hi ) */ 269 " fill-entry" /* ( next totcl ) */ 270 " over +" /* ( next totcl ) */ 271 " then" /* ( next totcl ) */ 272 " 2dup size - 0>=" /* ( next totcl next comp? ) */ 273 " swap size max-res-entries /" /* ( next totcl comp? next smallest ) */ 274 " - 0< or" /* ( next totcl ) */ 275 " until" /* ( next totcl ) */ 276 " nip size - 0< if -1 else 0 then" 277 " ;" 278 279 " : claim-resources" /* ( -- error? ) */ 280 " attempt-claim if release-resources -1 else 0 then" 281 " ;" 282 283 /* \ Given a 0-relative disk offset compute the proper physical address */ 284 " : offset>pa" /* ( disk-offset -- 64bit-pa error? ) */ 285 " 0 num-res-entries 0 do" /* ( disk-offset 0 ) */ 286 " i res-entry-len +" /* ( disk-offset len' ) */ 287 " 2dup - 0< if" /* ( disk-offset len' ) */ 288 " - i res-entry-len +" /* ( offset-into-pa ) \ briefly -ve */ 289 " i res-entry-pa + 0" /* ( pa 0 ) */ 290 " unloop exit" /* ( pa 0 ) */ 291 " then" /* ( disk-offset len' ) */ 292 " loop" /* ( disk-offset len' ) */ 293 " drop -1" /* ( offset error ) */ 294 " ;" 295 296 /* \ Map the virtual window to the physical-address corresponding to the */ 297 /* \ given 0-relative disk offset */ 298 " : get-window" /* ( offset -- va len error? ) */ 299 " dup offset>pa if" /* ( offset pa ) */ 300 " -1" /* ( offset pa -1 ) */ 301 " else" /* ( offset pa ) */ 302 " dup in-window? 0= if" /* ( offset pa ) */ 303 " unmap-window" /* ( offset pa ) */ 304 " over window-size mod - map-window" /* ( offset ) */ 305 " else" 306 " drop" 307 " then" 308 " window-base over window-size mod +" /* ( offset va ) */ 309 " swap window-left 0" /* ( va len 0 ) */ 310 " then" /* ( va len error? ) */ 311 " ;" 312 313 " headers" 314 315 /* \ Write len1 bytes from src into va. */ 316 " : partial-write" /* ( src len0 va len1 -- len' ) */ 317 " rot min dup >r move r>" 318 " ;" 319 320 /* \ Read len1 bytes from src into va. */ 321 " : partial-read" /* ( src len0 va len1 -- len' ) */ 322 " rot min dup >r >r swap r> move r>" 323 " ;" 324 325 " defer operation ' partial-write is operation" 326 327 /* \ Write or Read len given the src address. The block-operation word */ 328 /* \ determines the physical address that corresponds to the current file */ 329 /* \ position, and maps/unmaps the 64K virtual window */ 330 " : block-operation" /* ( src len acf -- len' ) */ 331 " is operation" 332 " 0 -rot begin" /* ( 0 src len ) */ 333 " dup 0>" /* ( len' src len more? ) */ 334 " while" /* ( len' src len ) */ 335 " 2dup filepos" /* ( len' src len src len filepos ) */ 336 " get-window if" /* ( len' src len src len va len ) */ 337 " 2drop 2drop 2drop exit" /* ( len' ) */ 338 " then" /* ( len src len src len va len ) */ 339 " operation" /* ( len src len len' ) */ 340 " dup filepos + to filepos" /* ( len src len len' ) */ 341 " >r r@ - rot r@ + rot r> + rot" /* ( len' src' len' ) */ 342 " repeat" /* ( len' src' len' ) */ 343 " 2drop" /* ( len' ) */ 344 " ;" 345 346 " : range-bad?" /* ( adr -- range-bad? ) */ 347 " 0 size between 0=" 348 " ;" 349 350 " : space-left" /* ( -- space-left ) */ 351 " size filepos -" 352 " ;" 353 354 " : hex-number" /* ( adr,len -- true | n false ) */ 355 " base @ >r hex $number r> base !" 356 " ;" 357 358 " : parse-size" /* ( $nums -- 64bit-size | 0 ) \ poss ',' seperated ints */ 359 " ascii , left-parse-string" /* ( $num $num ) */ 360 " hex-number if 2drop 0 exit then" /* ( $num n ) */ 361 " over 0= if nip nip exit then" /* ( $num n ) */ 362 " -rot hex-number if drop 0 exit then" /* ( hi lo ) */ 363 " swap lxjoin" 364 " ;" 365 366 " : set-size" /* ( adr len -- error? ) */ 367 " parse-size dup 0= if" /* ( size ) */ 368 " drop -1" /* ( -1 ) */ 369 " else" /* ( size ) */ 370 " window-size round-up" /* ( size' ) */ 371 " dup to size" /* ( size' ) */ 372 " d# 512 / to #blocks" /* ( ) */ 373 " \" nolabel\" my-label pack" /* \ first open cannot have a label */ 374 " drop 0" /* ( 0 ) */ 375 " then" /* ( error? ) */ 376 " ;" 377 378 " : $=" /* (s adr1 len1 adr2 len2 -- same? ) */ 379 " rot tuck <> if 3drop false exit then" /* ( adr1 adr2 len1 ) */ 380 " comp 0=" /* ( same? ) */ 381 " ;" 382 383 " : is-label?" /* ( adr len -- is-label? ) \ $= "nolabel" or <a-z> */ 384 " dup 1 = if" /* ( adr len ) */ 385 " drop c@ ascii a ascii z between" /* ( is-label? ) */ 386 " else" /* ( adr len ) */ 387 " \" nolabel\" $=" /* ( is-label? ) */ 388 " then" /* ( is-label? ) */ 389 " ;" 390 391 " : set-label" /* ( adr len -- error? ) */ 392 " my-label label-size erase" 393 " dup 1+ label-size > if" 394 " 2drop -1" 395 " else" 396 " my-label pack drop 0" 397 " then" 398 " ;" 399 400 " : process-args" /* ( arg$ -- error? ) */ 401 " ascii = left-parse-string" /* ( value$ key$ ) */ 402 " new-disk? if" /* ( value$ key$ ) */ 403 " 2dup \" size\" $= if" /* ( value$ key$ ) */ 404 " 2drop set-size exit" /* ( error? ) */ 405 " then" /* ( value$ key$ ) */ 406 " else" /* ( value$ key$ ) */ 407 " 2dup is-label? if" /* ( value$ key$ ) */ 408 " 2swap 2drop set-label exit" /* ( error? ) */ 409 " then" /* ( value$ key$ ) */ 410 " then" /* ( value$ key$ ) */ 411 " .\" Inappropriate argument \" type cr 2drop -1" /* ( -1 ) */ 412 " ;" 413 414 /* \ Publish the physical chunks that make up the ramdisk in the */ 415 /* \ existing property */ 416 " : create-existing-prop" /* ( -- ) */ 417 " 0 0 encode-bytes" /* ( adr 0 ) */ 418 " num-res-entries 0 do" /* ( adr 0 ) */ 419 " i /res-entry * my-resources + >r" /* ( adr len ) */ 420 " r@ >res-pa.hi l@ encode-int encode+" /* ( adr len ) */ 421 " r@ >res-pa.lo l@ encode-int encode+" /* ( adr len ) */ 422 " r@ >res-len.hi l@ encode-int encode+" /* ( adr len ) */ 423 " r> >res-len.lo l@ encode-int encode+" /* ( adr len ) */ 424 " loop" /* ( adr len ) */ 425 " \" existing\" property" /* ( ) */ 426 " ;" 427 428 " external" 429 430 " : read" /* ( adr,len -- len' ) */ 431 " space-left" /* ( adr len space-left ) */ 432 " min ['] partial-read" /* ( adr len' read-acf ) */ 433 " block-operation" /* ( len' ) */ 434 " ;" 435 436 " : write" /* ( adr,len -- len' ) */ 437 " space-left" /* ( adr len space-left ) */ 438 " min ['] partial-write" /* ( adr len' write-acf ) */ 439 " block-operation" /* ( len' ) */ 440 " ;" 441 442 " : seek" /* ( offset other -- error? ) */ 443 " offset-high + swap offset-low + swap drop" /* \ "other" arg unused */ 444 " dup 0< if" /* ( offset ) */ 445 " size +" /* ( offset' ) */ 446 " then" /* ( offset' ) */ 447 " 0 + dup range-bad? if" /* ( offset' ) */ 448 " drop -1" /* ( -1 ) */ 449 " else" /* ( offset' ) */ 450 " to filepos false" /* ( 0 ) */ 451 " then" /* ( error? ) */ 452 " ;" 453 454 " : load" /* ( addr -- size ) */ 455 " \" load\" label-package $call-method" 456 " ;" 457 458 " : offset" /* ( rel -- abs ) \ needed for device_type = block */ 459 " offset-low +" 460 " ;" 461 462 /* \ release resources, initialize data, remove existing property */ 463 /* \ Can be called with no instance data */ 464 " : destroy" /* ( -- ) */ 465 " \" existing\" delete-property" 466 " 0 to size" 467 " -1 to new-disk?" 468 " release-resources" 469 " ;" 470 471 " : open" /* ( -- flag ) */ 472 " my-args process-args if" 473 " 0 exit" /* \ unrecognized arguments */ 474 " then" 475 " new-disk? if" 476 " claim-resources if 0 exit then" /* \ can't claim */ 477 " create-existing-prop" /* \ advertise resources */ 478 " 0 to new-disk?" /* \ no longer a new-disk */ 479 " then" 480 " claim-window" /* \ claim virtual window */ 481 " my-label count init-label-package 0= if 0 exit then" 482 " -1" 483 " ;" 484 485 " : close" /* ( -- ) */ 486 " window-base if " 487 " release-window" 488 " then" 489 " ; " 490 "finish-device " 491 492 "pop-package" 493 494 ; /* end of ramdisk_fth[] initialization */ 495 496 497 /* 498 * Create an actual ramdisk instance. 499 */ 500 static void 501 create_ramdisk_node(const char *ramdisk_name) 502 { 503 char *fth_buf; 504 size_t buf_size; 505 506 buf_size = sizeof (ramdisk_fth) + strlen(ramdisk_name); 507 508 fth_buf = bkmem_alloc(buf_size); 509 if (fth_buf == NULL) { 510 prom_panic("unable to allocate Forth buffer for ramdisk"); 511 } 512 513 (void) snprintf(fth_buf, buf_size, ramdisk_fth, ramdisk_name); 514 515 prom_interpret(fth_buf, 0, 0, 0, 0, 0); 516 517 bkmem_free(fth_buf, buf_size); 518 } 519 520 int 521 create_ramdisk(const char *ramdisk_name, size_t size, char **device_path) 522 { 523 static int first_time = 1; 524 char buf[OBP_MAXPATHLEN]; 525 ihandle_t ih; 526 527 /* 528 * Ensure that size is a multiple of page size (rounded up). 529 */ 530 size = ptob(btopr(size)); 531 532 /* EXPORT DELETE START */ 533 bootlog("wanboot", BOOTLOG_VERBOSE, "Creating ramdisk, size=0x%lx", 534 size); 535 /* EXPORT DELETE END */ 536 537 if (strcmp(ramdisk_name, RD_ROOTFS) == 0 || 538 strcmp(ramdisk_name, RD_BOOTFS) == 0) { 539 540 if (first_time) { 541 first_time = 0; 542 543 create_ramdisk_node(RD_ROOTFS); 544 create_ramdisk_node(RD_BOOTFS); 545 } 546 547 (void) snprintf(buf, sizeof (buf), "/%s:nolabel", ramdisk_name); 548 *device_path = strdup(buf); 549 550 if (*device_path != NULL) { 551 (void) snprintf(buf, sizeof (buf), "/%s:size=%x,%x", 552 ramdisk_name, 553 (uint32_t)(size >> 32), (uint32_t)size); 554 555 if ((ih = prom_open(buf)) != 0) { 556 return (ih); 557 } 558 } 559 } 560 561 /* EXPORT DELETE START */ 562 bootlog("wanboot", BOOTLOG_CRIT, "Cannot create ramdisk \"%s\"", 563 ramdisk_name); 564 /* EXPORT DELETE END */ 565 prom_panic("create_ramdisk: fatal error"); 566 /* NOTREACHED */ 567 } 568