.set HIGH,31 # mask for total disable .set SZPT,4 # number of pages of user page table allocated per user .set MCKVEC,4 # offset into Scbbase of machine check vector # Trap vectors and C interface for Vax # # # # System control block # .set INTSTK,1 # handle this interrupt on the interrupt stack .set HALT,3 # halt if this interrupt occurs .align 9 .globl Scbbase Scbbase: .long Xrandom + HALT # unused .long Xmachcheck + HALT # machine check interrupt .long Xkspnotval + HALT # kernal stack not valid .long Xpowfail + HALT # power fail .long Xprivinflt # privileged instruction .long Xxfcflt # xfc instruction .long Xresopflt # reserved operand .long Xresadflt # reserved addressing .long Xprotflt # protection .long Xsegflt # segmentation .long Xtracep # trace pending .long Xbptflt # bpt instruction .long Xrandom + HALT # compatibility mode fault .long Xarithtrap # arithmetic trap .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xsyscall # chmk .long Xchme+HALT # chme .long Xchms+HALT # chms .long Xchmu+HALT # chmu .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # software level 1 .long Xrandom + HALT # software level 2 (asts) .long Xresched # reschedule nudge .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused ubabase: .long Xclockint + INTSTK # clock .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xconsrint + INTSTK # console receiver .long Xconsxint + INTSTK # console transmitter # I/O vectors # IPL 14 .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xua0int + INTSTK # UBA 0 br4 .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused # IPL 15 .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xua0int + INTSTK # UBA 0 br5 .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xmba0int + INTSTK # mass bus adapter 0 .long Xmba1int + INTSTK # mass bus adapter 1 .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused # IPL 16 .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xua0int + INTSTK # UBA 0 br6 .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused # IPL 17 .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused .long Xrandom + HALT # unused # 0x200 # Produce a core image dump on mag tape .globl doadump doadump: movl sp,dumpstack # save stack pointer movab dumpstack,sp # reinit sp mfpr $PCBB,-(sp) # save u-area pointer mfpr $MAPEN,-(sp) # save value mfpr $IPL,-(sp) # ... mtpr $0,$MAPEN # turn off memory mapping mtpr $HIGH,$IPL # disable interrupts pushr $0x3fff # save regs 0 - 13 calls $0,_dump # produce dump halt .data .align 2 .space 58*4 # seperate stack for tape dumps .globl dumpstack dumpstack: .space 4 .text # I/O interrupt vector routines # # Catch random or unexpected interrupts .align 2 Xrandom: Xmachcheck: Xkspnotval: Xpowfail: Xchme: Xchms: Xchmu: halt # Massbus 0 adapter interrupts .align 2 Xmba0int: pushr $0x3f # save r0 - r5 movab MBA0_CSR,r0 # point at mba regs movl MBA_AS(r0),r1 # get attn summary bits cvtwl r1,-(sp) # push attn summary as arg pushl MBA_SR(r0) # pass sr as argument mnegl $1,MBA_SR(r0) # clear attention bit calls $2,_hpintr # call rp06 interrupt dispatcher brw int_ret # merge with common interrupt code # Massbus 1 adapter interrupts .align 2 Xmba1int: pushr $0x3f movab MBA1_CSR,r0 pushl MBA_AS(r0) mnegl $1,MBA_AS(r0) pushl MBA_SR(r0) # pass cr as argument_ mnegl $1,MBA_SR(r0) # clear attention bit calls $2,_htintr # call te16 interrupt dispatcher brw int_ret # return from interrupt # Unibus adapter interrupts .align 2 Xua0int: # UBA 0 interrupts pushr $0x3f # save regs 0-5 pushab UBA0 # save UBA base addr brb Xuacom # jump to common code Xua1int : # UBA 1 interrupts Xuacom : # common code for UBA interrupts popr $1 # UBA base addr mfpr $IPL,r2 # get br level movl UBR_OFF-20*4(r0)[r2],r3 # get unibus device vector bleq ubasrv # branch if zero vector or UBA service required # normal UBA interrupt point - device on a UBA has generated an # interrupt - r3 holds interrupt vector ubanorm : movl _UNIvec(r3),r1 # get interrupt service routine address # and controller code from UNIBUS vector area extzv $27,$4,r1,-(sp) # controller code is in 4 most # significant bits-1 of ISR addr bicl2 $0x78000000,r1 # clear code calls $1,(r1) # call ISR brw int_ret # go to common interrupt return # here for zero or negative UBA interrupt vector. # negative vector -> UBA requires service ubasrv : beql ubapass # # UBA service required # The following 'printf' calls should probably be replaced # with calls to an error logger and/or some corrective action. bitl $CFGFLT,UCN_OFF(r0) # any SBI faults ? beql UBAflt pushab SBImsg calls $1,_printf halt # # no SBI fault bits set in UBA config reg - must be # some error bits set in UBA status reg UBAflt : movl UST_OFF(r0),r2 # UBA status reg pushr r2 pushab UBAmsg calls $2,_printf movl r2,UST_OFF(r0) # clear error bits bicl2 $0x80000000,r1 # clear neg bit in vector bneq ubanorm # branch if normal UBA interrupt to process brb int_ret # restore regs and return # # zero interrupt vector - print message & continue ubapass : pushab ZERmsg calls $1,_printf brb int_ret # Console receiver interrupt .align 2 Xconsrint: pushr $0x3f # save registers 0 - 5 calls $0,_consrint brb int_ret # merge # Console transmit interrupt .align 2 Xconsxint: pushr $0x3f # save registers 0 - 5 calls $0,_consxint brb int_ret # Clock interrupt .align 2 Xclockint: pushr $0x3f # save regs 0 - 5 pushl 4+6*4(sp) # push psl pushl 4+6*4(sp) # push pc calls $2,_clock brb int_ret # # Common code for interrupts # At this point, the interrupt stack looks like: # # ___________ # | r0 | :isp # |-----------| # | ... | # |-----------| # | r13 | # |-----------| # | pc | # |-----------| # | psl | # |___________| int_ret: bbssi $0,idleflag,int_r0 # set idle escape flag (no wait instr) int_r0: popr $0x3f # restore regs 0 - 5 bitl $PSL_CURMOD,4(sp) # interrupt from user mode? beql int_r1 # no, from kernal, just rei tstb _runrun # should we reschedule? beql int_r1 # no, just rei # # If here, interrupt from user mode, and time to reschedule. # to do this, we set a software level 3 interrupt to # change to kernal mode, switch stacks, # and format kernal stack for a `qswitch' trap to force # a reschedule. # mtpr $3,$SIRR # request level 1 software interrupt int_r1: rei # return to interrupted process # # Trap and fault vector routines # # Reschedule trap (Software level 3 interrupt) .align 2 Xresched: movpsl -(sp) # get ps bicl2 $PSL_IPL,(sp) # lower ipl pushab resc1 # push pc rei # lower ipl, jump to resc1 resc1: pushl $0 # dummy code pushl $RESCHED # type brb alltraps # merge # privileged instruction fault .align 2 Xprivinflt: pushl $0 # push dummy code pushl $PRIVINFLT # push type brb alltraps # merge # xfc instruction fault .align 2 Xxfcflt: pushl $0 # push dummy code value pushl $XFCFLT # push type value brb alltraps # merge # reserved operand fault .align 2 Xresopflt: pushl $0 # push dummy code value pushl $RESOPFLT # push type value brb alltraps # merge # reserved addressing mode fault .align 2 Xresadflt: pushl $0 # push dummy code value pushl $RESADFLT # push type value brb alltraps # merge with common code # bpt instruction fault .align 2 Xbptflt: pushl $0 # push dummy code value pushl $BPTFLT # push type value brb alltraps # merge with common code # Trace trap .align 2 Xtracep: pushl $0 # push dummy code value pushl $TRCTRAP # push type value brb alltraps # go do it # Arithmitic trap .align 2 Xarithtrap: pushl $ARITHTRAP # push type value brb alltraps # merge with common code # Protection fault .align 2 Xprotflt: blbs (sp),Xsegflt # check for pt length violation addl2 $4,sp # pop fault param word pushl $PROTFLT brb alltraps # Segmentation fault .align 2 Xsegflt: addl2 $4,sp pushl $SEGFLT brb alltraps # # CHMK trap (syscall trap) # on entry, kernal stack: # # ___________ # | code | :ksp # |-----------| # | pc | # |-----------| # | psl | # |___________| # # # # stack (parameters) at calls to _trap: # # ___________ # | ap | :ksp # |-----------| # | r0 | # |-----------| # | ... | # |-----------| # | r13 | # |-----------| # | usp | # |-----------| # | type | # |-----------| # | code | # |-----------| # | pc | # |-----------| # | psl | # |___________| # .align 2 Xsyscall: pushl $SYSCALL # push type value alltraps: movq 8(sp),_u+PCB_PC # save pc bitl $PSL_CURMOD,12(sp) # from user mode? beql sysc1 # no # Prepare arguments to _trap, note that type has already been pushed mfpr $USP,-(sp) # get usp pushr $0x3fff # registers 0 - 13 pushl ap # ptr to syscall parameters # # Call _trap with wrong number of arguments # so args not popped by ret # calls $1,_trap # Restore popr $0x3fff # restore regs 0 - 13 mtpr (sp)+,$USP # restore usp addl2 $8,sp # pop type, code # bitl $PSL_CURMOD,4(sp) # are we returning to user mode? beql sysc2 # no # Return rei sysc1: movab emsg1,eptr # set message pointer brb err_print # print message and halt sysc2: movab emsg2,eptr # pointer to error message brb err_print # print msg and halt # # err_print # print message on console and die # message pointed to by eptr, terminated by zero byte. # err_print: mtpr $HIGH,$IPL # disable all interrupts mtpr $0,$TXCS # disable interrupts on console transmitter eloop1: mfpr $TXCS,ewk1 # get transmitter status bbc $TXCS_BRDY,ewk1,eloop1 # loop if not ready to transmit tstb *eptr # end of message? beql eout # yes, out of loop movzbl *eptr,ewk1 # get byte of message incl eptr # bump pointer mtpr ewk1,$TXDB # give byte to transmitter brb eloop1 # loop eout: halt .data eptr: .long 0 ewk1: .long 0 .text # # Initialization # # IPL == 1F # MAPEN == off # SCBB, PCBB not set # SBR, SLR not set # ISP, KSP not set # .globl start start: .word 0x0000 mtpr $HIGH,$IPL # no interrupts yet mtpr $Scbbase,$SCBB # set SCBB mtpr $_Sysmap,$SBR # set SBR mtpr $Syssize,$SLR # set SLR mtpr $_Sysmap,$P0BR # set temp P0BR mtpr $Syssize,$P0LR # set temp P0LR movl $_intstack+2048,sp # set ISP # initialize i/o adatpers movl $1,PHYSMBA0+4 # init & interrupt enable movl $4,PHYSMBA0+4 # init & interrupt enable movl $1,PHYSMBA1+4 # init interrupt enable movl $4,PHYSMBA1+4 # init interrupt enable movl $1,PHYSUBA+4 # init interrupt enable movl $0x78,PHYSUBA+4 # init interrupt enable movl Scbbase+MCKVEC,r5 # save machine check entry movab startint+INTSTK,Scbbase+MCKVEC # set new vector address # # will now see how much memory there really is # in 64kb chunks, save number of bytes in r7 # mtpr $HIGH-1,$IPL # allow machine check interrupts clrl r7 startlp: tstl (r7) # this chunk really there? acbl $8096*1024-1,$64*1024,r7,startlp # loop till machine check brb startint # full load of memory, avoid .align .align 2 startint: mtpr $0,$SBIFS # clear sbi fault status movl r5,Scbbase+MCKVEC # restore machine check vector movl $_intstack+2048,sp # reset interrupt stack pointer # clear memory starting with unitialized data (kernal) movab _edata,r6 movab _end+8096,r5 # clear uninitialized data and some slop strtclr: clrq (r6) acbl r5,$8,r6,strtclr # # initialize system page table # movab _etext+511,r1 # end of kernal text segment bbcc $31,r1,strt1 # turn off high order bit strt1: ashl $-9,r1,r1 # last page of kernal text clrl r2 # point at first kernal text page strtlp1: bisl3 $PG_V|PG_KR,r2,_Sysmap[r2] # initialize page table entry aoblss r1,r2,strtlp1 # fill text entries movab _end+511,r1 # end of kernal data segment bbcc $31,r1,strt2 # turn off high order bit strt2: ashl $-9,r1,r1 # last page of kernal data strtlp2: bisl3 $PG_V|PG_KW,r2,_Sysmap[r2] # fill data entries aoblss r1,r2,strtlp2 # init i/o space page table entries movl $PHYSUBA/512,r1 # page frame number for uba movab _Sysmap+uba_offset,r2 # page table address movab 15(r1),r3 # last pt entry strtlp3: bisl3 $PG_V|PG_KW,r1,(r2)+ # init pt entry aobleq r3,r1,strtlp3 movl $PHYSUMEM/512,r1 movab _Sysmap+umem_offset,r2 # page table address movab 15(r1),r3 # limit strtlp4: bisl3 $PG_V|PG_KW,r1,(r2)+ aobleq r3,r1,strtlp4 movl $PHYSMBA0/512,r1 movab _Sysmap+mba0_offset,r2 movab 15(r1),r3 strtlp5: bisl3 $PG_V|PG_KW,r1,(r2)+ aobleq r3,r1,strtlp5 movl $PHYSMBA1/512,r1 movab _Sysmap+mba1_offset,r2 movab 15(r1),r3 strtlp6: bisl3 $PG_V|PG_KW,r1,(r2)+ aobleq r3,r1,strtlp6 mtpr $1,$TBIA # invalidate all trans buffer entries mtpr $1,$MAPEN # turn on memory mapping jmp *$startmap # put system virtual address in pc startmap: # set maxmem = btoc(r7) ashl $-9,r7,_maxmem # # Setup context for proc[0] == Scheduler # # address first page past _end # this will be u area for proc[0]. # initialize u area page table entries. # initialize (slightly) the pcb. movab _end+511,r6 bicl2 $0x1ff,r6 # make page boundary # set up u area page table bbcc $31,r6,strt3 strt3: ashl $-9,r6,r3 # r3 = btoc(r6) bisl3 $PG_V|PG_KW,r3,_Sysmap+u_ptoffset # init first u pt entry movab _u,r1 # point at _u area mtpr r1,$TBIS movab usize*512(r1),PCB_KSP(r1) # init ksp mnegl $1,PCB_ESP(r1) # invalidate esp mnegl $1,PCB_SSP(r1) # invalidate ssp movl $0x80000000,PCB_USP(r1) # set user sp movab _u+usize*512,PCB_P0BR(r1) # p0 page table pointer clrl PCB_P0LR(r1) # size zero page table movb $4,PCB_P0LR+3(r1) # disable ast movab _u+(usize+SZPT)*512-0x800000,PCB_P1BR(r1) # p1 page table pointer movl $0x200000,PCB_P1LR(r1) # invalid p1 p t length movl $SZPT,PCB_SZPT(r1) # init number pages usr page table ashl $-9,r6,-(sp) # push arg for setupu pushl $1 # ditto movl sp,ap # set up arg pointer bsbw setupu addl2 $8,sp # pop stack mtpr r6,$PCBB # first pcb ldpctx # set regs, p0br, p0lr, p1br, p1lr, # astlvl, ksp, and change to kernal mode addl2 $8,sp # pop dummy pc, psl mtpr $0,$IPL # enable interrupts movab _end+511,r0 # calculate firstaddr bbcc $31,r0,strt4 strt4: ashl $-9,r0,-(sp) # convert to clicks and stack calls $1,_main # startup, fork off /etc/init # # proc[1] == /etc/init now running here. # execute code at location 0, in user mode. # pushl $PSL_CURMOD|PSL_PRVMOD # psl, user mode, ipl= 0 pushl $0 # pc, $location 0 rei # do /etc/init # # Primitives # _display: .globl _display _savfp: .globl _savfp _restfp: .globl _restfp .word 0x0000 ret _addupc: .globl _addupc .word 0x0000 movl 8(ap),r2 # &u.u_prof subl3 8(r2),4(ap),r0 # corrected pc blss addret extzv $1,$31,r0,r0 # logical right shift extzv $1,$31,12(r2),r1 # ditto for scale mull2 r1,r0 ashl $-14,r0,r0 incl r0 bicb2 $1,r0 cmpl r0,4(r2) # length bgequ addret addl2 (r2),r0 # base probew $3,$2,(r0) beql adderr addw2 12(ap),(r0) addret: ret adderr: clrl 12(r2) ret _fubyte: .globl _fubyte _fuibyte:.globl _fuibyte .word 0x0000 prober $3,$1,*4(ap) # byte accessible ? beql eret # no movzbl *4(ap),r0 ret _subyte: .globl _subyte _suibyte:.globl _suibyte .word 0x0000 probew $3,$1,*4(ap) # byte accessible ? beql eret # no movb 8(ap),*4(ap) clrl r0 ret _fuword: .globl _fuword _fuiword:.globl _fuiword .word 0x0000 prober $3,$4,*4(ap) beql eret movl *4(ap),r0 ret _suword: .globl _suword _suiword:.globl _suiword .word 0x0000 probew $3,$4,*4(ap) beql eret movl 8(ap),*4(ap) clrl r0 ret eret: mnegl $1,r0 # error return ret _copyin: .globl _copyin _copyiin:.globl _copyiin .word 0x0000 movl 12(ap),r0 # copy length movl 4(ap),r1 # copy user address cmpl $512,r0 # probing one page or less ? bgeq cishort # yes ciloop: prober $3,$512,(r1) # bytes accessible ? beql eret # no addl2 $512,r1 # incr user address ptr acbl $513,$-512,r0,ciloop # reduce count and loop cishort: prober $3,r0,(r1) # bytes accessible ? beql eret # no movc3 12(ap),*4(ap),*8(ap) clrl r0 ret _copyout: .globl _copyout _copyiout:.globl _copyiout .word 0x0000 movl 12(ap),r0 # get count movl 8(ap),r1 # get user address cmpl $512,r0 # can do in one probew? bgeq coshort # yes coloop: probew $3,$512,(r1) # bytes accessible? beql eret # no addl2 $512,r1 # increment user address acbl $513,$-512,r0,coloop # reduce count and loop coshort: probew $3,r0,(r1) # bytes accessible? beql eret # no movc3 12(ap),*4(ap),*8(ap) clrl r0 ret _idle: .globl _idle .word 0x0000 mtpr $0,$IPL # enable interrupts waitloc: blbc idleflag,waitloc # loop until interrupt ewaitloc: bbcci $0,idleflag,idle1 # clear idle escape flag idle1: ret .data .globl _waitloc .globl _ewaitloc .align 2 _waitloc: .long waitloc _ewaitloc: .long ewaitloc idleflag: .long 0 .text # save reg's and ret loc into save area - return 0 .globl _save _save : # save(save_area) .word 0x0 mtpr $HIGH,$IPL movl 4(ap),r0 # save area addr movab 2*4(ap),sp # restore stack to val before 'save' call movl 8(fp),ap # restore ap " " " movl 16(fp),r1 # restore pc " " " movl 12(fp),fp # restore fp " " " movq r6,(r0)+ movq r8,(r0)+ movq r10,(r0)+ movq ap,(r0)+ # ap & fp movl sp,(r0)+ movl r1,(r0)+ # ret loc of call to 'save' movpsl -(sp) pushl r1 svpctx # save reg's -> PCB movpsl -(sp) # set up for return bicl2 $PSL_IS|PSL_IPL,(sp) # undo SVPCTX pushl r1 # ret loc clrl r0 # return val rei # # # switch to another process's '_u' area - return val 1 .globl _resume _resume : # resume(proc_addr,save_addr) .word 0x0 mtpr $HIGH,$IPL # inhibit interrupts ashl $9,4(ap),r5 # proc byte addr # area of proc argument movl 8(ap),retloc bsbw setupu # set up '_sysmap' PTE's to map into '_u' movl _u,sp # KSP from u-area mtpr r5,$PCBB ldpctx addl2 $8,sp # clear ps,pc from stack movl retloc,r1 # 'ssav' or 'qsav' addr movq (r1)+,r6 movq (r1)+,r8 movq (r1)+,r10 movq (r1)+,ap movl (r1)+,sp movl $1,r0 # return val mtpr $0,$IPL jmp *(r1)+ # return to caller at 'save' address # .data .align 2 retloc: .space 1*4 .text # initialize u area page table entries setupu: movl (sp)+,r0 # get return pc addl3 $PG_V|PG_KW,4(ap),r1 # first pt entry of user area movab usize(r1),r2 # one past last pt entry of user movab _Sysmap+u_ptoffset,r3 # addr for 1st user pt entry movab _u,r4 mtpr r4,$TBIS # invalidate old trans buffer entry movl r1,(r3)+ # store page table entry addl2 _u+PCB_SZPT,r2 # add on size of user page table brb setulp1 setulp: mtpr r4,$TBIS # ivalidate page table entry movl r1,(r3)+ # store page table entry setulp1: addl2 $512,r4 aoblss r2,r1,setulp # -> till done jmp (r0) # funny return in case of changing stacks # disable interrupts _spl1: .globl _spl1 .word 0x0000 mfpr $IPL,r0 # get IPL value mtpr $2,$IPL # disable RESCHED & AST interrupts ret _spl4: .globl _spl4 .word 0x0000 mfpr $IPL,r0 mtpr $0x14,$IPL # disable bus level 4 interrupts ret _spl5: .globl _spl5 .word 0x0000 mfpr $IPL,r0 mtpr $0x15,$IPL # disable bus level 5 interrupts ret _spl6: .globl _spl6 _spl7: .globl _spl7 .word 0x0000 mfpr $IPL,r0 mtpr $0x18,$IPL # disable bus level 7 and clock interrupts ret # enable interrupts _spl0: .globl _spl0 .word 0x0000 mfpr $IPL,r0 mtpr $0,$IPL ret # restore interrupt state _splx: .globl _splx .word 0x0000 mfpr $IPL,r0 mtpr 4(ap),$IPL ret # # Copy 1 relocation unit (512 bytes) # from one physical address to another _copyseg: .globl _copyseg .word 0x0000 mfpr $IPL,r0 # get current pri level mtpr $HIGH,$IPL # turn off interrupts bisl3 $PG_V|PG_KR,4(ap),_Sysmap+CMAP1 bisl3 $PG_V|PG_KW,8(ap),_Sysmap+CMAP2 mtpr $CADDR1,$TBIS # invalidate entry for copy mtpr $CADDR2,$TBIS movc3 $512,CADDR1,CADDR2 mtpr r0,$IPL # restore pri level ret # zero out physical memory # specified in relocation units (512 bytes) _clearseg: .globl _clearseg .word 0x0000 mfpr $IPL,r0 # get current pri level mtpr $HIGH,$IPL # extreme pri level bisl3 $PG_V|PG_KW,4(ap),_Sysmap+CMAP1 mtpr $CADDR1,$TBIS movc5 $0,(r0),$0,$512,CADDR1 mtpr r0,$IPL # restore pri level ret # Check address # given virtual address, byte count, and rw flag # returns 0 on no access _useracc: .globl _useracc .word 0x0000 movl 4(ap),r0 # get va movl 8(ap),r1 # count tstl 12(ap) # test for read access ? bneq userar # yes cmpl $512,r1 # can we do it in one probe ? bgeq uaw2 # yes uaw1: probew $3,$512,(r0) beql uaerr # no access addl2 $512,r0 acbl $513,$-512,r1,uaw1 uaw2: probew $3,r1,(r0) beql uaerr movl $1,r0 ret userar: cmpl $512,r1 bgeq uar2 uar1: prober $3,$512,(r0) beql uaerr addl2 $512,r0 acbl $513,$-512,r1,uar1 uar2: prober $3,r1,(r0) beql uaerr movl $1,r0 ret uaerr: clrl r0 ret # kernacc # check for kernal access privileges # .globl _kernacc _kernacc: .word 0x0000 movl 4(ap),r0 # virtual address bbcc $31,r0,kacc1 mfpr $SBR,r2 # address and length of page table (system) mfpr $SLR,r3 brb kacc2 kacc1: bbsc $30,r0,kacc3 mfpr $P0BR,r2 # user P0 mfpr $P0LR,r3 brb kacc2 kacc3: mfpr $P1BR,r2 # user P1 (stack) mfpr $P1LR,r3 kacc2: addl3 8(ap),r0,r1 # ending virtual address ashl $-9,r0,r0 # page number ashl $-9,r1,r1 bbc $30,4(ap),kacc6 cmpl r0,r3 # user stack blss kacerr # address too low brb kacc4 kacc6: cmpl r1,r3 # compare last page to P0LR or SLR bgeq kacerr # address too high kacc4: movl (r2)[r0],r1 bbc $31,r1,kacerr # valid bit is off cmpzv $27,$4,r1,$1 # check protection code bleq kacerr # no access allowed tstb 12(ap) bneq kacc5 # only check read access cmpzv $27,$2,r1,$3 # check low 2 bits of prot code beql kacerr # no write access kacc5: aobleq r1,r0,kacc4 # next page movl $1,r0 # no errors ret kacerr: clrl r0 # error ret # calculate physical address of user virtual address _realaddr: .globl _realaddr .word 0x0000 movl 4(ap),r0 # virtual address blss raerr # we don't map kernal virtual addresses bbsc $30,r0,rasseg # stack segment address mfpr $P0BR,r1 mfpr $P0LR,r2 ashl $-9,r0,r3 # get page number cmpl r3,r2 # valid page number? bgeq raerr # no ra1: movl (r1)[r3],r4 # get page table entry bbc $31,r4,raerr # valid bit off - error ashl $9,r4,r5 # construct physical address extzv $0,$9,r0,r0 # offset within page bisl2 r5,r0 # final physical address ret rasseg: mfpr $P1BR,r1 mfpr $P1LR,r2 ashl $-9,r0,r3 cmpl r3,r2 bgeq ra1 raerr: clrl r0 ret # # unsigned int divide : # (int) i = udiv( (int)dvdnd , (int) divis) # # unsigned int remainder : # (int) j = urem( (int)dvdnd , (int) divis) # .text .align 1 .globl _udiv .globl _urem # _udiv : .word 0 # no reg save movl 4(ap),r0 # dividend clrl r1 ediv 8(ap),r0,r0,r1 # quotient in r0 ret # .align 1 _urem : .word 0 movl 4(ap),r0 clrl r1 ediv 8(ap),r0,r1,r0 # remainder in r0 ret # define user area virtual address .set physpages,1024 .set kernsize,256 # number of page table entries allocated to kernal .globl _u .set usize,4 # size of user area, in pages .set _u,0x80000000 + kernsize*512 .set u_ptoffset,256*4 # offset into _Sysmap of ptentries of _u .set CMAP1,u_ptoffset + 16*4 # offset into _Sysmap of 1st seg copy entry .set CMAP2,CMAP1+4 # ditto 2ed entry .set CADDR1,_u + 16*512 # virtual address of 1st copy segment .set CADDR2,CADDR1+512 # ditto second segment .set PHYSUBA,0x20006000 # real address of uba .set PHYSMBA0,0x20010000 # real addr of mba 0 .set PHYSMBA1,0x20012000 # real addre of mba1 .set PHYSUMEM,0x2013e000 # real address of unibus memory .set uba_offset,CMAP1+16*4 # offset in Sysmap of uba entries .set umem_offset,uba_offset+16*4 # ... unibus device registers .set mba0_offset,umem_offset+16*4 # ... massbus 0 .set mba1_offset,mba0_offset+16*4 # ... massbus 1 .set mba2_offset,mba1_offset+16*4 # ... massbus 2 .set mba3_offset,mba2_offset+16*4 # ... massbus 3 .set qsoff,0x140 # offset to 'qsav' pcb in 'u' area .set ssoff,360 #offset to "ssav' in u_area # # Error messages # .data emsg1: .byte 0xa,0xa,0xa,0xd,0x54,0x52,0x41,0x50,0x20 .byte 0x46,0x52,0x4f,0x4d,0x20 .byte 0x4b,0x45,0x52,0x4e,0x41,0x4c,0x20 .byte 0x4d,0x4f,0x44,0x45,0xa,0xa,0xd,0x0 emsg2: .byte 0xa,0xa,0xa,0xd,0x54,0x52,0x41,0x50,0x20 .byte 0x52,0x45,0x54,0x55,0x52,0x4e,0x20 .byte 0x44,0x4f,0x20 .byte 0x4b,0x45,0x52,0x4e,0x41,0x4c,0x20 .byte 0x4d,0x4f,0x44,0x45,0xa,0xa,0xd,0x0 SBImsg : .byte 'S,'B,'I,' ,'f,'a,'u,'l,'t,' ,012,0 UBAmsg : .byte 'U,'B,'A,' ,'e,'r,'r,'o,'r,' ,'%,'x,012,0 ZERmsg : .byte 'Z,'e,'r,'o,' ,'V,'e,'c,'t,'o,'r,012,0 # # _Sysmap: # system page table # # structure: # 2 pages of page table entries # reserved for kernal text and data. # 1 additional page of page table entries # used in mapping the u area (16 entries), # utility entries (16 entries), # unibus adapter (16 entries), # unibus device memory (16 entries), # massbus adapter 0 (16 entries), # massbus adapter 1 (16 entries), # massbus adapter 2 (16 entries), # massbus adapter 3 (16 entries). # # .align 2 .globl _Sysmap _Sysmap: .space 3*128*4 # 3 pages of page table entries for kernal .set Syssize,3*128 # number pt entries in sys page table