4.1 boot block for uda50
rbbb.rice%rand-relay at sri-unix.UUCP
rbbb.rice%rand-relay at sri-unix.UUCP
Fri Nov 4 14:48:42 AEST 1983
From: David Chase <rbbb.rice at rand-relay>
Here is a (the?) boot program for a 750 with ra81 on uda50 running bsd4.1.
It really works, or else I wouldn't be writing this.
David Chase, Rice University
----------------------------------------------------------------
This is the boot block program to boot Unix from a UDA device.
Actually, this is a general boot program, and can be used on any 750 with
any devices, given that the appropriate boot ROMs are installed.
It's been tested on UDAs and RK07s, but not yet on a MASSBUS device.
Note that the CSR locations MUST be where the ROMs expect them; usual
configurations have devices at non-standard locations. (eg, our UDA boot
ROMs expect the CSR at 772150.) You often must change the hardwired CSR
in sys/stand/uda.c as well, to make it conform.
This program may be freely distributed but the opening comments MUST be left
intact.
------------
/*
* VAX 11-750 disk boot program to load "/boot" from
* a UNIX filesystem into low core and to execute that file.
*
* This program can only read regular small 10k byte files
* from the root of a UNIX filesystem. That is to say, it cannot
* (does not care to) look at indirect blocks. It just loads
* the (up to) first 10 blocks addressed by the direct map
* pointers, and goes from there.
*
* If anything goes wrong during the boot, an error code is left in R7.
* The codes are defined below.
*
* written by Scott Comer at the urging of Mike Caplinger.
* copyright (c) LCSE, Rice University, Houston TX
*/
.set DATA, 0x3000 /* start of impure data area */
.set STACK, 0xfa00 /* good place for the stack */
.set BOOTBASE, 0xfe00 /* relocated home of boot block */
/* these three hold the register contents needed by the */
/* rom driver subroutine to access the boot device */
.set driver_r1, DATA
.set driver_r2, driver_r1+4
.set driver_r3, driver_r2+4
.set driver, driver_r3+4 /* addr of driver routine */
.set inode_start, driver+4
.set di_mode, inode_start /* disk resident inode */
.set di_nlink, di_mode+2
.set di_uid, di_nlink+2
.set di_gid, di_uid+2
.set di_size, di_gid+2
.set di_addr, di_size+4
.set di_atime, di_addr+40 /* 13 map ptrs: 3 bytes each */
.set di_mtime, di_atime+4
.set di_ctime, di_mtime+4
.set inode_end, di_ctime+4
.set inode_size, inode_end-inode_start
.set BLOCK_SIZE, 1024 /* file system block size */
.set inodes_per_block, BLOCK_SIZE/inode_size
.set blocks_before_ilist, 2 /* boot and super blocks */
.set dir_size, 16 /* size of directory entry */
.set name_size, 14 /* size of name string */
.set ENTADR,024 /* offset to entry addr in a.out */
.set root_inode, 2 /* root dir inode no. */
.set NOT_FIRST_64K, 0x1001
.set UNSUPPORTED_DEVICE, 0x1002
.set RETURN_FROM_BOOT, 0x1003
.set COULD_NOT_FIND_BOOT, 0x1004
.set FILE_TOO_LARGE, 0x1005
.set FILE_READ_ERROR, 0x1006
init:
.long 0 /* boot block parameters */
.long 0 /* (all unused, hence 0) */
.long 0
/*
The registers are set by the console subsystem as follows. Those marked with
stars are saved by the driver subroutine. Those marked with a "d" are used
by the driver subroutine, and must contain the indicated values before
calling the driver.
r0 = type of boot device (see 750 hardware reference, console)
ds r1 = address of the unibus i/o page
ds r2 = boot device CSR address
ds r3 = boot device unit number
s r4 =
ds r5 = software boot flags (driver: offset to buffer for read)
s r6 = driver subroutine address
r7 =
d r8 = LBN of block to read from disk
r9 =
s r10 =
s r11 =
s ap =
fp =
s sp =
Memory is mapped as follows:
0000 to 01ff Boot block program
0200 to f9ff Available
fa00 to fdff Drivers and control routines
fe00 to ffff Available
The /boot programs are small (size <= 10240 bytes), and are ultimatly loaded
starting at 0000. The UNIX boot block programs all assume this; hence I
shall too. Because of this, the boot block program will have to relocate
itself. Addresses above 27ff are available as scratch. Thus, the final layout
of memory will be:
0000 to 27ff /boot program
2800 to f8ff Available for scratch
f900 to f9ff Stack
fa00 to fdff Drivers and control routines
fe00 to ffff Boot block program (relocated)
Upon calling the loaded program (/boot), the registers are expected to
contain the following:
r10 = boot device code (this is different from DEC codes; see table, later)
r11 = software boot flags (from console boot command)
*/
start:
clrl r7
movl r0, r10 /* save the device type */
moval init, r11 /* base address of good memory */
movl r5, ap /* save the boot flags */
tstl r11 /* see if it is zero */
beql 1f
movzwl $NOT_FIRST_64K, r7
halt /* not in first 64k of memory */
1: moval STACK(r11), sp /* put the stack somewhere good */
/* save the register contents needed by the boot driver */
movl r1, driver_r1(r11)
movl r2, driver_r2(r11)
movl r3, driver_r3(r11)
movl r6, driver(r11)
/* relocate the boot program */
movc3 $end, (r11), BOOTBASE(r11)
jmp BOOTBASE+start2(r11)
start2:
/* running relocated */
pushl $root_inode /* go read the / directory */
calls $1, BOOTBASE+get_inode(r11)
calls $0, BOOTBASE+read_file(r11)
calls $0, BOOTBASE+search_boot(r11) /* look for 'boot' */
/* the inode number of 'boot' is now in r0 */
restart:
pushl r0 /* read in 'boot' */
calls $1, BOOTBASE+get_inode(r11)
calls $0, BOOTBASE+read_file(r11)
/* if we make it thus far, boot has been loaded into */
/* memory starting at location 0. */
/* we still have to set up the registers as /boot will */
/* want them. After that, the program is called */
movl r11, r9 /* save the base pointer */
/* boot strap device codes from microcode routines */
.set AnyMassBus, 0
.set RK07, 1
.set RL02, 2
.set UDA50, 17
.set TU58, 64
cmpb r10, $AnyMassBus
bneq 1f
movzbl $0, r10 /* massbus disk */
brb 2f
1: cmpb r10, $RK07
bneq 1f
movzbl $3, r10 /* rk07 disk */
brb 2f
1: cmpb r10, $UDA50
bneq 1f
movzbl $9, r10 /* uda50 */
brb 2f
1: movzwl $UNSUPPORTED_DEVICE, r7
halt /* unsupported device */
2: movl ap, r11 /* software boot flags */
addl3 di_size(r9), r9, r2 /* address to start clear */
moval BOOTBASE(r9), r1 /* address to stop clearing */
1: cmpl r2, r1
bgeq 2f
clrb (r2)+
brb 1b
2: calls $0, (r9)
movzwl $RETURN_FROM_BOOT, r7
halt /* end of program */
boot_file:
.byte 'b, 'o, 'o, 't, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
search_boot:
.word 0xffc /* r11-r2 */
/* search the root directory for 'boot' */
/* returns the inode number in r0, or halts */
movl r11, r10 /* pointer to first directory entry */
addl3 di_size(r11), r11, r9 /* first byte past directory */
1: tstw (r10) /* check the inode number */
beql 2f /* this entry is unused */
cmpc3 $name_size, BOOTBASE+boot_file(r11), 2(r10) /* check the name */
bneq 2f
movzwl (r10), r0 /* found it, return the inumber */
ret
2: addl2 $dir_size, r10 /* continue the search with the */
cmpl r10, r9 /* gone past the end... */
blss 1b
movzwl $COULD_NOT_FIND_BOOT, r7
halt /* could not find 'boot' */
read_file:
.word 0xffc /* r11-r2 */
cmpl di_size(r11), $10240 /* no large files here */
bleq 1f
movzwl $FILE_TOO_LARGE, r7
halt /* file too large */
1: moval di_addr(r11), r2
clrl r3
2: extzv $0, $24, (r2), r4
beql 3f /* end of the list */
pushl r3
pushl r4
calls $2, BOOTBASE+read_block(r11)
addl2 $3, r2
addl2 $BLOCK_SIZE, r3
brb 2b
3: ret
read_block:
.word 0xffc /* r11-r2 */
clrq -(sp) /* make room for the buf addr */
movl driver_r1(r11), r1
movl driver_r2(r11), r2
movl driver_r3(r11), r3
mull3 $2, 4(ap), r4 /* mult by 2 to get lbn */
movl r4, r8
movl 8(ap), r5
addl3 r5, r11, (sp) /* for massbus babies */
jsb *driver(r11) /* read the first block */
blbs r0, 1f
movzwl $FILE_READ_ERROR, r7
halt /* error reading file */
1: addl3 $1, r4, r8
addl2 $512, r5
addl3 r5, r11, (sp) /* for massbus babies */
jsb *driver(r11) /* read the second block */
blbs r0, 1f
movzwl $FILE_READ_ERROR, r7
halt /* error reading file */
1: ret
get_inode:
.word 0xffc /* r11-r2 */
/* turn into offset from beginning of disk */
/* (remember that inodes are numbered from 1?) */
addl3 $(inodes_per_block * blocks_before_ilist - 1), 4(ap), r0
clrl r1
ediv $inodes_per_block, r0, r0, r2
pushl $0 /* read into 0 */
pushl r0
calls $2, BOOTBASE+read_block(r11) /* read a block */
mull2 $inode_size, r2
addl2 r11, r2
movc3 $inode_size, (r2), inode_start(r11)
ret
end:
----------------------------------------------------------------
More information about the Comp.unix.wizards
mailing list