diff options
Diffstat (limited to 'slof/fs/packages/disk-label.fs')
-rw-r--r-- | slof/fs/packages/disk-label.fs | 520 |
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 |