+#
+# Machine Language Assist for UC Berkeley Virtual Vax/Unix
+#
+# locore.s 2.2 1/15/80
+#
+
+ .set HIGH,31 # mask for total disable
+ .set MCKVEC,4 # offset into Scbbase of machine check vector
+ .set NBPG,512
+ .set PGSHIFT,9
+
+ .set CLSIZE,2
+ .set BSIZE,NBPG*CLSIZE
+ .set NBUF,48
+ .set UPAGES,6 # size of user area, in pages
+
+# ====================================
+# 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 PGSHIFT
+ .globl Scbbase
+Scbbase:
+ .long Xrandom + HALT # unused
+ .long Xmachcheck + HALT # machine check interrupt
+ .long Xkspnotval + HALT # kernel 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 and pt length violation
+ .long Xtransflt # address translation not valid fault
+ .long Xtracep # trace pending
+ .long Xbptflt # bpt instruction
+ .long Xcompatflt # 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 # 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 Xcnrint + INTSTK # console receiver
+ .long Xcnxint + INTSTK # console transmitter
+
+#
+# I/O vectors
+#
+
+# IPL 14
+ .long X14stray + INTSTK # stray!
+ .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 stack
+ 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
+ .globl dumpstack
+ .space 58*4 # separate stack for tape dumps
+dumpstack:
+ .space 4
+ .text
+
+#
+# Debugging print switches given here so they won't move around
+#
+ .data
+ .align 2
+ .globl _printsw
+_printsw:
+ .space 4
+ .globl _coresw
+_coresw:
+ .space 4
+ .text
+
+# =============================
+# I/O interrupt vector routines
+# =============================
+
+#
+# Physical i/o addresses
+#
+ .set PHYSUBA,0x20006000 # uba 0
+ .set PHYSMBA0,0x20010000 # mba 0
+ .set PHYSMBA1,0x20012000 # mba 1
+ .set PHYSUMEM,0x2013e000 # unibus memory
+
+#
+# Catch random or unexpected interrupts
+#
+ .align 2
+Xrandom:
+Xmachcheck:
+Xkspnotval:
+Xpowfail:
+Xchme:
+Xchms:
+Xchmu:
+ halt
+
+X14stray:
+ pushr $0x3f
+ pushab straym
+ calls $1,_printf
+ popr $0x3f
+ rei
+
+#
+# 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 sr 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:
+ pushr $0x3f # save regs 0-5
+ mfpr $IPL,r2 # get br level
+ movl UBA0+UBR_OFF-20*4[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. Get the service routine
+# address and controller code from the UNIBUS vector area
+# and service the interrupt.
+#
+ubanorm:
+ movl _UNIvec(r3),r1
+ extzv $27,$4,r1,r0 # controller code is in 4 most
+ # significant bits-1 of ISR addr
+ bicl2 $0x78000000,r1 # clear code
+ jlbc r1,ubanpdma # no pseudo dma here
+ jmp -1(r1) # branch to pseudo dma rtn
+ubanpdma:
+ pushl r0 # controller code
+ calls $1,(r1) # call ISR
+ brw int_ret # go to common interrupt return
+
+#
+# Come 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,UBA0+UCN_OFF # any SBI faults ?
+ beql UBAflt
+ pushr $0xf # save regs 0-3
+ pushab SBImsg
+ calls $1,_printf
+ popr $0xf
+ halt
+#
+# No SBI fault bits set in UBA config reg - must be
+# some error bits set in UBA status reg.
+#
+UBAflt:
+ movl UBA0+UST_OFF,r2 # UBA status reg
+ pushr $0xf # save regs 0-3
+ mfpr $IPL,-(sp)
+ mtpr $HIGH,$IPL
+ pushl UBA0+UFUBAR_OFF
+ pushl UBA0+UFMER_OFF
+ pushl r2
+ pushab UBAmsg
+ calls $4,_printf
+ mtpr (sp)+,$IPL
+ popr $0xf
+ movl r2,UBA0+UST_OFF # clear error bits
+ bicl2 $0x80000000,r3 # clear neg bit in vector
+ jneq ubanorm # branch if normal UBA interrupt
+ # to process
+ brw int_ret # restore regs and return
+#
+# Zero interrupt vector - print message & continue
+#
+# WE GET SO MANY OF THESE THAT WE ONLY COUNT THEM
+#
+ubapass:
+# pushr $0xf
+# pushab ZERmsg
+# calls $1,_printf
+# popr $0xf
+ incl _zvcnt
+ brw int_ret
+ .data
+ .globl _zvcnt
+_zvcnt: .space 4
+ .text
+
+#
+# DZ pseudo dma routine:
+# r0 - controller number
+#
+ .align 1
+ .globl _dzdma
+_dzdma:
+# bisw2 $4,*_draddr # leading edge for dr11-c
+ mull2 $8*20,r0
+ movab _dzpdma(r0),r3 # pdma structure base
+ # for this controller
+dzploop:
+ movl r3,r0
+ movl (r0)+,r1 # device register address
+ movzbl 1(r1),r2 # get line number
+ bitb $0x80,r2 # TRDY on?
+ beql dzprei # no
+ bicb2 $0xf8,r2 # clear garbage bits
+ mull2 $20,r2
+ addl2 r2,r0 # point at line's pdma structure
+ movl (r0)+,r2 # p_mem
+ cmpl r2,(r0)+ # p_mem < p_end ?
+ bgequ dzpcall # no, go call dzxint
+ movb (r2)+,6(r1) # dztbuf = *p_mem++
+ movl r2,-8(r0)
+ brb dzploop # check for another line
+dzprei:
+# bicw2 $4,*_draddr # trailing edge for dr11-c
+ popr $0x3f
+ rei
+
+dzpcall:
+ pushl (r0) # push tty address
+ calls $1,_dzxint # call interrupt rtn
+ brb dzploop # check for another line
+
+#
+# Console receiver interrupt
+#
+ .align 2
+Xcnrint:
+ pushr $0x3f # save registers 0 - 5
+ calls $0,_cnrint
+ brb int_ret # merge
+
+#
+# Console transmit interrupt
+#
+ .align 2
+Xcnxint:
+ pushr $0x3f # save registers 0 - 5
+ calls $0,_cnxint
+ 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
+# ...
+# r5
+# 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 kernel, 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 kernel mode, switch stacks, and format
+# kernel stack for a `qswitch' trap to force a reschedule.
+#
+ mtpr $3,$SIRR # request level 1 software interrupt
+int_r1:
+ rei # return to interrupted process
+
+# ==================================
+# User area virtual addresses
+# ==================================
+
+ .set kernsize,512 # number of pte's allocated to kernel
+ .globl _u
+ .set _u,0x80000000 + kernsize*NBPG
+ .globl _utilutl
+ .set _utilutl,_u+16*NBPG
+ .globl _umbabeg
+ .set _umbabeg,_utilutl+16*NBPG
+ .globl _umbaend
+ .set _umbaend,_umbabeg+6*16*NBPG
+ .globl _swaputl
+ .set _swaputl,_u+128*NBPG
+ .globl _forkutl
+ .set _forkutl,_swaputl+UPAGES*NBPG
+ .globl _xswaputl
+ .set _xswaputl,_forkutl+UPAGES*NBPG
+ .globl _xswap2utl
+ .set _xswap2utl,_xswaputl+UPAGES*NBPG
+ .globl _pushutl
+ .set _pushutl,_xswap2utl+UPAGES*NBPG
+ .globl _vfutl
+ .set _vfutl,_pushutl+UPAGES*NBPG
+ .globl _usrpt
+ .set _usrpt,_vfutl+UPAGES*NBPG
+ .set u_ptoffset,kernsize*4 # offset in _Sysmap of pte's of _u
+ .set CMAP1,u_ptoffset+16*4 # offset in _sysmap of 1st copyseg entry
+ .set CMAP2,CMAP1+4 # ... of 2nd copyseg entry
+ .set CADDR1,_u+16*NBPG # virtual address of 1st copy segment
+ .set CADDR2,CADDR1+NBPG # ... of second copy segment
+
+
+#
+# offsets in Sysmap
+#
+ .set uba_offset,u_ptoffset+32*4 # ... of uba entries
+ .set umem_offset,uba_offset+16*4 # ... of unibus device registers
+ .set mba0_offset,umem_offset+16*4 # ... of massbus 0
+ .set mba1_offset,mba0_offset+16*4 # ... of massbus 1
+ .set mba2_offset,mba1_offset+16*4 # ... of massbus 2
+ .set mba3_offset,mba2_offset+16*4 # ... of massbus 3
+
+# ==========================
+# Sysmap - system page table
+# ==========================
+#
+# structure:
+# 4 pages of page table entries
+# reserved for kernel text and data.
+# 1 page to map u area and other utilities
+# 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).
+# used for phys & swap I/O
+# 6*4 entries for various other utilities
+# 4 pages to map user page tables of resident processes
+#
+
+ .data
+ .align 2
+ .globl _Sysmap
+ .globl _Umap
+ .globl _Tempmap
+ .globl _Swapmap
+ .globl _Forkmap
+ .globl _Xswapmap
+ .globl _Xswap2map
+ .globl _Pushmap
+ .globl _Vfmap
+ .globl _Usrptmap
+_Sysmap:
+ .space 4*128*4 # four pages of pte's for kernel
+_Umap:
+ .space 16*4 # u-area (could be just 6*4)
+_Tempmap:
+ .space 16*4*7 # utility area & others
+_Swapmap:
+ .space UPAGES*4 # swap utility area
+_Forkmap:
+ .space UPAGES*4 # fork area
+_Xswapmap:
+ .space UPAGES*4 # xswap area
+_Xswap2map:
+ .space UPAGES*4 # xswap2 area
+_Pushmap:
+ .space UPAGES*4 # pageout daemon utility
+_Vfmap:
+ .space UPAGES*4 # vfork utility
+_Usrptmap:
+ .space 8*128*4 # user page table area
+
+ .set Syssize,13*128+6*UPAGES # number pt entries in sys page table
+ .globl _mmap
+ .set _mmap,_Sysmap+CMAP2+4
+ .globl _vmmap
+ .set _vmmap,CADDR2+NBPG
+ .globl _mcrmap
+ .set _mcrmap,_Sysmap+CMAP2+8
+ .globl _mcr
+ .set _mcr,CADDR2+(2*NBPG)
+ .set mcr_offset,CMAP2+8
+ .text
+
+# ==============================
+# Trap and fault vector routines
+# ==============================
+
+#
+# Reschedule trap (Software level 3 interrupt)
+#
+ .align 2
+Xresched:
+ mtpr $0,$IPL # lower ipl
+ pushl $0 # dummy code
+ pushl $RESCHED # type
+ brw alltraps # merge
+
+#
+# Privileged instruction fault
+#
+ .align 2
+Xprivinflt:
+ pushl $0 # push dummy code
+ pushl $PRIVINFLT # push type
+ brw alltraps # merge
+
+#
+# Xfc instruction fault
+#
+ .align 2
+Xxfcflt:
+ pushl $0 # push dummy code value
+ pushl $XFCFLT # push type value
+ brw alltraps # merge
+
+#
+# Reserved operand fault
+#
+ .align 2
+Xresopflt:
+ pushl $0 # push dummy code value
+ pushl $RESOPFLT # push type value
+ brw alltraps # merge
+
+#
+# Reserved addressing mode fault
+#
+ .align 2
+Xresadflt:
+ pushl $0 # push dummy code value
+ pushl $RESADFLT # push type value
+ brw alltraps # merge with common code
+
+#
+# Bpt instruction fault
+#
+ .align 2
+Xbptflt:
+ pushl $0 # push dummy code value
+ pushl $BPTFLT # push type value
+ brw alltraps # merge with common code
+
+#
+# Compatibility mode fault
+#
+ .align 2
+Xcompatflt:
+ pushl $COMPATFLT # push type value
+ brw alltraps # merge with common code
+
+#
+# Trace trap
+#
+ .align 2
+Xtracep:
+ pushl $0 # push dummy code value
+ pushl $TRCTRAP # push type value
+ brw alltraps # go do it
+
+#
+# Arithmetic trap
+#
+ .align 2
+Xarithtrap:
+ pushl $ARITHTRAP # push type value
+ brw alltraps # merge with common code
+
+#
+# Protection and segmentation fault
+#
+ .align 2
+Xprotflt:
+ blbs (sp),segflt # check for pt length violation
+ addl2 $4,sp # pop fault param word
+ pushl $PROTFLT
+ brw alltraps
+
+#
+# Segmentation fault
+#
+segflt:
+ addl2 $4,sp
+ pushl $SEGFLT
+ brb alltraps
+
+#
+# Translation Not Valid Fault
+#
+ .align 2
+Xtransflt:
+ bbs $1,(sp),tableflt # check for page table fault
+ addl2 $4,sp # pop fault parameter word
+ pushl $PAGEFLT # push type value
+ bbs $31,4(sp),alltraps # is faulting address in kernel
+ brb usrtraps # page faults in user space
+ # even in kernel mode are ok
+#
+# Page table fault
+#
+tableflt:
+ addl2 $4,sp # pop fault parameter word
+ pushl $TABLEFLT # push type value
+ cmpl _end,4(sp) # cannot tolerate sysmap faults
+ bgequ alltraps
+ brb usrtraps # a table fault on a user page
+ # table in kernel mode is ok
+
+#
+# CHMK trap (syscall trap)
+#
+# Kernel stack on entry:
+#
+# 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:
+ bitl $PSL_CURMOD,12(sp) # from user mode?
+ beql sysc1 # no
+#
+# Prepare arguments to _trap. Note that type has already been pushed.
+#
+usrtraps:
+ 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
+ignresch:
+ addl2 $8,sp # pop type, code
+ mtpr $HIGH,$IPL # make sure we are not going to
+ # a higher IPL
+ rei
+
+#
+# ``Trap from kernel mode'' -- one special case here is to ignore
+# RESCHED traps which happen in the kernel... these happen only
+# when a clock interrupt occured before the RESCHED AST could
+# be delivered, and the clock interrupt lowered the ipl, usually
+# because the addupc() in clock page faulted because the running
+# process was profiling. In this case we are context switching
+# away from the current process anyways, so ignoring the RESCHED
+# trap is the right thing to do.
+#
+sysc1:
+ cmpl (sp),$RESCHED # spurious RESCHED traps from kernel
+ beql ignresch # ... can be ignored
+ movab emsg1,eptr # set message pointer
+ brb err_print # print message 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 # dis. interrupts on cons. xmtr.
+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 adapters.
+#
+ 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 mach check
+ brb startint # full load of memory
+
+ .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
+#
+# calculate size of cmap[] based on available memory, and allocate space for it
+#
+ movab _end,r5
+ movl r5,_cmap
+ bbss $31,_cmap,cm0
+cm0:
+ subl3 r5,r7,r1
+ divl2 $(NBPG*CLSIZE)+CMSIZE,r1
+ mull2 $CMSIZE,r1
+ addl3 _cmap,r1,_ecmap
+#
+# Clear memory starting with kernel bss
+#
+ movab _edata,r6
+ movab _ecmap,r5 # clear to end of cmap[]
+strtclr:
+ clrq (r6)
+ acbl r5,$8,r6,strtclr
+
+#
+# Initialize system page table
+#
+ movab _etext+NBPG-1,r1 # end of kernel text segment
+ bbcc $31,r1,strt1 # turn off high order bit
+strt1:
+ ashl $-9,r1,r1 # last page of kernel text
+ clrl r2 # point at first kernel text page
+strtlp1:
+ bisl3 $PG_V|PG_KR,r2,_Sysmap[r2] # initialize page table entry
+ aoblss r1,r2,strtlp1 # fill text entries
+ addl3 _ecmap,$NBPG-1,r1 # end of cmap[]
+ bbcc $31,r1,strt2 # turn off high order bit
+strt2:
+ ashl $-9,r1,r1 # last page of kernel data
+strtlp2:
+ bisl3 $PG_V|PG_KW,r2,_Sysmap[r2] # fill data entries
+ aoblss r1,r2,strtlp2
+#
+# initialize memory controller mapping
+#
+ .set PHYSMCR,0x20002000
+ movl $PHYSMCR/NBPG,r1
+ movab _Sysmap+mcr_offset,r2
+ bisl3 $PG_V|PG_KW,r1,(r2)
+#
+# Initialize I/O space page table entries
+#
+ movl $PHYSUBA/NBPG,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/NBPG,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/NBPG,r1
+ movab _Sysmap+mba0_offset,r2
+ movab 15(r1),r3
+strtlp5:
+ bisl3 $PG_V|PG_KW,r1,(r2)+
+ aobleq r3,r1,strtlp5
+ movl $PHYSMBA1/NBPG,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
+#
+# Now we move forward, virtually.
+#
+startmap:
+ ashl $-9,r7,_maxmem # set maxmem = btoc(r7)
+ movl _maxmem,_physmem
+ movl _maxmem,_freemem
+
+#
+# Setup context for proc[0] == Scheduler
+#
+# Address first page past _ecmap.
+# This will be u area for proc[0].
+# Initialize u area page table entries.
+# Initialize (slightly) the pcb.
+#
+ addl3 _ecmap,$NBPG-1,r6
+ bicl2 $NBPG-1,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 upt entry
+ movab _u,r1 # point at _u area
+ mtpr r1,$TBIS
+ movab UPAGES*NBPG(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
+# The shape of the following computation is historical...
+# P0BR and P1BR should CLSIZE*NBPG bytes apart,
+# otherwise their values are irrelevant.
+ movab _u+UPAGES*NBPG,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+(UPAGES+CLSIZE)*NBPG-0x800000,PCB_P1BR(r1) # p1 pt pointer
+ movl $0x200000,PCB_P1LR(r1) # invalid p1 pt length
+ movl $CLSIZE,PCB_SZPT(r1) # init u.u_pcb.pcb_szpt
+ movl $1,r2
+strt5:
+ incl r3
+ bisl3 $PG_V|PG_KW,r3,_Sysmap+u_ptoffset[r2]
+ addl2 $NBPG,r1
+ mtpr r1,$TBIS
+ aoblss $UPAGES,r2,strt5
+
+ mtpr r6,$PCBB # first pcb
+#
+# set regs, p0br, p0lr, p1br, p1lr,
+# astlvl, ksp, and change to kernel mode
+#
+ ldpctx
+ addl2 $8,sp # pop dummy pc, psl
+ mtpr $0,$IPL # enable interrupts
+ addl3 _ecmap,$NBPG-1,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.vm
+#
+# 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.vm
+
+# ==========
+# Primitives
+# ==========
+
+_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
+ emul r1,r0,$0,r0
+ ashq $-14,r0,r0
+ tstl r1
+ bneq addret
+ incl r0
+ bicb2 $1,r0
+ blss addret
+ 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
+ .word 0x0000
+ movl 12(ap),r0 # copy length
+ blss eret
+ movl 4(ap),r1 # copy user address
+ cmpl $NBPG,r0 # probing one page or less ?
+ bgeq cishort # yes
+ciloop:
+ prober $3,$NBPG,(r1) # bytes accessible ?
+ beql eret # no
+ addl2 $NBPG,r1 # incr user address ptr
+ acbl $NBPG+1,$-NBPG,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
+ .word 0x0000
+ movl 12(ap),r0 # get count
+ blss eret
+ movl 8(ap),r1 # get user address
+ cmpl $NBPG,r0 # can do in one probew?
+ bgeq coshort # yes
+coloop:
+ probew $3,$NBPG,(r1) # bytes accessible?
+ beql eret # no
+ addl2 $NBPG,r1 # increment user address
+ acbl $NBPG+1,$-NBPG,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(save_area)
+#
+# Save reg's and ret loc into save area - return 0.
+# The contents of CMAP2 will be saved in the soft pcb extension.
+#
+ .globl _save
+_save:
+ .word 0x0
+ mtpr $HIGH,$IPL
+ movl _Sysmap+CMAP2,_u+PCB_CMAP2 # save copyseg mapping
+ movl 4(ap),r0 # save area addr
+ movab 3*4(ap),sp # restore stack to val before 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
+
+#
+# resume(proc_addr, save_addr)
+#
+# Switch to another process's '_u' area - return val 1
+# restores CMAP2 contents from from software pcb
+#
+ .globl _resume
+_resume :
+ .word 0x0
+ mtpr $HIGH,$IPL # inhibit interrupts
+ movl 8(ap),retloc
+# map u-area
+ clrl r0
+ movab _u,r1
+ movl 4(ap),r2
+res1: cvtwl (r2)[r0],r3 # get u click number from proc
+ bisl3 $PG_V|PG_KW,r3,_Umap[r0]
+ mtpr r1,$TBIS
+ addl2 $NBPG,r1
+ aoblss $UPAGES,r0,res1
+
+# restore CMAP2 contents for copyseg
+ movl _u+PCB_CMAP2,_Sysmap+CMAP2
+ mtpr $CADDR2,$TBIS
+
+ movl _u,sp # KSP from u-area
+ ashl $9,_Umap,r5 # pcb address
+ 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
+
+#
+# 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 ints
+ 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 (NBPG bytes)
+# from user virtual address to physical address
+#
+_copyseg: .globl _copyseg
+ .word 0x0000
+ mfpr $IPL,r0 # get current pri level
+ mtpr $HIGH,$IPL # turn off interrupts
+ bisl3 $PG_V|PG_KW,8(ap),_Sysmap+CMAP2
+ mtpr $CADDR2,$TBIS # invalidate entry for copy
+ movc3 $NBPG,*4(ap),CADDR2
+ bicl3 $PG_V|PG_M|PG_KW,_Sysmap+CMAP2,r1
+ cmpl r1,8(ap)
+ beql okcseg
+badcseg:
+ halt
+ jmp badcseg
+okcseg:
+ mtpr r0,$IPL # restore pri level
+ ret
+
+#
+# zero out physical memory
+# specified in relocation units (NBPG 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,(sp),$0,$NBPG,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 $NBPG,r1 # can we do it in one probe ?
+ bgeq uaw2 # yes
+uaw1:
+ probew $3,$NBPG,(r0)
+ beql uaerr # no access
+ addl2 $NBPG,r0
+ acbl $NBPG+1,$-NBPG,r1,uaw1
+uaw2:
+ probew $3,r1,(r0)
+ beql uaerr
+ movl $1,r0
+ ret
+
+userar:
+ cmpl $NBPG,r1
+ bgeq uar2
+uar1:
+ prober $3,$NBPG,(r0)
+ beql uaerr
+ addl2 $NBPG,r0
+ acbl $NBPG+1,$-NBPG,r1,uar1
+uar2:
+ prober $3,r1,(r0)
+ beql uaerr
+ movl $1,r0
+ ret
+uaerr:
+ clrl r0
+ ret
+
+#
+# kernacc - check for kernel access privileges
+#
+# We can't use the probe instruction directly because
+# it ors together current and previous mode.
+#
+ .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
+ bbs $31,4(ap),kacc6
+ 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],r3
+ bbc $31,4(ap),kacc4a
+ bbc $31,r3,kacerr # valid bit is off
+kacc4a:
+ cmpzv $27,$4,r3,$1 # check protection code
+ bleq kacerr # no access allowed
+ tstb 12(ap)
+ bneq kacc5 # only check read access
+ cmpzv $27,$2,r3,$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
+
+#
+# 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
+_udiv :
+ .word 0 # no reg save
+ movl 4(ap),r0 # dividend
+ clrl r1
+ ediv 8(ap),r0,r0,r1 # quotient in r0
+ ret
+
+# .globl _urem
+# .align 1
+#_urem:
+# .word 0
+# movl 4(ap),r0
+# clrl r1
+# ediv 8(ap),r0,r1,r0 # remainder in r0
+# ret
+
+# ==============
+# Error messages
+# ==============
+
+ .data
+emsg1: .asciz "\nTrap from kernel mode\n\r"
+SBImsg: .asciz "SBI fault\n"
+UBAmsg: .asciz "UBA error UBASR %X, FMER %X, FUBAR %X\n"
+ZERmsg: .asciz "Zero vector\n"
+straym: .asciz "Stray interrupt\n"
+
+# these should be memall'ed
+ .data
+ .globl _buffers
+ .align PGSHIFT
+_buffers: .space NBUF*BSIZE