aboutsummaryrefslogtreecommitdiff
path: root/slof/fs/packages/disk-label.fs
diff options
context:
space:
mode:
Diffstat (limited to 'slof/fs/packages/disk-label.fs')
-rw-r--r--slof/fs/packages/disk-label.fs520
1 files changed, 388 insertions, 132 deletions
diff --git a/slof/fs/packages/disk-label.fs b/slof/fs/packages/disk-label.fs
index 08761fd..6079555 100644
--- a/slof/fs/packages/disk-label.fs
+++ b/slof/fs/packages/disk-label.fs
@@ -11,200 +11,332 @@
\ ****************************************************************************/
+\ 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 16384 blocks (8MB)
+d# 16384 value max-prep-partition-blocks
+
s" disk-label" device-name
-INSTANCE VARIABLE partition
-INSTANCE VARIABLE part-offset
-INSTANCE VARIABLE block-size
-INSTANCE VARIABLE block
-INSTANCE VARIABLE args
-INSTANCE VARIABLE args-len
+0 INSTANCE VALUE partition
+0 INSTANCE VALUE part-offset
+
+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
+
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
-: seek lxjoin part-offset @ + xlsplit s" seek" $call-parent ;
-: read s" read" $call-parent ;
-: init-block ( -- )
- s" block-size" ['] $call-parent CATCH IF ABORT" no block-size" THEN
- block-size !
- block-size @ alloc-mem dup block-size @ erase block ! ;
+\ DOS partition label (MBR) specific structures
-: parse-partition ( -- okay? )
- 0 part-offset ! 0 partition ! my-args args-len ! args !
+STRUCT
+ 1b8 field mbr>boot-loader
+ /l field mbr>disk-signature
+ /w field mbr>null
+ 40 field mbr>partition-table
+ /w field mbr>magic
- \ Fix up the "0" thing yaboot does.
- args-len @ 1 = IF args @ c@ [char] 0 = IF 0 args-len ! THEN THEN
+CONSTANT /mbr
- \ Check for "full disk" arguments.
- my-args [char] , findchar 0= IF true EXIT THEN drop \ no comma
- my-args [char] , split args-len ! args !
- dup 0= IF 2drop true EXIT THEN \ no first argument
+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
- \ Check partition #.
- base @ >r decimal $number r> base !
- IF cr ." Not a partition #" false EXIT THEN
+CONSTANT /partition-entry
- \ Store part #, done.
- partition ! true ;
-: try-dos-partition ( -- okay? )
- partition @ 1 5 within 0= IF cr ." Partition # not 1-4" false EXIT THEN
+\ Defined by IEEE 1275-1994 (3.8.1)
- \ Read partition table.
- 0 0 seek drop block @ block-size @ read drop
- block @ 1fe + 2c@ bwjoin aa55 <> IF cr ." No partitions" false EXIT THEN
+: offset ( d.rel -- d.abs )
+ part-offset 0 d+
+;
- \ Could/should check for valid partition here... aa55 is not enough really.
+: 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
+;
- \ Get the partition offset.
- partition @ 10 * 1b6 + block @ + 4c@ bljoin block-size @ * part-offset !
- true ;
+: 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
+;
-\ Check for an ISO-9660 filesystem on the disk
-\ : try-iso9660-partition ( -- true|false )
-\ implement me if you can ;-)
-\ ;
+\ 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
+;
-\ 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 and read starting from 16th sector:
- 10 800 * 0 seek drop
- block @ block-size @ read drop
- \ Check for CD-ROM volume magic:
- block @ c@ 1 =
- block @ 1+ 5 s" CD001" str=
- and
+: (.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 ;
-: try-dos-files ( -- found? )
- block @ 1fe + 2c@ bwjoin aa55 <> IF false EXIT THEN
- block @ c@ e9 <> IF
- block @ c@ eb <> block @ 2+ c@ 90 <> or IF false EXIT THEN THEN
- s" fat-files" find-package IF args @ args-len @ rot interpose THEN true
+: init-block ( -- )
+ s" block-size" ['] $call-parent CATCH IF ABORT" parent has no block-size." THEN
+ to block-size
+ d# 2048 alloc-mem
+ dup d# 2048 erase
+ to block
+ debug-disk-label? IF
+ ." init-block: block-size=" block-size .d ." block=0x" block u. cr
+ THEN
;
-CREATE ext2-magic 2 allot
-: try-ext2-files ( -- found? )
- 438 0 seek drop ext2-magic 2 read drop
- ext2-magic w@-le ef53 <> IF false EXIT THEN
- s" ext2-files" find-package IF args @ args-len @ rot interpose THEN true
+
+\ This word returns true if the currently loaded block has _NO_ MBR magic
+: no-mbr? ( -- true|false )
+ 0 read-sector block mbr>magic w@-le aa55 <>
;
-: try-iso9660-files
- \ seek and read starting from 16th sector for volume descriptors
- block @ 1+ 5 s" CD001" str=
- IF \ found ISO9660 signature
- s" iso-9660" find-package IF args @ args-len @ rot interpose THEN
- TRUE
- ELSE
- FALSE
- THEN
+: 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 )
;
+: partition>part-entry ( partition -- part-entry )
+ 1- /partition-entry * block mbr>partition-table +
+;
-: try-files ( -- found? )
- \ If no path, then full disk.
- args-len @ 0= IF true EXIT THEN
+: partition>start-sector ( partition -- sector-offset )
+ partition>part-entry part-entry>sector-offset l@-le
+;
- 0 0 seek drop
- block @ block-size @ read drop
- try-dos-files IF true EXIT THEN
- try-ext2-files IF true EXIT THEN
+: 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
+;
- \ Seek to the begining of logical 2048-byte sector 16
- \ refer to Chapter C.11.1 in PAPR 2.0 Spec
- 10 800 * 0 seek drop
- block @ block-size @ read drop
- try-iso9660-files IF true EXIT THEN
+: (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 )
+;
- \ ... more filesystem types here ...
+: find-dos-partition ( partition# -- false | offset count active? id true )
+ to partition 0 to part-start 0 to part-offset
- false
+ \ 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-partitions ( -- found? )
- try-dos-partition IF try-files EXIT THEN
- \ try-iso9660-partition IF try-files EXIT THEN
- \ ... more partition types here...
- false ;
+: try-dos-partition ( -- okay? )
+ \ Read partition table and check magic.
+ no-mbr? IF cr ." No DOS disk-label found." cr false EXIT THEN
-: open
- init-block
- parse-partition 0= IF
- false EXIT
+ 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 @ 0= IF
- try-files EXIT
+
+ partition 1 5 dos-logical-partitions +
+ within 0= IF
+ cr ." Partition # not 1-" 4 dos-logical-partitions + . cr false EXIT
THEN
- try-partitions
-;
-: close
- block @ block-size @ free-mem ;
+ \ Could/should check for valid partition here... the magic is not enough really.
-\ Workaround for not having "value" variables yet.
-: block-size block-size @ ;
+ \ Get the partition offset.
-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
+ partition find-dos-partition IF
+ ( offset count active? id )
+ 2drop drop
+ block-size * to part-offset
+ true
+ ELSE
+ false
+ THEN
+;
-CONSTANT /partition-entry
+\ 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 begining 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: sector block size is always 512 bytes for DOS partition tables.
+
+\ NOTE: block-size is always 512 bytes for DOS partition tables.
: load-from-dos-boot-partition ( addr -- size )
- 0 0 seek drop
- block @ 200 read drop
- \ Check for DOS partition table magic:
- block @ 1fe + 2c@ bwjoin aa55 <> IF FALSE EXIT THEN
- \ Now step through the partition table:
- block @ 1be + ( addr part-off )
- 4 0 DO
- dup part-entry>active c@ 80 = ( addr part-off active? )
- over part-entry>id c@ 41 = and IF ( addr part-off )
- dup part-entry>sector-offset 4c@ bljoin ( addr part-off sect-off )
- \ seek to the boot partition
- 200 * 0 seek drop ( addr part-off )
- part-entry>sector-count 4c@ bljoin ( addr sect-count )
- 200 * read ( size )
- UNLOOP EXIT
+ no-mbr? IF 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
- /partition-entry + ( addr part-off )
LOOP
- 2drop 0
+ drop 0
;
+
+\ load from a bootable partition
+
: load-from-boot-partition ( addr -- size )
load-from-dos-boot-partition
\ More boot partition formats ...
;
+
\ 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
@@ -220,7 +352,8 @@ CONSTANT /partition-entry
\ 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.
+\ 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:
@@ -230,6 +363,7 @@ CONSTANT /partition-entry
>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
@@ -244,14 +378,136 @@ CONSTANT /partition-entry
r> close-dev ( size )
;
+\ 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
+
+ my-args to args-len to args
+
+ \ Fix up the "0" thing yaboot does.
+ args-len 1 = IF args c@ [char] 0 = IF 0 to args-len THEN THEN
+
+ \ Check for "full disk" arguments.
+ my-args [char] , findchar 0= IF true EXIT THEN drop \ no comma
+ 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# 2048 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 )
- args-len @ IF
- TRUE ABORT" Load done w/o filesystem"
+ debug-disk-label? IF
+ ." load: " dup u. cr
+ THEN
+
+ args-len IF
+ TRUE ABORT" Load done w/o filesystem"
ELSE
- partition @ IF
+ partition IF
0 0 seek drop
200000 read
ELSE