1 /* 2 * Copyright (c) 1980, 1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 /* "@(#)tuboot.c 7.2 (Berkeley) 08/28/86" */ 8 9 /* 10 * VAX tu58 console cassette boot block 11 * 12 * Helge Skrivervik CSRG/UCB 18jun83 13 * 14 * Reads a program from a rt-11 directory on tape 15 * and executes it. Programs must be stripped of 16 * the header and is loaded ``bits as is''. 17 * You can return to this loader via ``ret'' as 18 * you are called ``calls $0,ent''. 19 * Error checking and recovery is almost nonexistant 20 * due to the severe space constraints. 21 * 22 * NOTE: Any changes to this program are likely to 23 * bring the size over 512 bytes .... 24 * 25 * Based on tp format bootstrap originally written by Thomas Ferrin. 26 * 27 */ 28 .set CTABLE,0x400 /* where to load the rad50 cnv table */ 29 .set RELOC,0x70000 30 /* rt-11 directory definitions */ 31 .set DIRBLK,6 /* rt-11 directory starts at block 6 */ 32 .set FILSIZ,8 /* rt-11 direc entry offset for file size */ 33 .set ENTSIZ,14 /* size of 1 rt-11 dir entry, bytes */ 34 .set BLKSIZ,512 /* tape block size, bytes */ 35 .set NUMDIR,2 /* no. of dir blocks on tape */ 36 .set FNSIZ,8 /* size of rad50 filename + 2 */ 37 .set NAME,2 /* direc entry offset for filename */ 38 .set STATUS,1 /* direc entry offset for entry status */ 39 /* rt-11 directory entry status */ 40 .set RT_ESEG,8 /* end of directory segment */ 41 .set RT_NULL,2 /* empty entry */ 42 .set RT_FILE,4 /* valid file entry */ 43 /* processor registers and bits */ 44 .set RXCS,32 45 .set RXDB,33 46 .set TXCS,34 47 .set TXDB,35 48 .set RXCS_DONE,0x80 49 .set TXCS_RDY,0x80 50 .set TXCS_pr,7 /* bit position of TXCS ready bit */ 51 .set RXCS_pd,7 /* bit position of RXCS done bit */ 52 /* console storage registers and bits */ 53 .set CSRS,0x1c 54 .set CSRD,0x1d 55 .set CSTS,0x1e 56 .set CSTD,0x1f 57 /* TU commands and bits */ 58 .set TU_BREAK,1 59 .set TU_INIT,4 60 .set TU_CONTINUE,16 61 .set TU_READY,7 /* bit position of CSRS ready bit */ 62 .set TU_PACKETLEN,8 /* length of readcom block */ 63 /* local stack variables */ 64 .set ext,-4 /* file ext. */ 65 .set name,-20 /* 12 bytes for full name */ 66 .set rt_name,-20-FNSIZ /* rad50 file name */ 67 /* reboot flags for boot */ 68 .set RB_ASK,3 /* ask name and come up single user */ 69 70 /* 71 * Initialization. 72 */ 73 init: 74 .word 0 /* entry mask for dec monitor */ 75 nop;nop;nop;nop;nop /* some no-ops for 750 boot rom to skip */ 76 nop;nop;nop;nop;nop 77 movl $RELOC,fp /* core loc to which to move this program */ 78 addl3 $rt_name,fp,sp /* set stack pointer; leave room for locals */ 79 clrl r0 80 1: 81 movc3 $end,(r0),(fp) /* move boot up to relocated position */ 82 jmp start+RELOC 83 84 start: 85 mtpr $TU_BREAK,$CSTS /* set break condition */ 86 clrl r2 /* nulls */ 87 bsbw xmit2 /* wait 2 character times */ 88 mfpr $CSRD,r2 /* clear receive buffer */ 89 movzwl $TU_INIT|(TU_INIT<<8),r2 /* load 2 INIT opcodes */ 90 bsbw xmit2 /* xmit 'em */ 91 1: 92 mfpr $CSRD,r7 /* get recv data */ 93 cmpb r7,$TU_CONTINUE /* is it a continue flag? */ 94 bneq 1b /* nope, look more */ 95 96 movab name(fp),r4 /* start of filename storage */ 97 clrq (r4) /* init name field */ 98 clrq name+8(fp) 99 clrq rt_name(fp) /* init rad50 filename */ 100 movzbl $'=,r0 /* prompt character */ 101 bsbw putc /* output char to main console */ 102 103 /* 104 * Read in a file name from console. 105 */ 106 movl r4,r1 /* loc at which to store file name */ 107 nxtc: 108 bsbw getc /* get input char's in file name */ 109 cmpb r0,$012 /* terminator ? */ 110 beql nullc 111 movb r0,(r1)+ 112 brb nxtc 113 nullc: 114 cmpl r4,r1 115 beql start /* restart if empty string */ 116 clrb (r1) /* add null byte at end */ 117 118 /* 119 * User-specified filename has been stored at name(fp), 120 * read the entire directory contents into low core. 121 */ 122 dirred: 123 movl $DIRBLK,r10 /* directory starts at block DIRBLK */ 124 movl $(NUMDIR*BLKSIZ),r6 /* no. bytes in total dir */ 125 clrl r11 /* start address */ 126 bsbw taper /* read no. bytes indicated */ 127 /* 128 * Read in the character conversion table which reside in block 1 129 * (the second block) on the cassette. Place it after the directory 130 * on low core (from 0x400). 131 */ 132 movl $1,r10 /* block number */ 133 movl $BLKSIZ,r6 /* read one block */ 134 bsbw taper 135 136 /* 137 * Convert the ascii filename to rad50. 138 * R4 still points to name(fp) 139 */ 140 movl $6,r3 /* max length of filename */ 141 1: 142 cmpb $'.,(r4)+ /* look for '.' */ 143 beql 1f 144 sobgtr r3,1b 145 incl r4 /* point past '.' if ext is present */ 146 1: 147 clrb -1(r4) /* end name with null */ 148 movl $3,r3 /* max length of extension */ 149 movab ext(fp),r5 /* place extension here */ 150 1: 151 movb (r4)+,(r5)+ 152 beql 1f /* the string is null terminated */ 153 sobgtr r3,1b 154 1: 155 movab name(fp),r4 156 movab rt_name(fp),r5 /* ptr to rad50 name */ 157 bsbw rad50 /* convert filename */ 158 movab ext(fp),r4 159 movab rt_name+4(fp),r5 160 bsbw rad50 /* convert extension */ 161 162 /* 163 * Search entire directory for user-specified file name. 164 */ 165 166 movab rt_name(fp),r4 /* search for this file */ 167 movl $10,r5 /* point to first file entry */ 168 movzwl -2(r5),r10 /* r10 = block # where files begin */ 169 2: 170 cmpc3 $6,NAME(r5),(r4) /* see if dir entry matches filename */ 171 beql fndfil /* found match */ 172 1: 173 addw2 FILSIZ(r5),r10 /* add file length to block pointer */ 174 addl2 $ENTSIZ,r5 /* move to next entry */ 175 /* cpmb STATUS(r5),$RT_NULL /* check if deleted file */ 176 /* beql 1b /* not really necessary since deleted entries will fail */ 177 /* to compare anyway */ 178 cmpb STATUS(r5),$RT_ESEG /* check if end of segment */ 179 bneq 2b 180 brw start /* entry not in directory; start over */ 181 182 /* 183 * Found desired directory entry 184 */ 185 fndfil: 186 /* start block no., 2 bytes in r10 */ 187 movzwl FILSIZ(r5),r6 /* file size (blocks) */ 188 mull2 $BLKSIZ,r6 /* file size (bytes) */ 189 cmpl r6,$RELOC-512 /* check if file fits below stack */ 190 blss filok 191 brw start /* file too large */ 192 193 /* 194 * Read in desired file from tape. 195 */ 196 filok: 197 movl r6,r5 /* start of bss space */ 198 clrl r11 /* start address */ 199 bsbb taper 200 201 /* 202 * Clear core. 203 */ 204 subl3 r5,$RELOC-4,r0 /* no. bytes to clear */ 205 1: 206 clrb (r5)+ 207 sobgtr r0,1b 208 209 /* 210 * Jump to start of file & execute. 211 */ 212 addl3 $20,fp,ap /* ?? */ 213 clrl r5 214 movl $RB_ASK,r11 215 calls $0,(r5) 216 bad: 217 brw start 218 219 /* 220 * Read (r6) bytes from block (r10) 221 * into loc (r11). 222 */ 223 taper: 224 clrl r8 /* initialize checksum */ 225 movab readcom,r0 /* read command packet addr */ 226 movzbl $TU_PACKETLEN/2,r1 /* size of readcom block */ 227 1: 228 movzwl (r0)+,r2 /* get 2 chars from block */ 229 bsbb xmit /* xmit and update ckecksum */ 230 sobgtr r1,1b /* loop if more */ 231 232 /* 233 * Now do variable part of packet. 234 */ 235 movl r6,r2 /* byte count */ 236 bsbb xmit 237 movl r10,r2 /* starting block number */ 238 bsbb xmit 239 movzwl r8,r2 /* accumulated ckecksum */ 240 bsbb xmit 241 242 /* 243 * Collect read packet from device. 244 */ 245 1: 246 bsbb recv2 /* get 2 packet characters */ 247 decb r2 /* data packet? */ 248 bneq 1f /* branch on end of data */ 249 movzbl r1,r8 /* get byte count of packet */ 250 251 /* 252 * Read data into memory. 253 */ 254 2: 255 bsbb recv1 /* get a char */ 256 movb r1,(r11)+ /* stuff into memory */ 257 sobgtr r8,2b /* loop if more */ 258 bsbb recv2 /* skip checksum */ 259 brb 1b /* read next packet */ 260 261 /* 262 * End of data xfer; check for errors. 263 */ 264 1: 265 bsbb recv2 /* get success code */ 266 tstl r1 /* error in read? */ 267 blss 9f /* branch if status error */ 268 movl $5,r0 269 1: 270 bsbb recv2 /* discard 10 bytes */ 271 sobgtr r0,1b 272 rsb 273 274 /* Fatal error */ 275 9: 276 movab ermsg,r1 277 1: 278 movb (r1)+,r0 279 beql bad 280 bsbb putc 281 brb 1b 282 283 /* 284 * Update checksum in r8 and xmit 2 characters. 285 */ 286 xmit: 287 addw2 r2,r8 /* update checksum */ 288 adwc $0,r8 /* add in carry */ 289 290 /* send the 2 characters contained in r2 */ 291 xmit2: 292 bsbb 1f /* xmit one of 'em */ 293 ashl $-8,r2,r2 /* get next char */ 294 /* fall into... */ 295 1: 296 mfpr $CSTS,r7 /* get xmit status */ 297 bbc $TU_READY,r7,1b /* loop until ready */ 298 mtpr r2,$CSTD /* send char */ 299 rsb 300 301 /* 302 * Receive 2 characters, return in r2 and r1. 303 */ 304 recv2: 305 bsbb recv1 /* recv one of 'em */ 306 /* fall into... */ 307 308 /* 309 * Receive 1 character. 310 */ 311 recv1: 312 movzbl r1,r2 /* save previous byte */ 313 1: 314 mfpr $CSRS,r7 /* get recv status */ 315 bbc $TU_READY,r7,1b /* loop until ready */ 316 mfpr $CSRD,r1 /* get char */ 317 blss 9b /* branch on recv error */ 318 rsb 319 320 getc: 321 mfpr $RXCS,r0 322 bbc $RXCS_pd,r0,getc /* receiver ready ? */ 323 mfpr $RXDB,r0 324 extzv $0,$7,r0,r0 325 cmpb r0,$015 326 bneq putc /* echo and return */ 327 bsbb putc /* carriage return */ 328 /* movb $0,r0 */ 329 /* bsbb putc */ /* delay */ 330 movb $012,r0 /* send line feed and return */ 331 putc: 332 mfpr $TXCS,r2 333 bbc $TXCS_pr,r2,putc /* transmitter ready ? */ 334 mtpr r0,$TXDB 335 rsb 336 337 /* 338 * Convert the filename given from the console 339 * to radix 50 (rt-11) format. 340 */ 341 rad50: 342 clrw r1 343 bsbb getb50 /* get next ascii byte, exit if null */ 344 mull3 $03100,r0,r1 345 bsbb getb50 346 mull3 $050,r0,r2 347 addl2 r2,r1 348 bsbb getb50 349 addl2 r0,r1 /* last byte, just add it in */ 350 movw r1,(r5)+ /* save result */ 351 brb rad50 352 353 getb50: 354 movzbl (r4)+,r0 /* get next ascii byte */ 355 beql 1f /* if zero: end of string */ 356 movzbl CTABLE(r0),r0 /* and get the r50 byte from the table*/ 357 rsb 358 1: 359 tstl (sp)+ /* we're through, get back to where */ 360 /* rad50 was called */ 361 movw r1,(r5) /* but first save the result */ 362 rsb 363 364 .align 2 365 readcom: 366 .byte 2 /* command packet flag */ 367 .byte 10 /* number of bytes in message */ 368 .byte 2 /* tu read opcode */ 369 .byte 0 /* modifier */ 370 .byte 0 /* unit number */ 371 .byte 0 /* switches */ 372 .word 0 /* sequence number */ 373 /* byte count and block number follow */ 374 375 ermsg: 376 .asciz "tuerr\r\n" 377 end: 378 379 /* 380 * Ascii to rad 50 conversion table, 381 * stored on the second block on the cassette 382 * 383 * NOTE: Always make sure this table ends up 384 * starting at byte 512!!!! 385 */ 386 .align 2 387 .data 2 388 .long 0x1d1d1d1d 389 .long 0x1d1d1d1d 390 .long 0x1d1d1d1d 391 .long 0x1d1d1d1d 392 .long 0x1d1d1d1d 393 .long 0x1d1d1d1d 394 .long 0x1d1d1d1d 395 .long 0x1d1d1d1d 396 .long 0x1d1d1d00 397 .long 0x1d1d1d1b 398 .long 0x1d1d1d1d 399 .long 0x1d1c1d1d 400 .long 0x21201f1e 401 .long 0x25242322 402 .long 0x1d1d2726 403 .long 0x1d1d1d1d 404 .long 0x302011d 405 .long 0x7060504 406 .long 0xb0a0908 407 .long 0xf0e0d0c 408 .long 0x13121110 409 .long 0x17161514 410 .long 0x1d1a1918 411 .long 0x1d1d1d1d 412 .long 0x302011d 413 .long 0x7060504 414 .long 0xb0a0908 415 .long 0xf0e0d0c 416 .long 0x13121110 417 .long 0x17161514 418 .long 0x1d1a1918 419 .long 0x1d1d1d1d 420 .long 0x1d1d1d1d 421 .long 0x1d1d1d1d 422 .long 0x1d1d1d1d 423 .long 0x1d1d1d1d 424 .long 0x1d1d1d1d 425 .long 0x1d1d1d1d 426 .long 0x1d1d1d1d 427 .long 0x1d1d1d1d 428 .long 0x1d1d1d00 429 .long 0x1d1d1d1b 430 .long 0x1d1d1d1d 431 .long 0x1d1c1d1d 432 .long 0x21201f1e 433 .long 0x25242322 434 .long 0x1d1d2726 435 .long 0x1d1d1d1d 436 .long 0x302011d 437 .long 0x7060504 438 .long 0xb0a0908 439 .long 0xf0e0d0c 440 .long 0x13121110 441 .long 0x17161514 442 .long 0x1d1a1918 443 .long 0x1d1d1d1d 444 .long 0x302011d 445 .long 0x7060504 446 .long 0xb0a0908 447 .long 0xf0e0d0c 448 .long 0x13121110 449 .long 0x17161514 450 .long 0x1d1a1918 451 .long 0x1d1d1d 452 .data 453