Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / slof / fs / packages / disk-label.fs
diff --git a/qemu/roms/SLOF/slof/fs/packages/disk-label.fs b/qemu/roms/SLOF/slof/fs/packages/disk-label.fs
new file mode 100644 (file)
index 0000000..fe1c25e
--- /dev/null
@@ -0,0 +1,660 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ *     IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ Set debug-disk-label? to true to get debug messages for the disk-label code.
+false VALUE debug-disk-label?
+
+\ This value defines the maximum number of blocks (512b) to load from a PREP
+\ partition. This is required to keep the load time in reasonable limits if the
+\ PREP partition becomes big.
+\ If we ever want to put a large kernel with initramfs from a PREP partition
+\ we might need to increase this value. The default value is 65536 blocks (32MB)
+d# 65536 value max-prep-partition-blocks
+
+s" disk-label" device-name
+
+0 INSTANCE VALUE partition
+0 INSTANCE VALUE part-offset
+0 INSTANCE VALUE disk-chrp-boot
+
+0 INSTANCE VALUE part-start
+0 INSTANCE VALUE lpart-start
+0 INSTANCE VALUE part-size
+0 INSTANCE VALUE dos-logical-partitions
+
+0 INSTANCE VALUE block-size
+0 INSTANCE VALUE block
+
+0 INSTANCE VALUE args
+0 INSTANCE VALUE args-len
+
+0 INSTANCE VALUE gpt-part-size
+0 INSTANCE VALUE seek-pos
+
+
+INSTANCE VARIABLE block#  \ variable to store logical sector#
+INSTANCE VARIABLE hit#    \ partition counter
+INSTANCE VARIABLE success-flag
+
+\ ISO9660 specific information
+0ff constant END-OF-DESC
+3 constant  PARTITION-ID
+48 constant VOL-PART-LOC
+
+
+\ DOS partition label (MBR) specific structures
+
+STRUCT
+       1b8 field mbr>boot-loader
+        /l field mbr>disk-signature
+        /w field mbr>null
+        40 field mbr>partition-table
+        /w field mbr>magic
+
+CONSTANT /mbr
+
+STRUCT
+        /c field part-entry>active
+        /c field part-entry>start-head
+        /c field part-entry>start-sect
+        /c field part-entry>start-cyl
+        /c field part-entry>id
+        /c field part-entry>end-head
+        /c field part-entry>end-sect
+        /c field part-entry>end-cyl
+        /l field part-entry>sector-offset
+        /l field part-entry>sector-count
+
+CONSTANT /partition-entry
+
+STRUCT
+        8 field gpt>signature
+        4 field gpt>revision
+        4 field gpt>header-size
+        4 field gpt>header-crc32
+        4 field gpt>reserved
+        8 field gpt>current-lba
+        8 field gpt>backup-lba
+        8 field gpt>first-lba
+        8 field gpt>last-lba
+       10 field gpt>disk-guid
+        8 field gpt>part-entry-lba
+        4 field gpt>num-part-entry
+        4 field gpt>part-entry-size
+        4 field gpt>part-array-crc32
+      1a4 field gpt>reserved
+
+CONSTANT /gpt-header
+
+STRUCT
+       10 field gpt-part-entry>part-type-guid
+       10 field gpt-part-entry>part-guid
+        8 field gpt-part-entry>first-lba
+        8 field gpt-part-entry>last-lba
+        8 field gpt-part-entry>attribute
+       48 field gpt-part-entry>part-name
+
+CONSTANT /gpt-part-entry
+
+\ Defined by IEEE 1275-1994 (3.8.1)
+
+: offset ( d.rel -- d.abs )
+   part-offset xlsplit d+
+;
+
+: seek  ( pos.lo pos.hi -- status )
+   offset
+   debug-disk-label? IF 2dup ." seek-parent: pos.hi=0x" u. ." pos.lo=0x" u. THEN
+   s" seek" $call-parent
+   debug-disk-label? IF dup ." status=" . cr THEN
+;
+
+: read ( addr len -- actual )
+   debug-disk-label? IF 2dup swap ." read-parent: addr=0x" u. ." len=" .d THEN
+   s" read" $call-parent
+   debug-disk-label? IF dup ." actual=" .d cr THEN
+;
+
+
+\ read sector to array "block"
+: read-sector ( sector-number -- )
+   \ block-size is 0x200 on disks, 0x800 on cdrom drives
+   block-size * 0 seek drop      \ seek to sector
+   block block-size read drop    \ read sector
+;
+
+: (.part-entry) ( part-entry )
+   cr ." part-entry>active:        " dup part-entry>active c@ .d
+   cr ." part-entry>start-head:    " dup part-entry>start-head c@ .d
+   cr ." part-entry>start-sect:    " dup part-entry>start-sect c@ .d
+   cr ." part-entry>start-cyl:     " dup part-entry>start-cyl  c@ .d
+   cr ." part-entry>id:            " dup part-entry>id c@ .d
+   cr ." part-entry>end-head:      " dup part-entry>end-head c@ .d
+   cr ." part-entry>end-sect:      " dup part-entry>end-sect c@ .d
+   cr ." part-entry>end-cyl:       " dup part-entry>end-cyl c@ .d
+   cr ." part-entry>sector-offset: " dup part-entry>sector-offset l@-le .d
+   cr ." part-entry>sector-count:  " dup part-entry>sector-count l@-le .d
+   cr
+;
+
+: (.name) r@ begin cell - dup @ <colon> = UNTIL xt>name cr type space ;
+
+: init-block ( -- )
+   s" block-size" ['] $call-parent CATCH IF ABORT" parent has no block-size." THEN
+   to block-size
+   d# 4096 alloc-mem
+   dup d# 4096 erase
+   to block
+   debug-disk-label? IF
+      ." init-block: block-size=" block-size .d ." block=0x" block u. cr
+   THEN
+;
+
+: partition>part-entry ( partition -- part-entry )
+   1- /partition-entry * block mbr>partition-table +
+;
+
+: partition>start-sector ( partition -- sector-offset )
+   partition>part-entry part-entry>sector-offset l@-le
+;
+
+\ This word returns true if the currently loaded block has _NO_ MBR magic
+: no-mbr? ( -- true|false )
+   0 read-sector
+   1 partition>part-entry part-entry>id c@ ee = IF TRUE EXIT THEN \ GPT partition found
+   block mbr>magic w@-le aa55 <>
+;
+
+\ This word returns true if the currently loaded block has _NO_ GPT partition id
+: no-gpt? ( -- true|false )
+   0 read-sector
+   1 partition>part-entry part-entry>id c@ ee <>
+;
+
+: pc-extended-partition? ( part-entry-addr -- true|false )
+   part-entry>id c@      ( id )
+   dup 5 = swap          ( true|false id )
+   dup f = swap          ( true|false true|false id )
+   85 =                  ( true|false true|false true|false )
+   or or                 ( true|false )
+;
+
+: count-dos-logical-partitions ( -- #logical-partitions )
+   no-mbr? IF 0 EXIT THEN
+   0 5 1 DO                                ( current )
+      i partition>part-entry               ( current part-entry )
+      dup pc-extended-partition? IF
+         part-entry>sector-offset l@-le    ( current sector )
+         dup to part-start to lpart-start  ( current )
+         BEGIN
+            part-start read-sector          \ read EBR
+            1 partition>start-sector IF
+               \ ." Logical Partition found at " part-start .d cr
+               1+
+            THEN \ another logical partition
+            2 partition>start-sector
+            ( current relative-sector )
+            ?dup IF lpart-start + to part-start false ELSE true THEN
+         UNTIL
+      ELSE
+         drop
+      THEN
+   LOOP
+;
+
+: (get-dos-partition-params) ( ext-part-start part-entry -- offset count active? id )
+   dup part-entry>sector-offset l@-le rot + swap ( offset part-entry )
+   dup part-entry>sector-count l@-le swap        ( offset count part-entry )
+   dup part-entry>active c@ 80 = swap            ( offset count active? part-entry )
+   part-entry>id c@                              ( offset count active? id )
+;
+
+: find-dos-partition ( partition# -- false | offset count active? id true )
+   to partition 0 to part-start 0 to part-offset
+
+   \ no negative partitions
+   partition 0<= IF 0 to partition false EXIT THEN
+
+   \ load MBR and check it
+   no-mbr? IF 0 to partition false EXIT THEN
+
+   partition 4 <= IF \ Is this a primary partition?
+      0 partition partition>part-entry
+      (get-dos-partition-params)
+      \ FIXME sanity checks?
+      true EXIT
+   ELSE
+      partition 4 - 0 5 1 DO                      ( logical-partition current )
+         i partition>part-entry                   ( log-part current part-entry )
+         dup pc-extended-partition? IF
+            part-entry>sector-offset l@-le        ( log-part current sector )
+            dup to part-start to lpart-start      ( log-part current )
+            BEGIN
+               part-start read-sector             \ read EBR
+               1 partition>start-sector IF        \ first partition entry
+                  1+ 2dup = IF                    ( log-part current )
+                     2drop
+                     part-start 1 partition>part-entry
+                     (get-dos-partition-params)
+                     true UNLOOP EXIT
+                  THEN
+                  2 partition>start-sector
+                  ( log-part current relative-sector )
+
+                  ?dup IF lpart-start + to part-start false ELSE true THEN
+               ELSE
+                  true
+               THEN
+            UNTIL
+         ELSE
+            drop
+         THEN
+      LOOP
+      2drop false
+   THEN
+;
+
+: try-dos-partition ( -- okay? )
+   \ Read partition table and check magic.
+   no-mbr? IF cr ." No DOS disk-label found." cr false EXIT THEN
+
+   count-dos-logical-partitions TO dos-logical-partitions
+
+   debug-disk-label? IF
+      ." Found " dos-logical-partitions .d ." logical partitions" cr
+      ." Partition = " partition .d cr
+   THEN
+
+   partition 1 5 dos-logical-partitions +
+   within 0= IF
+      cr ." Partition # not 1-" 4 dos-logical-partitions + . cr false EXIT
+   THEN
+
+   \ Could/should check for valid partition here...  the magic is not enough really.
+
+   \ Get the partition offset.
+
+   partition find-dos-partition IF
+     ( offset count active? id )
+     2drop
+     to part-size
+     block-size * to part-offset
+     true
+   ELSE
+     false
+   THEN
+;
+
+\ Check for an ISO-9660 filesystem on the disk
+\ : try-iso9660-partition ( -- true|false )
+\ implement me if you can ;-)
+\ ;
+
+
+\ Check for an ISO-9660 filesystem on the disk
+\ (cf. CHRP IEEE 1275 spec., chapter 11.1.2.3)
+: has-iso9660-filesystem  ( -- TRUE|FALSE )
+   \ Seek to the beginning of logical 2048-byte sector 16
+   \ refer to Chapter C.11.1 in PAPR 2.0 Spec
+   \ was: 10 read-sector, but this might cause trouble if you
+   \ try booting an ISO image from a device with 512b sectors.
+   10 800 * 0 seek drop      \ seek to sector
+   block 800 read drop       \ read sector
+   \ Check for CD-ROM volume magic:
+   block c@ 1 =
+   block 1+ 5 s" CD001"  str=
+   and
+   dup IF 800 to block-size THEN
+;
+
+
+\ Load from first active DOS boot partition.
+
+\ NOTE: block-size is always 512 bytes for DOS partition tables.
+
+: load-from-dos-boot-partition ( addr -- size )
+   no-mbr? IF drop FALSE EXIT THEN  \ read MBR and check for DOS disk-label magic
+
+   count-dos-logical-partitions TO dos-logical-partitions
+
+   debug-disk-label? IF
+      ." Found " dos-logical-partitions .d ." logical partitions" cr
+      ." Partition = " partition .d cr
+   THEN
+
+   \ Now walk through the partitions:
+   5 dos-logical-partitions + 1 DO
+      \ ." checking partition " i .
+      i find-dos-partition IF        ( addr offset count active? id )
+         41 = and                    ( addr offset count prep-boot-part? )
+         IF                          ( addr offset count )
+            max-prep-partition-blocks min  \ reduce load size
+            swap                     ( addr count offset )
+            block-size * to part-offset
+            0 0 seek drop            ( addr offset )
+            block-size * read        ( size )
+            UNLOOP EXIT
+         ELSE
+            2drop                    ( addr )
+         THEN
+      THEN
+   LOOP
+   drop 0
+;
+
+\ Check for GPT PReP partition GUID
+9E1A2D38     CONSTANT GPT-PREP-PARTITION-1
+C612         CONSTANT GPT-PREP-PARTITION-2
+4316         CONSTANT GPT-PREP-PARTITION-3
+AA26         CONSTANT GPT-PREP-PARTITION-4
+8B49521E5A8B CONSTANT GPT-PREP-PARTITION-5
+
+: gpt-prep-partition? ( -- true|false )
+   block gpt-part-entry>part-type-guid l@-le GPT-PREP-PARTITION-1 = IF
+      block gpt-part-entry>part-type-guid 4 + w@-le
+      GPT-PREP-PARTITION-2 = IF
+         block gpt-part-entry>part-type-guid 6 + w@-le
+         GPT-PREP-PARTITION-3 = IF
+            block gpt-part-entry>part-type-guid 8 + w@
+            GPT-PREP-PARTITION-4 = IF
+               block gpt-part-entry>part-type-guid a + w@
+               block gpt-part-entry>part-type-guid c + l@ swap lxjoin
+               GPT-PREP-PARTITION-5 = IF
+                   TRUE EXIT
+               THEN
+            THEN
+         THEN
+      THEN
+   THEN
+   FALSE
+;
+
+: load-from-gpt-prep-partition ( addr -- size )
+   no-gpt? IF drop FALSE EXIT THEN
+   debug-disk-label? IF
+      cr ." GPT partition found " cr
+   THEN
+   1 read-sector block gpt>part-entry-lba l@-le
+   block-size * to seek-pos
+   block gpt>part-entry-size l@-le to gpt-part-size
+   block gpt>num-part-entry l@-le dup 0= IF FALSE EXIT THEN
+   1+ 1 ?DO
+      seek-pos 0 seek drop
+      block gpt-part-size read drop gpt-prep-partition? IF
+         debug-disk-label? IF
+            ." GPT PReP partition found " cr
+         THEN
+         block gpt-part-entry>first-lba x@ xbflip
+         block gpt-part-entry>last-lba x@ xbflip
+         over - 1+                 ( addr offset len )
+         swap                      ( addr len offset )
+         block-size * to part-offset
+         0 0 seek drop             ( addr len )
+         block-size * read         ( size )
+         UNLOOP EXIT
+      THEN
+      seek-pos gpt-part-size i * + to seek-pos
+   LOOP
+   FALSE
+;
+
+\ Extract the boot loader path from a bootinfo.txt file
+\ In: address and length of buffer where the bootinfo.txt has been loaded to.
+\ Out: string address and length of the boot loader (within the input buffer)
+\      or a string with length = 0 when parsing failed.
+
+\ Here is a sample bootinfo file:
+\ <chrp-boot>
+\   <description>Linux Distribution</description>
+\   <os-name>Linux</os-name>
+\   <boot-script>boot &device;:1,\boot\yaboot.ibm</boot-script>
+\   <icon size=64,64 color-space=3,3,2>
+\     <bitmap>[..]</bitmap>
+\   </icon>
+\ </chrp-boot>
+
+: parse-bootinfo-txt  ( addr len -- str len )
+   2dup s" <boot-script>" find-substr       ( addr len pos1 )
+   2dup = IF
+      \ String not found
+      3drop 0 0 EXIT
+   THEN
+   dup >r - swap r> + swap                  ( addr1 len1 )
+
+   2dup s" &device;:" find-substr           ( addr1 len1 posdev )
+   2dup = IF
+      3drop 0 0 EXIT
+   THEN
+   9 +                                      \ Skip the "&device;:" string
+   dup >r - swap r> + swap                  ( addr2 len2 )
+   2dup s" </boot-script>" find-substr nip  ( addr2 len3 )
+
+   debug-disk-label? IF
+      ." Extracted boot loader from bootinfo.txt: '"
+      2dup type ." '" cr
+   THEN
+;
+
+\ Try to load \ppc\bootinfo.txt from the disk (used mainly on CD-ROMs), and if
+\ available, get the boot loader path from this file and load it.
+\ See the "CHRP system binding to IEEE 1275" specification for more information
+\ about bootinfo.txt. An example file can be found in the comment of
+\ parse-bootinfo-txt ( addr len -- str len )
+
+: load-chrp-boot-file ( addr -- size )
+   \ Create bootinfo.txt path name and load that file:
+   my-parent instance>path
+   disk-chrp-boot @ 1 = IF
+       s" :1,\ppc\bootinfo.txt" $cat strdup       ( addr str len )
+   ELSE
+       s" :\ppc\bootinfo.txt" $cat strdup       ( addr str len )
+   THEN
+   open-dev dup 0= IF 2drop 0 EXIT THEN
+   >r dup                                   ( addr addr R:ihandle )
+   dup s" load" r@ $call-method             ( addr addr size R:ihandle )
+   r> close-dev                             ( addr addr size )
+
+   \ Now parse the information from bootinfo.txt:
+   parse-bootinfo-txt                       ( addr fnstr fnlen )
+   dup 0= IF 3drop 0 EXIT THEN
+   \ Does the string contain parameters (i.e. a white space)?
+   2dup 20 findchar IF
+      ( addr fnstr fnlen offset )
+      >r 2dup r@ - 1- swap r@ + 1+ swap     ( addr fnstr fnlen pstr plen  R: offset )
+      encode-string s" bootargs" set-chosen
+      drop r>
+   THEN
+
+   \ Create the full path to the boot loader:
+   my-parent instance>path      ( addr fnstr fnlen nstr nlen )
+   s" :" $cat 2swap $cat strdup             ( addr str len )
+   \ Update the bootpath:
+   2dup encode-string s" bootpath" set-chosen
+   \ And finally load the boot loader itself:
+   open-dev dup 0= IF ." failed to load CHRP boot loader." 2drop 0 EXIT THEN
+   >r s" load" r@ $call-method              ( size R:ihandle )
+   r> close-dev                             ( size )
+;
+
+\ load from a bootable partition
+: load-from-boot-partition ( addr -- size )
+   debug-disk-label? IF ." Trying DOS boot " .s cr THEN
+   dup load-from-dos-boot-partition ?dup 0 <> IF nip EXIT THEN
+
+   debug-disk-label? IF ." Trying CHRP boot " .s cr THEN
+   1 disk-chrp-boot !
+   dup load-chrp-boot-file ?dup 0 <> IF .s cr nip EXIT THEN
+   0 disk-chrp-boot !
+
+   debug-disk-label? IF ." Trying GPT boot " .s cr THEN
+   load-from-gpt-prep-partition
+   \ More boot partition formats ...
+;
+
+\ parse partition number from my-args
+
+\ my-args has the following format
+\ [<partition>[,<path>]]
+
+\ | example my-args  | example boot command      |
+\ +------------------+---------------------------+
+\ | 1,\boot\vmlinuz  | boot disk:1,\boot\vmlinuz |
+\ | 2                | boot disk:2               |
+
+\ 0 means the whole disk, this is the same behavior
+\ as if no partition is specified (yaboot wants this).
+
+: parse-partition ( -- okay? )
+   0 to partition
+   0 to part-offset
+   0 to part-size
+
+   my-args to args-len to args
+
+   debug-disk-label? IF
+      cr ." disk-label parse-partition: my-args=" my-args type cr
+   THEN
+
+   \ Called without arguments?
+   args-len 0 = IF true EXIT THEN
+
+   \ Check for "full disk" arguments.
+   my-args [char] , findchar 0= IF \ no comma?
+      args c@ isdigit not IF       \ ... and not a partition number?
+         true EXIT                 \ ... then it's not a partition we can parse
+      THEN
+   ELSE
+      drop
+   THEN
+   my-args [char] , split to args-len to args
+   dup 0= IF 2drop true EXIT THEN \ no first argument
+
+   \ Check partition #.
+   base @ >r decimal $number r> base !
+   IF cr ." Not a partition #" false EXIT THEN
+
+   \ Store part #, done.
+   to partition
+   true
+;
+
+
+\ try-files and try-partitions
+
+: (interpose-filesystem) ( str len -- )
+   find-package IF args args-len rot interpose THEN
+;
+
+: try-dos-files ( -- found? )
+   no-mbr? IF false EXIT THEN
+
+   \ block 0 byte 0-2 is a jump instruction in all FAT
+   \ filesystems.
+   \ e9 and eb are jump instructions in x86 assembler.
+   block c@ e9 <> IF
+      block c@ eb <>
+      block 2+ c@ 90 <> or
+      IF false EXIT THEN
+   THEN
+   s" fat-files" (interpose-filesystem)
+   true
+;
+
+: try-ext2-files ( -- found? )
+   2 read-sector               \ read first superblock
+   block d# 56 + w@-le         \ fetch s_magic
+   ef53 <> IF false EXIT THEN  \ s_magic found?
+   s" ext2-files" (interpose-filesystem)
+   true
+;
+
+
+: try-iso9660-files
+   has-iso9660-filesystem 0= IF false exit THEN
+   s" iso-9660" (interpose-filesystem)
+   true
+;
+
+: try-files ( -- found? )
+   \ If no path, then full disk.
+   args-len 0= IF true EXIT THEN
+
+   try-dos-files IF true EXIT THEN
+   try-ext2-files IF true EXIT THEN
+   try-iso9660-files IF true EXIT THEN
+
+   \ ... more filesystem types here ...
+
+   false
+;
+
+: try-partitions ( -- found? )
+   try-dos-partition IF try-files EXIT THEN
+   \ try-iso9660-partition IF try-files EXIT THEN
+   \ ... more partition types here...
+   false
+;
+
+\ Interface functions for disk-label package
+\ as defined by IEEE 1275-1994 3.8.1
+
+: close ( -- )
+   debug-disk-label? IF ." Closing disk-label: block=0x" block u. ." block-size=" block-size .d cr THEN
+   block d# 4096 free-mem
+;
+
+
+: open ( -- true|false )
+   init-block
+
+   parse-partition 0= IF
+      close
+      false EXIT
+   THEN
+
+   partition IF
+       try-partitions
+   ELSE
+       try-files
+   THEN
+   dup 0= IF debug-disk-label? IF ." not found." cr THEN close THEN \ free memory again
+;
+
+
+\ Boot & Load w/o arguments is assumed to be boot from boot partition
+
+: load ( addr -- size )
+   debug-disk-label? IF
+      ." load: " dup u. cr
+   THEN
+
+   args-len IF
+      TRUE ABORT" Load done w/o filesystem"
+   ELSE
+      partition IF
+         0 0 seek drop
+         part-size IF
+            part-size max-prep-partition-blocks min   \ Load size
+         ELSE
+            max-prep-partition-blocks
+         THEN
+         200 *  read
+      ELSE
+         has-iso9660-filesystem IF
+             dup load-chrp-boot-file ?dup 0 > IF nip EXIT THEN
+         THEN
+         load-from-boot-partition
+        dup 0= ABORT" No boot partition found"
+      THEN
+   THEN
+;