1*33388Sbostic /* 2*33388Sbostic * @(#)tmscpboot.c 7.2 (Berkeley) 01/22/88 3*33388Sbostic * 4*33388Sbostic * TK50 tape boot block for distribution tapes 5*33388Sbostic * works on Q-bus tk50 drive on uVaxen 6*33388Sbostic * 7*33388Sbostic * Rick Lindsley 8*33388Sbostic * richl@tektronix.tek.com 9*33388Sbostic * 10*33388Sbostic * reads a program from a tp directory on a tape and executes it 11*33388Sbostic * program must be stripped of the header and is loaded ``bits as is'' 12*33388Sbostic * you can return to this loader via ``ret'' as you are called ``calls $0,ent'' 13*33388Sbostic */ 1433387Sbostic .set RELOC,0x70000 15*33388Sbostic /* tp directory definitions */ 1633387Sbostic .set FILSIZ,38 # tp direc offset for file size 1733387Sbostic .set BNUM,44 # tp dir offset for start block no. 1833387Sbostic .set ENTSIZ,64 # size of 1 TP dir entry, bytes 1933387Sbostic .set PTHSIZ,32 # size of TP path name, bytes 2033387Sbostic .set BLKSIZ,512 # tape block size, bytes 2133387Sbostic .set NUMDIR,24 # no. of dir blocks on tape 2233387Sbostic .set ENTBLK,8 # no. of dir entries per tape block 2333387Sbostic /* processor registers and bits */ 2433387Sbostic .set RXCS,32 2533387Sbostic .set RXDB,33 2633387Sbostic .set TXCS,34 2733387Sbostic .set TXDB,35 2833387Sbostic .set RXCS_DONE,0x80 2933387Sbostic .set TXCS_RDY,0x80 3033387Sbostic .set TXCS_pr,7 /* bit position of TXCS ready bit */ 3133387Sbostic .set RXCS_pd,7 /* bit position of RXCS done bit */ 3233387Sbostic /* UBA registers */ 3333387Sbostic .set MAPSTART,0x20088000 # for a uVax, anyway 3433387Sbostic .set UBAMEM,0x1ffc2000 # again, for a uVax 3533387Sbostic .set MRV,0x80000000 # map register valid bit 3633387Sbostic /* TMSCP UBA registers */ 3733387Sbostic .set TMSCP_CSR, 0774500 # CSR of tk50 3833387Sbostic .set TMSCPip,0 # initialization and polling 3933387Sbostic .set TMSCPsa,2 # status and address 4033387Sbostic /* handy values for tmscp communication area */ 4133387Sbostic .set TMSCP_OWN,0x80000000 4233387Sbostic .set TMSCP_ERR,0x8000 4333387Sbostic .set TMSCP_STEP4,0x4000 4433387Sbostic .set TMSCP_STEP3,0x2000 4533387Sbostic .set TMSCP_STEP2,0x1000 4633387Sbostic .set TMSCP_STEP1,0x800 4733387Sbostic .set TMSCP_IE,0x80 4833387Sbostic .set TMSCP_GO,1 4933387Sbostic /* handy offsets into tmscp communication area (from tmscpca) */ 5033387Sbostic .set cmdint,4 5133387Sbostic .set rspint,6 5233387Sbostic .set rspdsc,8 5333387Sbostic .set cmddsc,12 5433387Sbostic /* handy offsets into mscp packets (from %rCMD or %rRSP) */ 5533387Sbostic .set msglen,0 5633387Sbostic .set vcid,3 5733387Sbostic .set unit,8 5833387Sbostic .set op,12 5933387Sbostic .set status,14 6033387Sbostic .set modifier,14 6133387Sbostic .set bytecnt,16 6233387Sbostic .set cntflgs,18 6333387Sbostic .set buffer,20 6433387Sbostic .set tmkcnt,20 6533387Sbostic .set lbn,32 6633387Sbostic .set dscptr,40 6733387Sbostic /* TMSCP commands and modifiers */ 6833387Sbostic .set M_OP_STCON,4 6933387Sbostic .set M_OP_ONLIN,9 7033387Sbostic .set M_OP_READ,33 7133387Sbostic .set M_OP_REPOS,37 7233387Sbostic .set M_MD_REWND,2 7333387Sbostic .set M_MD_IMMED,0x80 7433387Sbostic .set M_MD_CLSEX,0x200 7533387Sbostic .set M_ST_MASK,0x1f 7633387Sbostic .set M_ST_TAPEM,14 7733387Sbostic /* miscellaneous */ 7833387Sbostic .set IUR, 0x37 7933387Sbostic .set SID, 0x3e 8033387Sbostic .set VAX_630,8 8133387Sbostic /* local stack variables */ 8233387Sbostic .set tmscpca,-240-PTHSIZ-26 # struct tmscpca (see tmscpreg.h) 8333387Sbostic .set rsp,-240-PTHSIZ-10 # tmscp response area 8433387Sbostic .set cmd,-120-PTHSIZ-10 # tmscp command area 8533387Sbostic .set name,-PTHSIZ-10 # operator-typed file name 8633387Sbostic .set dirread,-10 # is the tape directory incore already? 8733387Sbostic .set mtapa,-8 # cur tape addr (last blk we read) 8833387Sbostic .set tapa,-4 # desired tape addr (inclusive) 8933387Sbostic /* register usage */ 9033387Sbostic .set rCMD,r7 9133387Sbostic .set rRSP,r8 9233387Sbostic .set rUBADDR,r9 9333387Sbostic .set rMAPREGS,r10 9433387Sbostic .set rCSR,r11 9533387Sbostic /* ===== */ 9633387Sbostic 9733387Sbostic /* initialization */ 9833387Sbostic init: 9933387Sbostic # 10033387Sbostic # if on a uVax, we were loaded by VMB from tape. We also have 10133387Sbostic # only one unibus, at 0x1fffc2000 (see above). Elstwise, this 10233387Sbostic # boot program will almost certainly need help. 10333387Sbostic # 10433387Sbostic mfpr $SID,r0 10533387Sbostic cmpzv $24,$8,r0,$VAX_630 10633387Sbostic beql 1f 10733387Sbostic halt 10833387Sbostic # 10933387Sbostic # We must have been loaded by VMB, and thus we are at a non-zero 11033387Sbostic # location. sp will contain the base address of the area at which 11133387Sbostic # we were loaded. So we add sp to $end to get the true end-of-program 11233387Sbostic # address. 11333387Sbostic # 11433387Sbostic 1: movl sp,r6 # r6 - beginning of program 11533387Sbostic movl $RELOC,fp # core loc to which to move this program 11633387Sbostic addl3 $-512,fp,sp # set stack pointer; leave room for locals 11733387Sbostic addl3 $-512,fp,r0 # zero our destination mem .. we start here 11833387Sbostic addl3 $end,fp,r1 # and end here 11933387Sbostic clr: clrl (r0)+ 12033387Sbostic cmpl r0,r1 12133387Sbostic jlss clr 12233387Sbostic 12333387Sbostic movc3 $end,(r6),(fp) # copy to relocated position 12433387Sbostic addl3 $reginit,$RELOC,r0 12533387Sbostic jmp (r0) # and go there 12633387Sbostic reginit: 12733387Sbostic /* initialize our registers. Should need to do this only once */ 12833387Sbostic addl3 $UBAMEM, $TMSCP_CSR, %rCSR # set up CSR register 12933387Sbostic movl $MAPSTART, %rMAPREGS # locate map registers 13033387Sbostic 13133387Sbostic moval tmscpca(fp), %rUBADDR # set unibus address for comm area 13233387Sbostic extzv $0,$9,%rUBADDR,%rUBADDR # format: (MR# << 9) | (&comm & 0x1ff) 13333387Sbostic ashl $-9,$RELOC-512,r0 # setting up map register for our stack 13433387Sbostic bisl3 $MRV,r0,(%rMAPREGS) # mark our stack valid (MR #0) 13533387Sbostic 13633387Sbostic moval cmd(fp),%rCMD # location of cmd mscp packet 13733387Sbostic moval rsp(fp),%rRSP # location of rsp mscp packet 13833387Sbostic bsbw inittmscp # init the unit 13933387Sbostic bsbw onlin # set tape online 14033387Sbostic bsbw rew # rewind tape 14133387Sbostic 14233387Sbostic start: 143*33388Sbostic #ifdef DEBUG 144*33388Sbostic movzbl $11,r0 # newline 145*33388Sbostic bsbw putc 146*33388Sbostic movzbl $13,r0 # return 147*33388Sbostic bsbw putc 148*33388Sbostic #endif 14933387Sbostic movzbl $'=,r0 # prompt 150*33388Sbostic bsbw putc 15133387Sbostic bsbw getname 15233387Sbostic 15333387Sbostic # desired TP filename is in name(fp). Now read in entire tp directory 15433387Sbostic # contents into low core, starting at loc 0. Because tk50's are slow, 15533387Sbostic # and because we are going to go over 512 bytes anyway, and because 15633387Sbostic # it requires so little effort, we'll keep track of whether the data 15733387Sbostic # at location 0 is the tape directory. 15833387Sbostic 15933387Sbostic tstw dirread(fp) # if directory needs to be read in, do so 16033387Sbostic bneq 1f 16133387Sbostic bsbw readdir 16233387Sbostic 1: 16333387Sbostic # 16433387Sbostic # all of directory is now in locore, @ 0. 16533387Sbostic # search for filename; return to start if it isn't there. 16633387Sbostic # 16733387Sbostic clrl r0 # start at location 0 16833387Sbostic nxtdir: moval name(fp),r2 16933387Sbostic movl r0,r1 17033387Sbostic 1: cmpb (r1),(r2) 17133387Sbostic bneq 2f 17233387Sbostic tstb (r1) 17333387Sbostic beql found 17433387Sbostic incl r1 17533387Sbostic incl r2 17633387Sbostic brb 1b 17733387Sbostic 2: acbl $NUMDIR*BLKSIZ-1,$ENTSIZ,r0,nxtdir 17833387Sbostic brw start # entry not in directory; start over 17933387Sbostic 18033387Sbostic # entry IS here; read it in from tape 18133387Sbostic 18233387Sbostic found: movzwl BNUM(r0),tapa(fp) # start block no., 2 bytes 18333387Sbostic addl2 $2-1,tapa(fp) # skip over this program (2 blocks) 18433387Sbostic # minus 1 because we will read THROUGH 18533387Sbostic # this block; so we want to stop just 18633387Sbostic # before it 18733387Sbostic movzwl FILSIZ(r0),r4 # low 2 bytes file size 18833387Sbostic insv FILSIZ-1(r0),$16,$8,r4 # file size, high byte 18933387Sbostic cmpl r4,$RELOC-512 # check if file fits below stack 19033387Sbostic bgeq start # file too large 19133387Sbostic 19233387Sbostic # Now advance to proper place on tape. tapa has our 19333387Sbostic # desired address 19433387Sbostic 19533387Sbostic clrw dirread(fp) # we are about to obliterate our incore copy 19633387Sbostic # of the directory 19733387Sbostic 2: clrl r3 # rrec expects r3 to point to a buffer. 0 will do ... 19833387Sbostic bsbw rrec 19933387Sbostic cmpl mtapa(fp),tapa(fp) 20033387Sbostic blss 2b 20133387Sbostic 20233387Sbostic # tape now positioned correctly. Read in program. Number of bytes 20333387Sbostic # to read is in r4. We must round up to an even BLKSIZ boundary. 20433387Sbostic # Clear the area we are putting it at; unix expects zeroes in its 20533387Sbostic # data and bss section. 20633387Sbostic 20733387Sbostic addl2 $BLKSIZ-1,r4 # round up 20833387Sbostic bicl2 $BLKSIZ-1,r4 # mask out 20933387Sbostic movl r4,r5 # use r5; need to save r4 for later 21033387Sbostic 1: clrl (r5) 21133387Sbostic sobgtr r5,1b 21233387Sbostic 21333387Sbostic # now read in file. 21433387Sbostic 21533387Sbostic clrl r3 # read into page 0 (incremented by rrec) 21633387Sbostic ashl $-9,r4,r5 # r5 now holds # blks to read 21733387Sbostic addl2 r5,tapa(fp) # compute desired tape blk # 21833387Sbostic 1: bsbw rrec 21933387Sbostic cmpl mtapa(fp),tapa(fp) # got it yet? 22033387Sbostic blss 1b 22133387Sbostic 22233387Sbostic # begin execution. Call as a function. 22333387Sbostic clrl r5 22433387Sbostic calls $0,(r5) 22533387Sbostic 22633387Sbostic # now, since the called function has reset the tape drive for 22733387Sbostic # us (!) we must reinit it again ourselves. 22833387Sbostic 22933387Sbostic ashl $-9,$RELOC-512,r0 # set up map register for our stack 23033387Sbostic bisl3 $MRV,r0,(%rMAPREGS) # mark our stack valid (MR #0) 23133387Sbostic bsbw inittmscp # re-init drive 23233387Sbostic bsbw onlin # re-online it 23333387Sbostic brw start 23433387Sbostic 23533387Sbostic # getname will set name(fp) and leave len(name(fp)) in r6 23633387Sbostic getname:moval name(fp),r1 # mov to register for ease of access 23733387Sbostic nxtc: bsbw getc 23833387Sbostic cmpb r0,$012 # end of line? 23933387Sbostic beql nullc 24033387Sbostic movb r0,(r1)+ 24133387Sbostic brb nxtc 24233387Sbostic nullc: moval name(fp),r0 24333387Sbostic subl3 r0,r1,r6 # length of path name 24433387Sbostic jeql start # just hit return; nothing useful here 24533387Sbostic clrb (r1)+ # add null at end 24633387Sbostic incl r6 # add null to length 24733387Sbostic rsb 24833387Sbostic 24933387Sbostic getc: mfpr $RXCS,r0 25033387Sbostic bbc $RXCS_pd,r0,getc /* receiver ready ? */ 25133387Sbostic mfpr $RXDB,r0 25233387Sbostic extzv $0,$7,r0,r0 25333387Sbostic cmpb r0,$015 25433387Sbostic bneq putc 25533387Sbostic bsbw putc 25633387Sbostic movb $0,r0 25733387Sbostic bsbw putc 25833387Sbostic movb $012,r0 25933387Sbostic 26033387Sbostic putc: mfpr $TXCS,r2 26133387Sbostic bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 26233387Sbostic extzv $0,$7,r0,r0 26333387Sbostic mtpr r0,$TXDB 26433387Sbostic rsb 26533387Sbostic 26633387Sbostic inittmscp: 26733387Sbostic movw $0,TMSCPip(%rCSR) # start step 1 26833387Sbostic 1: bitw $TMSCP_STEP1,TMSCPsa(%rCSR) 26933387Sbostic beql 1b 270*33388Sbostic #ifdef DEBUG 271*33388Sbostic movzbl $'1,r0 272*33388Sbostic bsbw putc 273*33388Sbostic #endif 27433387Sbostic init2: movw $TMSCP_ERR,TMSCPsa(%rCSR) # start step 2 27533387Sbostic 2: bitw $TMSCP_STEP2,TMSCPsa(%rCSR) 27633387Sbostic beql 2b 277*33388Sbostic #ifdef DEBUG 278*33388Sbostic movzbl $'2,r0 279*33388Sbostic bsbw putc 280*33388Sbostic #endif 28133387Sbostic init3: addl3 $8,%rUBADDR,r0 # start step 3 28233387Sbostic cvtlw r0,TMSCPsa(%rCSR) 28333387Sbostic 3: bitw $TMSCP_STEP3,TMSCPsa(%rCSR) 28433387Sbostic beql 3b 285*33388Sbostic #ifdef DEBUG 286*33388Sbostic movzbl $'3,r0 287*33388Sbostic bsbw putc 288*33388Sbostic #endif 28933387Sbostic init4: addl3 $8,%rUBADDR,r0 # start step 4 29033387Sbostic ashl $-16,r0,r0 29133387Sbostic cvtlw r0,TMSCPsa(%rCSR) 29233387Sbostic 4: bitw $TMSCP_STEP4,TMSCPsa(%rCSR) 29333387Sbostic beql 4b 294*33388Sbostic #ifdef DEBUG 295*33388Sbostic movzbl $'4,r0 296*33388Sbostic bsbw putc 297*33388Sbostic #endif 29833387Sbostic setchar: 29933387Sbostic movw $TMSCP_GO,TMSCPsa(%rCSR) 30033387Sbostic moval 140(%rUBADDR),tmscpca+cmddsc(fp) 30133387Sbostic moval tmscpca+cmddsc(fp),dscptr(%rCMD) 30233387Sbostic movb $1,vcid(%rCMD) 30333387Sbostic moval 20(%rUBADDR),tmscpca+rspdsc(fp) 30433387Sbostic moval tmscpca+rspdsc(fp),dscptr(%rRSP) 30533387Sbostic clrw cntflgs(%rCMD) 30633387Sbostic 30733387Sbostic movb $M_OP_STCON,op(%rCMD) 30833387Sbostic clrw modifier(%rCMD) 30933387Sbostic clrl buffer(%rCMD) 31033387Sbostic clrl bytecnt(%rCMD) 311*33388Sbostic bsbw tmscpcmd 312*33388Sbostic #ifdef DEBUG 313*33388Sbostic movzbl $'S,r0 314*33388Sbostic bsbw putc 315*33388Sbostic #endif 31633387Sbostic rsb 31733387Sbostic 31833387Sbostic tmscpcmd: 31933387Sbostic movw $116,msglen(%rCMD) # 116 -- size of an mscp packet 32033387Sbostic bisl2 $TMSCP_OWN,tmscpca+cmddsc(fp) 32133387Sbostic movw $116,msglen(%rRSP) 32233387Sbostic bisl2 $TMSCP_OWN,tmscpca+rspdsc(fp) 32333387Sbostic movw TMSCPip(%rCSR),r0 # start polling 32433387Sbostic wait: cvtwl TMSCPsa(%rCSR),r0 32533387Sbostic bitl $TMSCP_ERR,r0 32633387Sbostic beql 1f 32733387Sbostic movw modifier(%rRSP),r1 # so we can read status easily 32833387Sbostic halt # some error or other 32933387Sbostic 1: tstl tmscpca+4(fp) 33033387Sbostic beql 2f 33133387Sbostic clrw tmscpca+4(fp) 33233387Sbostic 2: bitl $TMSCP_OWN,tmscpca+rspdsc(fp) 33333387Sbostic bneq wait 33433387Sbostic 33533387Sbostic # cmd done 33633387Sbostic 33733387Sbostic clrw tmscpca+rspint(fp) 33833387Sbostic extzv $0,$5,status(%rRSP),r0 33933387Sbostic tstl r0 34033387Sbostic beql ok # no errors 34133387Sbostic cmpl $M_ST_TAPEM, r0 34233387Sbostic beql ok # not an error, just a tape mark 34333387Sbostic halt # some unknown error 34433387Sbostic ok: rsb 34533387Sbostic 34633387Sbostic rew: movb $M_OP_REPOS,op(%rCMD) 34733387Sbostic movw $M_MD_REWND|M_MD_IMMED,modifier(%rCMD) 34833387Sbostic clrl buffer(%rCMD) 34933387Sbostic clrl bytecnt(%rCMD) 35033387Sbostic bsbw tmscpcmd 351*33388Sbostic #ifdef DEBUG 352*33388Sbostic movzbl $'r,r0 # to indicate r)ewind 353*33388Sbostic bsbw putc 354*33388Sbostic #endif 35533387Sbostic movl $-1,mtapa(fp) # no blocks read yet 35633387Sbostic rsb 357*33388Sbostic 35833387Sbostic onlin: movb $M_OP_ONLIN,op(%rCMD) 35933387Sbostic clrw modifier(%rCMD) 36033387Sbostic clrl buffer(%rCMD) 36133387Sbostic clrl bytecnt(%rCMD) 36233387Sbostic bsbw tmscpcmd 363*33388Sbostic #ifdef DEBUG 364*33388Sbostic movzbl $'O,r0 # to indicate O)nline 365*33388Sbostic bsbw putc 366*33388Sbostic #endif 36733387Sbostic rsb 368*33388Sbostic 36933387Sbostic # Read the tp directory. Number of blocks to read is in tapa(fp), 37033387Sbostic # and will be read into memory starting at location 0. 37133387Sbostic readdir:bsbw rew # beginning of tape 37233387Sbostic addl3 $2,$NUMDIR,tapa(fp) # blocks to read (skip this 1k program) 37333387Sbostic clrl r3 # using mem starting at 0 as free space 37433387Sbostic bsbw rrec; bsbw rrec # read and discard first two blocks -- 37533387Sbostic # those are this program 37633387Sbostic bsbw rrec # read and discard first tp block 37733387Sbostic clrl r3 # reset starting place 37833387Sbostic incw dirread(fp) # show that directory is incore 37933387Sbostic 1: bsbw rrec 38033387Sbostic cmpl mtapa(fp),tapa(fp) # done yet? 38133387Sbostic blss 1b 38233387Sbostic rsb 38333387Sbostic 38433387Sbostic # read 1 block from mag tape into page indicated by r3, which will 38533387Sbostic # automatically be incremented here. mtapa is also advanced. 38633387Sbostic 38733387Sbostic rrec: bisl3 $MRV,r3,4(%rMAPREGS) # using map register #1 38833387Sbostic movl $BLKSIZ,bytecnt(%rCMD) # how much to read 38933387Sbostic ashl $9,$1,buffer(%rCMD) # indicating mr #1. We just happen to 39033387Sbostic # be on a page boundary, so filling in 39133387Sbostic # the low 9 bits is not necessary. 39233387Sbostic movb $M_OP_READ,op(%rCMD) 39333387Sbostic clrw modifier(%rCMD) 39433387Sbostic bsbw tmscpcmd 395*33388Sbostic #ifdef DEBUG 396*33388Sbostic movzbl $'R,r0 # to indicate R)ead a record 397*33388Sbostic bsbw putc 398*33388Sbostic #endif 39933387Sbostic incl mtapa(fp) 40033387Sbostic incl r3 40133387Sbostic rsb 40233387Sbostic end: 403