1 # 2 # @(#)tmscpboot.c 7.1 (Berkeley) 01/22/88 3 # 4 # TK50 tape boot block for distribution tapes 5 # works on Q-bus tk50 drive on uVaxen 6 # 7 # Rick Lindsley 8 # richl@tektronix.tek.com 9 # 10 # reads a program from a tp directory on a tape and executes it 11 # program must be stripped of the header and is loaded ``bits as is'' 12 # you can return to this loader via ``ret'' as you are called ``calls $0,ent'' 13 # 14 .set RELOC,0x70000 15 /* tp directory definitions */ 16 .set FILSIZ,38 # tp direc offset for file size 17 .set BNUM,44 # tp dir offset for start block no. 18 .set ENTSIZ,64 # size of 1 TP dir entry, bytes 19 .set PTHSIZ,32 # size of TP path name, bytes 20 .set BLKSIZ,512 # tape block size, bytes 21 .set NUMDIR,24 # no. of dir blocks on tape 22 .set ENTBLK,8 # no. of dir entries per tape block 23 /* processor registers and bits */ 24 .set RXCS,32 25 .set RXDB,33 26 .set TXCS,34 27 .set TXDB,35 28 .set RXCS_DONE,0x80 29 .set TXCS_RDY,0x80 30 .set TXCS_pr,7 /* bit position of TXCS ready bit */ 31 .set RXCS_pd,7 /* bit position of RXCS done bit */ 32 /* UBA registers */ 33 .set MAPSTART,0x20088000 # for a uVax, anyway 34 .set UBAMEM,0x1ffc2000 # again, for a uVax 35 .set MRV,0x80000000 # map register valid bit 36 /* TMSCP UBA registers */ 37 .set TMSCP_CSR, 0774500 # CSR of tk50 38 .set TMSCPip,0 # initialization and polling 39 .set TMSCPsa,2 # status and address 40 /* handy values for tmscp communication area */ 41 .set TMSCP_OWN,0x80000000 42 .set TMSCP_ERR,0x8000 43 .set TMSCP_STEP4,0x4000 44 .set TMSCP_STEP3,0x2000 45 .set TMSCP_STEP2,0x1000 46 .set TMSCP_STEP1,0x800 47 .set TMSCP_IE,0x80 48 .set TMSCP_GO,1 49 /* handy offsets into tmscp communication area (from tmscpca) */ 50 .set cmdint,4 51 .set rspint,6 52 .set rspdsc,8 53 .set cmddsc,12 54 /* handy offsets into mscp packets (from %rCMD or %rRSP) */ 55 .set msglen,0 56 .set vcid,3 57 .set unit,8 58 .set op,12 59 .set status,14 60 .set modifier,14 61 .set bytecnt,16 62 .set cntflgs,18 63 .set buffer,20 64 .set tmkcnt,20 65 .set lbn,32 66 .set dscptr,40 67 /* TMSCP commands and modifiers */ 68 .set M_OP_STCON,4 69 .set M_OP_ONLIN,9 70 .set M_OP_READ,33 71 .set M_OP_REPOS,37 72 .set M_MD_REWND,2 73 .set M_MD_IMMED,0x80 74 .set M_MD_CLSEX,0x200 75 .set M_ST_MASK,0x1f 76 .set M_ST_TAPEM,14 77 /* miscellaneous */ 78 .set IUR, 0x37 79 .set SID, 0x3e 80 .set VAX_630,8 81 /* local stack variables */ 82 .set tmscpca,-240-PTHSIZ-26 # struct tmscpca (see tmscpreg.h) 83 .set rsp,-240-PTHSIZ-10 # tmscp response area 84 .set cmd,-120-PTHSIZ-10 # tmscp command area 85 .set name,-PTHSIZ-10 # operator-typed file name 86 .set dirread,-10 # is the tape directory incore already? 87 .set mtapa,-8 # cur tape addr (last blk we read) 88 .set tapa,-4 # desired tape addr (inclusive) 89 /* register usage */ 90 .set rCMD,r7 91 .set rRSP,r8 92 .set rUBADDR,r9 93 .set rMAPREGS,r10 94 .set rCSR,r11 95 /* ===== */ 96 97 /* initialization */ 98 init: 99 # 100 # if on a uVax, we were loaded by VMB from tape. We also have 101 # only one unibus, at 0x1fffc2000 (see above). Elstwise, this 102 # boot program will almost certainly need help. 103 # 104 mfpr $SID,r0 105 cmpzv $24,$8,r0,$VAX_630 106 beql 1f 107 halt 108 # 109 # We must have been loaded by VMB, and thus we are at a non-zero 110 # location. sp will contain the base address of the area at which 111 # we were loaded. So we add sp to $end to get the true end-of-program 112 # address. 113 # 114 1: movl sp,r6 # r6 - beginning of program 115 movl $RELOC,fp # core loc to which to move this program 116 addl3 $-512,fp,sp # set stack pointer; leave room for locals 117 addl3 $-512,fp,r0 # zero our destination mem .. we start here 118 addl3 $end,fp,r1 # and end here 119 clr: clrl (r0)+ 120 cmpl r0,r1 121 jlss clr 122 123 movc3 $end,(r6),(fp) # copy to relocated position 124 addl3 $reginit,$RELOC,r0 125 jmp (r0) # and go there 126 reginit: 127 /* initialize our registers. Should need to do this only once */ 128 addl3 $UBAMEM, $TMSCP_CSR, %rCSR # set up CSR register 129 movl $MAPSTART, %rMAPREGS # locate map registers 130 131 moval tmscpca(fp), %rUBADDR # set unibus address for comm area 132 extzv $0,$9,%rUBADDR,%rUBADDR # format: (MR# << 9) | (&comm & 0x1ff) 133 ashl $-9,$RELOC-512,r0 # setting up map register for our stack 134 bisl3 $MRV,r0,(%rMAPREGS) # mark our stack valid (MR #0) 135 136 moval cmd(fp),%rCMD # location of cmd mscp packet 137 moval rsp(fp),%rRSP # location of rsp mscp packet 138 bsbw inittmscp # init the unit 139 bsbw onlin # set tape online 140 bsbw rew # rewind tape 141 142 start: 143 # movzbl $11,r0 # newline 144 # bsbw putc 145 # movzbl $13,r0 # return 146 # bsbw putc 147 movzbl $'=,r0 # prompt 148 bsbw putc 149 bsbw getname 150 151 # desired TP filename is in name(fp). Now read in entire tp directory 152 # contents into low core, starting at loc 0. Because tk50's are slow, 153 # and because we are going to go over 512 bytes anyway, and because 154 # it requires so little effort, we'll keep track of whether the data 155 # at location 0 is the tape directory. 156 157 tstw dirread(fp) # if directory needs to be read in, do so 158 bneq 1f 159 bsbw readdir 160 1: 161 # 162 # all of directory is now in locore, @ 0. 163 # search for filename; return to start if it isn't there. 164 # 165 clrl r0 # start at location 0 166 nxtdir: moval name(fp),r2 167 movl r0,r1 168 1: cmpb (r1),(r2) 169 bneq 2f 170 tstb (r1) 171 beql found 172 incl r1 173 incl r2 174 brb 1b 175 2: acbl $NUMDIR*BLKSIZ-1,$ENTSIZ,r0,nxtdir 176 brw start # entry not in directory; start over 177 178 # entry IS here; read it in from tape 179 180 found: movzwl BNUM(r0),tapa(fp) # start block no., 2 bytes 181 addl2 $2-1,tapa(fp) # skip over this program (2 blocks) 182 # minus 1 because we will read THROUGH 183 # this block; so we want to stop just 184 # before it 185 movzwl FILSIZ(r0),r4 # low 2 bytes file size 186 insv FILSIZ-1(r0),$16,$8,r4 # file size, high byte 187 cmpl r4,$RELOC-512 # check if file fits below stack 188 bgeq start # file too large 189 190 # Now advance to proper place on tape. tapa has our 191 # desired address 192 193 clrw dirread(fp) # we are about to obliterate our incore copy 194 # of the directory 195 2: clrl r3 # rrec expects r3 to point to a buffer. 0 will do ... 196 bsbw rrec 197 cmpl mtapa(fp),tapa(fp) 198 blss 2b 199 200 # tape now positioned correctly. Read in program. Number of bytes 201 # to read is in r4. We must round up to an even BLKSIZ boundary. 202 # Clear the area we are putting it at; unix expects zeroes in its 203 # data and bss section. 204 205 addl2 $BLKSIZ-1,r4 # round up 206 bicl2 $BLKSIZ-1,r4 # mask out 207 movl r4,r5 # use r5; need to save r4 for later 208 1: clrl (r5) 209 sobgtr r5,1b 210 211 # now read in file. 212 213 clrl r3 # read into page 0 (incremented by rrec) 214 ashl $-9,r4,r5 # r5 now holds # blks to read 215 addl2 r5,tapa(fp) # compute desired tape blk # 216 1: bsbw rrec 217 cmpl mtapa(fp),tapa(fp) # got it yet? 218 blss 1b 219 220 # begin execution. Call as a function. 221 clrl r5 222 calls $0,(r5) 223 224 # now, since the called function has reset the tape drive for 225 # us (!) we must reinit it again ourselves. 226 227 ashl $-9,$RELOC-512,r0 # set up map register for our stack 228 bisl3 $MRV,r0,(%rMAPREGS) # mark our stack valid (MR #0) 229 bsbw inittmscp # re-init drive 230 bsbw onlin # re-online it 231 brw start 232 233 # getname will set name(fp) and leave len(name(fp)) in r6 234 getname:moval name(fp),r1 # mov to register for ease of access 235 nxtc: bsbw getc 236 cmpb r0,$012 # end of line? 237 beql nullc 238 movb r0,(r1)+ 239 brb nxtc 240 nullc: moval name(fp),r0 241 subl3 r0,r1,r6 # length of path name 242 jeql start # just hit return; nothing useful here 243 clrb (r1)+ # add null at end 244 incl r6 # add null to length 245 rsb 246 247 getc: mfpr $RXCS,r0 248 bbc $RXCS_pd,r0,getc /* receiver ready ? */ 249 mfpr $RXDB,r0 250 extzv $0,$7,r0,r0 251 cmpb r0,$015 252 bneq putc 253 bsbw putc 254 movb $0,r0 255 bsbw putc 256 movb $012,r0 257 258 putc: mfpr $TXCS,r2 259 bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 260 extzv $0,$7,r0,r0 261 mtpr r0,$TXDB 262 rsb 263 264 inittmscp: 265 movw $0,TMSCPip(%rCSR) # start step 1 266 1: bitw $TMSCP_STEP1,TMSCPsa(%rCSR) 267 beql 1b 268 # movzbl $'1,r0 269 # bsbw putc 270 init2: movw $TMSCP_ERR,TMSCPsa(%rCSR) # start step 2 271 2: bitw $TMSCP_STEP2,TMSCPsa(%rCSR) 272 beql 2b 273 # movzbl $'2,r0 274 # bsbw putc 275 init3: addl3 $8,%rUBADDR,r0 # start step 3 276 cvtlw r0,TMSCPsa(%rCSR) 277 3: bitw $TMSCP_STEP3,TMSCPsa(%rCSR) 278 beql 3b 279 # movzbl $'3,r0 280 # bsbw putc 281 init4: addl3 $8,%rUBADDR,r0 # start step 4 282 ashl $-16,r0,r0 283 cvtlw r0,TMSCPsa(%rCSR) 284 4: bitw $TMSCP_STEP4,TMSCPsa(%rCSR) 285 beql 4b 286 # movzbl $'4,r0 287 # bsbw putc 288 setchar: 289 movw $TMSCP_GO,TMSCPsa(%rCSR) 290 moval 140(%rUBADDR),tmscpca+cmddsc(fp) 291 moval tmscpca+cmddsc(fp),dscptr(%rCMD) 292 movb $1,vcid(%rCMD) 293 moval 20(%rUBADDR),tmscpca+rspdsc(fp) 294 moval tmscpca+rspdsc(fp),dscptr(%rRSP) 295 clrw cntflgs(%rCMD) 296 297 movb $M_OP_STCON,op(%rCMD) 298 clrw modifier(%rCMD) 299 clrl buffer(%rCMD) 300 clrl bytecnt(%rCMD) 301 bsbw tmscpcmd 302 # movzbl $'S,r0 303 # bsbw putc 304 305 rsb 306 307 tmscpcmd: 308 movw $116,msglen(%rCMD) # 116 -- size of an mscp packet 309 bisl2 $TMSCP_OWN,tmscpca+cmddsc(fp) 310 movw $116,msglen(%rRSP) 311 bisl2 $TMSCP_OWN,tmscpca+rspdsc(fp) 312 movw TMSCPip(%rCSR),r0 # start polling 313 wait: cvtwl TMSCPsa(%rCSR),r0 314 bitl $TMSCP_ERR,r0 315 beql 1f 316 movw modifier(%rRSP),r1 # so we can read status easily 317 halt # some error or other 318 1: tstl tmscpca+4(fp) 319 beql 2f 320 clrw tmscpca+4(fp) 321 2: bitl $TMSCP_OWN,tmscpca+rspdsc(fp) 322 bneq wait 323 324 # cmd done 325 326 clrw tmscpca+rspint(fp) 327 extzv $0,$5,status(%rRSP),r0 328 tstl r0 329 beql ok # no errors 330 cmpl $M_ST_TAPEM, r0 331 beql ok # not an error, just a tape mark 332 halt # some unknown error 333 ok: rsb 334 335 rew: movb $M_OP_REPOS,op(%rCMD) 336 movw $M_MD_REWND|M_MD_IMMED,modifier(%rCMD) 337 clrl buffer(%rCMD) 338 clrl bytecnt(%rCMD) 339 bsbw tmscpcmd 340 # movzbl $'r,r0 # to indicate r)ewind 341 # bsbw putc 342 movl $-1,mtapa(fp) # no blocks read yet 343 rsb 344 345 onlin: movb $M_OP_ONLIN,op(%rCMD) 346 clrw modifier(%rCMD) 347 clrl buffer(%rCMD) 348 clrl bytecnt(%rCMD) 349 bsbw tmscpcmd 350 # movzbl $'O,r0 # to indicate O)nline 351 # bsbw putc 352 rsb 353 354 # Read the tp directory. Number of blocks to read is in tapa(fp), 355 # and will be read into memory starting at location 0. 356 readdir:bsbw rew # beginning of tape 357 addl3 $2,$NUMDIR,tapa(fp) # blocks to read (skip this 1k program) 358 clrl r3 # using mem starting at 0 as free space 359 bsbw rrec; bsbw rrec # read and discard first two blocks -- 360 # those are this program 361 bsbw rrec # read and discard first tp block 362 clrl r3 # reset starting place 363 incw dirread(fp) # show that directory is incore 364 1: bsbw rrec 365 cmpl mtapa(fp),tapa(fp) # done yet? 366 blss 1b 367 rsb 368 369 # read 1 block from mag tape into page indicated by r3, which will 370 # automatically be incremented here. mtapa is also advanced. 371 372 rrec: bisl3 $MRV,r3,4(%rMAPREGS) # using map register #1 373 movl $BLKSIZ,bytecnt(%rCMD) # how much to read 374 ashl $9,$1,buffer(%rCMD) # indicating mr #1. We just happen to 375 # be on a page boundary, so filling in 376 # the low 9 bits is not necessary. 377 movb $M_OP_READ,op(%rCMD) 378 clrw modifier(%rCMD) 379 bsbw tmscpcmd 380 # movzbl $'R,r0 # to indicate R)ead a record 381 # bsbw putc 382 incl mtapa(fp) 383 incl r3 384 rsb 385 end: 386