xref: /titanic_50/usr/src/psm/stand/boot/sparc/common/ramdisk.c (revision 18c2aff776a775d34a4c9893a4c72e0434d68e36)
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