Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / slof / fs / packages / disk-label.fs
1 \ *****************************************************************************
2 \ * Copyright (c) 2004, 2008 IBM Corporation
3 \ * All rights reserved.
4 \ * This program and the accompanying materials
5 \ * are made available under the terms of the BSD License
6 \ * which accompanies this distribution, and is available at
7 \ * http://www.opensource.org/licenses/bsd-license.php
8 \ *
9 \ * Contributors:
10 \ *     IBM Corporation - initial implementation
11 \ ****************************************************************************/
12
13
14 \ Set debug-disk-label? to true to get debug messages for the disk-label code.
15 false VALUE debug-disk-label?
16
17 \ This value defines the maximum number of blocks (512b) to load from a PREP
18 \ partition. This is required to keep the load time in reasonable limits if the
19 \ PREP partition becomes big.
20 \ If we ever want to put a large kernel with initramfs from a PREP partition
21 \ we might need to increase this value. The default value is 65536 blocks (32MB)
22 d# 65536 value max-prep-partition-blocks
23
24 s" disk-label" device-name
25
26 0 INSTANCE VALUE partition
27 0 INSTANCE VALUE part-offset
28 0 INSTANCE VALUE disk-chrp-boot
29
30 0 INSTANCE VALUE part-start
31 0 INSTANCE VALUE lpart-start
32 0 INSTANCE VALUE part-size
33 0 INSTANCE VALUE dos-logical-partitions
34
35 0 INSTANCE VALUE block-size
36 0 INSTANCE VALUE block
37
38 0 INSTANCE VALUE args
39 0 INSTANCE VALUE args-len
40
41 0 INSTANCE VALUE gpt-part-size
42 0 INSTANCE VALUE seek-pos
43
44
45 INSTANCE VARIABLE block#  \ variable to store logical sector#
46 INSTANCE VARIABLE hit#    \ partition counter
47 INSTANCE VARIABLE success-flag
48
49 \ ISO9660 specific information
50 0ff constant END-OF-DESC
51 3 constant  PARTITION-ID
52 48 constant VOL-PART-LOC
53
54
55 \ DOS partition label (MBR) specific structures
56
57 STRUCT
58        1b8 field mbr>boot-loader
59         /l field mbr>disk-signature
60         /w field mbr>null
61         40 field mbr>partition-table
62         /w field mbr>magic
63
64 CONSTANT /mbr
65
66 STRUCT
67         /c field part-entry>active
68         /c field part-entry>start-head
69         /c field part-entry>start-sect
70         /c field part-entry>start-cyl
71         /c field part-entry>id
72         /c field part-entry>end-head
73         /c field part-entry>end-sect
74         /c field part-entry>end-cyl
75         /l field part-entry>sector-offset
76         /l field part-entry>sector-count
77
78 CONSTANT /partition-entry
79
80 STRUCT
81         8 field gpt>signature
82         4 field gpt>revision
83         4 field gpt>header-size
84         4 field gpt>header-crc32
85         4 field gpt>reserved
86         8 field gpt>current-lba
87         8 field gpt>backup-lba
88         8 field gpt>first-lba
89         8 field gpt>last-lba
90        10 field gpt>disk-guid
91         8 field gpt>part-entry-lba
92         4 field gpt>num-part-entry
93         4 field gpt>part-entry-size
94         4 field gpt>part-array-crc32
95       1a4 field gpt>reserved
96
97 CONSTANT /gpt-header
98
99 STRUCT
100        10 field gpt-part-entry>part-type-guid
101        10 field gpt-part-entry>part-guid
102         8 field gpt-part-entry>first-lba
103         8 field gpt-part-entry>last-lba
104         8 field gpt-part-entry>attribute
105        48 field gpt-part-entry>part-name
106
107 CONSTANT /gpt-part-entry
108
109 \ Defined by IEEE 1275-1994 (3.8.1)
110
111 : offset ( d.rel -- d.abs )
112    part-offset xlsplit d+
113 ;
114
115 : seek  ( pos.lo pos.hi -- status )
116    offset
117    debug-disk-label? IF 2dup ." seek-parent: pos.hi=0x" u. ." pos.lo=0x" u. THEN
118    s" seek" $call-parent
119    debug-disk-label? IF dup ." status=" . cr THEN
120 ;
121
122 : read ( addr len -- actual )
123    debug-disk-label? IF 2dup swap ." read-parent: addr=0x" u. ." len=" .d THEN
124    s" read" $call-parent
125    debug-disk-label? IF dup ." actual=" .d cr THEN
126 ;
127
128
129 \ read sector to array "block"
130 : read-sector ( sector-number -- )
131    \ block-size is 0x200 on disks, 0x800 on cdrom drives
132    block-size * 0 seek drop      \ seek to sector
133    block block-size read drop    \ read sector
134 ;
135
136 : (.part-entry) ( part-entry )
137    cr ." part-entry>active:        " dup part-entry>active c@ .d
138    cr ." part-entry>start-head:    " dup part-entry>start-head c@ .d
139    cr ." part-entry>start-sect:    " dup part-entry>start-sect c@ .d
140    cr ." part-entry>start-cyl:     " dup part-entry>start-cyl  c@ .d
141    cr ." part-entry>id:            " dup part-entry>id c@ .d
142    cr ." part-entry>end-head:      " dup part-entry>end-head c@ .d
143    cr ." part-entry>end-sect:      " dup part-entry>end-sect c@ .d
144    cr ." part-entry>end-cyl:       " dup part-entry>end-cyl c@ .d
145    cr ." part-entry>sector-offset: " dup part-entry>sector-offset l@-le .d
146    cr ." part-entry>sector-count:  " dup part-entry>sector-count l@-le .d
147    cr
148 ;
149
150 : (.name) r@ begin cell - dup @ <colon> = UNTIL xt>name cr type space ;
151
152 : init-block ( -- )
153    s" block-size" ['] $call-parent CATCH IF ABORT" parent has no block-size." THEN
154    to block-size
155    d# 4096 alloc-mem
156    dup d# 4096 erase
157    to block
158    debug-disk-label? IF
159       ." init-block: block-size=" block-size .d ." block=0x" block u. cr
160    THEN
161 ;
162
163 : partition>part-entry ( partition -- part-entry )
164    1- /partition-entry * block mbr>partition-table +
165 ;
166
167 : partition>start-sector ( partition -- sector-offset )
168    partition>part-entry part-entry>sector-offset l@-le
169 ;
170
171 \ This word returns true if the currently loaded block has _NO_ MBR magic
172 : no-mbr? ( -- true|false )
173    0 read-sector
174    1 partition>part-entry part-entry>id c@ ee = IF TRUE EXIT THEN \ GPT partition found
175    block mbr>magic w@-le aa55 <>
176 ;
177
178 \ This word returns true if the currently loaded block has _NO_ GPT partition id
179 : no-gpt? ( -- true|false )
180    0 read-sector
181    1 partition>part-entry part-entry>id c@ ee <>
182 ;
183
184 : pc-extended-partition? ( part-entry-addr -- true|false )
185    part-entry>id c@      ( id )
186    dup 5 = swap          ( true|false id )
187    dup f = swap          ( true|false true|false id )
188    85 =                  ( true|false true|false true|false )
189    or or                 ( true|false )
190 ;
191
192 : count-dos-logical-partitions ( -- #logical-partitions )
193    no-mbr? IF 0 EXIT THEN
194    0 5 1 DO                                ( current )
195       i partition>part-entry               ( current part-entry )
196       dup pc-extended-partition? IF
197          part-entry>sector-offset l@-le    ( current sector )
198          dup to part-start to lpart-start  ( current )
199          BEGIN
200             part-start read-sector          \ read EBR
201             1 partition>start-sector IF
202                \ ." Logical Partition found at " part-start .d cr
203                1+
204             THEN \ another logical partition
205             2 partition>start-sector
206             ( current relative-sector )
207             ?dup IF lpart-start + to part-start false ELSE true THEN
208          UNTIL
209       ELSE
210          drop
211       THEN
212    LOOP
213 ;
214
215 : (get-dos-partition-params) ( ext-part-start part-entry -- offset count active? id )
216    dup part-entry>sector-offset l@-le rot + swap ( offset part-entry )
217    dup part-entry>sector-count l@-le swap        ( offset count part-entry )
218    dup part-entry>active c@ 80 = swap            ( offset count active? part-entry )
219    part-entry>id c@                              ( offset count active? id )
220 ;
221
222 : find-dos-partition ( partition# -- false | offset count active? id true )
223    to partition 0 to part-start 0 to part-offset
224
225    \ no negative partitions
226    partition 0<= IF 0 to partition false EXIT THEN
227
228    \ load MBR and check it
229    no-mbr? IF 0 to partition false EXIT THEN
230
231    partition 4 <= IF \ Is this a primary partition?
232       0 partition partition>part-entry
233       (get-dos-partition-params)
234       \ FIXME sanity checks?
235       true EXIT
236    ELSE
237       partition 4 - 0 5 1 DO                      ( logical-partition current )
238          i partition>part-entry                   ( log-part current part-entry )
239          dup pc-extended-partition? IF
240             part-entry>sector-offset l@-le        ( log-part current sector )
241             dup to part-start to lpart-start      ( log-part current )
242             BEGIN
243                part-start read-sector             \ read EBR
244                1 partition>start-sector IF        \ first partition entry
245                   1+ 2dup = IF                    ( log-part current )
246                      2drop
247                      part-start 1 partition>part-entry
248                      (get-dos-partition-params)
249                      true UNLOOP EXIT
250                   THEN
251                   2 partition>start-sector
252                   ( log-part current relative-sector )
253
254                   ?dup IF lpart-start + to part-start false ELSE true THEN
255                ELSE
256                   true
257                THEN
258             UNTIL
259          ELSE
260             drop
261          THEN
262       LOOP
263       2drop false
264    THEN
265 ;
266
267 : try-dos-partition ( -- okay? )
268    \ Read partition table and check magic.
269    no-mbr? IF cr ." No DOS disk-label found." cr false EXIT THEN
270
271    count-dos-logical-partitions TO dos-logical-partitions
272
273    debug-disk-label? IF
274       ." Found " dos-logical-partitions .d ." logical partitions" cr
275       ." Partition = " partition .d cr
276    THEN
277
278    partition 1 5 dos-logical-partitions +
279    within 0= IF
280       cr ." Partition # not 1-" 4 dos-logical-partitions + . cr false EXIT
281    THEN
282
283    \ Could/should check for valid partition here...  the magic is not enough really.
284
285    \ Get the partition offset.
286
287    partition find-dos-partition IF
288      ( offset count active? id )
289      2drop
290      to part-size
291      block-size * to part-offset
292      true
293    ELSE
294      false
295    THEN
296 ;
297
298 \ Check for an ISO-9660 filesystem on the disk
299 \ : try-iso9660-partition ( -- true|false )
300 \ implement me if you can ;-)
301 \ ;
302
303
304 \ Check for an ISO-9660 filesystem on the disk
305 \ (cf. CHRP IEEE 1275 spec., chapter 11.1.2.3)
306 : has-iso9660-filesystem  ( -- TRUE|FALSE )
307    \ Seek to the beginning of logical 2048-byte sector 16
308    \ refer to Chapter C.11.1 in PAPR 2.0 Spec
309    \ was: 10 read-sector, but this might cause trouble if you
310    \ try booting an ISO image from a device with 512b sectors.
311    10 800 * 0 seek drop      \ seek to sector
312    block 800 read drop       \ read sector
313    \ Check for CD-ROM volume magic:
314    block c@ 1 =
315    block 1+ 5 s" CD001"  str=
316    and
317    dup IF 800 to block-size THEN
318 ;
319
320
321 \ Load from first active DOS boot partition.
322
323 \ NOTE: block-size is always 512 bytes for DOS partition tables.
324
325 : load-from-dos-boot-partition ( addr -- size )
326    no-mbr? IF drop FALSE EXIT THEN  \ read MBR and check for DOS disk-label magic
327
328    count-dos-logical-partitions TO dos-logical-partitions
329
330    debug-disk-label? IF
331       ." Found " dos-logical-partitions .d ." logical partitions" cr
332       ." Partition = " partition .d cr
333    THEN
334
335    \ Now walk through the partitions:
336    5 dos-logical-partitions + 1 DO
337       \ ." checking partition " i .
338       i find-dos-partition IF        ( addr offset count active? id )
339          41 = and                    ( addr offset count prep-boot-part? )
340          IF                          ( addr offset count )
341             max-prep-partition-blocks min  \ reduce load size
342             swap                     ( addr count offset )
343             block-size * to part-offset
344             0 0 seek drop            ( addr offset )
345             block-size * read        ( size )
346             UNLOOP EXIT
347          ELSE
348             2drop                    ( addr )
349          THEN
350       THEN
351    LOOP
352    drop 0
353 ;
354
355 \ Check for GPT PReP partition GUID
356 9E1A2D38     CONSTANT GPT-PREP-PARTITION-1
357 C612         CONSTANT GPT-PREP-PARTITION-2
358 4316         CONSTANT GPT-PREP-PARTITION-3
359 AA26         CONSTANT GPT-PREP-PARTITION-4
360 8B49521E5A8B CONSTANT GPT-PREP-PARTITION-5
361
362 : gpt-prep-partition? ( -- true|false )
363    block gpt-part-entry>part-type-guid l@-le GPT-PREP-PARTITION-1 = IF
364       block gpt-part-entry>part-type-guid 4 + w@-le
365       GPT-PREP-PARTITION-2 = IF
366          block gpt-part-entry>part-type-guid 6 + w@-le
367          GPT-PREP-PARTITION-3 = IF
368             block gpt-part-entry>part-type-guid 8 + w@
369             GPT-PREP-PARTITION-4 = IF
370                block gpt-part-entry>part-type-guid a + w@
371                block gpt-part-entry>part-type-guid c + l@ swap lxjoin
372                GPT-PREP-PARTITION-5 = IF
373                    TRUE EXIT
374                THEN
375             THEN
376          THEN
377       THEN
378    THEN
379    FALSE
380 ;
381
382 : load-from-gpt-prep-partition ( addr -- size )
383    no-gpt? IF drop FALSE EXIT THEN
384    debug-disk-label? IF
385       cr ." GPT partition found " cr
386    THEN
387    1 read-sector block gpt>part-entry-lba l@-le
388    block-size * to seek-pos
389    block gpt>part-entry-size l@-le to gpt-part-size
390    block gpt>num-part-entry l@-le dup 0= IF FALSE EXIT THEN
391    1+ 1 ?DO
392       seek-pos 0 seek drop
393       block gpt-part-size read drop gpt-prep-partition? IF
394          debug-disk-label? IF
395             ." GPT PReP partition found " cr
396          THEN
397          block gpt-part-entry>first-lba x@ xbflip
398          block gpt-part-entry>last-lba x@ xbflip
399          over - 1+                 ( addr offset len )
400          swap                      ( addr len offset )
401          block-size * to part-offset
402          0 0 seek drop             ( addr len )
403          block-size * read         ( size )
404          UNLOOP EXIT
405       THEN
406       seek-pos gpt-part-size i * + to seek-pos
407    LOOP
408    FALSE
409 ;
410
411 \ Extract the boot loader path from a bootinfo.txt file
412 \ In: address and length of buffer where the bootinfo.txt has been loaded to.
413 \ Out: string address and length of the boot loader (within the input buffer)
414 \      or a string with length = 0 when parsing failed.
415
416 \ Here is a sample bootinfo file:
417 \ <chrp-boot>
418 \   <description>Linux Distribution</description>
419 \   <os-name>Linux</os-name>
420 \   <boot-script>boot &device;:1,\boot\yaboot.ibm</boot-script>
421 \   <icon size=64,64 color-space=3,3,2>
422 \     <bitmap>[..]</bitmap>
423 \   </icon>
424 \ </chrp-boot>
425
426 : parse-bootinfo-txt  ( addr len -- str len )
427    2dup s" <boot-script>" find-substr       ( addr len pos1 )
428    2dup = IF
429       \ String not found
430       3drop 0 0 EXIT
431    THEN
432    dup >r - swap r> + swap                  ( addr1 len1 )
433
434    2dup s" &device;:" find-substr           ( addr1 len1 posdev )
435    2dup = IF
436       3drop 0 0 EXIT
437    THEN
438    9 +                                      \ Skip the "&device;:" string
439    dup >r - swap r> + swap                  ( addr2 len2 )
440    2dup s" </boot-script>" find-substr nip  ( addr2 len3 )
441
442    debug-disk-label? IF
443       ." Extracted boot loader from bootinfo.txt: '"
444       2dup type ." '" cr
445    THEN
446 ;
447
448 \ Try to load \ppc\bootinfo.txt from the disk (used mainly on CD-ROMs), and if
449 \ available, get the boot loader path from this file and load it.
450 \ See the "CHRP system binding to IEEE 1275" specification for more information
451 \ about bootinfo.txt. An example file can be found in the comment of
452 \ parse-bootinfo-txt ( addr len -- str len )
453
454 : load-chrp-boot-file ( addr -- size )
455    \ Create bootinfo.txt path name and load that file:
456    my-parent instance>path
457    disk-chrp-boot @ 1 = IF
458        s" :1,\ppc\bootinfo.txt" $cat strdup       ( addr str len )
459    ELSE
460        s" :\ppc\bootinfo.txt" $cat strdup       ( addr str len )
461    THEN
462    open-dev dup 0= IF 2drop 0 EXIT THEN
463    >r dup                                   ( addr addr R:ihandle )
464    dup s" load" r@ $call-method             ( addr addr size R:ihandle )
465    r> close-dev                             ( addr addr size )
466
467    \ Now parse the information from bootinfo.txt:
468    parse-bootinfo-txt                       ( addr fnstr fnlen )
469    dup 0= IF 3drop 0 EXIT THEN
470    \ Does the string contain parameters (i.e. a white space)?
471    2dup 20 findchar IF
472       ( addr fnstr fnlen offset )
473       >r 2dup r@ - 1- swap r@ + 1+ swap     ( addr fnstr fnlen pstr plen  R: offset )
474       encode-string s" bootargs" set-chosen
475       drop r>
476    THEN
477
478    \ Create the full path to the boot loader:
479    my-parent instance>path      ( addr fnstr fnlen nstr nlen )
480    s" :" $cat 2swap $cat strdup             ( addr str len )
481    \ Update the bootpath:
482    2dup encode-string s" bootpath" set-chosen
483    \ And finally load the boot loader itself:
484    open-dev dup 0= IF ." failed to load CHRP boot loader." 2drop 0 EXIT THEN
485    >r s" load" r@ $call-method              ( size R:ihandle )
486    r> close-dev                             ( size )
487 ;
488
489 \ load from a bootable partition
490 : load-from-boot-partition ( addr -- size )
491    debug-disk-label? IF ." Trying DOS boot " .s cr THEN
492    dup load-from-dos-boot-partition ?dup 0 <> IF nip EXIT THEN
493
494    debug-disk-label? IF ." Trying CHRP boot " .s cr THEN
495    1 disk-chrp-boot !
496    dup load-chrp-boot-file ?dup 0 <> IF .s cr nip EXIT THEN
497    0 disk-chrp-boot !
498
499    debug-disk-label? IF ." Trying GPT boot " .s cr THEN
500    load-from-gpt-prep-partition
501    \ More boot partition formats ...
502 ;
503
504 \ parse partition number from my-args
505
506 \ my-args has the following format
507 \ [<partition>[,<path>]]
508
509 \ | example my-args  | example boot command      |
510 \ +------------------+---------------------------+
511 \ | 1,\boot\vmlinuz  | boot disk:1,\boot\vmlinuz |
512 \ | 2                | boot disk:2               |
513
514 \ 0 means the whole disk, this is the same behavior
515 \ as if no partition is specified (yaboot wants this).
516
517 : parse-partition ( -- okay? )
518    0 to partition
519    0 to part-offset
520    0 to part-size
521
522    my-args to args-len to args
523
524    debug-disk-label? IF
525       cr ." disk-label parse-partition: my-args=" my-args type cr
526    THEN
527
528    \ Called without arguments?
529    args-len 0 = IF true EXIT THEN
530
531    \ Check for "full disk" arguments.
532    my-args [char] , findchar 0= IF \ no comma?
533       args c@ isdigit not IF       \ ... and not a partition number?
534          true EXIT                 \ ... then it's not a partition we can parse
535       THEN
536    ELSE
537       drop
538    THEN
539    my-args [char] , split to args-len to args
540    dup 0= IF 2drop true EXIT THEN \ no first argument
541
542    \ Check partition #.
543    base @ >r decimal $number r> base !
544    IF cr ." Not a partition #" false EXIT THEN
545
546    \ Store part #, done.
547    to partition
548    true
549 ;
550
551
552 \ try-files and try-partitions
553
554 : (interpose-filesystem) ( str len -- )
555    find-package IF args args-len rot interpose THEN
556 ;
557
558 : try-dos-files ( -- found? )
559    no-mbr? IF false EXIT THEN
560
561    \ block 0 byte 0-2 is a jump instruction in all FAT
562    \ filesystems.
563    \ e9 and eb are jump instructions in x86 assembler.
564    block c@ e9 <> IF
565       block c@ eb <>
566       block 2+ c@ 90 <> or
567       IF false EXIT THEN
568    THEN
569    s" fat-files" (interpose-filesystem)
570    true
571 ;
572
573 : try-ext2-files ( -- found? )
574    2 read-sector               \ read first superblock
575    block d# 56 + w@-le         \ fetch s_magic
576    ef53 <> IF false EXIT THEN  \ s_magic found?
577    s" ext2-files" (interpose-filesystem)
578    true
579 ;
580
581
582 : try-iso9660-files
583    has-iso9660-filesystem 0= IF false exit THEN
584    s" iso-9660" (interpose-filesystem)
585    true
586 ;
587
588 : try-files ( -- found? )
589    \ If no path, then full disk.
590    args-len 0= IF true EXIT THEN
591
592    try-dos-files IF true EXIT THEN
593    try-ext2-files IF true EXIT THEN
594    try-iso9660-files IF true EXIT THEN
595
596    \ ... more filesystem types here ...
597
598    false
599 ;
600
601 : try-partitions ( -- found? )
602    try-dos-partition IF try-files EXIT THEN
603    \ try-iso9660-partition IF try-files EXIT THEN
604    \ ... more partition types here...
605    false
606 ;
607
608 \ Interface functions for disk-label package
609 \ as defined by IEEE 1275-1994 3.8.1
610
611 : close ( -- )
612    debug-disk-label? IF ." Closing disk-label: block=0x" block u. ." block-size=" block-size .d cr THEN
613    block d# 4096 free-mem
614 ;
615
616
617 : open ( -- true|false )
618    init-block
619
620    parse-partition 0= IF
621       close
622       false EXIT
623    THEN
624
625    partition IF
626        try-partitions
627    ELSE
628        try-files
629    THEN
630    dup 0= IF debug-disk-label? IF ." not found." cr THEN close THEN \ free memory again
631 ;
632
633
634 \ Boot & Load w/o arguments is assumed to be boot from boot partition
635
636 : load ( addr -- size )
637    debug-disk-label? IF
638       ." load: " dup u. cr
639    THEN
640
641    args-len IF
642       TRUE ABORT" Load done w/o filesystem"
643    ELSE
644       partition IF
645          0 0 seek drop
646          part-size IF
647             part-size max-prep-partition-blocks min   \ Load size
648          ELSE
649             max-prep-partition-blocks
650          THEN
651          200 *  read
652       ELSE
653          has-iso9660-filesystem IF
654              dup load-chrp-boot-file ?dup 0 > IF nip EXIT THEN
655          THEN
656          load-from-boot-partition
657          dup 0= ABORT" No boot partition found"
658       THEN
659    THEN
660 ;