Subject: sdboot
To: None <port-hp700@netbsd.org>
From: ITOH Yasufumi <itohy@netbsd.org>
List: port-hp700
Date: 11/01/2003 23:59:42
------- =_aaaaaaaaaa0
Content-Type: text/plain; charset="us-ascii"
Content-ID: <21873.1067697575.1@pino.my.domain>
Content-Transfer-Encoding: 7bit
Folks,
I'm writing sdboot, the first stage boot for sd disks.
It may need more work, but would be useful for testing.
Currently, it reads raw binary "/boot.test" and execute it.
FFS (UFS1 and UFS2) and LFS (UFS1) are supported.
Here's some hints of the usage:
0. Build hppa toolchain.
1. Extract this at sys/arch/hp700/stand.
2. Build boot programs.
% cd sys/arch/hp700/stand
% nbmake-hp700 obj dependall
% cd sdboot.test
% nbmake-hp700 obj dependall
3. Write sdboot at the top of a disk.
Note this overwrites the existing contents of the disk.
# dd conv=sync,notrunc bs=2k count=4 if=obj.hp700/sdboot of=/dev/rsdxx
4. Write disklabel to the disk
The size of partition "a" must not exceed 2GB.
(example omitted since it may be somewhat complicated :)
5. newfs partition "a" and mount it.
# newfs /dev/rsd0a
# mount /dev/sd0a /mnt
6. Copy the secondary boot to the partition.
# objcopy -O binary .../hp700/stand/boot/obj.hp700/boot /mnt/boot.test
7. Put kernel and binaries to the partition.
8. Try booting from the disk.
9. test and debug
enjoy,
--
ITOH Yasufumi
------- =_aaaaaaaaaa0
Content-Type: text/plain; name="sdboot.test.shar"; charset="us-ascii"
Content-ID: <21873.1067697575.2@pino.my.domain>
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="sdboot.test.shar"
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# sdboot.test
# sdboot.test/README.sdboot
# sdboot.test/Makefile
# sdboot.test/start.s
# sdboot.test/main.c
# sdboot.test/milli_tiny.s
# sdboot.test/readufs.c
# sdboot.test/readufs.h
# sdboot.test/readufs_ffs.c
# sdboot.test/readufs_lfs.c
# sdboot.test/iplsum.c
#
echo c - sdboot.test
mkdir -p sdboot.test > /dev/null 2>&1
echo x - sdboot.test/README.sdboot
sed 's/^X//' >sdboot.test/README.sdboot << 'END-of-sdboot.test/README.sdboot'
X# $NetBSD$
X
XCoding notice:
X
X In order to make this relocatable,
X
X 1. Do not place any objects in text segment
X 1.1. For compiler,
X (1) do not declare or define any objects to be placed in
X text segment, that is, do not use const
X (but declaring a pointer to const is probably OK),
X
X (2) make sure string literals, if any, are placed in data
X segment (use traditional compiler),
X
X (3) avoid initialization of automatic objects (non-static
X function-local variables) of aggregate types (arrays,
X structs and unions), which may implicitly emits
X constant data.
X
X In summary, do not use ANSI extension. Use traditional C. :-)
X
X 1.2. For linker, do not actually place objects in text segment.
X
X 2. Do not use function pointers.
X
X
XOn-disk layout:
X
X We have 6.5KB for the primary boot.
X
X disk address
X start size
X 000000 0000FC LIF header
X 0000FC 000104 unused
X 000200 000194 disklabel (404 bytes)
X 000394 00006C unused
X 000400 000400 ipl part 2 (1KB)
X 000800 000100 optional LIF directory
X 000900 000100 unused
X 000A00 000600 ipl part 3 (1.5KB)
X 001000 001000 ipl part 1 (4KB)
X 002000 (file system starts here)
X
X
XOn-memory layout on IPL startup:
X
X address offset
X start size
X 000000 001000 ipl part 1
X 001000 000A00 (not loaded yet)
X (bss section etc)
X x 001000 temporary disk buffer
X x+1000 stack
X
X
XThen the IPL will load the rest of itself:
X
X address offset
X start size
X 000000 001000 ipl part 1
X 001000 000400 ipl part 2
X 001400 000600 ipl part 3
X 001A00 xxxxxx (bss section etc)
END-of-sdboot.test/README.sdboot
echo x - sdboot.test/Makefile
sed 's/^X//' >sdboot.test/Makefile << 'END-of-sdboot.test/Makefile'
X# $NetBSD$
X
XPROG= sdboot
XSRCS= start.s main.c readufs.c readufs_ffs.c readufs_lfs.c milli_tiny.s
X
XCPPFLAGS+= -mpa-risc-1-0 -I${.CURDIR}/../../../.. -I. -D_STANDALONE
X# configuration for readufs module
XCPPFLAGS+= -DUSE_LFS -DUSE_FFS -DUSE_UFS1 -DUSE_UFS2
X# IODC can handle only 2GB, so this is enough
XCPPFLAGS+= -D__daddr_t=int32_t
X# require -O for relocatable code
X# -funsigned-char reduces size
XDBG= -O -funsigned-char -W -Wall
X# ANSI C feature prevents from being relocatable
X#CPPFLAGS+= -traditional # would be best
XCPPFLAGS+= -fwritable-strings -Dconst=
X
XBINDIR= /usr/mdec
XSTRIPFLAG=
XBINMODE= 444
XMKMAN= no
X
X# standalone program
XLIBCRTBEGIN=
XLIBCRT0=
XLIBCRTEND=
XLIBC=
X
X${PROG}: iplsum
X ${LD} -Ttext 0 -Tdata 0 -e '$$START$$' -N -o $@1 $(OBJS)
X ${LD} -Ttext 0x100 -Tdata 0x23456780 -e '$$START$$' -N -o $@2 $(OBJS)
X ${SIZE} $@1
X ${OBJCOPY} -O binary -j .data $@1 $@1.bin
X ${OBJCOPY} -O binary -j .data $@2 $@2.bin
X cmp $@1.bin $@2.bin # should be same
X ${OBJCOPY} -O binary -j .text $@1 $@2.bin
X test ! -s $@2.bin # text section must be empty
X ./iplsum $@1.bin $@
X
Xiplsum: iplsum.c
X ${HOST_CC} -o $@ ${.CURDIR}/iplsum.c
X
XCLEANFILES+= ${PROG}1 ${PROG}2 ${PROG}1.bin ${PROG}2.bin ${PROG}.bin iplsum
XCLEANFILES+= main.o.s readufs.o.s readufs_ffs.o.s readufs_lfs.o.s \
X main.o.s.s readufs.o.s.s readufs_ffs.o.s.s readufs_lfs.o.s.s
X
X.include <bsd.prog.mk>
X
X# override default rules
X
X# Place code to data section.
X.s.o:
X sed -e 's/\.code/.data/' \
X -e '/\.subspa/{' -e 's/\.SUBSPA \$$BSS\$$.*/.section .bss,"aw",@nobits/p' -e 'd' -e } \
X -e 's/\.allow$$/.level 1.0/' -e 's/\.allow/.level/' \
X -e 's/\.bss/.section .bss,"aw",@nobits/' \
X $< | ${AS} -o $@
X
X# Place code to data section, and make sure all address calculations
X# are relative to $global$.
X.c.o:
X ${CC} ${CFLAGS} ${CPPFLAGS} -o $@.s -S $<
X @grep -i 'ldil' $@.s | egrep -v "ldil L'-?[0-9]*,"; \
X case "$$?" in 1) exit 0;; \
X *) echo 'found non-relocatable code' >&2; exit 1;; esac
X sed -e 's/\.text/.data/' $@.s >$@.s.s
X ${AS} -o $@ $@.s.s
END-of-sdboot.test/Makefile
echo x - sdboot.test/start.s
sed 's/^X//' >sdboot.test/start.s << 'END-of-sdboot.test/start.s'
X; $NetBSD$
X
X; Copyright (c) 2003 ITOH Yasufumi.
X; All rights reserved.
X;
X; Redistribution and use in source and binary forms, with or without
X; modification, are permitted provided that the following conditions
X; are met:
X; 1. Redistributions of source code must retain the above copyright
X; notice, this list of conditions and the following disclaimer.
X; 2. Redistributions in binary form must reproduce the above copyright
X; notice, this list of conditions and the following disclaimer in the
X; documentation and/or other materials provided with the distribution.
X; 3. All advertising materials mentioning features or use of this software
X; must display the following acknowledgement:
X; This product includes software developed by ITOH Yasufumi.
X; 4. The name of the authors may not be used to endorse or promote products
X; derived from this software without specific prior written permission
X;
X; THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS''
X; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
X; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
X; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
X; BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
X; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
X; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
X; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
X; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
X; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
X; THE POSSIBILITY OF SUCH DAMAGE.
X
X .level 1.0
X
X .code
X .origin 0
X ;
X ; LIF (Logical Interchange Format) header
X ;
Xlifhdr: .byte 0x80,0x00 ; LIF magic
X .string "NetBSD" ; volume label (6 chars, fill with space)
X .origin 0xf0
X ; 0xf0
Xlif_ipl_addr:
X .word top-lifhdr ; start at 4KB (must be 2KB aligned)
Xlif_ipl_size:
X .word 0x00001000 ; size 4KB (must be 2KB aligned)
Xlif_ipl_entry:
X .word $START$-top ; entry offset
X
X ; ipl part 1 starts here
X .origin 4096
Xtop:
X ;
X ; IPL startup
X ;
X .export $START$,entry
X$START$:
X b,n start ; 0: entry address
X
XBOOT_IF_VERSION: .equ 0
X; version 0: arg0 = interactive flag, arg1 = version (0),
X; arg2 = end addr, arg3 = selected boot partition
X; r1, r3 - r22, r28, r29, r31 = cleared to zeros
X
Xcksum: .word 0 ; 4: checksum will be stored here
Xversion: .word BOOT_IF_VERSION ; 8: version of interface of primary to
X ; secondary boot
Xrsvd1: .word 0 ; 12: future use
Xrsvd2: .word 0 ; 16: future use
Xrsvd3: .word 0 ; 20: future use
X
Xstart:
X ; set data pointer for relocatable data access
X blr %r0,%r27
X ; get PSW at entry
X ssm 0,%r4
X .export $global$,data
X$global$:
X
X ; save parameters for main
X copy %arg0,%r3
X
Xtmpdiskbufsz: .equ 0x1000 ; 4KB
Xtmpdiskbuf_labelsec: .equ 0x0200 ; dbtob(LABELSECTOR)
Xtmpdiskbuf_labelsecsz: .equ 512
Xtmpdiskbuf_part2: .equ 0x0400
Xtmpdiskbuf_part2sz: .equ 0x0400
Xtmpdiskbuf_part3: .equ 0x0A00
Xtmpdiskbuf_part3sz: .equ 0x0600
X
Xpart1sz: .equ 0x1000
X
X ; get next free address
X .import _end,data
X addil L%_end-$global$,%r27;%r1
X ldo R%_end-$global$(%r1),%r1
X
X ; 32bit environment (and this code) requires stack is 64byte aligned.
X ldi 64-1,%r2
X add %r1,%r2,%r1
X andcm %r1,%r2,%r6 ; r6 = tmp disk buffer
X ldo tmpdiskbufsz+64(%r6),%sp ; tmp stack
X
X bl print,%rp
X ldo str_start-$global$(%r27),%arg0
X
X ;
X ; read part 2 and 3 of ipl (see README.sdboot)
X ;
X
X ; read disk blocks which contains ipl part 2 and part 3
X copy %r6,%arg0
X ldi 0,%arg2 ; offset = 0
X bl boot_input,%rp
X ldi tmpdiskbufsz,%arg1 ; read size
X
X ; part 2 address
X ldo top-$global$+part1sz(%r27),%r19
X
X ; copy part 2
X ldo tmpdiskbuf_part2(%r6),%r20
X addi,tr tmpdiskbuf_part2sz/4,%r0,%r2 ; loop count, skip next
Xcpipl2: stws,ma %r1,4(0,%r19) ; write to dst
X addib,uv,n -1,%r2,cpipl2 ; check loop condition
X ldws,ma 4(0,%r20),%r1 ; read from src
X
X ; copy part 3
X ; (r19 already has destination address of part 3)
X ldo tmpdiskbuf_part3(%r6),%r20
X addi,tr tmpdiskbuf_part3sz/4,%r0,%r2 ; loop count, skip next
Xcpipl3: stws,ma %r1,4(0,%r19) ; write to dst
X addib,uv,n -1,%r2,cpipl3 ; check loop condition
X ldws,ma 4(0,%r20),%r1 ; read from src
X
X ; flush data cache / invalidate instruction cache
X ldo top-$global$+part1sz(%r27),%r1 ; part 2 address
X ldi 16,%r20 ; 16: cache line size
Xflipl: fdc 0(0,%r1) ; flush data cache line at r1
X comb,< %r1,%r19,flipl
X fic,m %r20(0,%r1) ; flush instruction cache line at r1, r1 += 16
X sync ; I/O operation is guaranteed to finish
X ; in eight instructions after sync
X ;
X ; Now, whole the IPL is loaded
X ;
X
X ; clear BSS
X .import _edata,data
X addil L%_edata-$global$,%r27;%r1
X ldo R%_edata-$global$(%r1),%r1
Xclrbss: comb,< %r1,%r6,clrbss
X stws,ma %r0,4(0,%r1)
X
X ; we have read disklabel -- save it for later use
X .import labelsector,data
X addil L%labelsector-$global$,%r27;%r1
X ldo R%labelsector-$global$(%r1),%r20
X ldo tmpdiskbuf_labelsec(%r6),%r21
X addi,tr tmpdiskbuf_labelsecsz/4,%r0,%r2 ; loop count, skip next
Xcplbl: stws,ma %r1,4(0,%r20) ; write to dst
X addib,uv,n -1,%r2,cplbl ; check loop condition
X ldws,ma 4(0,%r21),%r1 ; read from src
X
X ; set stack
X ; (r6 points at free space, 64byte aligned)
X ; 32bit environment (and this code) requires stack is 64byte aligned.
X ldo 64(%r6),%sp ; 64 > 48: frame marker (32) + args(up to 4)
X
X ; stack usage
X ; 12bytes arguments
X ; 32 frame marker
X
X ; parameters for main
X copy %r3,%arg0
X copy %r4,%arg2
X
X .import ipl_main,entry
X bl ipl_main,%rp
X copy %sp,%arg1
X
X ; main returned --- perform reset
X bl print,%rp
X ldo str_reset-$global$(%r27),%arg0
X ; FALLTHROUGH
X
XIOMOD_CMD: .equ 0xFFFC0000 + (4*12)
XIOMOD_CMD_STOP: .equ 0
XIOMOD_CMD_RESET: .equ 5
X
X; void reboot(void)
X; void halt(void)
X .export reboot,entry
X .export halt,entry
Xreboot:
X addi,tr IOMOD_CMD_RESET,%r0,%r1 ; %r1 = IOMOD_CMD_RESET, skip next
Xhalt: ldi IOMOD_CMD_STOP,%r1
Xiomcmd: ldil L%IOMOD_CMD,%r2
X ldo R%IOMOD_CMD(%r2),%r2
X stwas %r1,0(%r2)
X b,n .
X
Xstr_start:
X .stringz "\nloading..."
Xstr_reset:
X .stringz "\r\nresetting..."
X .align 4
X
X; void dispatch(unsigned interactive, unsigned top, unsigned end, int part)
X .export dispatch,entry
Xdispatch:
X ; flush data cache / invalidate instruction cache
X copy %arg1,%r1
X ldi 16,%r20 ; 16: cache line size
Xflush: fdc 0(0,%r1) ; flush data cache line at r1
X comb,< %r1,%arg2,flush
X fic,m %r20(0,%r1) ; flush instruction cache line at r1, r1 += 16
X sync
X copy %r0,%r1 ; I/O operation is guaranteed to finish
X copy %r0,%r3 ; in eight instructions after sync
X copy %r0,%r4
X copy %r0,%r5 ; while waiting, clear unused registers
X copy %r0,%r6 ; for future compatibility
X copy %r0,%r7
X copy %r0,%r8
X copy %r0,%r9
X copy %r0,%r10
X copy %r0,%r11
X copy %r0,%r12
X copy %r0,%r13
X copy %r0,%r14
X copy %r0,%r15
X copy %r0,%r16
X copy %r0,%r17
X copy %r0,%r18
X copy %r0,%r19
X copy %r0,%r20
X copy %r0,%r21
X copy %r0,%r22
X copy %r0,%r28 ; r23-r26: arg3-arg0, r27: dp
X copy %r0,%r29 ; r30: sp
X copy %r0,%r31
X ldo reboot-$global$(%r27),%rp ; reboot if returns
X bv %r0(%arg1) ; execute top address
X ldi BOOT_IF_VERSION,%arg1
X
X;
X; IODC subroutines
X;
XPZ_MEM_CONSOLE: .equ 0x3a0
XPZ_MEM_BOOT: .equ 0x3d0
XPZ_MEM_KEYBOARD: .equ 0x400
X
XDEV_PATH: .equ 0x00
XDEV_LAYERS: .equ 0x08
XDEV_HPA: .equ 0x20 ; hard physical adderss space
XDEV_SPA: .equ 0x24 ; soft physical address space
XDEV_IODC_ENTRY: .equ 0x28
XDEV_CLASS: .equ 0x2c
XDEV_CL_DUPLEX: .equ 0x7 ; full-duplex console class
X
XIODC_ENTRY_IO_BOOTIN: .equ 0
XIODC_ENTRY_IO_CONSOLEIN: .equ 2
XIODC_ENTRY_IO_CONSOLEOUT: .equ 3
X
X; call_iodc
X; inputs:
X; %ret0 IODC base in page zero
X; %rp return address
X; %r29 arg 8
X; %r19 arg 7
X; %r20 arg 6
X; %r21 arg 5
X; %r25 arg 1
X; outputs
X; all scratch regs undefined, unless defined by the IODC call
Xcall_iodc:
X ; set common arguments in registers
X addil L%retbuf-$global$,%r27;%r1
X ldo R%retbuf-$global$(%r1),%r22 ; arg4: return buffer
X ldo DEV_LAYERS(%ret0),%arg3 ; arg3: layer
X ldw DEV_SPA(%ret0),%arg2 ; arg2: spa
X ldw DEV_HPA(%ret0),%arg0 ; arg0: hpa
X ; check if narrow or wide mode
X ssm 0,%r1 ; get PSW
X bb,< %r1,4,call_iodc_64 ; if W, call in 64bit mode
X ldw DEV_IODC_ENTRY(%ret0),%r1 ; ENTRY_IO address
X
X ; narrow mode
X stw %r29,-68(%sp) ; arg8: maxsize / lang
X stw %r19,-64(%sp) ; arg7: size
X stw %r20,-60(%sp) ; arg6: buf
X stw %r21,-56(%sp) ; arg5: devaddr / unused
X bv %r0(%r1) ; call ENTRY_IO
X stw %r22,-52(%sp) ; arg4: return buffer
X
Xcall_iodc_64:
X .allow 2.0
X ; On PA64 convention, arg0 - arg7 are passed in registers.
X ; Parameters are placed in INCREASING order.
X ; The argument pointer points at the first stack parameter.
X ; stack usage:
X ; 64bytes allocated for register arguments arg0-arg7
X ; 8 arg8 (argument pointer points here)
X ; 16 frame marker
X std %r29,-16-8(%sp) ; arg8: maxsize / lang
X; std %sp,-8(%sp) ; psp in frame marker
X bv %r0(%r1) ; call ENTRY_IO
X ldo -16-8(%sp),%r29 ; argument pointer
X .allow
X
X;
X; console output
X;
X; void putch(int)
X; void print(const char *string)
X .align 4
X .export putch,entry
X .export print,entry
Xputch:
X ldo 128(%sp),%sp
X stb %arg0,-120(%sp) ; this is a kludge
X stb %r0,-119(%sp) ; (see stack usage below)
X addi,tr -120,%sp,%arg0 ; string address, skip next
Xprint:
X .proc
X .callinfo frame=128,save_rp,no_unwind
X .entry
X ldo 128(%sp),%sp
X stw %rp,-128-20(%sp)
X
X ; stack usage:
X ; 36byte IODC buffer (assume %sp was 64byte aligned)
X ; 4 saved reg
X ; 88 arguments, frame marker
X ; 32bit: 36 (arguments) + 32 (frame marker)
X ; 64bit: 72 (arguments) + 16 (frame marker)
Xprbufsiz: .equ 36
X
X ; save callee-saves
X stw %r3,-92(%sp)
X
X copy %arg0,%r3
X
Xprloop:
X copy %r0,%r19
X ldi prbufsiz,%r20
X ldo -128(%sp),%r1
X
Xstrloop:
X ldb 0(%r3),%r2
X comb,= %r2,%r0,endstr
X stbs,ma %r2,1(0,%r1)
X ldo 1(%r19),%r19
X comb,<> %r19,%r20,strloop
X ldo 1(%r3),%r3
X
Xendstr:
X comb,=,n %r19,%r0,endpr
X
X ; see IODC 3-51
X ; arg0 hpa
X ; arg1 option (ENTRY_IO_CONSOLEOUT (3))
X ; arg2 spa
X ; arg3 ID_addr (pointer to LAYER)
X ; arg4 R_addr (pointer to return buffer (64word?))
X ; arg5 unused (0)
X ; arg6 memaddr (64byte-aligned) string buffer
X ; arg7 reqsize
X ; arg8 lang (0)
X ldi PZ_MEM_CONSOLE,%ret0 ; IODC base in page zero
X copy %r0,%r29 ; arg8: lang
X; copy %r19,%r19 ; arg7: size
X ldo -128(%sp),%r20 ; arg6: buf
X; copy %r0,%r21 ; arg5: unused
X bl call_iodc,%rp
X ldi IODC_ENTRY_IO_CONSOLEOUT,%arg1 ; arg1: option
X b,n prloop
X
Xendpr:
X ; restore callee-saves
X ldw -92(%sp),%r3
X
X ; return subroutine
X ldw -128-20(%sp),%rp
X bv %r0(%rp)
X .exit
X ldo -128(%sp),%sp
X .procend
X
X;
X; console input
X;
X; int getch(void)
X .align 4
X .export getch,entry
Xgetch:
X .proc
X .callinfo frame=192,save_rp,no_unwind
X .entry
X stw %rp,-20(%sp)
X ldo 192(%sp),%sp
X
X ; stack usage:
X ; 64byte IODC buffer (assume %sp was 64byte aligned)
X ; 40 unused
X ; 88 arguments, frame marker
X ; 32bit: 36 (arguments) + 32 (frame marker)
X ; 64bit: 72 (arguments) + 16 (frame marker)
X
X ; check if console is full or half duplex
X ldw PZ_MEM_CONSOLE+DEV_CLASS(%r0),%r1 ; device class
X extru %r1,31,4,%r1 ; right 4bits are valid
X ldi PZ_MEM_CONSOLE,%ret0
X comib,=,n DEV_CL_DUPLEX,%r1,getch_console ; use CONSOLE if full
X ldi PZ_MEM_KEYBOARD,%ret0 ; otherwise KEYBOARD
Xgetch_console:
X
X ; see IODC 3-50
X ; arg0 hpa
X ; arg1 option (ENTRY_IO_CONSOLEIN (2))
X ; arg2 spa
X ; arg3 ID_addr (pointer to LAYER)
X ; arg4 R_addr (pointer to return buffer (64word?))
X ; arg5 unused (0)
X ; arg6 memaddr (64byte-aligned, must have 64byte) data buffer
X ; arg7 reqsize
X ; arg8 lang (0)
X; copy %rp,%rp ; IODC base in page zero
X copy %r0,%r29 ; arg8: lang
X ldi 1,%r19 ; arg7: size (1)
X ldo -192(%sp),%r20 ; arg6: buf
X; copy %r0,%r21 ; arg5: unused
X bl call_iodc,%rp
X ldi IODC_ENTRY_IO_CONSOLEIN,%arg1 ; arg1: option
X
X ; make return value
X comb,<> %ret0,%r0,getch_ret ; return -1 on error
X ldi -1,%ret0
X ldi 1,%r19
X
X ; check if narrow or wide mode
X ssm 0,%r1 ; get PSW
X bb,< %r1,4,getch_64
X addil L%retbuf-$global$,%r27;%r1
X ldw R%retbuf-$global$(%r1),%r2 ; ret[0]
X comclr,<> %r19,%r2,%ret0 ; return 0 if no char available
Xgetch_retc:
X ldb -192(%sp),%ret0 ; otherwise return the char
X
Xgetch_ret:
X ; return subroutine
X ldw -192-20(%sp),%rp
X bv %r0(%rp)
X .exit
X ldo -192(%sp),%sp
X
Xgetch_64:
X .allow 2.0
X ldd R%retbuf-$global$(%r1),%r2 ; ret[0] (64bit)
X b getch_retc
X cmpclr,*<> %r19,%r2,%ret0 ; return 0 if no char available
X .allow
X .procend
X
X;
X; read boot device
X;
X; void boot_input(void *buf, unsigned len, unsigned pos)
X .align 4
X .export boot_input,entry
Xboot_input:
X .proc
X .callinfo frame=128,save_rp,no_unwind
X .entry
X stw %rp,-20(%sp)
X ldo 128(%sp),%sp
X
X ; stack usage:
X ; 40byte unused (alignment)
X ; 88 arguments, frame marker
X ; 32bit: 36 (arguments) + 32 (frame marker)
X ; 64bit: 72 (arguments) + 16 (frame marker)
X
X ; see IODC 3-46
X ; arg0 hpa
X ; arg1 option (ENTRY_IO_BOOTIN (0))
X ; arg2 spa
X ; arg3 ID_addr (pointer to LAYER)
X ; arg4 R_addr (pointer to return buffer (64word?))
X ; arg5 devaddr
X ; arg6 memaddr (64byte-aligned) string buffer
X ; arg7 reqsize
X ; arg8 maxsize
X ldi PZ_MEM_BOOT,%ret0 ; IODC base in page zero
X copy %arg1,%r29 ; arg8: maxsize
X copy %arg1,%r19 ; arg7: size
X copy %arg0,%r20 ; arg6: buf
X copy %arg2,%r21 ; arg5: devaddr
X bl call_iodc,%rp
X ldi IODC_ENTRY_IO_BOOTIN,%arg1 ; arg1: option
X
X ; return subroutine
X ldw -128-20(%sp),%rp
X bv %r0(%rp)
X .exit
X ldo -128(%sp),%sp
X .procend
X
X;
X; utilitiles
X; optimized for size
X;
X
X; int strcmp(const char *str1, const char *str2)
X .align 4
X .export strcmp,entry
Xstrcmp:
X .proc
X .callinfo frame=0,no_calls
X .entry
X ldbs,ma 1(0,%arg0),%r1
Xstrcmp_loop:
X comb,= %r1,%r0,strcmp_eos
X ldbs,ma 1(0,%arg1),%r19
X comb,=,n %r1,%r19,strcmp_loop
X ldbs,ma 1(0,%arg0),%r1
Xstrcmp_eos:
X bv %r0(%rp)
X .exit
X sub %r1,%r19,%ret0
X .procend
X
X; void memcpy(void *dst, const void *src, unsigned len)
X .align 4
X .export memcpy,entry
X .export memmove,entry
Xmemcpy:
Xmemmove:
X .proc
X .callinfo no_unwind ; multiple exit points
X .entry
X; copy %arg0,%ret0 ; uncomment this to conform ANSI
X comb,<<,n %arg0,%arg1,memcpy0 ; copy forward or backward?
X add %arg0,%arg2,%arg0 ; dst end address
X add,tr %arg1,%arg2,%arg1 ; src end address, skip next
Xmemcpy_bwd:
X stbs,mb %r1,-1(0,%arg0) ; write to dst
X addib,uv,n -1,%arg2,memcpy_bwd ; check loop condition
X ldbs,mb -1(0,%arg1),%r1 ; read from src
X bv,n %r0(%rp) ; return subroutine
Xmemcpy_fwd:
X stbs,ma %r1,1(0,%arg0) ; write to dst
Xmemcpy0:
X addib,uv,n -1,%arg2,memcpy_fwd ; check loop condition
X ldbs,ma 1(0,%arg1),%r1 ; read from src
X .exit
X bv,n %r0(%rp) ; return subroutine
X .procend
X
X;
X; string table
X; placed here to save space
X;
X .export str_seekseq, data
X .export str_startup, data
X .export str_bit_firmware, data
X .export str_crlf, data
X .export str_space, data
X .export str_rubout, data
Xstr_seekseq:
X .stringz "repositioning media...\r\n"
Xstr_startup:
X .string "\r\n\n"
X .stringz "NetBSD/hp700 FFS/LFS Primary Bootstrap\r\n\n"
Xstr_bit_firmware:
X .stringz "bit firmware\r\n"
Xstr_rubout:
X .byte 0x08, 0x20, 0x08, 0x00 ; "\b \b"
X
X .export str_bootpart, data
Xstr_bootpart:
X .string "boot partition (a-p, ! to reboot) [a]:"
Xstr_space:
X .stringz " "
X .export str_booting_part, data
Xstr_booting_part:
X .string "\r\nbooting from partition _"
Xstr_crlf:
X .stringz "\r\n"
X .export str_warn_2GB, data
Xstr_warn_2GB:
X .stringz "boot partition exceeds 2GB boundary\r\n"
X .export str_warn_unused, data
Xstr_warn_unused:
X .stringz "unused partition\r\n"
X .export str_nolabel, data
Xstr_nolabel:
X .stringz "no disklabel\r\n"
X
X .export str_filesystem, data
Xstr_filesystem:
X .stringz "filesystem: _FS\r\n"
X .export str_nofs, data
Xstr_nofs:
X .stringz "no filesystem found\r\n"
X .export str_lookup, data
X .export str_loading, data
X .export str_at, data
X .export str_dddot, data
X .export str_done, data
Xstr_lookup:
X .stringz "looking up "
Xstr_loading:
X .stringz "loading "
Xstr_at:
X .stringz " at 0x"
Xstr_dddot:
X .stringz "..."
Xstr_done:
X .stringz "done\r\n"
X
X .export str_boot1, data
X .export str_boot2, data
X .export str_boot3, data
Xstr_boot1:
X .stringz "boot.hp700"
Xstr_boot2:
X .stringz "boot"
Xstr_boot3:
X .stringz "usr/mdec/boot"
X;;;
X .export str_boottest, data
Xstr_boottest:
X .stringz "boot.test"
X;;;
X
X .export str_noboot, data
Xstr_noboot:
X .stringz "no secondary boot found\r\n"
X
X .bss
X .align 64
Xretbuf: .block 32*8 ; *4 for narrow mode / *8 for wide mode
X
X .export diskbuf,data
X .align 64
Xdiskbuf:
X .block 2048
X
X .data
X .subspa $UNWIND_END$, access=0x1f
X .export $UNWIND_END
X$UNWIND_END:
END-of-sdboot.test/start.s
echo x - sdboot.test/main.c
sed 's/^X//' >sdboot.test/main.c << 'END-of-sdboot.test/main.c'
X/* $NetBSD$ */
X
X/*
X * Copyright (c) 2003 ITOH Yasufumi.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X * notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X * notice, this list of conditions and the following disclaimer in the
X * documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X * must display the following acknowledgement:
X * This product includes software developed by ITOH Yasufumi.
X * 4. The name of the authors may not be used to endorse or promote products
X * derived from this software without specific prior written permission
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS''
X * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
X * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
X * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
X * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
X * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
X * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
X * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
X * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
X * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
X * THE POSSIBILITY OF SUCH DAMAGE.
X */
X
X#include <sys/types.h>
X#include <sys/param.h>
X#include <ufs/ufs/dinode.h>
X#include <sys/disklabel.h>
X#include "readufs.h"
X
X#define STACK_SIZE ((unsigned) (64*1024))
X#define LOAD_ALIGN ((unsigned) 2048)
X
X#define PZ_MEM_BOOT 0x3d0
X#define DEV_CLASS 0x2c
X#define DEV_CL_MASK 0xf
X#define DEV_CL_SEQU 0x2 /* sequential record access media */
X
Xstatic char *hexstr __P((char *, unsigned));
Xvoid ipl_main __P((unsigned /*interactive*/,
X unsigned /*sptop*/, unsigned /*psw*/));
Xvoid load_file __P((const char *, unsigned /*loadadr*/,
X unsigned /*interactive*/, int /*part*/));
Xvoid load_file_ino __P((ino_t, const char *, unsigned /*loadadr*/,
X unsigned /*interactive*/, int /*part*/));
X
Xvoid reboot __P((void)), halt __P((void));
Xvoid dispatch __P((unsigned /*interactive*/, unsigned /*top*/,
X unsigned /*end*/, int /*part*/));
Xvoid print __P((const char *));
Xvoid putch __P((int));
Xint getch __P((void));
Xint boot_input __P((void *, int /*len*/, int /*pos*/));
X
X/* to make generated code relocatable, do NOT mark them as const */
Xextern char str_seekseq[], str_startup[], str_bit_firmware[];
Xextern char str_crlf[], str_space[], str_rubout[];
Xextern char str_bootpart[], str_booting_part[];
Xextern char str_warn_2GB[], str_warn_unused[], str_nolabel[];
Xextern char str_filesystem[], str_nofs[];
Xextern char str_lookup[], str_loading[], str_at[], str_dddot[], str_done[];
Xextern char str_boot1[], str_boot2[], str_boot3[];
Xextern char str_noboot[];
X
X#ifdef __GNUC__
X#define memcpy(d, s, n) __builtin_memcpy(d, s, n)
X#endif
X
X/* disklabel */
Xunion {
X char dklsec[512];
X struct disklabel dkl; /* to ensure alignment */
X} labelsector;
X#define dklabel (*(struct disklabel *)(labelsector.dklsec + LABELOFFSET))
X
Xunsigned offset_raw_read;
X
Xextern char diskbuf[2048];
X#define BLK_PER_READ 4
X#define MASK_BLK_PER_READ (BLK_PER_READ - 1)
X
Xvoid
XRAW_READ(buf, blkpos, bytelen)
X void *buf;
X daddr_t blkpos;
X size_t bytelen;
X{
X char *b = buf;
X size_t off, readlen;
X int devoff;
X static int prvdevoff = -dbtob(BLK_PER_READ);
X int pos;
X
X for ( ; bytelen > 0; b += readlen, bytelen -= readlen) {
X /*
X * read 2KB, avoiding unneeded read
X */
X devoff = dbtob(blkpos & ~MASK_BLK_PER_READ) + offset_raw_read;
X if (prvdevoff != devoff) {
X#if 1 /* supports sequential medial */
X if ((*(unsigned *)(PZ_MEM_BOOT+DEV_CLASS) & DEV_CL_MASK)
X == DEV_CL_SEQU) {
X /*
X * sequential media
X * -- read sequentially or rewind
X */
X pos = prvdevoff + dbtob(BLK_PER_READ);
X if (devoff < pos)
X pos = 0; /* rewind */
X
X /* "repositioning media...\r\n" */
X if (devoff - pos > 512 * 1024)
X print(str_seekseq);
X
X for (; pos < devoff; pos += dbtob(BLK_PER_READ))
X boot_input(diskbuf,
X dbtob(BLK_PER_READ), pos);
X }
X#endif
X prvdevoff = devoff;
X boot_input(diskbuf, dbtob(BLK_PER_READ), devoff);
X }
X /*
X * copy specified size to the destination
X */
X off = dbtob(blkpos & MASK_BLK_PER_READ),
X readlen = dbtob(BLK_PER_READ) - off;
X if (readlen > bytelen)
X readlen = bytelen;
X memcpy(b, diskbuf + off, readlen);
X blkpos = (blkpos & ~MASK_BLK_PER_READ) + BLK_PER_READ;
X }
X}
X
X/*
X * convert number to hex string
X * buf must have enough space
X */
Xstatic char *
Xhexstr(buf, val)
X char *buf;
X unsigned val;
X{
X unsigned v;
X char rev[16];
X char *r = rev, *b = buf;
X
X /* inverse order */
X do {
X v = val & 0xf;
X *r++ = (v <= 9) ? '0' + v : 'a' - 10 + v;
X val >>= 4;
X } while (val);
X
X /* reverse string */
X while (r > rev)
X *b++ = *--r;
X
X *b = '\0';
X return buf;
X}
X
Xvoid
Xipl_main(interactive, sptop, psw)
X unsigned interactive; /* parameters from PDC */
X unsigned sptop; /* value of sp on function entry */
X unsigned psw; /* PSW on startup */
X{
X char buf[32];
X int part = 0; /* default partition "a" */
X unsigned secsz, partoff, partsz;
X int c, c1;
X unsigned loadadr;
X
X print(str_startup); /* title banner */
X
X#if 0
X print(hexstr(buf, interactive));
X print(str_crlf);
X print(hexstr(buf, sptop));
X print(str_crlf);
X print(hexstr(buf, psw));
X print(str_crlf);
X#endif
X
X print(hexstr(buf, (psw & 0x08000000) ? (unsigned) 0x64 : 0x32));
X print(str_bit_firmware); /* "bit firmware\r\n" */
X
X /*
X * check disklabel
X * (dklabel has disklabel on startup)
X */
X if (dklabel.d_magic == DISKMAGIC && (secsz = dklabel.d_secsize) != 0) {
X /*
X * select boot partition
X */
X if (interactive) {
X select_partition:
X /* "boot partition (a-p, ! to reboot) [a]:" */
X print(str_bootpart);
X part = 0; /* default partition "a" */
X c1 = 0;
X while ((c = getch()) >= 0) {
X switch (c) {
X case '\n':
X case '\r':
X goto break_while;
X case '\b':
X case '\177':
X if (c1) {
X print(str_rubout);
X part = c1 = 0;
X }
X break;
X case '!': /* reset */
X if (c1 == 0) {
X part = -1;
X goto echoback;
X }
X break;
X default:
X if (c1 == 0 && c >= 'a' && c <= 'p') {
X part = c - 'a';
X echoback:
X putch(c);
X c1 = 1;
X }
X break;
X }
X }
X break_while:
X if (part == -1)
X return; /* reset */
X }
X
X /*
X * "\r\nbooting from partition _\r\n"
X */
X str_booting_part[25] = 'a' + part;
X print(str_booting_part);
X
X partoff = dklabel.d_partitions[part].p_offset;
X partsz = dklabel.d_partitions[part].p_size;
X
X if (part >= (int) dklabel.d_npartitions || partsz == 0) {
X print(str_warn_unused); /* "unused partition\r\n" */
X goto select_partition;
X }
X
X /* boot partition must be below 2GB */
X if (partoff + partsz >=
X (unsigned)((unsigned)2*1024*1024*1024 -1 + secsz) / secsz) {
X /* "boot partition exceeds 2GB boundary\r\n" */
X print(str_warn_2GB);
X goto select_partition;
X }
X
X /*
X * following device accessess are only in the partition
X */
X offset_raw_read = partoff * secsz;
X } else {
X /*
X * no disklabel --- assume the whole of the device
X * is a filesystem
X */
X print(str_nolabel); /* "no disklabel\r\n" */
X }
X
X if (ufs_init()) {
X print(str_nofs); /* "no filesystem found\r\n" */
X return;
X }
X str_filesystem[12] = (ufs_info.fstype == UFSTYPE_FFS) ? 'F' : 'L';
X print(str_filesystem); /* "filesystem: _FS\r\n" */
X
X loadadr = (sptop + STACK_SIZE + LOAD_ALIGN - 1) & (-LOAD_ALIGN);
X#if 1 /* test */
X { extern char str_boottest[];
X load_file(str_boottest, loadadr, interactive, part); /* "boot.test" */
X }
X#else
X load_file(str_boot1, loadadr, interactive, part); /* "boot.hp700" */
X load_file(str_boot2, loadadr, interactive, part); /* "boot" */
X load_file(str_boot3, loadadr, interactive, part); /* "usr/mdec/boot" */
X#endif
X
X print(str_noboot); /* "no secondary boot found\r\n" */
X}
X
Xvoid
Xload_file(path, loadadr, interactive, part)
X const char *path;
X unsigned loadadr, interactive;
X int part;
X{
X
X /* look-up the file */
X print(str_lookup); /* "looking up " */
X print(path);
X print(str_crlf);
X load_file_ino(ufs_lookup_path(path), path, loadadr, interactive, part);
X}
X
Xvoid
Xload_file_ino(ino, fn, loadadr, interactive, part)
X ino_t ino;
X const char *fn; /* for message only */
X unsigned loadadr, interactive;
X int part;
X{
X union ufs_dinode dinode;
X size_t sz;
X char buf[32];
X
X if (ino == 0 || ufs_get_inode(ino, &dinode))
X return; /* not found */
X
X print(str_loading); /* "loading " */
X print(fn);
X print(str_at); /* " at 0x" */
X print(hexstr(buf, loadadr));
X print(str_dddot); /* "..." */
X
X sz = DI_SIZE(&dinode);
X ufs_read(&dinode, (void *) loadadr, 0, sz);
X
X print(str_done); /* "done\r\n" */
X dispatch(interactive, loadadr, loadadr + sz, part);
X}
END-of-sdboot.test/main.c
echo x - sdboot.test/milli_tiny.s
sed 's/^X//' >sdboot.test/milli_tiny.s << 'END-of-sdboot.test/milli_tiny.s'
X; $NetBSD$
X
X; Copyright (c) 2003 ITOH Yasufumi.
X; All rights reserved.
X;
X; Redistribution and use in source and binary forms, with or without
X; modification, are permitted provided that the following conditions
X; are met:
X; 1. Redistributions of source code must retain the above copyright
X; notice, this list of conditions and the following disclaimer.
X; 2. Redistributions in binary form must reproduce the above copyright
X; notice, this list of conditions and the following disclaimer in the
X; documentation and/or other materials provided with the distribution.
X; 3. All advertising materials mentioning features or use of this software
X; must display the following acknowledgement:
X; This product includes software developed by ITOH Yasufumi.
X; 4. The name of the authors may not be used to endorse or promote products
X; derived from this software without specific prior written permission
X;
X; THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS''
X; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
X; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
X; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
X; BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
X; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
X; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
X; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
X; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
X; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
X; THE POSSIBILITY OF SUCH DAMAGE.
X
X; millicode library, optimized for size
X
X .level 1.0
X .code
X .align 4
X
X; $$divU unsigned division, return quotient
X;
X; inputs:
X; %r26 divident
X; %r25 divisor
X; %r31 return address
X; outputs:
X; %r29 quotient
X; %r1, %r25, %r26 undefined
X .export $$divU,millicode
X$$divU:
X .proc
X .callinfo millicode,no_unwind
X .entry
X comb,<,n %r25,0,bigdivisor_divU ; special case (>=0x80000000)
X bl sub_divU,%r29
X subt,= %r0,%r25,%r1 ; trap divide by 0, negate
X
X bv %r0(%r31) ; return millicode
X .exit
X addc %r26,%r26,%r29 ; fix quotient
Xbigdivisor_divU:
X comclr,<< %r26,%r25,%r29 ; if divident >= divisor
X ldi 1,%r29 ; quotient is 1
X bv,n %r0(%r31) ; return millicode
X .procend
X
X; Note this is not a normal sobroutine
X; r29: return adderss
Xsub_divU:
X ldo 64(%sp),%sp
X stw %r19,-64(%sp)
X ldi 31,%r19
X
X ds %r0,%r1,%r0
X addc %r26,%r26,%r26
X ds %r0,%r25,%r1
Xloop_sub_divU: ; addc/ds 31 times
X addc %r26,%r26,%r26
X addib,<> -1,%r19,loop_sub_divU
X ds %r1,%r25,%r1
X
X ldw -64(%sp),%r19
X bv %r0(%r29)
X ldo -64(%sp),%sp
X
X; $$remU unsigned division, return remainder
X;
X; inputs:
X; %r26 divident
X; %r25 divisor
X; %r31 return address
X; outputs:
X; %r29 remainder
X; %r1, %r25, %r26 undefined
X .export $$remU,millicode
X$$remU:
X .proc
X .callinfo millicode,no_unwind
X .entry
X comb,<,n %r25,0,bigdivisor_remU ; special case (>=0x80000000)
X bl sub_divU,%r29
X subt,= %r0,%r25,%r1 ; trap divide by 0, negate
X
X comclr,>= %r1,%r0,%r0
X addl %r1,%r25,%r1 ; fix remainder
X bv %r0(%r31) ; return millicode
X .exit
X copy %r1,%r29 ; the return value is remainder
Xbigdivisor_remU:
X sub,>>= %r26,%r25,%r29 ; if divident < divisor
X copy %r26,%r29 ; the remainder is devident
X bv,n %r0(%r31) ; return millicode
X .procend
X
X; $$mulU unsigned multiplication
X;
X; inputs:
X; %r26 multiplicand
X; %r25 multiplier
X; %r31 return address
X; outputs:
X; %r29 product
X; %r1, %r25, %r26 undefined
X .export $$mulU,millicode
X .export $$mulI,millicode
X$$mulU:
X$$mulI: ; XXX actually wrong (not signed) but works for small positive numbers
X .proc
X .callinfo frame=0,no_calls,millicode
X .entry
X copy %r0,%r29
X ldi 32,%r1 ; loop counter
X
X add,nuv %r25,%r25,%r25 ; shift left, skip next if not C
Xloop_mul:
X sh1add,tr %r29,%r26,%r29 ; shift left and add, skip next
X sh1add %r29,%r0,%r29 ; shift left only
X addib,<>,n -1,%r1,loop_mul ; check loop condition
X add,nuv %r25,%r25,%r25 ; shift left, skip next if not C
X .exit
X bv,n %r0(%r31) ; return millicode
X .procend
END-of-sdboot.test/milli_tiny.s
echo x - sdboot.test/readufs.c
sed 's/^X//' >sdboot.test/readufs.c << 'END-of-sdboot.test/readufs.c'
X/* $Id: readufs.c,v 1.8 2003/04/08 09:19:32 itohy Exp $ */
X
X/*
X * Read UFS (FFS / LFS)
X *
X * Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy@netbsd.org).
X * Public domain.
X *
X * Intended to be used for boot programs (first stage).
X * DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT.
X */
X
X#include "readufs.h"
X
X#define fs ufs_info
X
Xstatic void raw_read_queue __P((void *buf, daddr_t blkpos, size_t bytelen));
Xstatic int ufs_read_indirect __P((daddr_t blk, int level, caddr_t *buf,
X unsigned *poff, size_t count));
X
X#ifdef DEBUG_WITH_STDIO
Xvoid ufs_list_dir __P((ino_t dirino));
Xint main __P((int argc, char *argv[]));
X#endif
X
X#ifdef DEBUG_WITH_STDIO
Xint fd;
X
Xvoid
XRAW_READ(buf, blkpos, bytelen)
X void *buf;
X daddr_t blkpos;
X size_t bytelen;
X{
X
X if (pread(fd, buf, bytelen, (off_t)dbtob(blkpos)) != (ssize_t) bytelen)
X err(1, "pread: buf %p, blk %d, len %u",
X buf, (int) blkpos, bytelen);
X}
X#endif
X
Xstruct ufs_info fs;
X
X/*
X * Read contiguous sectors at once for speedup.
X */
Xstatic size_t rq_len;
X
Xstatic void
Xraw_read_queue(buf, blkpos, bytelen)
X void *buf;
X daddr_t blkpos;
X size_t bytelen; /* must be DEV_BSIZE aligned */
X{
X static daddr_t rq_start;
X static char *rq_buf;
X
X if (rq_len) {
X if (bytelen && blkpos == rq_start + (ssize_t) btodb(rq_len)
X && buf == rq_buf + rq_len) {
X rq_len += bytelen;
X return;
X } else {
X#ifdef DEBUG_WITH_STDIO
X printf("raw_read_queue: read: buf %p, blk %d, len %d\n",
X rq_buf, (int) rq_start, rq_len);
X#endif
X RAW_READ(rq_buf, rq_start, rq_len);
X }
X }
X rq_buf = buf;
X rq_start = blkpos;
X rq_len = bytelen;
X}
X
X#define RAW_READ_QUEUE_INIT() (rq_len = 0)
X#define RAW_READ_QUEUE_FLUSH() \
X raw_read_queue((void *) 0, (daddr_t) 0, (size_t) 0)
X
X
X/*
X * Read a file, specified by dinode.
X * No support for holes or (short) symbolic links.
X */
Xsize_t
Xufs_read(di, buf, off, count)
X union ufs_dinode *di;
X void *buf;
X unsigned off; /* position in block */
X size_t count;
X{
X struct ufs_info *ufsinfo = &fs;
X size_t bsize = ufsinfo->bsize;
X caddr_t b = buf;
X int i;
X size_t disize, nread;
X daddr_t pos;
X#if defined(USE_UFS1) && defined(USE_UFS2)
X enum ufs_ufstype uver = ufsinfo->ufstype;
X#endif
X
X#ifdef DEBUG_WITH_STDIO
X printf("ufs_read: off: %d, count %u\n", off, count);
X#endif
X
X disize = DI_SIZE(di);
X
X if (disize < count + off * bsize)
X count = disize - off * bsize;
X
X /* FS block size alignment. */
X nread = count;
X count = (count + bsize - 1) & ~(bsize - 1);
X
X RAW_READ_QUEUE_INIT();
X
X /* Read direct blocks. */
X for ( ; off < NDADDR && count > 0; off++) {
X#if defined(USE_UFS1) && defined(USE_UFS2)
X if (uver == UFSTYPE_UFS1)
X pos = di->di1.di_db[off];
X else
X pos = di->di2.di_db[off];
X#else
X pos = di->di_thisver.di_db[off];
X#endif
X#if 0
X printf("ufs_read: read: blk: %d\n",
X (int) pos << ufsinfo->fsbtodb);
X#endif
X raw_read_queue(b, pos << ufsinfo->fsbtodb, bsize);
X b += bsize;
X count -= bsize;
X }
X off -= NDADDR;
X
X /* Read indirect blocks. */
X for (i = 0; i < NIADDR && count > 0; i++) {
X#if defined(USE_UFS1) && defined(USE_UFS2)
X if (uver == UFSTYPE_UFS1)
X pos = di->di1.di_ib[i];
X else
X pos = di->di2.di_ib[i];
X#else
X pos = di->di_thisver.di_ib[i];
X#endif
X count = ufs_read_indirect(pos, i, &b, &off, count);
X }
X
X RAW_READ_QUEUE_FLUSH();
X
X return nread;
X}
X
Xstatic int
Xufs_read_indirect(blk, level, buf, poff, count)
X daddr_t blk;
X int level;
X caddr_t *buf;
X unsigned *poff; /* position in block */
X size_t count;
X{
X struct ufs_info *ufsinfo = &fs;
X size_t bsize = ufsinfo->bsize;
X void *idbuf = alloca(bsize);
X#ifdef USE_UFS1
X int32_t *idbuf1 = idbuf;
X#endif
X#ifdef USE_UFS2
X int64_t *idbuf2 = idbuf;
X#endif
X daddr_t pos;
X unsigned off = *poff;
X unsigned b;
X
X#ifdef DEBUG_WITH_STDIO
X printf("ufs_read_indirect: off: %d, count %u\n", off, count);
X#endif
X if (off) {
X unsigned subindirsize = 1, indirsize;
X int i;
X
X for (i = level; i > 0; i--)
X subindirsize *= ufsinfo->nindir;
X indirsize = subindirsize * ufsinfo->nindir;
X if (off >= indirsize) {
X /* no need to read any data */
X *poff = off - indirsize;
X return 0;
X }
X
X b = off / subindirsize;
X off -= b * subindirsize;
X *poff = 0;
X } else
X b = 0;
X
X /* read the indirect block */
X RAW_READ(idbuf, blk << ufsinfo->fsbtodb, bsize);
X
X for ( ; b < ufsinfo->nindir && count > 0; b++) {
X#if defined(USE_UFS1) && defined(USE_UFS2)
X if (ufsinfo->ufstype == UFSTYPE_UFS1)
X#endif
X#ifdef USE_UFS1
X pos = idbuf1[b];
X#endif
X#if defined(USE_UFS1) && defined(USE_UFS2)
X else
X#endif
X#ifdef USE_UFS2
X pos = idbuf2[b];
X#endif
X
X if (level)
X count = ufs_read_indirect(pos, level - 1, buf, &off, count);
X else {
X#if 0
X printf("ufs_read: read: blk: %d\n",
X (int) pos << ufsinfo->fsbtodb);
X#endif
X raw_read_queue(*buf, pos << ufsinfo->fsbtodb, bsize);
X *buf += bsize;
X count -= bsize;
X }
X }
X
X return count;
X}
X
X/*
X * look-up fn in directory dirino
X */
Xino_t
Xufs_lookup(dirino, fn)
X ino_t dirino;
X const char *fn;
X{
X union ufs_dinode dirdi;
X struct direct *pdir;
X char *p, *endp;
X size_t disize;
X
X if (ufs_get_inode(dirino, &dirdi))
X return 0;
X
X if ((dirdi.di_common.di_mode & IFMT) != IFDIR)
X return 0; /* Not a directory */
X
X disize = DI_SIZE(&dirdi);
X
X p = alloca((disize + fs.bsize - 1) & ~(fs.bsize - 1));
X ufs_read(&dirdi, p, 0, disize);
X endp = p + disize;
X for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) {
X if (pdir->d_ino && !strcmp(fn, pdir->d_name))
X return pdir->d_ino;
X }
X return 0; /* No such file or directory */
X}
X
X/*
X * look-up a file in absolute pathname from the root directory
X */
Xino_t
Xufs_lookup_path(path)
X const char *path;
X{
X char fn[MAXNAMLEN + 1];
X char *p;
X ino_t ino = ROOTINO;
X
X do {
X while (*path == '/')
X path++;
X for (p = fn; *path && *path != '/'; )
X *p++ = *path++;
X *p++ = '\0';
X ino = ufs_lookup(ino, fn);
X } while (ino && *path);
X
X return ino;
X}
X
X#if 0
Xsize_t
Xufs_load_file(buf, dirino, fn)
X void *buf;
X ino_t dirino;
X const char *fn;
X{
X size_t cnt, disize;
X union ufs_dinode dinode;
X
X if (ufs_fn_inode(dirino, fn, &dinode))
X return (unsigned) 0;
X disize = DI_SIZE(&dinode);
X cnt = ufs_read(&dinode, buf, 0, disize);
X
X return cnt;
X}
X#endif
X
Xint
Xufs_init()
X{
X return 1
X#ifdef USE_FFS
X && try_ffs()
X#endif
X#ifdef USE_LFS
X && try_lfs()
X#endif
X ;
X}
X
X#ifdef DEBUG_WITH_STDIO
Xvoid
Xufs_list_dir(dirino)
X ino_t dirino;
X{
X union ufs_dinode dirdi;
X struct direct *pdir;
X char *p, *endp;
X size_t disize;
X
X if (ufs_get_inode(dirino, &dirdi))
X errx(1, "ino = %d: not found", dirino);
X
X disize = DI_SIZE(&dirdi);
X p = alloca((disize + fs.bsize - 1) & ~(fs.bsize - 1));
X ufs_read(&dirdi, p, 0, disize);
X endp = p + disize;
X for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) {
X if (pdir->d_ino)
X printf("%6d %s\n", pdir->d_ino, pdir->d_name);
X }
X}
X#endif
X
X#ifdef DEBUG_WITH_STDIO
Xint
Xmain(argc, argv)
X int argc __attribute__((unused));
X char *argv[];
X{
X union ufs_dinode dinode;
X
X if ((fd = open(argv[1], O_RDONLY)) < 0)
X err(1, "open: %s", argv[1]);
X
X if (ufs_init())
X errx(1, "%s: unknown fs", argv[1]);
X
X#if 1
X ufs_list_dir(ROOTINO);
X {
X void *p;
X size_t cnt;
X ino_t ino;
X size_t disize;
X
X if ((ino = ufs_lookup_path(argv[2])) == 0)
X errx(1, "%s: not found", argv[2]);
X ufs_get_inode(ino, &dinode);
X disize = DI_SIZE(&dinode);
X p = malloc((disize + fs.bsize - 1) & ~(fs.bsize - 1));
X cnt = ufs_read(&dinode, p, 0, disize);
X write(3, p, cnt);
X free(p);
X }
X#endif
X
X return 0;
X}
X#endif
END-of-sdboot.test/readufs.c
echo x - sdboot.test/readufs.h
sed 's/^X//' >sdboot.test/readufs.h << 'END-of-sdboot.test/readufs.h'
X/* $Id: readufs.h,v 1.9 2003/10/15 14:16:58 itohy Exp $ */
X
X/*
X * Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy@netbsd.org).
X * Public domain.
X */
X
X#include <sys/types.h>
X#include <sys/param.h>
X#include <ufs/ufs/dinode.h>
X#include <ufs/ufs/dir.h>
X
X/*
X * UFS1 / UFS2
X */
Xunion ufs_dinode {
X#ifdef USE_UFS1
X struct ufs1_dinode di1;
X#endif
X#ifdef USE_UFS2
X struct ufs2_dinode di2;
X#endif
X};
X
X/* short-cut for common fields (di_mode, di_nlink) */
X#ifdef USE_UFS1
X# define di_common di1
X#elif defined USE_UFS2
X# define di_common di2
X#endif
X
X/* for fields of same names and different locations */
X#if !(defined(USE_UFS1) && defined(USE_UFS2))
X# ifdef USE_UFS1
X# define di_thisver di1
X# endif
X# ifdef USE_UFS2
X# define di_thisver di2
X# endif
X#endif
X
X/* this is a size hack */
X#if defined(USE_UFS1) && defined(USE_UFS2)
X# define DI_SIZE(di) ((di)->di1.di_size)
X#else
X# define DI_SIZE(di) ((di)->di_thisver.di_size)
X#endif
X/* and may break following fields on UFS2 */
X#define di_gid di_gid__is_not_available
X#define di_blksize di_blksize__is_not_available
X
X/*
X * filesystem information
X */
Xstruct ufs_info {
X enum ufs_fstype {
X UFSTYPE_UNKNOWN
X#ifdef USE_FFS
X , UFSTYPE_FFS
X#endif
X#ifdef USE_LFS
X , UFSTYPE_LFS
X#endif
X } fstype;
X#if defined(USE_UFS1) && defined(USE_UFS2)
X enum ufs_ufstype {
X UFSTYPE_UFS1, UFSTYPE_UFS2
X } ufstype;
X#endif
X#if 0
X int (*get_inode) __P((ino_t ino, union ufs_dinode *dibuf));
X#endif
X
X /* superblock information */
X u_int32_t bsize; /* fs block size */
X u_int32_t nindir; /* # indirect per block */
X u_int32_t fsbtodb; /* block -> sector shift count */
X union {
X#ifdef USE_FFS
X struct {
X daddr_t iblkno; /* inode-block offset */
X int32_t old_cgoffset; /* cylinder group offset */
X int32_t old_cgmask; /* cylinder group mask */
X int32_t fragshift; /* block to fragmentation */
X int32_t inopb; /* # inodes per block */
X int32_t ipg; /* # inodes per group */
X int32_t fpg; /* # inodes per group * frag */
X int32_t magic; /* FS_UFSx_MAGIC */
X } u_ffs;
X#endif
X#ifdef USE_LFS
X struct {
X u_int32_t version; /* LFS version # */
X daddr_t idaddr; /* ifile inode disk address */
X u_int32_t inopb; /* inodes per block (v1) */
X /* inodes per frag (v2) */
X u_int32_t ifpb; /* inode addrs / ifile block */
X u_int32_t ioffset; /* start of inode in ifile */
X /* (in sector) */
X u_int32_t ibsize; /* size of inode block */
X } u_lfs;
X#endif
X } fs_u;
X};
X
Xextern struct ufs_info ufs_info;
X
Xint get_ffs_inode __P((ino_t ino, union ufs_dinode *dibuf));
Xint get_lfs_inode __P((ino_t ino, union ufs_dinode *dibuf));
X#if defined(USE_FFS) && defined(USE_LFS)
X#define ufs_get_inode(ino, di) ((ufs_info.fstype == UFSTYPE_FFS) ? \
X get_ffs_inode((ino), (di)) : get_lfs_inode((ino), (di)))
X#else
X# ifdef USE_FFS
X# define ufs_get_inode(ino, di) (get_ffs_inode((ino), (di)))
X# endif
X# ifdef USE_LFS
X# define ufs_get_inode(ino, di) (get_lfs_inode((ino), (di)))
X# endif
X#endif
X
Xvoid RAW_READ __P((void *buf, daddr_t blkpos, size_t bytelen));
X
Xsize_t ufs_read __P((union ufs_dinode *di, void *buf, unsigned off,
X size_t count));
Xino_t ufs_lookup __P((ino_t dirino, const char *fn));
Xino_t ufs_lookup_path __P((const char *path));
Xsize_t ufs_load_file __P((void *buf, ino_t dirino, const char *fn));
Xint ufs_init __P((void));
X
X#ifdef USE_FFS
Xint try_ffs __P((void));
X#endif
X
X#ifdef USE_LFS
Xint try_lfs __P((void));
X#endif
X
X#ifdef DEBUG_WITH_STDIO
X#include <fcntl.h>
X#include <err.h>
X#include <stdio.h>
X#include <unistd.h>
X#include <stdlib.h>
X#endif
X
X#ifdef __GNUC__
X# ifndef alloca
X# define alloca(n) __builtin_alloca(n)
X# endif
X# ifndef strcmp
X# define strcmp(p, q) __builtin_strcmp(p, q)
X# endif
X#endif
END-of-sdboot.test/readufs.h
echo x - sdboot.test/readufs_ffs.c
sed 's/^X//' >sdboot.test/readufs_ffs.c << 'END-of-sdboot.test/readufs_ffs.c'
X/* $Id: readufs_ffs.c,v 1.6 2003/04/08 09:19:32 itohy Exp $ */
X
X/*
X * FS specific support for 4.2BSD Fast Filesystem
X *
X * Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy@netbsd.org).
X * Public domain.
X *
X * Intended to be used for boot programs (first stage).
X * DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT.
X */
X
X#include "readufs.h"
X
X#include <ufs/ffs/fs.h>
X
X#define fsi (*ufsinfo)
X#define fsi_ffs fsi.fs_u.u_ffs
X
X/*
X * Read and check superblock.
X * If it is an FFS, save information from the superblock.
X */
Xint
Xtry_ffs()
X{
X union {
X struct fs sblk;
X unsigned char pad[SBLOCKSIZE];
X } buf;
X struct ufs_info *ufsinfo = &ufs_info;
X static int sblocs[] = SBLOCKSEARCH;
X int *sbl;
X int magic;
X
X#ifdef DEBUG_WITH_STDIO
X printf("trying FFS\n");
X#endif
X /* read FFS superblock */
X for (sbl = sblocs; ; sbl++) {
X if (*sbl == -1)
X return 1;
X
X RAW_READ(&buf, (daddr_t) btodb(*sbl), SBLOCKSIZE);
X
X magic = buf.sblk.fs_magic;
X#ifdef DEBUG_WITH_STDIO
X printf("FFS: sblk: pos %d magic 0x%x\n", btodb(*sbl), magic);
X#endif
X
X#ifdef USE_UFS1
X if (magic == FS_UFS1_MAGIC)
X break;
X#endif
X#ifdef USE_UFS2
X if (magic == FS_UFS2_MAGIC) {
X#ifdef USE_UFS1
X fsi.ufstype = UFSTYPE_UFS2;
X#endif
X break;
X }
X#endif
X }
X
X /*
X * XXX <ufs/ffs/fs.h> always uses fs_magic
X * (UFS1 only or UFS2 only is impossible)
X */
X fsi_ffs.magic = magic;
X#ifdef DEBUG_WITH_STDIO
X printf("FFS: detected UFS%d format\n", (magic == FS_UFS2_MAGIC) + 1);
X#endif
X
X /* This partition looks like an FFS. */
X fsi.fstype = UFSTYPE_FFS;
X#if 0
X fsi.get_inode = get_ffs_inode;
X#endif
X
X /* Get information from the superblock. */
X fsi.bsize = buf.sblk.fs_bsize;
X fsi.fsbtodb = buf.sblk.fs_fsbtodb;
X fsi.nindir = buf.sblk.fs_nindir;
X
X fsi_ffs.iblkno = buf.sblk.fs_iblkno;
X fsi_ffs.old_cgoffset = buf.sblk.fs_old_cgoffset;
X fsi_ffs.old_cgmask = buf.sblk.fs_old_cgmask;
X fsi_ffs.fragshift = buf.sblk.fs_fragshift;
X fsi_ffs.inopb = buf.sblk.fs_inopb;
X fsi_ffs.ipg = buf.sblk.fs_ipg;
X fsi_ffs.fpg = buf.sblk.fs_fpg;
X
X return 0;
X}
X
X/* for inode macros */
X#define fs_ipg fs_u.u_ffs.ipg
X#define fs_iblkno fs_u.u_ffs.iblkno
X#define fs_old_cgoffset fs_u.u_ffs.old_cgoffset
X#define fs_old_cgmask fs_u.u_ffs.old_cgmask
X#define fs_fpg fs_u.u_ffs.fpg
X#define fs_magic fs_u.u_ffs.magic
X#define fs_inopb fs_u.u_ffs.inopb
X#define fs_fragshift fs_u.u_ffs.fragshift
X#define fs_fsbtodb fsbtodb
X
X/*
X * Get inode from disk.
X */
Xint
Xget_ffs_inode(ino, dibuf)
X ino_t ino;
X union ufs_dinode *dibuf;
X{
X struct ufs_info *ufsinfo = &ufs_info;
X union ufs_dinode *buf = alloca((size_t) fsi.bsize);
X union ufs_dinode *di;
X unsigned ioff;
X
X RAW_READ(buf, fsbtodb(&fsi, ino_to_fsba(&fsi, ino)),
X (size_t) fsi.bsize);
X
X ioff = ino_to_fsbo(&fsi, ino);
X
X#if defined(USE_UFS1) && defined(USE_UFS2)
X if (ufsinfo->ufstype == UFSTYPE_UFS1)
X di = (void *) &(&buf->di1)[ioff];
X else {
X di = (void *) &(&buf->di2)[ioff];
X
X /* XXX for DI_SIZE() macro */
X di->di1.di_size = di->di2.di_size;
X }
X#else
X di = &buf[ioff];
X#endif
X
X#ifdef DEBUG_WITH_STDIO
X printf("FFS: dinode(%d): mode 0%o, nlink %d, size %u\n",
X ino, di->di_common.di_mode, di->di_common.di_nlink,
X (unsigned) DI_SIZE(di));
X#endif
X
X if (di->di_common.di_mode == 0)
X return 1; /* unused inode (file is not found) */
X
X *dibuf = *di;
X
X return 0;
X}
END-of-sdboot.test/readufs_ffs.c
echo x - sdboot.test/readufs_lfs.c
sed 's/^X//' >sdboot.test/readufs_lfs.c << 'END-of-sdboot.test/readufs_lfs.c'
X/* $Id: readufs_lfs.c,v 1.7 2003/10/15 14:16:58 itohy Exp $ */
X
X/*
X * FS specific support for 4.4BSD Log-structured Filesystem
X *
X * Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy@netbsd.org).
X * Public domain.
X *
X * Intended to be used for boot programs (first stage).
X * DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT.
X */
X
X#include "readufs.h"
X
X#include <sys/mount.h>
X#include <ufs/lfs/lfs.h>
X
X#ifndef USE_UFS1
X #error LFS currently requires USE_UFS1
X#endif
X
Xstatic struct ufs1_dinode ifile_dinode;
X
X#define fsi (*ufsinfo)
X#define fsi_lfs fsi.fs_u.u_lfs
X
X/*
X * Read and check superblock.
X * If it is an LFS, save information from the superblock.
X */
Xint
Xtry_lfs()
X{
X struct ufs_info *ufsinfo = &ufs_info;
X struct dlfs sblk, sblk2;
X struct dlfs *s = &sblk;
X daddr_t sbpos;
X int fsbshift;
X
X#ifdef DEBUG_WITH_STDIO
X printf("trying LFS\n");
X#endif
X sbpos = btodb(LFS_LABELPAD);
X
X /* read primary superblock */
X for (;;) {
X#ifdef DEBUG_WITH_STDIO
X printf("LFS: reading primary sblk at: 0x%x\n", (unsigned)sbpos);
X#endif
X RAW_READ(&sblk, sbpos, sizeof sblk);
X
X#ifdef DEBUG_WITH_STDIO
X printf("LFS: sblk: magic: 0x%x, version: %d\n",
X sblk.dlfs_magic, sblk.dlfs_version);
X#endif
X
X if (sblk.dlfs_magic != LFS_MAGIC)
X return 1;
X
X#ifdef DEBUG_WITH_STDIO
X printf("LFS: bsize %d, fsize %d, bshift %d, blktodb %d, fsbtodb %d, inopf %d, inopb %d\n",
X sblk.dlfs_bsize, sblk.dlfs_fsize,
X sblk.dlfs_bshift, sblk.dlfs_blktodb, sblk.dlfs_fsbtodb,
X sblk.dlfs_inopf, sblk.dlfs_inopb);
X#endif
X if ((fsi_lfs.version = sblk.dlfs_version) == 1) {
X fsbshift = 0;
X break;
X } else {
X daddr_t sbpos1;
X#if 0
X fsbshift = sblk.dlfs_bshift - sblk.dlfs_blktodb + sblk.dlfs_fsbtodb - DEV_BSHIFT;
X#endif
X fsbshift = sblk.dlfs_fsbtodb;
X sbpos1 = sblk.dlfs_sboffs[0] << fsbshift;
X if (sbpos == sbpos1)
X break;
X#ifdef DEBUG_WITH_STDIO
X printf("LFS: correcting primary sblk location\n");
X#endif
X sbpos = sbpos1;
X }
X }
X
X#ifdef DEBUG_WITH_STDIO
X printf("fsbshift: %d\n", fsbshift);
X printf("sboff[1]: %d\n", sblk.dlfs_sboffs[1]);
X#endif
X
X if (sblk.dlfs_sboffs[1] > 0) {
X#ifdef DEBUG_WITH_STDIO
X printf("LFS: reading secondary sblk at: 0x%x\n",
X sblk.dlfs_sboffs[1] << fsbshift);
X#endif
X /* read secondary superblock */
X RAW_READ(&sblk2, (daddr_t) sblk.dlfs_sboffs[1] << fsbshift,
X sizeof sblk2);
X
X#ifdef DEBUG_WITH_STDIO
X printf("LFS: sblk2: magic: 0x%x, version: %d\n",
X sblk2.dlfs_magic, sblk2.dlfs_version);
X#endif
X
X if (sblk2.dlfs_magic == LFS_MAGIC) {
X if (fsi_lfs.version == 1) {
X if (sblk.dlfs_otstamp > sblk2.dlfs_otstamp)
X s = &sblk2;
X } else {
X if (sblk.dlfs_serial > sblk2.dlfs_serial)
X s = &sblk2;
X }
X }
X }
X
X /* This partition looks like an LFS. */
X#if 0
X fsi.get_inode = get_lfs_inode;
X#endif
X /*
X * version 1: disk addr is in disk sector --- no shifting
X * version 2: disk addr is in fragment
X */
X fsi.fsbtodb = fsbshift;
X
X /* Get information from the superblock. */
X fsi.bsize = s->dlfs_bsize;
X fsi.nindir = s->dlfs_nindir;
X fsi_lfs.idaddr = s->dlfs_idaddr;
X fsi_lfs.ibsize = (fsi_lfs.version == 1) ? s->dlfs_bsize : s->dlfs_fsize;
X
X /*
X * version 1: number of inode per block
X * version 2: number of inode per fragment (but in dlfs_inopb)
X */
X fsi_lfs.inopb = s->dlfs_inopb;
X
X fsi_lfs.ifpb = s->dlfs_ifpb;
X fsi_lfs.ioffset = s->dlfs_cleansz + s->dlfs_segtabsz;
X
X /* ifile is always used to look-up other inodes, so keep its inode. */
X if (get_lfs_inode(LFS_IFILE_INUM, (union ufs_dinode *)&ifile_dinode))
X return 1; /* OOPS, failed to find inode of ifile! */
X
X fsi.fstype = UFSTYPE_LFS;
X
X return 0;
X}
X
X/*
X * Get inode from disk.
X */
Xint
Xget_lfs_inode(ino, dibuf)
X ino_t ino;
X union ufs_dinode *dibuf;
X{
X struct ufs_info *ufsinfo = &ufs_info;
X daddr_t daddr;
X char *buf = alloca(fsi.bsize);
X struct ufs1_dinode *di, *diend;
X int i;
X
X /* Get fs block which contains the specified inode. */
X if (ino == LFS_IFILE_INUM)
X daddr = fsi_lfs.idaddr;
X else {
X#ifdef DEBUG_WITH_STDIO
X printf("LFS: ino: %d\nifpb: %d, bsize: %d\n",
X ino, fsi_lfs.ifpb, fsi.bsize);
X#endif
X ufs_read((union ufs_dinode *) &ifile_dinode, buf,
X ino / fsi_lfs.ifpb + fsi_lfs.ioffset,
X fsi.bsize);
X i = ino % fsi_lfs.ifpb;
X daddr = (fsi_lfs.version == 1) ?
X ((IFILE_V1 *) buf + i)->if_daddr
X : ((IFILE *) buf + i)->if_daddr;
X }
X#ifdef DEBUG_WITH_STDIO
X printf("LFS(%d): daddr: %d\n", ino, (int) daddr);
X#endif
X
X if (daddr == LFS_UNUSED_DADDR)
X return 1;
X
X /* Read the inode block. */
X RAW_READ(buf, daddr << fsi.fsbtodb, fsi_lfs.ibsize);
X
X /* Search for the inode. */
X di = (struct ufs1_dinode *) buf;
X diend = di + fsi_lfs.inopb;
X
X for ( ; di < diend; di++)
X if (di->di_inumber == ino)
X goto found;
X /* not found */
X return 1;
X
Xfound:
X#ifdef DEBUG_WITH_STDIO
X printf("LFS: dinode(%d): mode 0%o, nlink %d, inumber %d, size %d, uid %d, db[0] %d\n",
X ino, di->di_mode, di->di_nlink, di->di_inumber,
X (int) di->di_size, di->di_uid, di->di_db[0]);
X#endif
X
X#if 0 /* currently UFS1 only */
X#if defined(USE_UFS1) && defined(USE_UFS2)
X /* XXX for DI_SIZE() macro */
X if (ufsinfo->ufstype != UFSTYPE_UFS1)
X di->di1.di_size = di->si2.di_size;
X#endif
X#endif
X
X dibuf->di1 = *di;
X
X return 0;
X}
END-of-sdboot.test/readufs_lfs.c
echo x - sdboot.test/iplsum.c
sed 's/^X//' >sdboot.test/iplsum.c << 'END-of-sdboot.test/iplsum.c'
X/* $NetBSD$ */
X
X/*
X * Calculate 32bit checksum of IPL and store in a certain location
X *
X * Written by ITOH Yasufumi
X * Public domain
X */
X
X#include <sys/types.h>
X#include <fcntl.h>
X#ifndef NO_STDLIB
X# include <unistd.h>
X#endif
X#include <stdio.h>
X#include <netinet/in.h>
X
X#ifndef __BIT_TYPES_DEFINED__
Xtypedef unsigned int u_int32_t;
X#endif
X
X/* see README.sdboot */
X#define IPLOFF (4*1024) /* 4KB */
X#define IPL1SIZE (4*1024) /* 4KB */
X#define IPL2SIZE (1*1024) /* 1KB */
X#define IPL2ONDISK 0x0400
X#define IPL3SIZE (3*512) /* 1.5KB */
X#define IPL3ONDISK 0x0A00
X#define IPLSIZE (IPL1SIZE + IPL2SIZE + IPL3SIZE)
X#define BOOTSIZE (IPLOFF + IPLSIZE)
X#define BOOTBLOCKSIZE 8192
X
Xu_int32_t bootblk[BOOTSIZE / sizeof(u_int32_t) + 1];
X
X#define SUMOFF ((IPLOFF + 4) / sizeof(u_int32_t))
X
X#ifdef __STDC__
Xint main(int, char *[]);
X#endif
X
Xint
Xmain(argc, argv)
X int argc;
X char *argv[];
X{
X int fd, len;
X u_int32_t sum, *p;
X int iploff, iplsumsize;
X
X if (argc != 3) {
X fprintf(stderr, "usage: %s <input> <output>\n", argv[0]);
X return 1;
X }
X
X /* read file */
X if ((fd = open(argv[1], O_RDONLY)) < 0) {
X perror(argv[1]);
X return 1;
X }
X if ((len = read(fd, bootblk, sizeof bootblk)) <= IPLOFF) {
X fprintf(stderr, "%s: too short\n", argv[1]);
X return 1;
X } else if (len > BOOTSIZE) {
X fprintf(stderr, "%s: too long\n", argv[1]);
X return 1;
X }
X (void) close(fd);
X
X /* sanity check */
X if ((ntohl(bootblk[0]) & 0xffff0000) != 0x80000000) {
X fprintf(stderr, "%s: bad LIF magic\n", argv[1]);
X return 1;
X }
X iploff = ntohl(bootblk[0xf0 / sizeof(u_int32_t)]);
X iplsumsize = ntohl(bootblk[0xf4 / sizeof(u_int32_t)]);
X printf("%d bytes free, ipl offset = %d, ipl sum size = %d\n",
X BOOTSIZE - len, iploff, iplsumsize);
X if (iploff != IPLOFF || iplsumsize <= 0 || iplsumsize % 2048 ||
X iploff + iplsumsize > BOOTBLOCKSIZE) {
X fprintf(stderr, "%s: bad ipl offset / size\n", argv[1]);
X return 1;
X }
X
X /* checksum */
X sum = 0;
X for (p = bootblk + IPLOFF / sizeof(u_int32_t);
X p < bootblk + (IPLOFF + IPL1SIZE) / sizeof(u_int32_t); p++)
X sum += ntohl(*p);
X
X bootblk[SUMOFF] = htonl(ntohl(bootblk[SUMOFF]) - sum);
X
X /* transfer ipl part 2 */
X memcpy(bootblk + IPL2ONDISK / sizeof(u_int32_t),
X bootblk + (IPLOFF + IPL1SIZE) / sizeof(u_int32_t),
X IPL2SIZE);
X
X /* transfer ipl part 3 */
X memcpy(bootblk + IPL3ONDISK / sizeof(u_int32_t),
X bootblk + (IPLOFF + IPL1SIZE + IPL2SIZE) / sizeof(u_int32_t),
X IPL3SIZE);
X
X /* write file */
X if ((fd = creat(argv[2], 0666)) < 0) {
X perror(argv[2]);
X return 1;
X }
X if ((len = write(fd, bootblk, BOOTBLOCKSIZE)) != BOOTBLOCKSIZE) {
X if (len < 0)
X perror(argv[2]);
X else
X fprintf(stderr, "%s: short write\n", argv[2]);
X close(fd);
X (void) unlink(argv[2]);
X return 1;
X }
X if (close(fd)) {
X perror(argv[2]);
X (void) unlink(argv[2]);
X return 1;
X }
X
X return 0;
X}
END-of-sdboot.test/iplsum.c
exit
------- =_aaaaaaaaaa0--