diff options
Diffstat (limited to 'sys/arch/sparc64/stand/bootblk/bootblk.fth')
-rw-r--r-- | sys/arch/sparc64/stand/bootblk/bootblk.fth | 613 |
1 files changed, 613 insertions, 0 deletions
diff --git a/sys/arch/sparc64/stand/bootblk/bootblk.fth b/sys/arch/sparc64/stand/bootblk/bootblk.fth new file mode 100644 index 00000000000..42f5e21089b --- /dev/null +++ b/sys/arch/sparc64/stand/bootblk/bootblk.fth @@ -0,0 +1,613 @@ +\ $OpenBSD: bootblk.fth,v 1.1 2001/08/18 04:16:37 jason Exp $ +\ $NetBSD: bootblk.fth,v 1.3 2001/08/15 20:10:24 eeh Exp $ +\ +\ IEEE 1275 Open Firmware Boot Block +\ +\ Parses disklabel and UFS and loads the file called `ofwboot' +\ +\ +\ Copyright (c) 1998 Eduardo Horvath. +\ All rights reserved. +\ +\ Redistribution and use in source and binary forms, with or without +\ modification, are permitted provided that the following conditions +\ are met: +\ 1. Redistributions of source code must retain the above copyright +\ notice, this list of conditions and the following disclaimer. +\ 2. Redistributions in binary form must reproduce the above copyright +\ notice, this list of conditions and the following disclaimer in the +\ documentation and/or other materials provided with the distribution. +\ 3. All advertising materials mentioning features or use of this software +\ must display the following acknowledgement: +\ This product includes software developed by Eduardo Horvath. +\ 4. The name of the author may not be used to endorse or promote products +\ derived from this software without specific prior written permission +\ +\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +\ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +\ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +\ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +\ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +\ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +\ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +\ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +\ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +\ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\ + +offset16 +hex +headers + +false value boot-debug? + +\ +\ First some housekeeping: Open /chosen and set up vectors into +\ client-services + +" /chosen" find-package 0= if ." Cannot find /chosen" 0 then +constant chosen-phandle + +" /openprom/client-services" find-package 0= if + ." Cannot find client-services" cr abort +then constant cif-phandle + +defer cif-claim ( align size virt -- base ) +defer cif-release ( size virt -- ) +defer cif-open ( cstr -- ihandle|0 ) +defer cif-close ( ihandle -- ) +defer cif-read ( len adr ihandle -- #read ) +defer cif-seek ( low high ihandle -- -1|0|1 ) +\ defer cif-peer ( phandle -- phandle ) +\ defer cif-getprop ( len adr cstr phandle -- ) + +: find-cif-method ( method,len -- xf ) + cif-phandle find-method drop +; + +" claim" find-cif-method to cif-claim +" open" find-cif-method to cif-open +" close" find-cif-method to cif-close +" read" find-cif-method to cif-read +" seek" find-cif-method to cif-seek + +: twiddle ( -- ) ." ." ; \ Need to do this right. Just spit out periods for now. + +\ +\ Support routines +\ + +: strcmp ( s1 l1 s2 l2 -- true:false ) + rot tuck <> if 3drop false exit then + comp 0= +; + +\ Move string into buffer + +: strmov ( s1 l1 d -- d l1 ) + dup 2over swap -rot ( s1 l1 d s1 d l1 ) + move ( s1 l1 d ) + rot drop swap +; + +\ Move s1 on the end of s2 and return the result + +: strcat ( s1 l1 s2 l2 -- d tot ) + 2over swap ( s1 l1 s2 l2 l1 s1 ) + 2over + rot ( s1 l1 s2 l2 s1 d l1 ) + move rot + ( s1 s2 len ) + rot drop ( s2 len ) +; + +: strchr ( s1 l1 c -- s2 l2 ) + begin + dup 2over 0= if ( s1 l1 c c s1 ) + 2drop drop exit then + c@ = if ( s1 l1 c ) + drop exit then + -rot /c - swap ca1+ ( c l2 s2 ) + swap rot + again +; + + +: cstr ( ptr -- str len ) + dup + begin dup c@ 0<> while + repeat + over - +; + +\ +\ BSD FFS parameters +\ + +fload assym.fth.h + +sbsize buffer: sb-buf +-1 value boot-ihandle +dev_bsize value bsize +0 value raid-offset \ Offset if it's a raid-frame partition + +: strategy ( addr size start -- nread ) + raid-offset + bsize * 0 " seek" boot-ihandle $call-method + -1 = if + ." strategy: Seek failed" cr + abort + then + " read" boot-ihandle $call-method +; + +\ +\ Cylinder group macros +\ + +: cgbase ( cg fs -- cgbase ) fs_fpg l@ * ; +: cgstart ( cg fs -- cgstart ) + 2dup fs_cgmask l@ not and ( cg fs stuff -- ) + over fs_cgoffset l@ * -rot ( stuffcg fs -- ) + cgbase + +; +: cgdmin ( cg fs -- 1st-data-block ) dup fs_dblkno l@ -rot cgstart + ; +: cgimin ( cg fs -- inode-block ) dup fs_iblkno l@ -rot cgstart + ; +: cgsblock ( cg fs -- super-block ) dup fs_sblkno l@ -rot cgstart + ; +: cgstod ( cg fs -- cg-block ) dup fs_cblkno l@ -rot cgstart + ; + +\ +\ Block and frag position macros +\ + +: blkoff ( pos fs -- off ) fs_qbmask x@ and ; +: fragoff ( pos fs -- off ) fs_qfmask x@ and ; +: lblktosize ( blk fs -- off ) fs_bshift l@ << ; +: lblkno ( pos fs -- off ) fs_bshift l@ >> ; +: numfrags ( pos fs -- off ) fs_fshift l@ >> ; +: blkroundup ( pos fs -- off ) dup fs_bmask l@ -rot fs_qbmask x@ + and ; +: fragroundup ( pos fs -- off ) dup fs_fmask l@ -rot fs_qfmask x@ + and ; +\ : fragroundup ( pos fs -- off ) tuck fs_qfmask x@ + swap fs_fmask l@ and ; +: fragstoblks ( pos fs -- off ) fs_fragshift l@ >> ; +: blkstofrags ( blk fs -- frag ) fs_fragshift l@ << ; +: fragnum ( fsb fs -- off ) fs_frag l@ 1- and ; +: blknum ( fsb fs -- off ) fs_frag l@ 1- not and ; +: dblksize ( lbn dino fs -- size ) + -rot ( fs lbn dino ) + di_size x@ ( fs lbn di_size ) + -rot dup 1+ ( di_size fs lbn lbn+1 ) + 2over fs_bshift l@ ( di_size fs lbn lbn+1 di_size b_shift ) + rot swap << >= ( di_size fs lbn res1 ) + swap ndaddr >= or if ( di_size fs ) + swap drop fs_bsize l@ exit ( size ) + then tuck blkoff swap fragroundup ( size ) +; + + +: ino-to-cg ( ino fs -- cg ) fs_ipg l@ / ; +: ino-to-fsbo ( ino fs -- fsb0 ) fs_inopb l@ mod ; +: ino-to-fsba ( ino fs -- ba ) \ Need to remove the stupid stack diags someday + 2dup ( ino fs ino fs ) + ino-to-cg ( ino fs cg ) + over ( ino fs cg fs ) + cgimin ( ino fs inode-blk ) + -rot ( inode-blk ino fs ) + tuck ( inode-blk fs ino fs ) + fs_ipg l@ ( inode-blk fs ino ipg ) + mod ( inode-blk fs mod ) + swap ( inode-blk mod fs ) + dup ( inode-blk mod fs fs ) + fs_inopb l@ ( inode-blk mod fs inopb ) + rot ( inode-blk fs inopb mod ) + swap ( inode-blk fs mod inopb ) + / ( inode-blk fs div ) + swap ( inode-blk div fs ) + blkstofrags ( inode-blk frag ) + + +; +: fsbtodb ( fsb fs -- db ) fs_fsbtodb l@ << ; + +\ +\ File stuff +\ + +niaddr /w* constant narraysize + +struct + 8 field >f_ihandle \ device handle + 8 field >f_seekp \ seek pointer + 8 field >f_fs \ pointer to super block + dinode_SIZEOF field >f_di \ copy of on-disk inode + 8 field >f_buf \ buffer for data block + 4 field >f_buf_size \ size of data block + 4 field >f_buf_blkno \ block number of data block +constant file_SIZEOF + +file_SIZEOF buffer: the-file +sb-buf the-file >f_fs x! + +dinode_SIZEOF buffer: cur-inode +h# 2000 buffer: indir-block +-1 value indir-addr + +\ +\ Translate a fileblock to a disk block +\ +\ We only allow single indirection +\ + +: block-map ( fileblock -- diskblock ) + \ Direct block? + dup ndaddr < if ( fileblock ) + cur-inode di_db ( arr-indx arr-start ) + swap la+ l@ exit ( diskblock ) + then ( fileblock ) + ndaddr - ( fileblock' ) + \ Now we need to check the indirect block + dup sb-buf fs_nindir l@ < if ( fileblock' ) + cur-inode di_ib l@ dup ( fileblock' indir-block indir-block ) + indir-addr <> if ( fileblock' indir-block ) + to indir-addr ( fileblock' ) + indir-block ( fileblock' indir-block ) + sb-buf dup fs_bsize l@ ( fileblock' indir-block fs fs_bsize ) + swap indir-addr swap ( fileblock' indir-block fs_bsize indiraddr fs ) + fsbtodb ( fileblock' indir-block fs_bsize db ) + strategy ( fileblock' nread ) + then ( fileblock' nread|indir-block ) + drop \ Really should check return value + indir-block swap la+ l@ exit + then + dup sb-buf fs_nindir - ( fileblock'' ) + \ Now try 2nd level indirect block -- just read twice + dup sb-buf fs_nindir l@ dup * < if ( fileblock'' ) + cur-inode di_ib 1 la+ l@ ( fileblock'' indir2-block ) + to indir-addr ( fileblock'' ) + \ load 1st level indir block + indir-block ( fileblock'' indir-block ) + sb-buf dup fs_bsize l@ ( fileblock'' indir-block fs fs_bsize ) + swap indir-addr swap ( fileblock'' indir-block fs_bsize indiraddr fs ) + fsbtodb ( fileblock'' indir-block fs_bsize db ) + strategy ( fileblock'' nread ) + drop ( fileblock'' ) + dup sb-buf fs_nindir / ( fileblock'' indir-offset ) + indir-block swap la+ l@ ( fileblock'' indirblock ) + to indir-addr ( fileblock'' ) + \ load 2nd level indir block + indir-block ( fileblock'' indir-block ) + sb-buf dup fs_bsize l@ ( fileblock'' indir-block fs fs_bsize ) + swap indir-addr swap ( fileblock'' indir-block fs_bsize indiraddr fs ) + fsbtodb ( fileblock'' indir-block fs_bsize db ) + strategy ( fileblock'' nread ) + drop ( fileblock'' ) + sb-buf fs_nindir l@ mod indir-block swap la+ l@ exit + then + ." block-map: exceeded max file size" cr + abort +; + +\ +\ Read file into internal buffer and return pointer and len +\ + +2000 buffer: cur-block \ Why do dynamic allocation? +-1 value cur-blockno +0 value cur-offset + +: buf-read-file ( fs -- len buf ) + cur-offset swap ( seekp fs ) + 2dup blkoff ( seekp fs off ) + -rot 2dup lblkno ( off seekp fs block ) + swap 2dup cur-inode ( off seekp block fs block fs inop ) + swap dblksize ( off seekp block fs size ) + rot dup cur-blockno ( off seekp fs size block block cur ) + <> if ( off seekp fs size block ) + block-map ( off seekp fs size diskblock ) + dup 0= if ( off seekp fs size diskblock ) + over cur-block swap 0 fill ( off seekp fs size diskblock ) + boot-debug? if ." buf-read-file fell off end of file" cr then + else + 2dup sb-buf fsbtodb cur-block -rot strategy ( off seekp fs size diskblock nread ) + rot 2dup <> if " buf-read-file: short read." cr abort then + then ( off seekp fs diskblock nread size ) + nip nip ( off seekp fs size ) + else ( off seekp fs size block block cur ) + 2drop ( off seekp fs size ) + then +\ dup cur-offset + to cur-offset \ Set up next xfer -- not done + nip nip swap - ( len ) + cur-block +; + +\ +\ Read inode into cur-inode -- uses cur-block +\ + +: read-inode ( inode fs -- ) + twiddle ( inode fs -- inode fs ) + + cur-block ( inode fs -- inode fs buffer ) + + over ( inode fs buffer -- inode fs buffer fs ) + fs_bsize l@ ( inode fs buffer -- inode fs buffer size ) + + 2over ( inode fs buffer size -- inode fs buffer size inode fs ) + 2over ( inode fs buffer size inode fs -- inode fs buffer size inode fs buffer size ) + 2swap tuck ( inode fs buffer size inode fs buffer size -- inode fs buffer size buffer size fs inode fs ) + + ino-to-fsba ( inode fs buffer size buffer size fs inode fs -- inode fs buffer size buffer size fs fsba ) + swap ( inode fs buffer size buffer size fs fsba -- inode fs buffer size buffer size fsba fs ) + fsbtodb ( inode fs buffer size buffer size fsba fs -- inode fs buffer size buffer size db ) + + dup to cur-blockno ( inode fs buffer size buffer size dstart -- inode fs buffer size buffer size dstart ) + strategy ( inode fs buffer size buffer size dstart -- inode fs buffer size nread ) + <> if ." read-inode - residual" cr abort then + dup 2over ( inode fs buffer -- inode fs buffer buffer inode fs ) + ino-to-fsbo ( inode fs buffer -- inode fs buffer buffer fsbo ) + dinode_SIZEOF * + ( inode fs buffer buffer fsbo -- inode fs buffer dinop ) + cur-inode dinode_SIZEOF move ( inode fs buffer dinop -- inode fs buffer ) + \ clear out the old buffers + drop ( inode fs buffer -- inode fs ) + 2drop +; + +\ Identify inode type + +: is-dir? ( dinode -- true:false ) di_mode w@ ifmt and ifdir = ; +: is-symlink? ( dinode -- true:false ) di_mode w@ ifmt and iflnk = ; + + + +\ +\ Hunt for directory entry: +\ +\ repeat +\ load a buffer +\ while entries do +\ if entry == name return +\ next entry +\ until no buffers +\ + +: search-directory ( str len -- ino|0 ) + 0 to cur-offset + begin cur-offset cur-inode di_size x@ < while ( str len ) + sb-buf buf-read-file ( str len len buf ) + over 0= if ." search-directory: buf-read-file zero len" cr abort then + swap dup cur-offset + to cur-offset ( str len buf len ) + 2dup + nip ( str len buf bufend ) + swap 2swap rot ( bufend str len buf ) + begin dup 4 pick < while ( bufend str len buf ) + dup d_ino l@ 0<> if ( bufend str len buf ) + boot-debug? if dup dup d_name swap d_namlen c@ type cr then + 2dup d_namlen c@ = if ( bufend str len buf ) + dup d_name 2over ( bufend str len buf dname str len ) + comp 0= if ( bufend str len buf ) + \ Found it -- return inode + d_ino l@ nip nip nip ( dino ) + boot-debug? if ." Found it" cr then + exit ( dino ) + then + then ( bufend str len buf ) + then ( bufend str len buf ) + dup d_reclen w@ + ( bufend str len nextbuf ) + repeat + drop rot drop ( str len ) + repeat + 2drop 2drop 0 ( 0 ) +; + +: ffs_oldcompat ( -- ) +\ Make sure old ffs values in sb-buf are sane + sb-buf fs_npsect dup l@ sb-buf fs_nsect l@ max swap l! + sb-buf fs_interleave dup l@ 1 max swap l! + sb-buf fs_postblformat l@ fs_42postblfmt = if + 8 sb-buf fs_nrpos l! + then + sb-buf fs_inodefmt l@ fs_44inodefmt < if + sb-buf fs_bsize l@ + dup ndaddr * 1- sb-buf fs_maxfilesize x! + niaddr 0 ?do + sb-buf fs_nindir l@ * dup ( sizebp sizebp -- ) + sb-buf fs_maxfilesize dup x@ ( sizebp sizebp *fs_maxfilesize fs_maxfilesize -- ) + rot ( sizebp *fs_maxfilesize fs_maxfilesize sizebp -- ) + + ( sizebp *fs_maxfilesize new_fs_maxfilesize -- ) swap x! ( sizebp -- ) + loop drop ( -- ) + sb-buf dup fs_bmask l@ not swap fs_qbmask x! + sb-buf dup fs_fmask l@ not swap fs_qfmask x! + then +; + +: read-super ( sector -- ) +0 " seek" boot-ihandle $call-method + -1 = if + ." Seek failed" cr + abort + then + sb-buf sbsize " read" boot-ihandle $call-method + dup sbsize <> if + ." Read of superblock failed" cr + ." requested" space sbsize . + ." actual" space . cr + abort + else + drop + then +; + +: ufs-open ( bootpath,len -- ) + boot-ihandle -1 = if + over cif-open dup 0= if ( boot-path len ihandle? ) + ." Could not open device" space type cr + abort + then ( boot-path len ihandle ) + to boot-ihandle \ Save ihandle to boot device + then 2drop + sboff read-super + sb-buf fs_magic l@ fs_magic_value <> if + 64 dup to raid-offset + dev_bsize * sboff + read-super + sb-buf fs_magic l@ fs_magic_value <> if + ." Invalid superblock magic" cr + abort + then + then + sb-buf fs_bsize l@ dup maxbsize > if + ." Superblock bsize" space . ." too large" cr + abort + then + fs_SIZEOF < if + ." Superblock bsize < size of superblock" cr + abort + then + ffs_oldcompat + boot-debug? if ." ufs-open complete" cr then +; + +: ufs-close ( -- ) + boot-ihandle dup -1 <> if + cif-close -1 to boot-ihandle + then +; + +: boot-path ( -- boot-path ) + " bootpath" chosen-phandle get-package-property if + ." Could not find bootpath in /chosen" cr + abort + else + decode-string 2swap 2drop + then +; + +: boot-args ( -- boot-args ) + " bootargs" chosen-phandle get-package-property if + ." Could not find bootargs in /chosen" cr + abort + else + decode-string 2swap 2drop + then +; + +2000 buffer: boot-path-str +2000 buffer: boot-path-tmp + +: split-path ( path len -- right len left len ) +\ Split a string at the `/' + begin + dup -rot ( oldlen right len left ) + ascii / left-parse-string ( oldlen right len left len ) + dup 0<> if 4 roll drop exit then + 2drop ( oldlen right len ) + rot over = ( right len diff ) + until +; + +: find-file ( load-file len -- ) + rootino dup sb-buf read-inode ( load-file len -- load-file len ino ) + -rot ( load-file len ino -- pino load-file len ) + \ + \ For each path component + \ + begin split-path dup 0<> while ( pino right len left len -- ) + cur-inode is-dir? not if ." Inode not directory" cr abort then + boot-debug? if ." Looking for" space 2dup type space ." in directory..." cr then + search-directory ( pino right len left len -- pino right len ino|false ) + dup 0= if ." Bad path" cr abort then ( pino right len cino ) + sb-buf read-inode ( pino right len ) + cur-inode is-symlink? if \ Symlink -- follow the damn thing + \ Save path in boot-path-tmp + boot-path-tmp strmov ( pino new-right len ) + + \ Now deal with symlink + cur-inode di_size x@ ( pino right len linklen ) + dup sb-buf fs_maxsymlinklen l@ ( pino right len linklen linklen maxlinklen ) + < if \ Now join the link to the path + cur-inode di_shortlink l@ ( pino right len linklen linkp ) + swap boot-path-str strmov ( pino right len new-linkp linklen ) + else \ Read file for symlink -- Ugh + \ Read link into boot-path-str + boot-path-str dup sb-buf fs_bsize l@ + 0 block-map ( pino right len linklen boot-path-str bsize blockno ) + strategy drop swap ( pino right len boot-path-str linklen ) + then ( pino right len linkp linklen ) + \ Concatenate the two paths + strcat ( pino new-right newlen ) + swap dup c@ ascii / = if \ go to root inode? + rot drop rootino -rot ( rino len right ) + then + rot dup sb-buf read-inode ( len right pino ) + -rot swap ( pino right len ) + then ( pino right len ) + repeat + 2drop drop +; + +: read-file ( size addr -- ) + \ Read x bytes from a file to buffer + begin over 0> while + cur-offset cur-inode di_size x@ > if ." read-file EOF exceeded" cr abort then + sb-buf buf-read-file ( size addr len buf ) + over 2over drop swap ( size addr len buf addr len ) + move ( size addr len ) + dup cur-offset + to cur-offset ( size len newaddr ) + tuck + ( size len newaddr ) + -rot - swap ( newaddr newsize ) + repeat + 2drop +; + +h# 5000 constant loader-base + +\ +\ Elf support -- find the load addr +\ + +: is-elf? ( hdr -- res? ) h# 7f454c46 = ; + +\ +\ Finally we finish it all off +\ + +: load-file-signon ( load-file len boot-path len -- load-file len boot-path len ) + ." Loading file" space 2over type cr ." from device" space 2dup type cr +; + +: load-file-print-size ( size -- size ) + ." Loading" space dup . space ." bytes of file..." cr +; + +: load-file ( load-file len boot-path len -- load-base ) + boot-debug? if load-file-signon then + the-file file_SIZEOF 0 fill \ Clear out file structure + ufs-open ( load-file len ) + find-file ( ) + + \ + \ Now we've found the file we should read it in in one big hunk + \ + + cur-inode di_size x@ ( file-len ) + dup " to file-size" evaluate ( file-len ) + boot-debug? if load-file-print-size then + 0 to cur-offset + loader-base ( buf-len addr ) + 2dup read-file ( buf-len addr ) + ufs-close ( buf-len addr ) + dup is-elf? if ." load-file: not an elf executable" cr abort then + + \ Luckily the prom should be able to handle ELF executables by itself + + nip ( addr ) +; + +: do-boot ( bootfile -- ) + ." OpenBSD IEEE 1275 Bootblock" cr + boot-path load-file ( -- load-base ) + dup 0<> if " to load-base init-program" evaluate then +; + + +boot-args ascii V strchr 0<> swap drop if + true to boot-debug? +then + +boot-args ascii D strchr 0= swap drop if + " /ofwboot" do-boot +then exit + + |