|
|
1.1 ! root 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) 8/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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.