248 lines
6.2 KiB
ArmAsm
248 lines
6.2 KiB
ArmAsm
/* @(#)underflow.s 1.1 94/10/31 SMI */
|
|
|
|
#undef WU_TRAP_CHECKS_CPUID
|
|
|
|
/*
|
|
* Copyright (c) 1990 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <sys/resource.h>
|
|
#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 "percpu_def.h"
|
|
#include "assym.s"
|
|
|
|
.seg "text"
|
|
.align 4
|
|
|
|
/*
|
|
* Window underflow trap handler.
|
|
*/
|
|
.global window_underflow
|
|
window_underflow:
|
|
sethi %hi(_nwindows), %l6
|
|
ld [%l6+%lo(_nwindows)], %l6
|
|
dec %l6
|
|
|
|
#ifdef WU_TRAP_CHECKS_CPUID
|
|
set _cpuid, %l5
|
|
lda [%l5]ASI_FLPR, %l7
|
|
and %l7, 3, %l7
|
|
cmp %l7, 2 ! cpuid not mapped
|
|
bne 1f
|
|
nop
|
|
|
|
sta %g0, [%l5]ASI_FLPR ! flush tlb
|
|
set CACHE_LINES*CACHE_LINESZ-1, %l3
|
|
and %l5, %l3, %l7 ! modulo cache size
|
|
set PAGEMASK, %l3
|
|
and %l7, %l3, %l7 ! round down to base of page
|
|
set KERNELBASE + CACHE_LINES*CACHE_LINESZ, %l3
|
|
ld [%l3 + %l7], %g0 ! replace the line
|
|
|
|
ld [%l5], %l7
|
|
GETCPU(%l5)
|
|
cmp %l5, %l7
|
|
bne _cpuid_bad
|
|
nop
|
|
|
|
!!! add more tests here, as desired.
|
|
|
|
1:
|
|
#endif WU_TRAP_CHECKS_CPUID
|
|
|
|
mov %wim, %l3
|
|
|
|
#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
|
|
nop; nop
|
|
jmp %l1 ! reexecute restore
|
|
rett %l2
|
|
|
|
wu_user:
|
|
restore ! get into window to be restored
|
|
!
|
|
! In order to restore the window from the stack, the stack
|
|
! must be aligned on a word boundary, and the part of the
|
|
! stack where the restore will be done must be present.
|
|
! We first check for alignment.
|
|
btst 0x7, %sp ! test sp alignment
|
|
bz wu_assume_stack_res
|
|
nop
|
|
|
|
!
|
|
! 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
|
|
|
|
! Most of the time the stack is resident in main memory,
|
|
! so we don't verify its presence before attempting to restore
|
|
! the window from the stack. Rather, we simply set the
|
|
! no-fault bit of the SRMMU's control register, so that
|
|
! doing the restore won't cause another trap in the case
|
|
! where the stack is not present. By checking the
|
|
! synchronous fault status register, we can determine
|
|
! whether the restore actually worked (ie. stack was present),
|
|
! or whether we first need to fault in the stack.
|
|
! Other sun4 trap handlers first probe for the stack, and
|
|
! then, if the stack is present, they restore from the stack.
|
|
! This approach CANNOT be used with a multiprocessor system
|
|
! because of a race condition: between the time that the
|
|
! stack is probed, and the restore from the stack is done, the
|
|
! stack could be stolen by the page daemon.
|
|
wu_assume_stack_res:
|
|
|
|
!!! SECURITY NOTE: this per-processor stuff uses supervisor
|
|
!!! mode stores, so the MMU never checks user permissions.
|
|
!!! So, check here that he is garfing user space.
|
|
set KERNELBASE, %l4
|
|
cmp %l4, %sp ! if in supervisor space,
|
|
bleu wu_stack_not_user ! branch out to "nonresident"
|
|
nop
|
|
|
|
sethi %hi(_v_mmu_wu), %l4
|
|
ld [%l4 + %lo(_v_mmu_wu)], %l4
|
|
jmp %l4
|
|
nop
|
|
|
|
wu_stack_not_user:
|
|
save
|
|
save
|
|
mov 0x0E, %l4 ! [fake up SFSR]
|
|
b wu_stack_not_res
|
|
mov %sp, %l5 ! [fake up SFAR]
|
|
|
|
! here is where we return after attempting to restore the
|
|
! underflowed window from the stack. check to see if the
|
|
! stack was actually present.
|
|
.global wu_chk_flt
|
|
wu_chk_flt:
|
|
btst MMU_SFSR_FAV, %l4 ! did a fault occurr?
|
|
bz wu_out ! no; just clean up and leave.
|
|
nop
|
|
|
|
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)
|
|
|
|
restore ! back to last user window
|
|
mov %psr, %g4 ! get CWP
|
|
save ! back to trap window
|
|
|
|
! now that we are back in the trap window, note that
|
|
! we have access to the following saved values:
|
|
! l7 -- computed sp.
|
|
! l4 -- fault status.
|
|
! l5 -- fault address.
|
|
|
|
!
|
|
! save remaining user state
|
|
!
|
|
mov %l7, %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]
|
|
|
|
#ifdef PC_cpu_tpsr
|
|
sethi %hi(_cpu_tpsr), %o0
|
|
st %l0, [%o0 + %lo(_cpu_tpsr)]
|
|
#endif
|
|
|
|
wr %l0, PSR_ET, %psr ! enable traps
|
|
nop; nop; nop
|
|
|
|
mov T_DATA_FAULT, %o0
|
|
add %sp, MINFRAME, %o1
|
|
mov %l5, %o2 ! fault address
|
|
mov %l4, %o3 ! fault status
|
|
call _trap ! trap(T_DATA_FAULT,
|
|
mov S_WRITE, %o4 ! rp, addr, be, S_WRITE)
|
|
|
|
b,a sys_rtt
|
|
|
|
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
|
|
nop; nop; nop
|
|
|
|
!
|
|
! 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
|
|
nop; nop
|
|
jmp %l1 ! reexecute restore
|
|
rett %l2
|