sdboot

[email protected] (ITOH Yasufumi)
Newsgroups gmane.os.netbsd.ports.hp700
Message-ID <[email protected]>
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
sdboot.test.shar (text/plain, 58.2 KB)
# 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 [email protected]
X	${OBJCOPY} -O binary -j .data $@2 [email protected]
X	cmp [email protected] [email protected]	# should be same
X	${OBJCOPY} -O binary -j .text $@1 [email protected]
X	test ! -s [email protected]	# text section must be empty
X	./iplsum [email protected] $@
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 [email protected] -S $<
X	@grep -i 'ldil' [email protected] | 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/' [email protected] >[email protected]
X	${AS} -o $@ [email protected]
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 ([email protected]).
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 ([email protected]).
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 ([email protected]).
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 ([email protected]).
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.