# include "rel.h" # define RP6CYL 815 /* no. RP06 cylinders/pack */ # define RP6TRK 19 /* no. tracks/cyl */ # define RP6SEC 22 /* no. sectors/track */ # define RM3CYL 823 /* RM03 */ #define RM3TRK 5 #define RM3SEC 32 # define RP6ST (rptrk*rpsec) # define MAXSEC (rpcyl*rptrk*rpsec) /* sectors/pack */ # define M0 0x20010000 /* phys addr MBA 0 */ # define M1 0x20012000 /* phys addr MBA 1 */ # define M_cr 1 /* MBA 0 control reg addr , longword offset */ # define M_sr 2 /* MBA 0 status reg offset */ # define M_map 0x200 /* start MBA 0 map reg's longword offset */ # define M_var 3 /* MBA 0 virt addr reg offset */ # define M_bc 4 /* MBA 0 byte count reg offset */ # define MBAinit 01 /* MBA init bit */ /* */ # define EXTREG 0x400 /* base for external reg's on MBA */ /* */ # define RP_cr 0 /* RP06 control reg offset, longword */ # define RP_sr 1 /* RP06 status reg offset */ # define RP_stk 5 /* RP06 sector/track reg offset */ # define RP_typ 06 /* drive type reg */ # define RP_off 011 /* RP offset reg */ # define RP_cyl 10 /* RP06 cylinder reg offset */ /* */ # define RP_GO 1 /* go bit */ # define RP_RED 070 /* RP06 read function code */ # define RP_DC 010 /* drive clear function code */ # define RP_DRY 0200 /* drive ready, status reg */ # define RP_ERR 040000 /* composite error, status reg */ # define RP_RIP 020 /* RP readin preset function code */ # define RP_FMT 0x1000 /* format bit in RP offset reg */ # define RP_MOL 0x1000 /* medium on-line bit in RP status reg */ /* */ # define RXCS 32 /* receiver control/staus */ # define RXDB 33 /* receiver data */ # define TXCS 34 /* transmitter control/status */ # define TXDB 35 /* transmitter data */ # define RXCS_DONE 0x80 /* receiver done */ # define TXCS_RDY 0x80 /* transmitter ready */ /* */ # define MAG410 0410 # define MAG411 0411 # define MAXUNI 1 # define NL 012 # define CR 015 # define CDEL 0x23 # define LDEL 0x40 # define BLKSIZ 512 # define HDRSIZ 040 /* task header size */ # define INOSIZ 64 /* no. bytes per inode entry */ # define INOBLK (BLKSIZ/INOSIZ) /* no. inodes/disk block */ # define NAMSIZ 14 /* no. char's in dir name field */ # define DIRSIZ 16 /* no. bytes/directory entry */ # define SLASH 057 /* '/' */ # define NADDR 13 /* no. addr blocks in inode entry */ # define KSP 0 /* */ # define IFMT 0170000 # define IFDIR 040000 # define IFREG 0100000 # define ROOTINO 2 /* root dir inode no. */ /* */ #define RP6typ 022 /* RP06 */ #define RM3typ 024 /* RM03 type */ struct dirent { short ino ; char dname[NAMSIZ] ; } ; struct inod { short i_mode ; short fill1[3] ; int i_size ; char i_addr[40] ; int fill2[3] ; } ; struct thdr { int hmagic ; int htsiz ; int hdsiz ; int hbsiz ; int hsmsiz ; int hentry ; int hrelb ; int hrflg ; } ; int filsiz ; char *entry ; char buf[BLKSIZ] , *namep ; char dbuf[BLKSIZ] ; short mode ; int addr[NADDR] ; int *mbap ; /* MBA ptr */ int *RPptr ; /* RP06 ptr */ int rpsec,rpcyl,rptrk; /* get set up in 'init' for RP06 or RM03 */ char *bufloc; int dtmp1[128] , dtmp2[128] , dtmp3[128] ; /* * This program, '/fboot', is always read in by code in the RP * boot block (block 0). It boots in the file specified by the * user. */ main() { /* set stack ptr and move code up to high end of core */ reloc() ; /* jump to re-located code */ asm(" .text") ; asm(" .globl _main1") ; asm(" jmp *$(_main1+2)") ; asm(" .align 2") ; } /* */ main1() { char ntmp[10*NAMSIZ] ; register int inum ; register struct inod *inp ; struct inod *getiblk() ; struct dirent *dsearch() , *pde ; int j ; floop : putnl() ; putstr("file : ") ; getcon(ntmp) ; /* null-terminated filename */ putnl() ; namep = ntmp ; inum = ROOTINO ; /* root dir inode no. */ while ((*namep) == SLASH) namep++ ; if ((*namep) == '\0') goto floop ; mbap = M0 ; RPptr = M0 + EXTREG ; if (init()) { putlin("init error") ; return(-1) ; } giblk : /* get disk block that has inode entry for inode no. 'inum' */ inp = getiblk(inum) ; /* 'cp' = ptr. to inode entry in 'buf[]' */ if (inp == (-1)) { ioerr : putlin("disk i/o error") ; goto floop ; } /* Get 'mode' and 'addr[]' entries for selected inode & save off */ iexpand(inp) ; /* inode mode is in 'mode'. * block no.'s are in 'addr[]'. * If inode is a directory, search all its blocks for pathname * component pointed to by 'namep'. * If inode is regular file, load blocks of file into core * for execution. */ if ((j = mode&IFMT) == IFDIR) { /* Directory */ if (*namep == '\0') goto floop ; /* no more pathname */ pde = dsearch() ; /* search all directory blocks */ if (pde == (-1)) goto ioerr ; /* i/o error */ if (pde == 0) goto floop ; /* pathname component not found */ /* Found pathname component (directory or file) - go get its inode and continue search. */ inum = pde->ino ; goto giblk ; } else { if (j == IFREG) { /* regular file */ if (*namep != '\0') goto floop ; /* should have been last component in pathname */ if (lodfil()) goto floop ; /* load file whose inode 'addr' blocks are in 'addr[]' */ /* * Code to check for task header, move code down to 0, * get task entry address, clear core, etc. */ fexec() ; goto floop ; /* returned from execution - go to loop */ } } goto floop ; /* wasn't directory or file */ } /* */ struct inod *getiblk(in) register int in ; { /* * Read in disk inode block which contains inode * no. 'in' - return ptr. to start of inode entry. */ register i ; i = (in + (INOBLK*2) - 1)/INOBLK ; if (dread(i,buf)) /* read block 'i' into 'buf[]' */ return(-1) ; /* i/o error */ return((int)buf + (((in-1) & (INOBLK-1))*INOSIZ)) ; } /* */ iexpand(ip) register struct inod *ip ; { /* * Get mode, file size and block no.'s from disk inode and store * away. * 'ip' = ptr. to inode entry. */ register int i ; register char *f , *t ; mode = ip->i_mode ; filsiz = ip->i_size ; f = (&ip->i_addr[0]) ; t = (&addr[0]) ; for (i = NADDR ; i ; i--) { (*t++) = (*f++) ; (*t++) = (*f++) ; (*t++) = (*f++) ; (*t++) = '\0' ; } return(0) ; } /* */ struct dirent *dsearch() { /* * Search blocks of directory inode 'inum', whose block * no.'s are in 'addr[]', for pathname component pointed * to by 'namep'. * Return (-1) for error. * Return (0) for no match. * Return ptr. to directory entry for match. */ register char c ; register struct dirent *cp ; register int i , j ; struct dirent *pfind() ; /* direct */ cp = pfind(addr,NADDR-3) ; /* search 'NADDR-3' blocks(in 'naddr[]') */ if (cp == (-1)) return(-1) ; /* i/o error */ if (cp == 0) return(0) ; /* zero block encountered - no more blocks */ if (cp == 1) goto level1 ; /* more blocks to search */ /* 'cp' must be ptr. to matched directory */ found : /* point to next pathname component */ while (((c = (*namep)) != '/') && (c !='\0')) namep++ ; if (c == '/') while (*namep == '/') namep++ ; return(cp) ; /* */ level1 : /* 1st level indirection */ if ((j = addr[NADDR-3]) == 0) return(0) ; if (dread(j,dtmp1)) return(-1) ; /* i/o error */ cp = pfind(dtmp1,128) ; if (cp == (-1)) return(-1) ; if (cp == 0) return(0) ; if (cp == 1) goto level2 ; goto found ; level2 : if ((j = addr[NADDR-2]) == 0) return(0) ; if (dread(j,dtmp1)) return(-1) ; for (i = 0 ; i < 128 ; i++) { if (dtmp1[i] == 0) return(0) ; if (dread(dtmp1[i],dtmp2)) return(-1) ; cp = pfind(dtmp2,128) ; if (cp == (-1)) return(-1) ; if (cp == 0) return(0) ; if (cp == 1) continue ; goto found ; } level3 : if ((j = addr[NADDR-1]) == 0) return(0) ; if (dread(j,dtmp1)) return(-1) ; for (i = 0 ; i < 128 ; i++) { if (dread(dtmp1[i],dtmp2)) return(-1) ; for (j = 0 ; j < 128 ; j++) { if (dread(dtmp2[i],dtmp3)) return(-1) ; cp = pfind(dtmp3,128) ; if (cp == (-1)) return(-1) ; if (cp == 0) return(0) ; if (cp == 1) continue ; goto found ; } } return(0) ; } /* */ struct dirent *pfind(ia,knt) int ia[] ; register int knt ; { /* * 'ia' : array of integer block no.'s. * 'knt' : no. entries in 'ia' * A zero block in 'ia[]' -> no match -> return(0) . * Return (-1) on i/o error. * Return (1) if no zero blocks and all blocks searched but * no match. * Return ptr. to directory entry for match. */ register int *bp , bn ; register struct dirent *ix ; bp = ia ; while (knt--) { if ((bn = (*bp++)) == 0) return(0) ; if (dread(bn,dbuf)) return(-1) ; for (ix = dbuf ; ix < &dbuf[BLKSIZ] ; ix++) { if (dnmatch(ix->dname,namep)) return(ix) ; } } return(1) ; } /* */ dnmatch(p1,p2) register char *p1 , *p2 ; { /* * 'p1' : ptr. to directory filename field * 'p2' : ptr. to null-terminated file pathname * Return(1) if match, * else, return(0). */ register int i ; register char c1 , c2 ; for (i = NAMSIZ ; i ; i--) { c1 = (*p1++) ; c2 = (*p2++) ; if (((c1 == '\0') && (c2 == '\0')) || (c2 == SLASH)) return(1) ; if (c1 != c2) return(0) ; } if ((c2 == '\0') || (c2 == SLASH)) return(1) ; return(0) ; } /* */ dread(dbn,cbuf) char *cbuf ; { /* * Read physical block no. 'dbn' from disk and * load into array 'cbuf[]'. * Return (-1) for i/o error. * Else return (0). */ register int i , j ; *(RPptr+RP_cr) = RP_DC | RP_GO ; /* RP06 drive clear function code */ *(RPptr+RP_cyl) = dbn/RP6ST ; /* cylinder no. */ i = dbn%RP6ST ; j = (i/rpsec)<<8 ; /* track */ *(RPptr+RP_stk) = j | (i%rpsec) ; /* sector : track */ *(mbap+M_bc) = (-BLKSIZ) ; i = (int)cbuf&0777; *(mbap+M_var) = i ; *(mbap+M_map) = (i = 0x80000000 | ((int)((int)cbuf>>9)&07777777)) ; *(mbap+M_map+1) = (++i) ; *(RPptr+RP_cr) = RP_RED | RP_GO ; /* read */ dwait() ; /* wait for i/o to finish */ if (derror()) { /* error */ putlin("fboot : disk read error"); return(-1); } return(0) ; /* normal return */ } /* */ dwait() { /* * Function to wait MBA 0 RP06 disc unit to be ready. */ while ((*(RPptr+RP_sr)&RP_DRY) == 0) ; } /* */ derror() { /* * Function to check for MBA 0 RP06 error. */ if (*(RPptr+RP_sr) & RP_ERR) return(-1) ; return(0) ; } /* */ init() { /* * Initialization. */ register int i; *(mbap+M_cr) = MBAinit ; /* MBA initialize */ if ((*(RPptr+RP_sr) & RP_MOL) == 0 ){ putlin("unit not online") ; return(-1) ; } *(RPptr+RP_cr) = RP_RIP | RP_GO ; /* readin preset */ *(RPptr+RP_off) = RP_FMT ; /* format bit in offset reg */ bufloc = 0 ; i = *(RPptr+RP_typ)&0777 ; /* get disk type */ if (i==RP6typ) { /* RP06 */ rpsec=RP6SEC; rpcyl=RP6CYL; rptrk=RP6TRK; } else { if (i==RM3typ) { rpsec=RM3SEC; rpcyl=RM3CYL; rptrk=RM3TRK; } else return(-1); } return(0) ; } /* */ lodfil() { /* * Function to load a file into low core - disk blocks no.'s * which comprise file are in 'addr[]'. * Return (-1) if i/o error, * else return (0). */ register int i , j , k , n ; int dtmp1[128] , dtmp2[128] ; /* direct */ for (i = 0 ; i < NADDR-3 ; i++) { if ((j = addr[i]) == 0) return(0) ; if (dread(j,bufloc)) return(-1) ; bufloc += BLKSIZ ; } level1 : /* 1st level indirection */ if ((j = addr[NADDR-3]) == 0) return(0) ; /* read in <=128 blocks into low core */ if ((k = r128(j)) < 0) return(-1) ; /* i/o error */ if (k > 0) return(0) ; /* no more blocks */ level2 : if ((j = addr[NADDR-2]) == 0) return(0) ; if (dread(j,dtmp1)) return(-1) ; for (i = 0 ; i < 128 ; i++) { if ((j = dtmp1[i]) == 0) return(0) ; if ((k = r128(j)) < 0) return(-1) ; if (k > 0) return(0) ; } level3 : if ((j = addr[NADDR-1]) == 0) return(0) ; if (dread(j,dtmp1)) return(-1) ; for (i = 0 ; i < 128 ; i++) { if ((k = dtmp1[i]) == 0) return(0) ; if (dread(k,dtmp2)) return(-1) ; for (j = 0 ; j < 128 ; j++) { if ((k = dtmp2[j]) == 0) return(0) ; if ((n = r128(k)) < 0) return(-1) ; if (n > 0) return(0) ; } } return(0) ; } /* */ r128(blk) int blk ; { /* * Read in disk block no. 'blk' into buffer. * Then read in the 128 disk blocks whose block no.'s are * in the buffer into low core. * Stop on a zero block no. - return(1). * Return(-1) on i/o error. * Return(0) if all 128 blocks read. */ int btmp[128] ; register int i , j ; if (dread(blk,btmp)) return(-1) ; for (i = 0 ; i < 128 ; i++) { if ((j = btmp[i]) == 0) return(1) ; /* no more blocks */ if (dread(j,bufloc)) return(-1) ; /* i/o error */ bufloc += BLKSIZ ; /* next core block loc */ } return(0) ; } /* */ halt() { asm(" halt") ; } /* */ putstr(csp) register char *csp ; { if (putcon(csp)) return(-1) ; return(0) ; } /* */ putlin(sptr) register char *sptr ; { if (putcon(sptr)) return(-1) ; if (putnl()) return(-1) ; return(0) ; } /* */ nullcon(nn) register nn ; { /* * Output 'nn' nulls to console terminal - * used for delay. */ while (nn--) putc(0) ; } /* */ putnl() { if (putcon("\r\n")) return(-1) ; return(0) ; } /* */ putcon(csp) register char *csp ; { /* * Function to output null-terminated string pointed to * by 'csp' to the VAX LSI terminal. */ register c ; c = 0 ; while (c = (*csp++)) putc(c) ; return(0) ; } /* */ putc(c) { /* wait for LSI printer to be ready */ while ((mfpr(TXCS) & TXCS_RDY) == 0) ; /* output character */ mtpr(TXDB,c&0177) ; } /* */ getcon(cs) register char *cs ; { /* * Function to return char's from VAX LSI keyboard to * char array 'cs' - input stops when CR or LF received - * null char appended to end of input */ register int c , c2 ; int getc() ; char *ocs; ocs=cs; inloop : c = getc() ; /* get 1 char from terminal */ putc(c) ; /* echo char */ if (c==CDEL) {cs--; goto inloop;} if (c==LDEL) {putc(CR);putc(0);putc(NL);cs=ocs; goto inloop;} if ((c == NL) || (c == CR)) { putc(CR) ; putc(0); putc(NL) ; (*cs++) = '\0' ; return(0) ; } else { (*cs++) = c ; goto inloop ; } } /* */ getc() { /* * Return char from VAX LSI terminal char buffer */ int mfpr() ; /* Wait for receiver done (user entered char) */ while ((mfpr(RXCS) & RXCS_DONE) == 0) ; return (mfpr(RXDB) & 0177) ; /* return char from receiver buffer */ } /* */ mtpr(regno,value) { asm(" mtpr 8(ap),4(ap)") ; } /* */ mfpr(regno) { asm(" mfpr 4(ap),r0") ; } /* */ a2l(as) register char *as ; { /* * Convert null-terminated ascii string to binary * and return value. * 1st char in string : * 0 -> octal * x -> hex * else decimal */ register value , base , sign , digit ; digit = value = sign = 0 ; base = 10 ; /* default base */ aloop : if ((digit = (*as++)) == 0) return(value) ; /* null */ if (digit == '-') { sign++ ; goto aloop ; } if (digit == '0') base = 8 ; /* octal base */ else { if (digit == 'x') base = 16 ; /* hex base */ else value = (digit-060) ; /* 060 = '0' */ } while (digit = (*as++)) { if (digit < '0') return(0) ; switch (base) { case 8 : { if (digit > '7') return(0) ; digit -= 060 ; break ; } case 10 : { if (digit > '9') return(0) ; digit -= 060 ; break ; } case 16 : { if (digit <= '9') { digit -= 060 ; break ; } if ((digit >= 'A') && (digit <= 'F')) { digit = (digit - 0101 + 10) ; break ; } if ((digit >= 'a') && (digit <= 'f')) { digit = digit - 0141 + 10 ; break ; } return(0) ; break ; } } value = (value * base) + digit ; } return (sign ? -value : value) ; } /* */ l2a(val,rptr) register int val ; register char *rptr ; { register int i ; register char *tp ; int knt ; char tmp[20] , sign ; knt = sign = 0 ; if (val < 0) { sign++ ; val = (-val) ; } tp = tmp ; loop : knt++ ; i = val/10 ; /* quotient & base 10 */ (*tp++) = val%10 + '0' ; /* ascii remainder */ val = i ; if (val == 0) { /* done dividing */ if (sign) { knt++ ; (*tp++) = '-' ; } for (i = knt ; i ; i--) (*rptr++) = tmp[i-1] ; (*rptr++) = '\0' ; return(knt) ; } else goto loop ; } /* */ fexec() { /* * Part of stand-alone programs that load programs into low core * and execute them. * This function : * 1) Checks if user specified file has a header - if so, * move start of exec. file down to 0. If file is 0410, * move data up to page boundary. * 2) Clear core. * 3) Jump to user task (calls). */ register struct thdr *hdp ; register char *corep1 , * corep2 ; register int k ; int i , stxt , sdat , sbss , clrmin ; register char *clrmax ; hdp = 0 ; clrmax = RELOC - 0x400 ; /* last addr+1 to clear */ i = hdp->hmagic ; /* task type code from task header */ entry = 0 ; /* default entry addr if no header */ clrmin = filsiz ; if ((i != MAG410) && (i != MAG411)) goto clrcor ; /* NO HEADER */ /* file has task header */ entry = hdp->hentry & 017777777777 ; stxt = hdp->htsiz ; /* no. of text bytes in file */ sdat = hdp->hdsiz ; /* no. data bytes */ sbss = hdp->hbsiz ; /* no. bytes in bss area */ filsiz = stxt + sdat ; /* file size = text + data */ clrmax = filsiz + sbss ; /* new upper limit to clear */ /* move file down to loc 0 */ corep1 = 0 ; corep2 = sizeof(struct thdr) ; for (k = filsiz ; k ; k--) (*corep1++) = (*corep2++) ; clrmin = stxt ; /* If 0410 file , move data up to page boundary */ if ((i == MAG410) && sdat ) { /* 0410 */ i = corep2 = ((stxt + 511) & 017777777000) ; /* page boundary */ corep2 += sdat ; /* end+1 of new data area */ corep1 = filsiz ; /* end+1 of current data area */ for (k = sdat ; k ; k--) /* move data up */ *(--corep2) = *(--corep1) ; clrmax += (i-stxt) ; /* adjust upper limit for moved data */ clrmin = i + sdat ; } /* clear core */ clrcor : for (corep1 = clrmin ; corep1 < clrmax ; corep1++) *corep1 = 0 ; /* execute user task */ asm(" .globl _entry") ; asm(" calls $0,*_entry") ; /* */ return(0) ; } /* */ reloc() { extern edata ; register int *to , *from , i ; mtpr(KSP,RELOC) ; /* set stack */ from = 0 ; to = RELOC ; for (i = (int)&edata-RELOC ; i > 0 ; i -= (sizeof *from)) (*to++) = (*from++) ; } /* */ l2x(val,rptr) register int val ; register char *rptr ; { register int i , j ; register char *tp ; int knt ; char tmp[20] , sign ; knt = sign = 0 ; if (val < 0) { sign++ ; val = (-val) ; } tp = tmp ; loop : knt++ ; i = val/16 ; /* quotient & base 16 */ j = val%16 ; (*tp++) = j + (j<10?0x30:0x57) ; val = i ; if (val == 0) { /* done dividing */ if (sign) { knt++ ; (*tp++) = '-' ; } for (i = knt ; i ; i--) (*rptr++) = tmp[i-1] ; (*rptr++) = '\0' ; return(knt) ; } else goto loop ; }