Interdata_v6/usr/sys/start.s
title 7/32 unix hardware support routines
*
* conditional assembly switches
*
PIC equ 0 if 1, use precision interrupt clock timing
* (must also be defined in low.s)
LRA equ 0 if 1, use hardware 'lra' instruction for address
* translation (8/32 only)
entry u
entry start,idle
entry initf,icode
entry fuword,fubyte,fuiword,fuibyte
entry suword,subyte,suiword,suibyte
entry savu,retu,aretu
entry copyin,copyout,clearseg,copyseg
entry incupc
entry spl
entry ss,oc,wd,wh,wdh,rd,rh,rdh
entry lra,lraddr
extrn uisa0,kisa0,ka6
extrn memtop
extrn ksp
extrn addrsw
extrn main
extrn end,edata
ifnz PIC
extrn stclk.a,stclk.b,sytim
endc
*
* psw bit definitions
*
ps.wait equ x'8000' wait state
ps.io equ x'4000' immediate interrupt mask
ps.mm equ x'2000' machine malfunction interrupt mask
ps.af equ x'1000' arith fault interrupt mask
ps.il equ x'0800' interrupt levels (8/32)
ps.rp equ x'0400' memory relocation / protection
ps.sq equ x'0200' system queue service mask
ps.prot equ x'0100' protect mode
ps.ureg equ x'00f0' user register set
*
* psw definitions
*
ps.user equ ps.io+ps.mm+ps.af+ps.rp+ps.prot+ps.ureg
ps.idle equ ps.wait+ps.io+ps.mm+ps.af+ps.rp+ps.ureg
ps.kern equ ps.io+ps.mm+ps.af+ps.rp+ps.ureg
ps.disb equ ps.mm+ps.af+ps.rp+ps.ureg
ps.trap equ ps.mm+ps.af
*
* reserved memory location definitions
*
isp equ x'd0' interrupt-service pointer table
mac.r0 equ x'300' memory-access controller seg regs
*
* register definitions
*
r0 equ 0
r1 equ 1
r2 equ 2
r3 equ 3
r4 equ 4
r5 equ 5
r6 equ 6
r7 equ 7
r8 equ 8
r9 equ 9
r10 equ 10
r11 equ 11
r12 equ 12
r13 equ 13
r14 equ 14
r15 equ 15
rf equ 15
sp equ r7
*
* per-process data area for current process - always mapped to segment e
*
u equ y'e0000'
usize equ 6
title start -- 7/32 unix system initialization
pure
start equ *
*
* on entry from bootstrap loader, disable mac & interrupts
*
lhi r1,ps.ureg disable everything
epsr r0,r1
*
* clear per-process data area and bss to zeroes
*
lis r0,0
la r5,end end of kernel
ahi r5,255 round up to 256 byte block
nhi r5,-256
la r2,256*usize(r5) end of u area
la r1,edata start of bss
clp equ *
st r0,0(r1) clear a word
ais r1,4 next word
cr r1,r2 finished?
bl clp no - repeat
*
* Find out how much memory is available
*
lr r1,r2 end of u area
li r2,y'fedcba98' test data value
memlp equ *
st r2,0(r1) try storing word
c r2,0(r1) did it work?
bne memend no - end of memory
ahi r1,256 yes - try next 256 byte block
c r1,memtop reached upper limit?
bl memlp no - keep looking
memend equ *
sis r1,1 highest valid address
st r1,memtop save it
ais r1,1
srl r1,8 max memory (in 256-byte blocks)
*
* initialize prototype mac registers for kernel address space:
*
* segments 0-n: map real low-core addressess (up to n*64k)
* e : maps per-process data area for current process
* all others : invalid
*
la r2,kisa0 kernel seg regs
li r0,y'0ff00010' prototype seg reg value
seglp equ *
chi r1,256 more than full segment left?
bm seglast no - set last segment
st r0,0(r2) set seg reg
ais r2,4
ai r0,y'10000' origin of next segment
shi r1,256 memory left
b seglp
*
seglast equ *
sis r1,1 last segment length - 1
bm segx no partial segment - skip
sll r1,20 move to seg length field
ni r0,y'fffff'
or r0,r1
st r0,0(r2) set seg reg
ais r2,4
*
segx equ *
l r2,ka6 per-process data segment
lr r0,r5 address of end of kernel
oi r0,usize*y'100000'+x'10' size & protection
st r0,0(r2) set as segment for pda
*
* start kernel stack pointer at top of per process area
*
la sp,256*usize+u-4
st sp,ksp save sp for interrupts
*
* load hardware mac registers from kernel prototypes, and enable
* memory relocation / protection and interrupts
*
la r1,kisa0 kernel seg regs
bal r6,addrsw load into mac regs
li r1,ps.kern enable mac & interrupts
epsr r0,r1
*
* call main() c routine to complete initialization
*
bal rf,main
*
* on return from main, enter 'user state' at user address 0 to exec
* init process
*
epsr r3,r3 disable the mac
nhi r3,x'ffff'-ps.rp
epsr r0,r3
la r1,uisa0 user seg regs
bal r6,addrsw switch address space
lhi r0,ps.user user state psw
lis r1,0 address 0 in user space
lpswr r0 enter process 1
title bootstrap program to load in init process
*
* exec("/etc/init", "/etc/init");
* for (;;)
* ;
*
align adc
icode equ *
svc 14,11 * exec *
dc a(initf-icode)
dc a(initp-icode)
b * didn't work -- loop forever
initp dc a(initf-icode)
dc 0
* string '/etc/init' -- must be in hex to avoid uppercase xlate
initf db x'2f',x'65',x'74',x'63'
db x'2f',x'69',x'6e',x'69',x'74',0
* extra patch space in case of emergency
db 0,0,0,0,0,0,0,0,0,0
db *
title 7/32 unix -- inter-address-space data transfer routines
*
* fubyte(i) - fetch a byte from user address <i>
* fuword(i) - fetch a word from user address <i>
* subyte(i,a) - store byte <a> at user address <i>
* suword(i,a) - store word <a> at user address <i>
*
* - if <i> is an illegal address (or write-protected for subyte or suword)
* the routine returns (-1).
*
fubyte equ *
fuibyte equ *
l r1,0(sp) user address
bal r6,lrau relocate
btc x'c',illaddr illegal address
lb r0,0(r1) fetch byte
br rf
*
fuword equ *
fuiword equ *
l r1,0(sp) user address
bal r6,lrau relocate
btc x'c',illaddr illegal address - exit
lhl r0,0(r1) fetch word as 2 halfwords
exhr r0,r0 ... in case not on word boundary
lhl r1,2(r1) ... (8/32)
or r0,r1
br rf
*
subyte equ *
suibyte equ *
l r1,0(sp) user address
bal r6,lrau relocate
btc x'e',illaddr illegal or protected address - exit
l r0,4(sp) byte to be stored
stb r0,0(r1) store it
lis r0,0 normal return
br rf
*
suword equ *
suiword equ *
l r1,0(sp) user address
bal r6,lrau relocate
btc x'e',illaddr illegal or write protected - exit
l r0,4(sp) word to be stored
sth r0,2(r1) store it as 2 halfwords
exhr r0,r0 ... in case not on word boundary
sth r0,0(r1) ... (8/32)
lis r0,0 normal return
br rf
*
* copyin (uaddr, kaddr, n)
* copyout (kaddr, uaddr, n)
* - copy <n> bytes from/to user address <uaddr> to/from kernel
* address <kaddr>
*
* - <n> must be a multiple of wordsize
*
copyin equ *
l r1,0(sp) user source address
bal r6,lrau
btc x'c',illaddr illegal address - exit
l r2,4(sp) kernel target address
b copy
*
copyout equ *
l r1,4(sp) user target address
bal r6,lrau
btc x'e',illaddr illegal address - exit
lr r2,r1
l r1,0(sp) kernel source address
copy equ *
l r4,8(sp) no. of bytes
sis r4,4 start at last word
copylp equ *
l r0,0(r1,r4) move a word
st r0,0(r2,r4)
sis r4,4 back up
bnm copylp repeat
*
lis r0,0
br rf
*
* Illegal or write-protected address - return (-1)
*
illaddr equ *
lcs r0,1 return -1
br rf
eject
*
* clearseg(i) : clear block number <i> in kernel space to zeroes
*
clearseg equ *
l r1,0(sp) block no.
sll r1,8 block origin address
lis r0,0
lhi r2,63*adc start at last word
clearlp equ *
st r0,0(r1,r2) clear a word
sis r2,4 back up
bnm clearlp repeat
br rf
*
* copyseg (i,j) : copy kernel block number <i> into kernel block <j>
*
copyseg equ *
l r2,4(sp) target block no.
sll r2,8 block origin
l r1,0(sp) source block no.
sll r1,8
lhi r3,63*adc start at last word
copyslp equ *
l r0,0(r1,r3) move a word
st r0,0(r2,r3)
sis r3,4 back up
bnm copyslp repeat
lis r0,0
br rf
title 7/32 unix -- user-kernel address space mapping
*
* lraddr - C interface to lra
*
* lraddr(aaddr, seg)
* char **addr; /* pointer to unrelocated address */
* int seg[]; /* pointer to copy of MAC segmentation registers */
*
* - replaces *addr by relocated address
* - returns condition code from lra instruction
*
lraddr equ *
l r5,0(sp) pointer to virtual addr
l r1,0(r5) virtual address
l r2,4(sp) pointer to seg regs
bal r6,lra relocate
st r1,0(r5) change virtual to real address
nhi r0,15 isolate cond code in new psw
br rf
* lra: load 'real' address
* input: r1 - address in user program space
* r2 - address of segmentation regs
* output: r1 - corresponding address in kernel space
* cc - condition code set as in real lra instruction
* uses: r0
*
* lrau : entry point using user seg regs (uisa0)
*
lrau equ *
la r2,uisa0 use uisa0 for seg regs
lra equ *
ifnz LRA
lra r1,0(r2) use hardware translation
br r6
else
lr r0,r1 save input addr
srl r1,14 seg no. * 4
ni r1,x'3c' clear extra bits
l r1,0(r1,r2) user seg reg
thi r1,x'10' check 'present' bit
bz lrabad zero - illegal address
lr r2,r1
srl r2,12 seg limit * 256
ahi r2,x'100' seg length in bytes
ni r2,y'fff00' clear extra bits
ni r0,y'ffff' offset in segment
cr r0,r2 within range?
bnl lrabad no - illegal address
lis r2,0
thi r1,x'60' write-protected?
bz lranwp no - skip
lis r2,2 set G bit in cc
lranwp equ *
ni r1,y'fff00' segment origin
ar r1,r0 add offset
b lraset
* unmapped address
lrabad equ *
lis r2,8 set C bit
* set condition code
lraset equ *
epsr r0,r0 current psw
nhi r0,-16 mask off old cond code
or r0,r2 set new cond code
epsr r2,r0 set new psw
br r6
endc
title 7/32 unix -- kernel-process switching routines
*
* savu(a)
* - save current kernel process stack environment
* in location <a>
*
savu equ *
l r1,0(sp) location
st sp,0(r1) save stack ptr
st r14,adc(r1) save stack base
br rf
*
* retu(a)
* - restore previously-saved kernel process stack environment
* from ppda at block number -- not address -- <a>
* - reset kernel seg reg e to map to address <a>, thus
* switching the 'current process'
*
retu equ *
l r1,0(sp) block number
sll r1,8 convert to address
lr r0,r1
oi r0,usize*y'100000'+x'10' length = usize
li r3,ps.disb-ps.rp disable the mac
epsr r2,r3
l r4,ka6 set as kernel ppd segment
st r0,0(r4)
l sp,0(r1) restore stack ptr
l r14,adc(r1) restore stack base
*
* switch to new ppd segment
*
la r1,kisa0 set new seg regs into
bal r6,addrsw hardware mac regs
epsr r0,r2 enable mac again
br rf
*
* aretu(a)
* - restore kernel process stack environment from alternate
* location <a>, in the current per-process data area
*
aretu equ *
l r1,0(sp) location
l sp,0(r1) restore stack ptr
l r14,adc(r1) restore stack base
br rf
title incupc -- update execution profile buffer
*
* incupc (pc, prof)
* struct \(
* int base; int length; int offset; int scale;
* \) *prof;
*
* - called from clock interrupt handler to update user execution profile
*
incupc equ *
l r4,4(sp) base of prof
l r3,0(sp) current program counter
s r3,8(r4) subtract offset
bmr rf < 0 : not within buffer
*
* scale pc into buffer
*
m r2,12(r4) scale pc
ais r2,1 round to fullword
slls r2,1
nhi r2,x'fffc'
c r2,4(r4) within buffer?
bnlr rf no : return
a r2,0(r4) address = base + offset
*
* get physical address of buffer location
*
lr r1,r2 program address
bal r6,lrau get physical address
btc x'e',incupcx illegal or write-protected -- error
*
* increment profile counter
*
lis r0,1
am r0,0(r1) increment counter in buffer
br rf
*
* memory fault -- turn off profiling
*
incupcx equ *
lis r0,0 zero prof scale
st r0,12(r4) to turn off profiling
br rf
title 7/32 unix - set processor level
*
* spl(n)
*
* - sets 'processor level' to <n> (i.e. only devices with
* priority >n may interrupt
* - returns previous value of processor level
* note:
* as currently implemented, spl(0) enables interrupts, and any
* nonzero processor level disables all interrupts. eventually
* the pdp-11 processor level mechanism should be emulated more
* closely, probably by using interdata system queue.
*
spl equ *
lis r0,0
epsr r1,r1 current psw status
thi r1,ps.io immediate interrupts enabled?
bnz spl.new yes - skip
lis r0,1 no - 'previous level' is 1
spl.new equ *
nhi r1,x'ffff'-ps.io mask off immediate interrupts
l r2,0(sp) new processor level
bnz spl.epsr nonzero - skip
ohi r1,ps.io zero - enable interrupts again
spl.epsr equ *
epsr r2,r1 load new psw status
br rf
title i/o instruction routines
ss equ * sense status
l r1,0(sp)
ssr r1,r0
br rf
*
oc equ * output command
l r1,0(sp)
oc r1,7(sp)
br rf
*
wd equ * write data
l r1,0(sp)
wd r1,7(sp)
br rf
*
wh equ * write halfword
l r1,0(sp)
wh r1,6(sp)
br rf
*
wdh equ * write 3 bytes
l r1,0(sp)
wd r1,5(sp)
wh r1,6(sp)
br rf
*
rd equ * read data
l r1,0(sp)
rdr r1,r0
br rf
*
rh equ * read halfword
l r1,0(sp)
rhr r1,r0
br rf
*
rdh equ * read 3 bytes
l r1,0(sp)
rdr r1,r2
rhr r1,r0
exhr r2,r2
or r0,r2
br rf
title 'idle' routine -- go into enabled wait state
idle equ *
ifnz PIC
bal r6,ras read and update system time
endc
li r1,ps.idle load 'wait' psw
epsr r0,r1
ifnz PIC
bal r6,ras read and update sys time
endc
epsr r1,r0 restore previous psw
br rf return to caller
ifnz PIC
*
* read and restart pic
* add current interval to sys time
*
ras equ * read and start clock
lhi r2,x'6c' addr of pic
rhr r2,r3 read interval
ras1 wh r2,stclk.a restart clock
ssr r2,r4
btc 8,ras1
oc r2,stclk.b
lhi r5,x'fff' max interval
sr r5,r3 real current clock interval
am r5,sytim add to system time
br r6 return
endc
end start