1 /* 2 * @(#)tmscpboot.c 7.2 (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 #ifdef DEBUG 144 movzbl $11,r0 # newline 145 bsbw putc 146 movzbl $13,r0 # return 147 bsbw putc 148 #endif 149 movzbl $'=,r0 # prompt 150 bsbw putc 151 bsbw getname 152 153 # desired TP filename is in name(fp). Now read in entire tp directory 154 # contents into low core, starting at loc 0. Because tk50's are slow, 155 # and because we are going to go over 512 bytes anyway, and because 156 # it requires so little effort, we'll keep track of whether the data 157 # at location 0 is the tape directory. 158 159 tstw dirread(fp) # if directory needs to be read in, do so 160 bneq 1f 161 bsbw readdir 162 1: 163 # 164 # all of directory is now in locore, @ 0. 165 # search for filename; return to start if it isn't there. 166 # 167 clrl r0 # start at location 0 168 nxtdir: moval name(fp),r2 169 movl r0,r1 170 1: cmpb (r1),(r2) 171 bneq 2f 172 tstb (r1) 173 beql found 174 incl r1 175 incl r2 176 brb 1b 177 2: acbl $NUMDIR*BLKSIZ-1,$ENTSIZ,r0,nxtdir 178 brw start # entry not in directory; start over 179 180 # entry IS here; read it in from tape 181 182 found: movzwl BNUM(r0),tapa(fp) # start block no., 2 bytes 183 addl2 $2-1,tapa(fp) # skip over this program (2 blocks) 184 # minus 1 because we will read THROUGH 185 # this block; so we want to stop just 186 # before it 187 movzwl FILSIZ(r0),r4 # low 2 bytes file size 188 insv FILSIZ-1(r0),$16,$8,r4 # file size, high byte 189 cmpl r4,$RELOC-512 # check if file fits below stack 190 bgeq start # file too large 191 192 # Now advance to proper place on tape. tapa has our 193 # desired address 194 195 clrw dirread(fp) # we are about to obliterate our incore copy 196 # of the directory 197 2: clrl r3 # rrec expects r3 to point to a buffer. 0 will do ... 198 bsbw rrec 199 cmpl mtapa(fp),tapa(fp) 200 blss 2b 201 202 # tape now positioned correctly. Read in program. Number of bytes 203 # to read is in r4. We must round up to an even BLKSIZ boundary. 204 # Clear the area we are putting it at; unix expects zeroes in its 205 # data and bss section. 206 207 addl2 $BLKSIZ-1,r4 # round up 208 bicl2 $BLKSIZ-1,r4 # mask out 209 movl r4,r5 # use r5; need to save r4 for later 210 1: clrl (r5) 211 sobgtr r5,1b 212 213 # now read in file. 214 215 clrl r3 # read into page 0 (incremented by rrec) 216 ashl $-9,r4,r5 # r5 now holds # blks to read 217 addl2 r5,tapa(fp) # compute desired tape blk # 218 1: bsbw rrec 219 cmpl mtapa(fp),tapa(fp) # got it yet? 220 blss 1b 221 222 # begin execution. Call as a function. 223 clrl r5 224 calls $0,(r5) 225 226 # now, since the called function has reset the tape drive for 227 # us (!) we must reinit it again ourselves. 228 229 ashl $-9,$RELOC-512,r0 # set up map register for our stack 230 bisl3 $MRV,r0,(%rMAPREGS) # mark our stack valid (MR #0) 231 bsbw inittmscp # re-init drive 232 bsbw onlin # re-online it 233 brw start 234 235 # getname will set name(fp) and leave len(name(fp)) in r6 236 getname:moval name(fp),r1 # mov to register for ease of access 237 nxtc: bsbw getc 238 cmpb r0,$012 # end of line? 239 beql nullc 240 movb r0,(r1)+ 241 brb nxtc 242 nullc: moval name(fp),r0 243 subl3 r0,r1,r6 # length of path name 244 jeql start # just hit return; nothing useful here 245 clrb (r1)+ # add null at end 246 incl r6 # add null to length 247 rsb 248 249 getc: mfpr $RXCS,r0 250 bbc $RXCS_pd,r0,getc /* receiver ready ? */ 251 mfpr $RXDB,r0 252 extzv $0,$7,r0,r0 253 cmpb r0,$015 254 bneq putc 255 bsbw putc 256 movb $0,r0 257 bsbw putc 258 movb $012,r0 259 260 putc: mfpr $TXCS,r2 261 bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 262 extzv $0,$7,r0,r0 263 mtpr r0,$TXDB 264 rsb 265 266 inittmscp: 267 movw $0,TMSCPip(%rCSR) # start step 1 268 1: bitw $TMSCP_STEP1,TMSCPsa(%rCSR) 269 beql 1b 270 #ifdef DEBUG 271 movzbl $'1,r0 272 bsbw putc 273 #endif 274 init2: movw $TMSCP_ERR,TMSCPsa(%rCSR) # start step 2 275 2: bitw $TMSCP_STEP2,TMSCPsa(%rCSR) 276 beql 2b 277 #ifdef DEBUG 278 movzbl $'2,r0 279 bsbw putc 280 #endif 281 init3: addl3 $8,%rUBADDR,r0 # start step 3 282 cvtlw r0,TMSCPsa(%rCSR) 283 3: bitw $TMSCP_STEP3,TMSCPsa(%rCSR) 284 beql 3b 285 #ifdef DEBUG 286 movzbl $'3,r0 287 bsbw putc 288 #endif 289 init4: addl3 $8,%rUBADDR,r0 # start step 4 290 ashl $-16,r0,r0 291 cvtlw r0,TMSCPsa(%rCSR) 292 4: bitw $TMSCP_STEP4,TMSCPsa(%rCSR) 293 beql 4b 294 #ifdef DEBUG 295 movzbl $'4,r0 296 bsbw putc 297 #endif 298 setchar: 299 movw $TMSCP_GO,TMSCPsa(%rCSR) 300 moval 140(%rUBADDR),tmscpca+cmddsc(fp) 301 moval tmscpca+cmddsc(fp),dscptr(%rCMD) 302 movb $1,vcid(%rCMD) 303 moval 20(%rUBADDR),tmscpca+rspdsc(fp) 304 moval tmscpca+rspdsc(fp),dscptr(%rRSP) 305 clrw cntflgs(%rCMD) 306 307 movb $M_OP_STCON,op(%rCMD) 308 clrw modifier(%rCMD) 309 clrl buffer(%rCMD) 310 clrl bytecnt(%rCMD) 311 bsbw tmscpcmd 312 #ifdef DEBUG 313 movzbl $'S,r0 314 bsbw putc 315 #endif 316 rsb 317 318 tmscpcmd: 319 movw $116,msglen(%rCMD) # 116 -- size of an mscp packet 320 bisl2 $TMSCP_OWN,tmscpca+cmddsc(fp) 321 movw $116,msglen(%rRSP) 322 bisl2 $TMSCP_OWN,tmscpca+rspdsc(fp) 323 movw TMSCPip(%rCSR),r0 # start polling 324 wait: cvtwl TMSCPsa(%rCSR),r0 325 bitl $TMSCP_ERR,r0 326 beql 1f 327 movw modifier(%rRSP),r1 # so we can read status easily 328 halt # some error or other 329 1: tstl tmscpca+4(fp) 330 beql 2f 331 clrw tmscpca+4(fp) 332 2: bitl $TMSCP_OWN,tmscpca+rspdsc(fp) 333 bneq wait 334 335 # cmd done 336 337 clrw tmscpca+rspint(fp) 338 extzv $0,$5,status(%rRSP),r0 339 tstl r0 340 beql ok # no errors 341 cmpl $M_ST_TAPEM, r0 342 beql ok # not an error, just a tape mark 343 halt # some unknown error 344 ok: rsb 345 346 rew: movb $M_OP_REPOS,op(%rCMD) 347 movw $M_MD_REWND|M_MD_IMMED,modifier(%rCMD) 348 clrl buffer(%rCMD) 349 clrl bytecnt(%rCMD) 350 bsbw tmscpcmd 351 #ifdef DEBUG 352 movzbl $'r,r0 # to indicate r)ewind 353 bsbw putc 354 #endif 355 movl $-1,mtapa(fp) # no blocks read yet 356 rsb 357 358 onlin: movb $M_OP_ONLIN,op(%rCMD) 359 clrw modifier(%rCMD) 360 clrl buffer(%rCMD) 361 clrl bytecnt(%rCMD) 362 bsbw tmscpcmd 363 #ifdef DEBUG 364 movzbl $'O,r0 # to indicate O)nline 365 bsbw putc 366 #endif 367 rsb 368 369 # Read the tp directory. Number of blocks to read is in tapa(fp), 370 # and will be read into memory starting at location 0. 371 readdir:bsbw rew # beginning of tape 372 addl3 $2,$NUMDIR,tapa(fp) # blocks to read (skip this 1k program) 373 clrl r3 # using mem starting at 0 as free space 374 bsbw rrec; bsbw rrec # read and discard first two blocks -- 375 # those are this program 376 bsbw rrec # read and discard first tp block 377 clrl r3 # reset starting place 378 incw dirread(fp) # show that directory is incore 379 1: bsbw rrec 380 cmpl mtapa(fp),tapa(fp) # done yet? 381 blss 1b 382 rsb 383 384 # read 1 block from mag tape into page indicated by r3, which will 385 # automatically be incremented here. mtapa is also advanced. 386 387 rrec: bisl3 $MRV,r3,4(%rMAPREGS) # using map register #1 388 movl $BLKSIZ,bytecnt(%rCMD) # how much to read 389 ashl $9,$1,buffer(%rCMD) # indicating mr #1. We just happen to 390 # be on a page boundary, so filling in 391 # the low 9 bits is not necessary. 392 movb $M_OP_READ,op(%rCMD) 393 clrw modifier(%rCMD) 394 bsbw tmscpcmd 395 #ifdef DEBUG 396 movzbl $'R,r0 # to indicate R)ead a record 397 bsbw putc 398 #endif 399 incl mtapa(fp) 400 incl r3 401 rsb 402 end: 403