V10/lsys/boot/naut/bda.s
#
# fake boot ROM for nautilus, KDB50
#
# read block 0 of some specified drive into memory,
# and branch there, with registers set to point to
# a device driver that can read other blocks.
# register conventions a la the comet boot ROMs
# we expect to be loaded at address 0xfa00,
# and that we have 1024 bytes to squander there
# (like the four comet ROMs)
#
#
# nautilus-specific defs
#
.set NMICSR,0x20080000 # nmi csrs -- device 0
.set NMIto2,30 # 0x40000000; add to get device 1
.set LOOP,0x10000 # csr0 loopback mode
#
# VAXBI defs
#
.set FIRSTBI,0x20000000 # BI 0 node 0
.set NSIZE,0x2000 # size of a BI node
.set BISIZE,0x2000000 # size of all the registers in a BI
#
# VAXBI and/or KDB50 defs
#
.set BITYPE,0
.set DB88,0x106 # device type for DB88
.set BICSR,0x4
.set SST,0x400 # node reset
.set BROKE,0x1000 # i'm broken
.set BISADR,0x20
.set BIEADR,0x24
.set IP,0xf2 # word -- ip reg
.set SAR,0xf4 # word -- read version of sa reg
.set SAW,0xf6 # word -- write version of sa
.set STEP0,10 # STEP1 == bit 11
.set BPOWN,31 # bit 31 == port owns descriptor
.set RTOC,4
#
# mscp defs
# packet offsets have 4 added to account for UQSSP header (mostly length)
#
.set m_crf,4 # command ref number
.set m_unit,8 # disk unit number
.set m_opcd,12 # opcode
.set m_sts,14 # status (word)
.set RPKSIZE,16 # as much as we want on rcv
.set m_bcnt,16 # byte count
.set SOSIZE,20 # as much as we send for ONLINE
.set m_buff,20 # buffer address
.set m_lbn,32 # block number
.set SRSIZE,36 # as much as we send to read
.set SOSIZE,36 # as much as we send for ONLINE
.set OPONL,011 # unit online
.set OPRD,041 # read block
#
# boot ROM conventions
#
.set WMEM,0x200 # sp == some working memory + WMEM
# usually working memory == 0
.set BSIZE,512 # size of a block
ourstack:
.byte 'U,'D # ROM id (though we're not in a ROM)
#
# here to start off, at 0xfa02
# registers:
# r1 bi node number; 0xf == node, 0xf0 == which BI
# r2 uninteresting to us; we put register addr there
# r3 unit number
# r5 boot flags; ignored but preserved
# sp working memory + WMEM
#
# registers to save: r0 r1 r3 r5 r10 r11 ap sp
# init the appropriate NBIA/NBIB
# assume the NBIA is already OK
#
movl sp,savesp
movab ourstack,sp
movl $NMICSR,r2
extzv $4,$2,r1,r6 # get BI number
bbc $1,r6,0f
bbss $NMIto2,r2,0f # second NBIA
0: bisl2 $LOOP,(r2) # set loopback mode
mull3 r6,$BISIZE,r7 # first node in this BI
addl2 $FIRSTBI,r7
movl BITYPE(r7),r8
movw $DB88,r8
movl r8,BITYPE(r7) # set device type in DB88
clrl BISADR(r7) # start address
movl $0x20000000,BIEADR(r7) # end address: all possible mem
bisl2 $BROKE,BICSR(r7) # set BROKE to clear it
bicl2 $LOOP,(r2) # and turn off loopback mode
#
# init the KDB50
#
extzv $0,$4,r1,r2 # pick out node number
mull2 $NSIZE,r2
addl2 r7,r2 # address of KDB50 regs
bisw2 $SST,BICSR(r2) # reset: kick into startup
0: movw SAR(r2),r7
blss oops
bbc $STEP0+1,r7,0b # wait for step1
movw $0x8000,SAW(r2) # no vector, ring size (2^0,2^0)
0: movw SAR(r2),r7
blss oops
bbc $STEP0+2,r7,0b # wait for step2
movab rsp,r6 # ring address
movw r6,SAW(r2)
0: movw SAR(r2),r7
blss oops
bbc $STEP0+3,r7,0b # wait for step3
ashl $-16,r6,r6
movw r6,SAW(r2)
0: movw SAR(r2),r7
blss oops
bbc $STEP0+4,r7,0b # wait for step4
movw $1,SAW(r2) # GO
#
# read block 0 into bottom of memory
#
pushl r0 # rblk eats it
movab rblk,r6 # set up device driver address
subl3 $WMEM,savesp,-(sp) # physical addr
# trick: we know driver doesn't use r5, so we needn't preserve boot flags
clrl r8 # block 0
jsb (r6)
blbc r0,oops
tstl (sp)+
movl (sp)+,r0
#
# start boot block
# registers now:
# r0 device type (unchanged)
# r1 BI node number (unchanged)
# r2 device register addr
# r3 device unit number (unchanged)
# r5 boot flags (unchanged)
# r6 address of our device driver
# sp `working memory + 0x200' (unchanged)
#
movl savesp,sp
jmp 0xc-WMEM(sp)
#
# here when something is broken
#
oops: halt
#
# device driver; called above and by boot block and friends
#
# r2 device registers
# r3 device unit number
# r5 buffer address, relative to `working memory' (ignored)
# 4(sp) physical buffer address; we use that
# r8 block number
#
# do not destroy r1-r6 r10 r11 ap
# on return, low bit of r0 set if we read it, clear if we failed
#
# always bring disk online, even if already is
#
rblk:
movq r10,-(sp)
clrl r0 # assume failure
movab cp,r10
movab rp,r11
movab rsp,r9
movl r3,m_unit(r10) # make ONLINE packet
movzbl $OPONL,m_opcd(r10)
movzbl $SOSIZE,(r10)
clrl m_bcnt(r10) # ugh
clrl m_buff(r10) # ugh
clrl m_lbn(r10) # ugh
bsbb sendrcv
bneq rfail
movzbl $OPRD,m_opcd(r10) # now make READ packet
movl 4+8(sp),m_buff(r10) # unmapped address
movzwl $BSIZE,m_bcnt(r10)
movl r8,m_lbn(r10)
movzbl $SRSIZE,(r10)
bsbb sendrcv
bneq rfail
incl r0 # success
rfail: movq (sp)+,r10
rsb
sendrcv:
movzbl $RPKSIZE,(r11)
movab m_crf(r10),RTOC(r9)
movab m_crf(r11),(r9)
bbss $BPOWN,(r9),0f # make response buffer available
0: bbss $BPOWN,RTOC(r9),0f # send the ONLINE packet
0: movw IP(r2),r7 # kick to make it go
0: bbs $BPOWN,(r9),0b # wait for answer
tstb m_sts(r11) # tstb: ignore `already online' flag
rsb
#
# KDB50 communication area
#
.align 2
savesp: .space 4 # working mem + WMEM
.space 8 # crap at the top
rsp: .space 4 # response descriptor
.space 4 # command descriptor
#
# a pair of packets
# +4 for length
#
cp: .space SRSIZE+4 # command packet
rp: .space RPKSIZE+4 # response packet