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--