248 lines
6.1 KiB
ArmAsm
248 lines
6.1 KiB
ArmAsm
/* @(#)underflow.s 1.1 94/10/31 SMI */
|
|
|
|
/*
|
|
* Copyright (c) 1989 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <machine/asm_linkage.h>
|
|
#include <machine/param.h>
|
|
#include <machine/psl.h>
|
|
#include <machine/trap.h>
|
|
#include <machine/mmu.h>
|
|
#include <machine/pte.h>
|
|
#include <machine/reg.h>
|
|
#include <machine/buserr.h>
|
|
#include <machine/pcb.h>
|
|
|
|
#include "assym.s"
|
|
|
|
.seg "text"
|
|
.align 4
|
|
|
|
PROT_INVAL = (PG_V) >> PG_S_BIT
|
|
VALID = (PG_V) >> PG_S_BIT
|
|
USER_INVAL = (PG_S) >> PG_S_BIT
|
|
|
|
/*
|
|
* Window underflow trap handler.
|
|
*/
|
|
.global window_underflow
|
|
window_underflow:
|
|
|
|
#ifdef PERFMETER
|
|
sethi %hi(_underflowcnt), %l5
|
|
ld [%l5 + %lo(_underflowcnt)], %l7
|
|
inc %l7
|
|
st %l7, [%l5 + %lo(_underflowcnt)]
|
|
#endif PERFMETER
|
|
|
|
! wim stored into %l3 by trap vector
|
|
sll %l3, 1, %l4 ! next WIM = rol(WIM, 1, NW)
|
|
srl %l3, %l6, %l5 ! trap vector set %l6 = NW-1
|
|
or %l5, %l4, %l5
|
|
mov %l5, %wim ! install it
|
|
btst PSR_PS, %l0 ! (wim delay 1) test for user trap
|
|
bz wu_user ! (wim delay 2)
|
|
restore ! delay slot
|
|
|
|
!
|
|
! Supervisor underflow.
|
|
! We do one more restore to get into the window to be restored.
|
|
! The first one was done in the delay slot coming here.
|
|
! We then restore from the stack.
|
|
!
|
|
restore ! get into window to be restored
|
|
wu_stack_res:
|
|
RESTORE_WINDOW(%sp)
|
|
save ! get back to original window
|
|
save
|
|
mov %l0, %psr ! reinstall sup PSR_CC
|
|
nop ! psr delay
|
|
jmp %l1 ! reexecute restore
|
|
rett %l2
|
|
|
|
wu_user:
|
|
!
|
|
! User underflow. Window to be restored is a user window.
|
|
! We must check whether the user stack is resident where the window
|
|
! will be restored from, which is pointed to by the windows sp.
|
|
! The sp is the fp of the window which tried to do the restore,
|
|
! so that it is still valid.
|
|
!
|
|
restore ! get into window to be restored
|
|
!
|
|
! Normally, we would check the alignment, and then probe the top
|
|
! and bottom of the save area on the stack. However we optimize
|
|
! this by checking that both ends of the save area are within a
|
|
! 4k unit (the biggest mask we can generate in one cycle), and
|
|
! the alignment in one shot. This allows us to do one probe to
|
|
! the page map. NOTE: this assumes a page size of at least 4k.
|
|
!
|
|
and %sp, 0xfff, %l0
|
|
#ifdef VA_HOLE
|
|
! check if the sp points into the hole in the address space
|
|
sethi %hi(_hole_shift), %l5 ! hole shift address
|
|
ld [%l5 + %lo(_hole_shift)], %l7
|
|
add %l0, (14*4), %l0 ! interlock, bottom of save area
|
|
sra %sp, %l7, %l5
|
|
inc %l5
|
|
andncc %l5, 1, %l5
|
|
bz 1f
|
|
andncc %l0, 0xff8, %g0
|
|
b,a wu_stack_not_res ! sp is in the hole
|
|
1:
|
|
#else
|
|
add %l0, (14*4), %l0
|
|
andncc %l0, 0xff8, %g0
|
|
#endif VA_HOLE
|
|
bz,a wu_sp_bot
|
|
lda [%sp]ASI_PM, %l1 ! check for stack page resident
|
|
!
|
|
! Stack is either misaligned or crosses a 4k boundary.
|
|
!
|
|
btst 0x7, %sp ! test sp alignment
|
|
bz wu_sp_top
|
|
add %sp, (14*4), %l0 ! delay slot, check top of save area
|
|
|
|
!
|
|
! A user underflow trap has happened with a misaligned sp.
|
|
! Fake a memory alignment trap.
|
|
!
|
|
save ! get back to orig window
|
|
save
|
|
mov %l3, %wim ! restore old wim, so regs are dumped
|
|
b sys_trap
|
|
mov T_ALIGNMENT, %l4 ! delay slot, fake alignment trap
|
|
|
|
wu_sp_top:
|
|
#ifdef VA_HOLE
|
|
sra %l0, %l7, %l5
|
|
inc %l5
|
|
andncc %l5, 1, %l5
|
|
bz,a 1f
|
|
lda [%l0]ASI_PM, %l1 ! get pme for this address
|
|
b,a wu_stack_not_res ! address is in the hole
|
|
1:
|
|
srl %l1, PG_S_BIT, %l1 ! get vws bits
|
|
sra %sp, %l7, %l5
|
|
inc %l5
|
|
andncc %l5, 1, %l5
|
|
bz 1f
|
|
andcc %l1, VALID, %g0 ! look for valid bit
|
|
b,a wu_stack_not_res ! stack page can never be resident
|
|
1:
|
|
#else
|
|
lda [%l0]ASI_PM, %l1 ! get pme for this address
|
|
srl %l1, PG_S_BIT, %l1 ! get vws bits
|
|
andcc %l1, VALID, %g0 ! look for valid bit
|
|
#endif VA_HOLE
|
|
|
|
bnz,a wu_sp_bot
|
|
lda [%sp]ASI_PM, %l1 ! delay slot, check bottom of save area
|
|
|
|
b,a wu_stack_not_res ! stack page not resident
|
|
|
|
wu_sp_bot:
|
|
srl %l1, PG_S_BIT, %l1 ! get vws bits
|
|
|
|
!!! SECURITY NOTE: check for user access to kernel space
|
|
!!! XXX - assumes that kernel space is always resident
|
|
|
|
andcc %l1, USER_INVAL, %g0 ! look for supervisor bit
|
|
bnz wu_stack_not_user
|
|
nop
|
|
|
|
andcc %l1, VALID, %g0 ! look for valid bit
|
|
bnz wu_ustack_res
|
|
nop
|
|
|
|
mov %sp, %l0 ! save fault address
|
|
|
|
wu_stack_not_res:
|
|
!
|
|
! Restore area on user stack is not resident.
|
|
! We punt and fake a page fault so that trap can bring the page in.
|
|
! If the page fault is successful we will reexecute the restore,
|
|
! and underflow with the page now resident.
|
|
!
|
|
sethi %hi(_masterprocp), %l6
|
|
ld [%l6 + %lo(_masterprocp)], %l6
|
|
ld [%l6 + P_STACK], %l7 ! setup kernel stack
|
|
SAVE_GLOBALS(%l7 + MINFRAME)
|
|
mov %l7, %g1 ! save computed sp
|
|
mov %l0, %g2 ! save fault address
|
|
mov GENERIC_INVALID, %g3 ! compute bus error reg code
|
|
btst PROT_INVAL, %l1
|
|
bnz,a 1f
|
|
mov GENERIC_PROTERR, %g3
|
|
1:
|
|
save ! back to last user window
|
|
mov %psr, %g4 ! get CWP
|
|
save ! back to trap window
|
|
|
|
!
|
|
! save remaining user state
|
|
!
|
|
mov %g1, %sp ! setup kernel stack
|
|
SAVE_OUTS(%sp + MINFRAME)
|
|
st %l0, [%sp + MINFRAME + PSR*4] ! psr
|
|
st %l1, [%sp + MINFRAME + PC*4] ! pc
|
|
st %l2, [%sp + MINFRAME + nPC*4] ! npc
|
|
|
|
mov %l3, %wim ! reinstall old wim
|
|
mov 1, %g1 ! UWM = 0x01 << CWP
|
|
sll %g1, %g4, %g1
|
|
sethi %hi(_uunix), %l6
|
|
ld [%l6 + %lo(_uunix)], %l6
|
|
st %g1, [%l6 + PCB_UWM] ! setup u.u_pcb.pcb_uwm
|
|
clr [%l6 + PCB_WBCNT]
|
|
|
|
wr %l0, PSR_ET, %psr ! enable traps
|
|
mov T_DATA_FAULT, %o0
|
|
add %sp, MINFRAME, %o1
|
|
mov %g2, %o2
|
|
mov %g3, %o3
|
|
call _trap ! trap(T_DATA_FAULT,
|
|
mov S_READ, %o4 ! rp, addr, be, S_READ)
|
|
|
|
b,a sys_rtt
|
|
|
|
!
|
|
! The user's save area is resident. Restore the window.
|
|
!
|
|
wu_ustack_res:
|
|
RESTORE_WINDOW(%sp)
|
|
save ! get back to original window
|
|
save
|
|
wu_out:
|
|
sethi %hi(_uunix), %l3
|
|
ld [%l3 + %lo(_uunix)], %l3
|
|
ld [%l3+PCB_FLAGS], %l3
|
|
clr %l5 ! interlock slot, clear a used reg
|
|
btst CLEAN_WINDOWS, %l3 ! check for clean window maint.
|
|
bz 1f
|
|
mov %l0, %psr ! reinstall system PSR_CC
|
|
|
|
!
|
|
! Maintain clean windows. We only need to clean the registers
|
|
! used in underflow as we know this is a user window.
|
|
!
|
|
mov %l1, %o6 ! put pc, npc in an unobtrusive place
|
|
mov %l2, %o7
|
|
clr %l0 ! clean the used ones
|
|
clr %l1
|
|
clr %l2
|
|
clr %l3
|
|
clr %l4
|
|
jmp %o6 ! reexecute restore
|
|
rett %o7
|
|
1:
|
|
nop
|
|
jmp %l1 ! reexecute restore
|
|
rett %l2
|
|
|
|
wu_stack_not_user:
|
|
mov PROT_INVAL, %l1
|
|
b wu_stack_not_res
|
|
mov %sp, %l0 ! [fake up SEVAR]
|