Files
Arquivotheca.SunOS-4.1.4/sys/sun4m/underflow.s
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

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