6297 lines
192 KiB
ArmAsm
6297 lines
192 KiB
ArmAsm
//++
|
||
//
|
||
// Module Name:
|
||
// trap.s
|
||
//
|
||
// Abstract:
|
||
// Low level interruption handlers
|
||
//
|
||
// Author:
|
||
// Bernard Lint 12-Jun-1995
|
||
//
|
||
// Environment:
|
||
// Kernel mode only
|
||
//
|
||
// Revision History:
|
||
//
|
||
//
|
||
// Open Design Issues:
|
||
//
|
||
//--
|
||
|
||
#if 1 // interruption logging is enabled in checked and free builds
|
||
#define INTERRUPTION_LOGGING 1
|
||
#endif // DBG
|
||
|
||
#include "ksia64.h"
|
||
|
||
.file "trap.s"
|
||
.explicit
|
||
|
||
//
|
||
// Globals imported:
|
||
//
|
||
|
||
PublicFunction(KeBugCheckEx)
|
||
PublicFunction(KiApcInterrupt)
|
||
PublicFunction(KiCheckForSoftwareInterrupt)
|
||
PublicFunction(KiDispatchException)
|
||
PublicFunction(KiExternalInterruptHandler)
|
||
PublicFunction(KiFloatTrap)
|
||
PublicFunction(KiFloatFault)
|
||
PublicFunction(KiGeneralExceptions)
|
||
PublicFunction(KiUnimplementedAddressTrap)
|
||
PublicFunction(KiNatExceptions)
|
||
PublicFunction(KiMemoryFault)
|
||
PublicFunction(KiOtherBreakException)
|
||
PublicFunction(KiPanicHandler)
|
||
PublicFunction(KiSingleStep)
|
||
PublicFunction(KiUnalignedFault)
|
||
PublicFunction(PsConvertToGuiThread)
|
||
PublicFunction(ExpInterlockedPopEntrySListFault)
|
||
PublicFunction(KiDebugFault)
|
||
PublicFunction(KeSetLowPsrBit)
|
||
PublicFunction(KiTestGdiBatchCount)
|
||
PublicFunction(KeCopySafe)
|
||
PublicFunction(KiIA32ExceptionVectorHandler)
|
||
PublicFunction(KiIA32InterruptionVectorHandler)
|
||
PublicFunction(KiIA32InterceptionVectorHandler)
|
||
|
||
|
||
.global KiSystemServiceHandler
|
||
.global KeServiceDescriptorTableShadow
|
||
.global KeGdiFlushUserBatch
|
||
.global KdDebuggerEnabled
|
||
.global MiDefaultPpe
|
||
|
||
// For Conditional Interrupt Logging
|
||
#define UserSystemcallBit 61
|
||
#define ExternalInterruptBit 62
|
||
|
||
.global KiVectorLogMask
|
||
|
||
|
||
|
||
//
|
||
// Register aliases used throughout the entire module
|
||
//
|
||
|
||
//
|
||
// Banked general registers
|
||
//
|
||
// h16-h23 can only be used when psr.ic=1.
|
||
//
|
||
// h24-h31 can only be used when psr.ic=0 (these are reserved for tlb
|
||
// and pal/machine check handlers when psr.ic=1).
|
||
//
|
||
|
||
//
|
||
// Shown below are aliases of bank 0 registers used in the low level handlers
|
||
// by macros ALLOCATE_TRAP_FRAME, SAVE_INTERRUPTION_RESOURCES, and
|
||
// RETURN_FROM_INTERRUPTION. When the code in the macros are changes, these
|
||
// register aliases must be reviewed.
|
||
//
|
||
|
||
rHIPSR = h16
|
||
rHpT2 = h16
|
||
|
||
rHIIPA = h17
|
||
rHRSC = h17
|
||
rHDfhPFS = h17 // used to preserve pfs in KiDisabledFpRegisterVector
|
||
|
||
rHIIP = h18
|
||
rHFPSR = h18
|
||
|
||
rHOldPreds = h19
|
||
rHBrp = h19
|
||
rHRNAT = h19
|
||
|
||
rHIFS = h20
|
||
rHPFS = h20
|
||
rHBSP = h20
|
||
|
||
rHISR = h21
|
||
rHUNAT = h21
|
||
rHBSPSTORE = h21
|
||
rHpT3 = h21
|
||
|
||
rHSp = h22
|
||
rHDfhBrp = h22 // used to preserve brp in KiDisabledFpRegisterVector
|
||
rHpT4 = h22
|
||
|
||
rHpT1 = h23
|
||
|
||
rTH3 = h24
|
||
|
||
rHHandler = h25
|
||
rTH1 = h26
|
||
rTH2 = h27
|
||
|
||
rHIIM = h28
|
||
rHIFA = h28
|
||
|
||
rHEPCVa = h29
|
||
rHEPCVa2 = h30
|
||
rPanicCode = h30
|
||
|
||
rTH4 = h31
|
||
|
||
//
|
||
// General registers used through out module
|
||
//
|
||
|
||
pApc = ps0 // User Apc Pending
|
||
pUser = ps1 // mode on entry was user
|
||
pKrnl = ps2 // mode on entry was kernel
|
||
pUstk = ps3
|
||
pKstk = ps4
|
||
pEM = ps5 // EM ISA on kernel entry
|
||
pIA = ps6 // X86 ISA on kernel entry
|
||
pKDbg = ps7 // Kernel debug Active
|
||
pUDbg = ps8 // Kernel debug Active
|
||
|
||
//
|
||
// Kernel registers used through out module
|
||
//
|
||
rkHandler = k6 // specific exception handler
|
||
|
||
|
||
|
||
|
||
//
|
||
// Macro definitions for this module only
|
||
//
|
||
|
||
//
|
||
// Define vector/exception entry/exit macros.
|
||
// N.B. All HANDLER_ENTRY functions go into .nsc section with
|
||
// KiNormalSystemCall being the first.
|
||
//
|
||
|
||
#define HANDLER_ENTRY(Name) \
|
||
.##global Name; \
|
||
.##proc Name; \
|
||
Name::
|
||
|
||
#define HANDLER_ENTRY_EX(Name, Handler) \
|
||
.##global Name; \
|
||
.##proc Name; \
|
||
.##type Handler, @function; \
|
||
.##personality Handler; \
|
||
Name::
|
||
|
||
#define VECTOR_ENTRY(Offset, Name, Extra0) \
|
||
.##org Offset; \
|
||
.##global Name; \
|
||
.##proc Name; \
|
||
Name::
|
||
|
||
|
||
#define VECTOR_EXIT(Name) \
|
||
.##endp Name
|
||
|
||
#define HANDLER_EXIT(Name) \
|
||
.##endp Name
|
||
|
||
|
||
//++
|
||
// Routine:
|
||
//
|
||
// IO_END_OF_INTERRUPT(rVector,rT1,rT2,pEOI)
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// HalEOITable Entry corresponding to the vectorNo is tested.
|
||
// If the entry is nonzero, then vectorNo is stored to the location
|
||
// specified in the entry. If the entry is zero, return.
|
||
//
|
||
// Arguements:
|
||
//
|
||
//
|
||
// Notes:
|
||
//
|
||
// MS preprocessor requires /* */ style comments
|
||
//
|
||
//--
|
||
|
||
#define IO_END_OF_INTERRUPT(rVector,rT1,rT2,pEOI) ;\
|
||
movl rT1 = KiPcr+PcEOITable ;\
|
||
;; ;\
|
||
ld8 rT1 = [rT1] ;\
|
||
;; ;\
|
||
shladd rT2 = rVector,3,rT1 ;\
|
||
;; ;\
|
||
ld8 rT1 = [rT2] ;\
|
||
;; ;\
|
||
cmp.ne pEOI = zero, rT1 ;\
|
||
;; ;\
|
||
(pEOI) st4.rel [rT1] = rVector
|
||
|
||
|
||
//++
|
||
// Routine:
|
||
//
|
||
// VECTOR_CALL_HANDLER(Handler, SpecificHandler)
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Common code for transfer to heavyweight handlers from
|
||
// interruption vectors. Put RSE in store intensive mode,
|
||
// cover current frame and call handler.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Handler: First level handler for this vector
|
||
// SpecificHandler: Specific handler to be called by the generic
|
||
// exception handler.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None
|
||
//
|
||
// Notes:
|
||
// Uses just the kernel banked registers (h16-h31)
|
||
//
|
||
// MS preprocessor requires /* */ style comments
|
||
//--
|
||
|
||
|
||
#define VECTOR_CALL_HANDLER(Handler,SpecificHandler) ;\
|
||
mov rHIFA = cr##.##ifa ;\
|
||
movl rHHandler = SpecificHandler ;\
|
||
br##.##sptk Handler ;\
|
||
;;
|
||
|
||
|
||
//++
|
||
// Routine:
|
||
//
|
||
// ALLOCATE_TRAP_FRAME
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Common code for allocating trap frame on kernel entry for heavyweight
|
||
// handler.
|
||
//
|
||
// On entry:
|
||
//
|
||
// On exit: sp -> trap frame; any instruction that depends on sp must be
|
||
// placed in the new instruction group. Interruption resources
|
||
// ipsr, iipa, iip, predicates, isr, sp, ifs are captured in
|
||
// seven of the banked registers h16-23. The last one is used
|
||
// by SAVE_INTERRUPTION_STATE as a pointer to save these resources
|
||
// in the trap frame.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None
|
||
//
|
||
// Notes:
|
||
// Uses just the kernel banked registers (h16-h31)
|
||
//
|
||
// MS preprocessor requires /* */ style comments below
|
||
//--
|
||
|
||
#define ALLOCATE_TRAP_FRAME ;\
|
||
;\
|
||
pOverflow1 = pt2 ;\
|
||
pOverflow2 = pt3 ;\
|
||
pOverflow3 = pt4 ;\
|
||
;\
|
||
mov rHIPSR = cr##.##ipsr ;\
|
||
movl rTH1 = KiPcr+PcInitialStack ;\
|
||
;\
|
||
mov rHIIP = cr##.##iip ;\
|
||
mov rHOldPreds = pr ;\
|
||
cover /* cover and save IFS */;\
|
||
;; ;\
|
||
;\
|
||
ld8 rTH4 = [rTH1], PcBStoreLimit-PcInitialStack ;\
|
||
mov rTH3 = ar##.##bsp ;\
|
||
tbit##.##z pt1, pt0 = sp, 63 ;\
|
||
;; ;\
|
||
;\
|
||
mov rHIIPA = cr##.##iipa ;\
|
||
ld8 rTH2 = [rTH1], PcStackLimit-PcBStoreLimit ;\
|
||
;\
|
||
mov rHIFS = cr##.##ifs ;\
|
||
mov rHSp = sp ;\
|
||
extr##.##u rHpT1 = rHIPSR, PSR_CPL, PSR_CPL_LEN /* get mode */;\
|
||
;; ;\
|
||
;\
|
||
cmp4##.##eq pKrnl, pUser = PL_KERNEL, rHpT1 /* set mode pred */;\
|
||
cmp4##.##eq pKstk, pUstk = PL_KERNEL, rHpT1 /* set stack pred */;\
|
||
add rHpT1 = PcKernelDebugActive-PcStackLimit, rTH1 ;\
|
||
;; ;\
|
||
;\
|
||
(pKstk) ld8 rTH1 = [rTH1] ;\
|
||
(pKstk) cmp##.##geu##.##unc pOverflow2 = rTH3, rTH2 ;\
|
||
(pKstk) add sp = -TrapFrameLength, sp /* allocate TF */;\
|
||
;; ;\
|
||
;\
|
||
ld1 rHpT1 = [rHpT1] /* load kernel db state */;\
|
||
(pKstk) cmp##.##leu##.##unc pOverflow1 = sp, rTH1 ;\
|
||
(pKstk) cmp##.##geu##.##unc pOverflow3 = sp, rTH3 ;\
|
||
;; ;\
|
||
;\
|
||
mov rHISR = cr##.##isr ;\
|
||
cmp##.##ne##.##or pKDbg = r0, rHpT1 /* kernel debug active? */;\
|
||
mov rPanicCode = PANIC_STACK_SWITCH ;\
|
||
;\
|
||
(pUstk) add sp = -ThreadStateSaveAreaLength-TrapFrameLength, rTH4 ;\
|
||
(pOverflow1) br.spnt.few KiPanicHandler ;\
|
||
(pOverflow2) br.spnt.few KiPanicHandler ;\
|
||
(pOverflow3) br.spnt.few KiPanicHandler
|
||
|
||
|
||
|
||
//++
|
||
// Routine:
|
||
//
|
||
// SAVE_INTERRUPTION_STATE(Label)
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Common code for saving interruption state on entry to a heavyweight
|
||
// handler.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Label: label for branching around BSP switch
|
||
//
|
||
// On entry:
|
||
//
|
||
// sp -> trap frame
|
||
//
|
||
// On exit:
|
||
//
|
||
// Static registers gp, teb, sp, fpsr spilled into the trap frame.
|
||
// Registers gp, teb, fpsr are set up for kernel mode execution.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None
|
||
//
|
||
// Notes:
|
||
//
|
||
// Interruption resources already captured in bank 0 registers h16-h23.
|
||
// It's safe to take data TLB fault when saving them into the trap
|
||
// frame because kernel stack is always resident in memory. This macro
|
||
// is carefully constructed to save the bank registers' contents in
|
||
// the trap frame and reuse them to capture other register states as
|
||
// soon as they are available. Until we have a virtual register
|
||
// allocation scheme in place, the bank 0 register aliases defined at
|
||
// the beginning of the file must be updated when this macro is modified.
|
||
//
|
||
// MS preprocessor requires /* */ style comments below
|
||
//--
|
||
|
||
|
||
#define SAVE_INTERRUPTION_STATE(Label) ;\
|
||
;\
|
||
/* Save interruption resources in trap frame */ ;\
|
||
;\
|
||
;\
|
||
ssm (1 << PSR_IC) | (1 << PSR_DFH) | (1 << PSR_AC) ;\
|
||
add rHpT1 = TrStIPSR, sp /* -> IPSR */;\
|
||
;; ;\
|
||
srlz##.##d ;\
|
||
st8 [rHpT1] = rHIPSR, TrStISR-TrStIPSR /* save IPSR */;\
|
||
add rHpT2 = TrPreds, sp /* -> Preds */;\
|
||
;; ;\
|
||
;\
|
||
st8 [rHpT1] = rHISR, TrStIIP-TrStISR /* save ISR */;\
|
||
st8 [rHpT2] = rHOldPreds, TrBrRp-TrPreds ;\
|
||
;; ;\
|
||
;\
|
||
mov rHUNAT = ar##.##unat ;\
|
||
st8 [rHpT1] = rHIIP, TrStIFS-TrStIIP /* save IIP */;\
|
||
mov rHBrp = brp ;\
|
||
;; ;\
|
||
;\
|
||
mov rHFPSR = ar##.##fpsr ;\
|
||
st8 [rHpT1] = rHIFS, TrStIIPA-TrStIFS /* save IFS */;\
|
||
mov rHPFS = ar##.##pfs ;\
|
||
;; ;\
|
||
;\
|
||
st8 [rHpT1] = rHIIPA, TrStFPSR-TrStIIPA /* save IIPA */;\
|
||
st8 [rHpT2] = rHBrp, TrRsPFS-TrBrRp ;\
|
||
;; ;\
|
||
;\
|
||
mov rHRSC = ar##.##rsc ;\
|
||
st8 [rHpT2] = rHPFS /* save PFS */;\
|
||
add rHpT2 = TrApUNAT, sp ;\
|
||
;\
|
||
mov rHBSP = ar##.##bsp ;\
|
||
;; ;\
|
||
;\
|
||
mov ar##.##rsc = r0 /* put RSE in lazy mode */;\
|
||
st8 [rHpT2] = rHUNAT, TrIntGp-TrApUNAT /* save UNAT */;\
|
||
;; ;\
|
||
;\
|
||
mov rHBSPSTORE = ar##.##bspstore /* get user bspstore point */;\
|
||
st8 [rHpT1] = rHFPSR, TrRsBSP-TrStFPSR /* save FPSR */;\
|
||
;; ;\
|
||
;\
|
||
st8##.##spill [rHpT2] = gp, TrIntTeb-TrIntGp /* spill GP */;\
|
||
st8 [rHpT1] = rHBSP /* save BSP */;\
|
||
;; ;\
|
||
;\
|
||
st8##.##spill [rHpT2] = teb, TrIntSp-TrIntTeb /* spill TEB (r13) */;\
|
||
(pUstk) mov teb = kteb /* sanitize teb */;\
|
||
sub rHBSP = rHBSP, rHBSPSTORE /* size of dirty region */;\
|
||
;; ;\
|
||
;\
|
||
st8##.##spill [rHpT2] = rHSp, TrApDCR-TrIntSp /* spill SP */;\
|
||
movl rHpT1 = KiPcr + PcKernelGP ;\
|
||
;; ;\
|
||
;\
|
||
(pUstk) mov rHRNAT = ar##.##rnat /* get RNAT */;\
|
||
movl rHFPSR = FPSR_FOR_KERNEL /* initial fpsr value */;\
|
||
;; ;\
|
||
;\
|
||
mov ar##.##fpsr = rHFPSR /* set fpsr */;\
|
||
add rHpT2 = TrRsRSC, sp ;\
|
||
dep rHRSC = rHBSP, rHRSC, RSC_MBZ1, RSC_LOADRS_LEN ;\
|
||
;; ;\
|
||
;\
|
||
ld8 gp = [rHpT1], PcInitialBStore-PcKernelGP /* load GP */;\
|
||
st8 [rHpT2] = rHRSC, TrRsBSPSTORE-TrRsRSC ;\
|
||
(pKstk) br##.##dpnt Label /* br if on kernel stack */;\
|
||
;; ;\
|
||
;\
|
||
/* */;\
|
||
/* If previous mode is user, switch to kernel backing store */;\
|
||
/* -- uses the "loadrs" approach. Note that we do not save the */;\
|
||
/* BSP/BSPSTORE in the trap frame if prvious mode was kernel */;\
|
||
/* */;\
|
||
;\
|
||
ld8 rHpT4 = [rHpT1] /* load kernel bstore */;\
|
||
st8 [rHpT2] = rHBSPSTORE, TrRsRNAT-TrRsBSPSTORE ;\
|
||
;; ;\
|
||
;\
|
||
st8 [rHpT2] = rHRNAT /* save user RNAT */;\
|
||
dep rHpT4 = rHBSPSTORE, rHpT4, 0, 9 ;\
|
||
/* adjust kernel BSPSTORE */;\
|
||
/* for NAT collection */;\
|
||
;; ;\
|
||
;\
|
||
/* */;\
|
||
/* Now running on kernel backing store */;\
|
||
/* */;\
|
||
;\
|
||
Label: ;\
|
||
(pUstk) mov ar##.##bspstore = rHpT4 /* switch to kernel BSP */;\
|
||
(pUstk) mov ar##.##rsc = RSC_KERNEL /* turn rse on, kernel mode */;\
|
||
bsw##.##1 /* switch back to user bank */;\
|
||
;; /* stop bit required */;\
|
||
|
||
|
||
|
||
//++
|
||
// Routine:
|
||
//
|
||
// RETURN_FROM_INTERRUPTION
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Common handler code to restore trap frame and resume execution
|
||
// at the interruption address.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// Label
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None
|
||
//
|
||
// Note:
|
||
//
|
||
// On entry: interrrupts disabled, sp -> trap frame
|
||
// On exit:
|
||
// MS preprocessor requires /* */ style comments below
|
||
//--
|
||
|
||
#define RETURN_FROM_INTERRUPTION(Label) ;\
|
||
;\
|
||
.##regstk 0,4,2,0 /* must match the alloc instruction below */ ;\
|
||
;\
|
||
rBSP = loc0 ;\
|
||
rRnat = loc1 ;\
|
||
;\
|
||
rpT1 = t1 ;\
|
||
rpT2 = t2 ;\
|
||
rpT3 = t3 ;\
|
||
rpT4 = t4 ;\
|
||
rThread = t6 ;\
|
||
rApcFlag = t7 ;\
|
||
rT1 = t8 ;\
|
||
rT2 = t9 ;\
|
||
;\
|
||
;\
|
||
alloc rT1 = 0,4,2,0 ;\
|
||
movl rpT1 = KiPcr + PcCurrentThread /* ->PcCurrentThread */;\
|
||
;; ;\
|
||
;\
|
||
invala ;\
|
||
(pUstk) ld8 rThread = [rpT1], PcDebugActive-PcCurrentThread ;\
|
||
(pKstk) br##.##call##.##spnt brp = KiRestoreTrapFrame ;\
|
||
;; ;\
|
||
;\
|
||
(pUstk) ld1 rT1 = [rpT1] /* load user debug active state */;\
|
||
(pUstk) add rpT1 = ThApcState+AsUserApcPending, rThread ;\
|
||
(pKstk) br##.##spnt Label##CriticalExitCode ;\
|
||
;; ;\
|
||
;\
|
||
ld1 rApcFlag = [rpT1], ThAlerted-ThApcState-AsUserApcPending ;\
|
||
add rBSP = TrRsBSP, sp ;\
|
||
add rRnat = TrRsRNAT, sp /* -> user RNAT */;\
|
||
;; ;\
|
||
;\
|
||
st1.nta [rpT1] = zero ;\
|
||
cmp##.##ne pApc = zero, rApcFlag ;\
|
||
cmp##.##ne pUDbg = zero, rT1 /* if ne, user debug active */;\
|
||
;; ;\
|
||
;\
|
||
PSET_IRQL (pApc, APC_LEVEL) ;\
|
||
movl gp = _gp /* restore to kernel gp value */;\
|
||
;\
|
||
(pApc) FAST_ENABLE_INTERRUPTS ;\
|
||
(pApc) mov out1 = sp ;\
|
||
(pApc) br##.##call##.##sptk brp = KiApcInterrupt ;\
|
||
;; ;\
|
||
;\
|
||
ld8 rBSP = [rBSP] /* user BSP */;\
|
||
ld8 rRnat = [rRnat] /* user RNAT */;\
|
||
;\
|
||
(pApc) FAST_DISABLE_INTERRUPTS ;\
|
||
PSET_IRQL (pApc, zero) ;\
|
||
(pUDbg) br##.##call##.##spnt brp = KiLoadUserDebugRegisters ;\
|
||
;; ;\
|
||
;\
|
||
br##.##call##.##sptk brp = KiRestoreTrapFrame ;\
|
||
;; ;\
|
||
;\
|
||
;\
|
||
Label##CriticalExitCode: ;\
|
||
;\
|
||
add loc2 = TrBrRp, sp ;\
|
||
add loc3 = TrRsRSC, sp ;\
|
||
bsw##.##0 ;\
|
||
;; ;\
|
||
;\
|
||
ld8 rHBrp = [loc2], TrStIPSR-TrBrRp ;\
|
||
ld8 rHRSC = [loc3] ;\
|
||
mov loc3 = RSC_KERNEL_DISABLED ;\
|
||
;; ;\
|
||
;\
|
||
ld8 rHIPSR = [loc2], TrRsPFS-TrStIPSR ;\
|
||
movl rHpT1 = KiPcr+PcHighFpOwner ;\
|
||
;; ;\
|
||
;\
|
||
ld8 rHPFS = [loc2] ;\
|
||
ld8 rHpT4 = [rHpT1], PcCurrentThread-PcHighFpOwner ;\
|
||
extr.u loc2 = rHRSC, RSC_MBZ1, RSC_LOADRS_LEN ;\
|
||
;; ;\
|
||
;\
|
||
sub rHBSPSTORE = rBSP, loc2 ;\
|
||
dep loc3 = loc2, loc3, RSC_LOADRS, RSC_LOADRS_LEN ;\
|
||
;; ;\
|
||
;\
|
||
mov ar##.##rsc = loc3 /* RSE off */ ;\
|
||
mov brp = rHBrp ;\
|
||
mov rHRNAT = rRnat ;\
|
||
;; ;\
|
||
;\
|
||
alloc rTH1 = 0,0,0,0 ;\
|
||
;; ;\
|
||
;\
|
||
loadrs /* pull in user regs */;\
|
||
/* up to tear point */ ;\
|
||
dep rHRSC = r0, rHRSC, RSC_MBZ1, RSC_LOADRS_LEN ;\
|
||
;; ;\
|
||
;\
|
||
(pUstk) mov ar##.##bspstore = rHBSPSTORE /* restore user BSP */ ;\
|
||
ld8 rHpT3 = [rHpT1], PcKernelDebugActive-PcCurrentThread ;\
|
||
mov ar##.##pfs = rHPFS /* restore PFS */;\
|
||
;; ;\
|
||
;\
|
||
(pUstk) mov ar##.##rnat = rHRNAT /* restore user RNAT */;\
|
||
ld1 rHpT1 = [rHpT1] ;\
|
||
add rHIFS = TrStIFS, sp ;\
|
||
;; ;\
|
||
;\
|
||
ld8 rHIFS = [rHIFS] /* load IFS */;\
|
||
cmp##.##ne pt0, pt1 = rHpT4, rHpT3 ;\
|
||
dep rHpT4 = 0, rHIPSR, PSR_MFH, 1 ;\
|
||
;; ;\
|
||
;\
|
||
mov ar.rsc = rHRSC /* restore user RSC */;\
|
||
(pKstk) cmp##.##ne##.##unc pKDbg, pt2 = rHpT1, r0 /* hardware debug? */ ;\
|
||
(pUstk) dep rHpT4 = 1, rHpT4, PSR_DFH, 1 ;\
|
||
;; ;\
|
||
;\
|
||
(pt0) mov rHIPSR = rHpT4 ;\
|
||
add rHpT4 = TrApUNAT, sp /* -> previous UNAT */;\
|
||
add rHpT1 = TrStIIPA, sp ;\
|
||
;; ;\
|
||
;\
|
||
ld8 rHUNAT = [rHpT4],TrPreds-TrApUNAT ;\
|
||
ld8 rHIIPA = [rHpT1], TrStIIP-TrStIIPA ;\
|
||
(pKDbg) dep rHIPSR = 1, rHIPSR, PSR_DB, 1 ;\
|
||
;; ;\
|
||
;\
|
||
ld8 rHOldPreds = [rHpT4], TrIntSp-TrPreds ;\
|
||
ld8 rHIIP = [rHpT1], TrStIFS-TrStIIP /* load IIP */;\
|
||
(pt2) dep rHIPSR = 0, rHIPSR, PSR_DB, 1 ;\
|
||
;; ;\
|
||
;\
|
||
ld8##.##fill sp = [rHpT4], TrStIFS-TrIntSp ;\
|
||
rsm 1 << PSR_IC /* reset ic bit */;\
|
||
;; ;\
|
||
;\
|
||
srlz##.##d /* must serialize */;\
|
||
;\
|
||
/* */;\
|
||
/* Restore status registers */;\
|
||
/* */;\
|
||
;\
|
||
mov cr##.##ipsr = rHIPSR /* restore previous IPSR */;\
|
||
mov cr##.##iipa = rHIIPA /* restore previous IIPA */;\
|
||
;\
|
||
mov cr##.##ifs = rHIFS /* restore previous IFS */;\
|
||
mov cr##.##iip = rHIIP /* restore previous IIP */;\
|
||
mov pr = rHOldPreds, -1 /* restore preds */;\
|
||
;; ;\
|
||
;\
|
||
/* */;\
|
||
/* Resume at point of interruption (rfi must be at end of instruction group)*/;\
|
||
/* */;\
|
||
mov ar##.##unat = rHUNAT /* restore UNAT */;\
|
||
mov h17 = r0 /* clear TB loop count */;\
|
||
rfi ;\
|
||
;;
|
||
|
||
|
||
//
|
||
// Interruption Vector Table. First level interruption vectors.
|
||
// This section must be 32K aligned. The special section ".drectve"
|
||
// is used to pass the align command to the linker.
|
||
//
|
||
.section .drectve, "MI", "progbits"
|
||
string "-section:.ivt,,align=0x8000"
|
||
|
||
.section .ivt = "ax", "progbits"
|
||
KiIvtBase:: // symbol for start of IVT
|
||
|
||
//++
|
||
//
|
||
// KiVhptTransVector
|
||
//
|
||
// Cause: The hardware VHPT walker encountered a TLB miss while attempting to
|
||
// reference the virtuall addressed VHPT linear table.
|
||
//
|
||
// Parameters: cr.iip - address of bundle for which the hardware VHPT walker was
|
||
// trying to resolve the TLB miss
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of the fault
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that caused
|
||
// a VHPT translation fault
|
||
//
|
||
// cr.ifa - original faulting address
|
||
//
|
||
// cr.isr - original faulting status information
|
||
//
|
||
// Handle: Extracts the PDE index from cr.iha (PTE address in VHPT) and
|
||
// generates a PDE address by adding to VHPT_DIRBASE. When accesses
|
||
// a page directory entry (PDE), there might be a TLB miss on the
|
||
// page directory table and returns a NaT on ld8.s. If so, branches
|
||
// to KiPageDirectoryTableFault. If the page-not-present bit of the
|
||
// PDE is not set, branches to KiPageNotPresentFault. Otherwise,
|
||
// inserts the PDE entry into the data TC (translation cache).
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x0000, KiVhptTransVector, cr.ifa)
|
||
|
||
#if 1
|
||
rva = h24
|
||
riha = h25
|
||
rpr = h26
|
||
rPte = h27
|
||
rPte2 = h28
|
||
rps = h29
|
||
risr = h30
|
||
riha2 = h31
|
||
rCache = h28
|
||
|
||
mov rva = cr.ifa // M0
|
||
mov riha = cr.iha // M0
|
||
mov rpr = pr // I
|
||
|
||
mov risr = cr.isr // M0
|
||
;;
|
||
|
||
|
||
#ifndef NO_IHA_CHECK
|
||
thash riha2 = rva // M0, for extra IHA checking
|
||
#endif
|
||
ld8.s rPte = [riha] // M
|
||
tbit.z pt3, pt4 = risr, ISR_X // I
|
||
|
||
;;
|
||
tnat.nz pt0 = rPte // I
|
||
tbit.z pt1 = rPte, PTE_VALID // I
|
||
|
||
(pt0) br.cond.spnt KiPageTableFault // B
|
||
(pt1) br.cond.spnt KiPteNotPresentFault // B
|
||
extr.u rCache = rPte, 2, 3 // I
|
||
;;
|
||
|
||
cmp.eq pt5 = 1, rCache // A
|
||
(pt5) br.cond.spnt KiPageTableFault // B
|
||
;;
|
||
|
||
.pred.rel "mutex",pt3,pt4
|
||
(pt4) itc.i rPte // M
|
||
;;
|
||
(pt3) itc.d rPte // M
|
||
;;
|
||
|
||
#if !defined(NT_UP)
|
||
|
||
ld8.s rPte2 = [riha] // M
|
||
mov rps = PAGE_SHIFT << PS_SHIFT // I
|
||
cmp.ne pt0 = zero, zero // I
|
||
;;
|
||
|
||
cmp.ne.or pt0 = rPte2, rPte // M
|
||
#ifndef NO_IHA_CHECK
|
||
cmp.ne.or pt0 = riha, riha2 // M, check if IHA is correct
|
||
#endif
|
||
tnat.nz.or pt0 = rPte2 // I
|
||
|
||
;;
|
||
(pt0) ptc.l rva, rps // M
|
||
#else
|
||
#ifndef NO_IHA_CHECK
|
||
cmp.ne pt0 = riha, riha2 // M, check if IHA is correct
|
||
mov rps = PAGE_SHIFT << PS_SHIFT // I
|
||
;;
|
||
(pt0) ptc.l rva, rps // M
|
||
#endif
|
||
#endif
|
||
mov pr = rpr, -1 // I
|
||
rfi;; // B
|
||
|
||
#else
|
||
rva = h24
|
||
riha = h25
|
||
rpr = h26
|
||
rpPde = h27
|
||
rPde = h28
|
||
rPde2 = h29
|
||
rps = h30
|
||
|
||
mov riha = cr.iha // M
|
||
mov rva = cr.ifa // M
|
||
mov rpr = pr // I
|
||
;;
|
||
|
||
thash rpPde = riha // M
|
||
;;
|
||
|
||
ld8.s rPde = [rpPde] // M, load PDE
|
||
;;
|
||
|
||
tnat.nz pt0, p0 = rPde // I
|
||
tbit.z pt1, p0 = rPde, PTE_VALID // I, if non-present page fault
|
||
|
||
(pt0) br.cond.spnt KiPageDirectoryFault // B
|
||
(pt1) br.cond.spnt KiPdeNotPresentFault // B
|
||
|
||
mov cr.ifa = riha // M
|
||
;;
|
||
itc.d rPde // M
|
||
;;
|
||
|
||
#if !defined(NT_UP)
|
||
ld8.s rPde2 = [rpPde] // M
|
||
mov rps = PAGE_SHIFT << PS_SHIFT // I
|
||
cmp.ne pt0 = zero, zero // I
|
||
;;
|
||
|
||
cmp.ne.or pt0 = rPde2, rPde // M, if PTEs are different
|
||
tnat.nz.or pt0 = rPde2 // I
|
||
|
||
;;
|
||
(pt0) ptc.l riha, rps // M, purge it
|
||
#endif
|
||
mov pr = rpr, -1 // I
|
||
rfi // B
|
||
;;
|
||
#endif
|
||
|
||
VECTOR_EXIT(KiVhptTransVector)
|
||
|
||
|
||
//++
|
||
//
|
||
// KiInstTlbVector
|
||
//
|
||
// Cause: The VHPT walker aborted the search for the instruction translation.
|
||
//
|
||
// Parameters: cr.iip - address of bundle for which the hardware VHPT walker was
|
||
// trying to resolve the TLB miss
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of the fault
|
||
//
|
||
// cr.iha - PTE address in the VHPT which the VHPT walker was attempting to
|
||
// reference
|
||
//
|
||
// cr.iitr - default translation inforamtion for the address that caused
|
||
// a instruction TLB miss
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: As the VHPT has aborted the search or the implemenation does not
|
||
// support the h/w page table walk, the handler needs to emulates the
|
||
// function. Since the offending PTE address is already available
|
||
// with cr.iha, the handler can access the PTE without performing THASH.
|
||
// Accessing a PTE with ld8.s may return a NaT. If so, it branches to
|
||
// KiPageTableFault. If the page-not-present bit of the PTE is not set,
|
||
// it branches to KiPageFault.
|
||
//
|
||
// Comments: Merced never casues this fault since it never abort the search on the
|
||
// VHPT.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x0400, KiInstTlbVector, cr.iipa)
|
||
|
||
rva = h24
|
||
riha = h25
|
||
rpr = h26
|
||
rPte = h27
|
||
rPte2 = h28
|
||
rps = h29
|
||
rCache = h28
|
||
|
||
KiInstTlbVector0:
|
||
mov riha = cr.iha // M
|
||
mov rva = cr.ifa // M
|
||
mov rpr = pr // I
|
||
;;
|
||
|
||
ld8.s rPte = [riha] // M
|
||
;;
|
||
|
||
tnat.nz pt0, p0 = rPte // I
|
||
tbit.z pt1, p0 = rPte, PTE_VALID // I
|
||
|
||
(pt0) br.cond.spnt KiPageTableFault // B
|
||
(pt1) br.cond.spnt KiPteNotPresentFault // B
|
||
|
||
extr.u rCache = rPte, 2, 3 // I
|
||
;;
|
||
|
||
cmp.eq pt3 = 1, rCache // A
|
||
(pt3) br.cond.spnt Ki4KInstTlbFault // B
|
||
|
||
itc.i rPte // M
|
||
;;
|
||
|
||
#if !defined(NT_UP)
|
||
|
||
ld8.s rPte2 = [riha] // M
|
||
mov rps = PAGE_SHIFT << PS_SHIFT // I
|
||
cmp.ne pt0 = zero, zero // I
|
||
;;
|
||
|
||
cmp.ne.or pt0 = rPte2, rPte // M
|
||
tnat.nz.or pt0 = rPte2 // I
|
||
|
||
;;
|
||
(pt0) ptc.l rva, rps // M
|
||
#endif
|
||
mov pr = rpr, -1 // I
|
||
rfi;; // B
|
||
|
||
VECTOR_EXIT(KiInstTlbVector)
|
||
|
||
|
||
//++
|
||
//
|
||
// KiDataTlbVector
|
||
//
|
||
// Cause: The VHPT walker aborted the search for the data translation.
|
||
//
|
||
// Parameters: cr.iip - address of bundle for which the hardware VHPT walker was
|
||
// trying to resolve the TLB miss
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of the fault
|
||
//
|
||
// cr.iha - PTE address in the VHPT which the VHPT walker was attempting to
|
||
// reference
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that caused
|
||
// a data TLB miss
|
||
//
|
||
// cr.ifa - address that caused a data TLB miss
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: As the VHPT has aborted the search or the implemenation does not
|
||
// support the h/w page table walk, the handler needs to emulates the
|
||
// function. Since the offending PTE address is already available
|
||
// with cr.iha, the handler can access the PTE without performing THASH.
|
||
// Accessing a PTE with ld8.s may return a NaT. If so, it branches to
|
||
// KiPageTableFault. If the page-not-present bit of the PTE is not set,
|
||
// it branches to KiPageFault.
|
||
//
|
||
// Comments: Merced never casues instruction TLB faults since the VHPT search always
|
||
// sucesses.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x0800, KiDataTlbVector, cr.ifa)
|
||
|
||
rva = h24
|
||
riha = h25
|
||
rpr = h26
|
||
rPte = h27
|
||
rPte2 = h28
|
||
rps = h29
|
||
rCache = h28
|
||
|
||
KiDataTlbVector0:
|
||
mov riha = cr.iha // M
|
||
mov rva = cr.ifa // M
|
||
mov rpr = pr // I
|
||
;;
|
||
|
||
ld8.s rPte = [riha] // M
|
||
;;
|
||
|
||
extr.u rCache = rPte, 2, 3 // I
|
||
;;
|
||
|
||
cmp.eq pt3 = 1, rCache // A
|
||
(pt3) br.cond.spnt Ki4KDataTlbFault // B
|
||
|
||
tnat.nz pt0, p0 = rPte // I
|
||
tbit.z pt1, p0 = rPte, PTE_VALID // I
|
||
|
||
(pt0) br.cond.spnt KiPageTableFault // B
|
||
(pt1) br.cond.spnt KiPteNotPresentFault // B
|
||
|
||
itc.d rPte // M
|
||
;;
|
||
|
||
#if !defined(NT_UP)
|
||
ld8.s rPte2 = [riha] // M
|
||
mov rps = PAGE_SHIFT << PS_SHIFT // I
|
||
cmp.ne pt0 = zero, zero // I
|
||
;;
|
||
|
||
cmp.ne.or pt0 = rPte2, rPte // M
|
||
tnat.nz.or pt0 = rPte2 // I
|
||
;;
|
||
|
||
(pt0) ptc.l rva, rps // M
|
||
#endif
|
||
mov pr = rpr, -1 // I
|
||
rfi;; // B
|
||
|
||
VECTOR_EXIT(KiDataTlbVector)
|
||
|
||
|
||
//++
|
||
//
|
||
// KiAltTlbVector
|
||
//
|
||
// Cause: There was a TLB miss for instruction execution and the VHPT
|
||
// walker was not enabled for the referenced region.
|
||
//
|
||
// Parameters: cr.iip - address of bundle that caused a TLB miss
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of the fault
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that caused
|
||
// the fault.
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: Currently, NT does not have any use of this vector.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x0c00, KiAltInstTlbVector, cr.iipa)
|
||
|
||
rva = h24
|
||
riha = h25
|
||
|
||
mov rva = cr.ifa
|
||
;;
|
||
thash riha = rva
|
||
;;
|
||
mov cr.iha = riha
|
||
;;
|
||
srlz.d
|
||
br.sptk KiInstTlbVector0
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiMemoryFault)
|
||
|
||
VECTOR_EXIT(KiAltInstTlbVector)
|
||
|
||
|
||
|
||
//++
|
||
//
|
||
// KiAltDataTlbVector
|
||
//
|
||
// Cause: There was a data TLB miss and the VHPT walker was not enabled for
|
||
// the referenced region.
|
||
//
|
||
// Parameters: cr.iip - address of bundle that caused a TLB miss
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of the fault
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that caused
|
||
// the fault.
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: Currently, NT does not have any use of this vector.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x1000, KiAltDataTlbVector, cr.ifa)
|
||
|
||
rva = h24
|
||
riha = h25
|
||
rpr = h26
|
||
rPte = h27
|
||
rKseglimit = h28
|
||
rIPSR = h30
|
||
rISR = h29
|
||
rVrn = h31
|
||
|
||
#if NO_VHPT_WALKER
|
||
|
||
rRR = h30
|
||
|
||
mov rva = cr.ifa // M
|
||
mov rpr = pr // I
|
||
;;
|
||
|
||
mov rRR = rr[rva]
|
||
movl rKseglimit = KSEG3_LIMIT
|
||
;;
|
||
|
||
thash riha = rva
|
||
tbit.z pt4 = rRR, 0
|
||
|
||
mov rIPSR = cr.ipsr
|
||
shr.u rVrn = rva, VRN_SHIFT // I, get VPN
|
||
(pt4) br.cond.spnt AltFault
|
||
;;
|
||
|
||
mov cr.iha = riha
|
||
;;
|
||
srlz.d
|
||
mov pr = rpr, -1
|
||
br.sptk KiDataTlbVector0
|
||
;;
|
||
|
||
AltFault:
|
||
|
||
#else
|
||
|
||
mov rva = cr.ifa // M
|
||
movl rKseglimit = KSEG3_LIMIT
|
||
;;
|
||
|
||
|
||
mov rIPSR = cr.ipsr
|
||
mov rpr = pr // I
|
||
shr.u rVrn = rva, VRN_SHIFT // I, get VPN
|
||
;;
|
||
|
||
#endif
|
||
extr.u rIPSR = rIPSR, PSR_CPL, PSR_CPL_LEN
|
||
;;
|
||
|
||
|
||
cmp.ne pt1 = PL_KERNEL, rIPSR
|
||
cmp.ne pt2 = KSEG3_VRN, rVrn // M/I
|
||
cmp.eq pt4 = KSEG4_VRN, rVrn
|
||
|
||
(pt1) br.cond.spnt KiCallMemoryFault // if it was User
|
||
(pt4) br.cond.spnt KiKseg4Fault
|
||
(pt2) br.cond.spnt NoKsegFault // B
|
||
|
||
cmp.leu pt0 = rKseglimit, rva
|
||
(pt0) br.cond.spnt NoKsegFault
|
||
|
||
mov rISR = cr.isr // M
|
||
movl rPte = VALID_KERNEL_PTE // L
|
||
|
||
mov rIPSR = cr.ipsr // M
|
||
shr.u rva = rva, PAGE_SHIFT // I
|
||
;;
|
||
tbit.z pt2, pt3 = rISR, ISR_SP // I
|
||
dep.z rva = rva, PAGE_SHIFT, 32 // I
|
||
;;
|
||
or rPte = rPte, rva // I
|
||
dep rIPSR = 1, rIPSR, PSR_ED, 1 // I
|
||
;;
|
||
|
||
(pt2) itc.d rPte // M
|
||
;;
|
||
(pt3) mov cr.ipsr = rIPSR // M
|
||
;;
|
||
|
||
mov pr = rpr, -1 // I
|
||
rfi // B
|
||
;;
|
||
|
||
NoKsegFault:
|
||
|
||
rPdeUtbase = h27
|
||
rva0 = h29
|
||
rPpe = h30
|
||
oldgp = h31
|
||
|
||
shr.u rva0 = rva, PAGE_SHIFT
|
||
movl rPdeUtbase = KiPcr+PcPdeUtbase
|
||
mov oldgp = gp
|
||
movl gp = _gp
|
||
;;
|
||
|
||
ld8 rPdeUtbase = [rPdeUtbase]
|
||
add rPpe = @gprel(MiDefaultPpe), gp
|
||
dep.z rva0 = rva0, PAGE_SHIFT, VRN_SHIFT-PAGE_SHIFT
|
||
;;
|
||
|
||
ld8 rPpe = [rPpe]
|
||
cmp.ne pt3, p0 = rva0, rPdeUtbase
|
||
mov gp = oldgp
|
||
(pt3) br.cond.spnt KiPageFault
|
||
;;
|
||
|
||
itc.d rPpe
|
||
;;
|
||
mov pr = rpr, -1
|
||
rfi;;
|
||
|
||
VECTOR_EXIT(KiAltDataTlbVector)
|
||
|
||
|
||
|
||
//++
|
||
//
|
||
// KiNestedTlbVector
|
||
//
|
||
// Cause: Instruction/Data TLB miss handler encountered a TLB miss while
|
||
// attempting to reference the PTE in the virtuall addressed
|
||
// VHPT linear table.
|
||
//
|
||
// Parameters: cr.iip - address of bundle for which the hardware VHPT walker was
|
||
// trying to resolve the TLB miss
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of VHPT translation fault
|
||
//
|
||
// cr.iha - address in VHPT which the VHPT walker was attempting to
|
||
// reference
|
||
//
|
||
// cr.idtr - default translation inforamtion for the virtual address
|
||
// contained in cr.iha
|
||
//
|
||
// cr.ifa - original faulting address
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// h16(riha) - PTE address in the VHPT which caused the Nested miss
|
||
//
|
||
// Handle: Currently, there is no use for Nested TLB vector. This should be
|
||
// a bug fault. Call KiPanicHandler.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x1400, KiNestedTlbVector, cr.ifa)
|
||
|
||
ALLOCATE_TRAP_FRAME
|
||
br.sptk KiPanicHandler
|
||
|
||
VECTOR_EXIT(KiNestedTlbVector)
|
||
|
||
//++
|
||
//
|
||
// KiInstKeyMissVector
|
||
//
|
||
// Cause: There was a instruction key miss in the translation. Since the
|
||
// architecture allows an implementation to choose a unified TC
|
||
// structure, the hyper space translation brought by the data
|
||
// access-bit may cause a instruction key miss fault. Only erroneous
|
||
// user code tries to execute the NT page table and hyper space.
|
||
//
|
||
// Parameters: cr.iip - address of bundle which caused a instruction key miss fault
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of the data key miss fault
|
||
//
|
||
// cr.idtr - default translation inforamtion of the address that caused
|
||
// the fault.
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: Save the whole register state and call MmAccessFault().
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x1800, KiInstKeyMissVector, cr.iipa)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiMemoryFault)
|
||
|
||
VECTOR_EXIT(KiInstKeyMissVector)
|
||
|
||
|
||
|
||
//++
|
||
//
|
||
// KiDataKeyMissVector
|
||
//
|
||
// Cause: The referenced translation had the different key ID from the one
|
||
// specified the key permission register. This is an indication of
|
||
// TLB miss on the NT page table and hyperspace.
|
||
//
|
||
// Parameters: cr.iip - address of bundle which caused the fault
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of the data key miss fault
|
||
//
|
||
// cr.idtr - default translation inforamtion of the address that caused
|
||
// the fault.
|
||
//
|
||
// cr.ifa - address that caused a data key miss
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: The handler needs to purge the faulting translation and install
|
||
// a new PTE by loading it from the VHPT. The key ID of the IDTR
|
||
// for the installing translation should be modified to be the same
|
||
// ID as the local region ID. This effectively creates a local
|
||
// space within the global kernel space.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x1c00, KiDataKeyMissVector, cr.ifa)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiMemoryFault)
|
||
|
||
VECTOR_EXIT(KiDataKeyMissVector)
|
||
|
||
//++
|
||
//
|
||
// KiDirtyBitVector
|
||
//
|
||
// Cause: The refereced data translation did not have the dirty-bit set and
|
||
// a write operation was made to this page.
|
||
//
|
||
// Parameters: cr.iip - address of bundle which caused a dirty bit fault
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of a data access fault
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that
|
||
// caused the fault
|
||
//
|
||
// cr.ifa - referenced data address that caused the dirty-bit fault
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: Save the whole register state and call MmAccessFault().
|
||
//
|
||
// Comments: There is always a TLB coherency problem on a multiprocessor
|
||
// system. Rather than implementing an atomic operation of setting
|
||
// dirty-bit within this handler, the handler instead calls the high
|
||
// level C routine, MmAccessFault(), to perform locking the page table
|
||
// and setting the dirty-bit of the PTE.
|
||
//
|
||
// It is too much effort to implement the atomic operation of setting
|
||
// the dirty-bit using cmpxchg; a potential nested TLB miss on load/store
|
||
// and restoring ar.ccv complicate the design of the handler.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x2000, KiDirtyBitVector, cr.ifa)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiMemoryFault)
|
||
|
||
VECTOR_EXIT(KiDirtyBitVector)
|
||
|
||
//++
|
||
//
|
||
// KiInstAccessBitVector
|
||
//
|
||
// Cause: There is a access-bit fault on the instruction translation. This only
|
||
// happens if the erroneous user mistakenly accesses the NT page table and
|
||
// hyper space.
|
||
//
|
||
// Parameters: cr.iip - address of bundle which caused a instruction access bit fault
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of a data access fault
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that
|
||
// caused the fault
|
||
//
|
||
// cr.ifa - referenced data address that caused the data access-bit fault
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: Save the whole register state and call MmAccessFault().
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x2400, KiInstAccessBitVector, cr.iipa)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiMemoryFault)
|
||
|
||
VECTOR_EXIT(KiInstAccessBitVector)
|
||
|
||
//++
|
||
//
|
||
// KiDataBitAccessVector
|
||
//
|
||
// Cause: The reference-bit in the the referenced translation was zero,
|
||
// indicating there was a TLB miss on the NT page table or hyperspace.
|
||
//
|
||
// Parameters: cr.iip - address of bundle which caused a data access bit fault
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of a data access fault
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that
|
||
// caused the fault
|
||
//
|
||
// cr.ifa - referenced data address that caused the data access-bit fault
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: The reference-bit is used to fault on PTEs for the NT page table and
|
||
// hyperspace. On a data access-bit fault, the handler needs to change the
|
||
// the default key ID of the IDTR to be the local key ID. This effectively
|
||
// creates the local space within the global kernel space.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x2800, KiDataAccessBitVector, cr.ifa)
|
||
|
||
rva = h24
|
||
rpr = h26
|
||
rIPSR = h27
|
||
rISR = h31
|
||
|
||
//
|
||
// check to see if non-present fault occurred on a speculative load.
|
||
// if so, set IPSR.ed bit. This forces to generate a NaT on ld.s after
|
||
// rfi
|
||
//
|
||
|
||
mov rpr = pr
|
||
mov rISR = cr.isr // M
|
||
mov rIPSR = cr.ipsr // M
|
||
;;
|
||
|
||
tbit.z pt0, p0 = rISR, ISR_SP // I
|
||
dep rIPSR = 1, rIPSR, PSR_ED, 1 // I
|
||
|
||
(pt0) br.cond.spnt KiCallMemoryFault // B
|
||
;;
|
||
|
||
mov cr.ipsr = rIPSR // M
|
||
;;
|
||
mov pr = rpr, -1 // I
|
||
rfi // B
|
||
;;
|
||
|
||
VECTOR_EXIT(KiDataBitAccessVector)
|
||
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiBreakVector
|
||
//
|
||
// Description:
|
||
//
|
||
// Interruption vector for break instruction.
|
||
//
|
||
// On entry:
|
||
//
|
||
// IIM contains break immediate value:
|
||
// -- BREAK_SYSCALL -> standard system call
|
||
// interrupts disabled
|
||
// r16-r31 switched to kernel bank
|
||
// r16-r31 all available since no TLB faults at this point
|
||
//
|
||
// Return value:
|
||
//
|
||
// if system call, sys call return value in v0.
|
||
//
|
||
// Process:
|
||
//--------------------------------------------------------------------
|
||
|
||
VECTOR_ENTRY(0x2C00, KiBreakVector, cr.iim)
|
||
|
||
mov rHIIM = cr.iim // get break value
|
||
movl rTH1 = KiPcr+PcSavedIIM
|
||
;;
|
||
st8 [rTH1] = rHIIM
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiOtherBreakException)
|
||
|
||
//
|
||
// Do not return from handler
|
||
//
|
||
|
||
VECTOR_EXIT(KiBreakVector)
|
||
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiExternalInterruptVector
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Interruption vector for External Interrrupt
|
||
//
|
||
// On entry:
|
||
//
|
||
// interrupts disabled
|
||
// r16-r31 switched to kernel bank
|
||
//
|
||
// Return value:
|
||
//
|
||
// none
|
||
//
|
||
// Process:
|
||
//--------------------------------------------------------------------
|
||
|
||
VECTOR_ENTRY(0x3000, KiExternalInterruptVector, r0)
|
||
|
||
mov h24 = cr.iip
|
||
movl h25 = MM_EPC_VA+0x20
|
||
;;
|
||
mov h26 = pr
|
||
cmp.ne pt0 = h25, h24
|
||
add h25 = 0x10, h25
|
||
;;
|
||
mov h27 = cr.ipsr
|
||
(pt0) cmp.ne pt0 = h25, h24
|
||
;;
|
||
|
||
dep h27 = 0, h27, PSR_I, 1
|
||
(pt0) br.cond.sptk kei_taken
|
||
;;
|
||
mov cr.ipsr = h27
|
||
;;
|
||
mov pr = h26, -1
|
||
rfi
|
||
;;
|
||
|
||
kei_taken:
|
||
mov pr = h26, -1
|
||
;;
|
||
ALLOCATE_TRAP_FRAME
|
||
;;
|
||
SAVE_INTERRUPTION_STATE(Keih_SaveTrapFrame)
|
||
br.many KiExternalInterruptHandler
|
||
;;
|
||
|
||
//
|
||
// Do not return (rfi from handler)
|
||
//
|
||
|
||
VECTOR_EXIT(KiExternalInterruptVector)
|
||
|
||
//++
|
||
//
|
||
// KiPageNotPresentVector
|
||
//
|
||
// Cause: The translation for the referenced page did not have a present-bit
|
||
// set.
|
||
//
|
||
// Parameters: cr.iip - address of bundle which caused a page not present fault
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of a page not present ault
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that
|
||
// caused the fault
|
||
//
|
||
// cr.ifa - referenced data address if the fault occurred on the data
|
||
// reference
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: This is the page fault. The handler saves the register context and
|
||
// calls MmAccessFault().
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5000, KiPageNotPresentVector, cr.ifa)
|
||
|
||
rva = h24
|
||
riha = h25
|
||
rpr = h26
|
||
rPte = h27
|
||
rps = h29
|
||
|
||
mov rva = cr.ifa // M
|
||
mov rpr = pr // I
|
||
;;
|
||
|
||
thash riha = rva // M
|
||
cmp.ne pt1 = r0, r0
|
||
mov rps = PAGE_SHIFT << PS_SHIFT // I
|
||
;;
|
||
|
||
ld8.s rPte = [riha] // M
|
||
;;
|
||
|
||
tnat.nz pt0, p0 = rPte // I
|
||
tbit.z.or pt1, p0 = rPte, PTE_ACCESS
|
||
tbit.z.or pt1, p0 = rPte, PTE_VALID // I, if non-present page fault
|
||
|
||
(pt0) br.cond.spnt KiPageTableFault // B
|
||
(pt1) br.cond.spnt KiPteNotPresentFault // B
|
||
|
||
//
|
||
// if we find a valid PTE that is speculatively fetched into the TLB
|
||
// then, purge it and return.
|
||
//
|
||
|
||
ptc.l rva, rps // M
|
||
;;
|
||
|
||
mov pr = rpr, -1 // I
|
||
rfi;; // B
|
||
|
||
VECTOR_EXIT(KiPageNotPresentVector)
|
||
|
||
|
||
|
||
//++
|
||
//
|
||
// KiKeyPermVector
|
||
//
|
||
// Cause: Read, write or execution key permissions were violated.
|
||
//
|
||
// Parameters: cr.iip - address of bundle which caused a key permission fault
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of a key permission fault
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that
|
||
// caused the fault
|
||
//
|
||
// cr.ifa - referenced data address if the key permission occurred on
|
||
// the data reference
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: This should not happen. The EM/NT does not utilize the key permissions.
|
||
// The handler saves the register state and calls the bug check.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5100, KiKeyPermVector, cr.ifa)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiMemoryFault)
|
||
|
||
VECTOR_EXIT(KiKeyPermVector)
|
||
|
||
|
||
|
||
//++
|
||
//
|
||
// KiInstAccessRightsVector
|
||
//
|
||
// Cause: The referenced page had a access rights violation.
|
||
//
|
||
// Parameters: cr.iip - address of bundle which caused a data access bit fault
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of a data access fault
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that
|
||
// caused the fault
|
||
//
|
||
// cr.ifa - referenced data address that caused the data ccess-bit fault
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: The handler saves the register context and calls MmAccessFault().
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5200, KiInstAccessRightsVector, cr.iipa)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiMemoryFault)
|
||
|
||
VECTOR_EXIT(KiInstAccessRightsVector)
|
||
|
||
|
||
|
||
//++
|
||
//
|
||
// KiDataAccessRightsVector
|
||
//
|
||
// Cause: The referenced page had a data access rights violation.
|
||
//
|
||
// Parameters: cr.iip - address of bundle which caused a data access rights fault
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of a data access rights fault
|
||
//
|
||
// cr.idtr - default translation inforamtion for the address that
|
||
// caused the fault
|
||
//
|
||
// cr.ifa - referenced data address that caused the data access rights
|
||
// fault
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: The handler saves the register context and calls MmAccessFault().
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5300, KiDataAccessRightsVector, cr.ifa)
|
||
|
||
rva = h24
|
||
rpr = h26
|
||
rIPSR = h27
|
||
rISR = h31
|
||
|
||
//
|
||
// check to see if non-present fault occurred on a speculative load.
|
||
// if so, set IPSR.ed bit. This forces to generate a NaT on ld.s after
|
||
// rfi
|
||
//
|
||
|
||
mov rpr = pr
|
||
mov rISR = cr.isr // M
|
||
mov rIPSR = cr.ipsr // M
|
||
;;
|
||
|
||
tbit.z pt0, p0 = rISR, ISR_SP // I
|
||
dep rIPSR = 1, rIPSR, PSR_ED, 1 // I
|
||
|
||
(pt0) br.cond.spnt KiCallMemoryFault // B
|
||
;;
|
||
|
||
mov cr.ipsr = rIPSR // M
|
||
;;
|
||
mov pr = rpr, -1 // I
|
||
rfi // B
|
||
;;
|
||
|
||
VECTOR_EXIT(KiDataAccessRightsVector)
|
||
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiGeneralExceptionsVector
|
||
//
|
||
// Description:
|
||
//
|
||
// Interruption vector for General Exceptions
|
||
//
|
||
// On entry:
|
||
// interrupts disabled
|
||
// r16-r31 switched to kernel bank
|
||
//
|
||
// Return value:
|
||
//
|
||
// none
|
||
//
|
||
// Process:
|
||
//--------------------------------------------------------------------
|
||
|
||
VECTOR_ENTRY(0x5400, KiGeneralExceptionsVector, cr.isr)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiGeneralExceptions)
|
||
|
||
//
|
||
// Do not return (rfi from handler)
|
||
//
|
||
|
||
VECTOR_EXIT(KiGeneralExceptionsVector)
|
||
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiDisabledFpRegisterVector
|
||
//
|
||
// Description:
|
||
//
|
||
// Interruption vector for Disabled FP-register vector
|
||
//
|
||
// On entry:
|
||
// interrupts disabled
|
||
// r16-r31 switched to kernel bank
|
||
//
|
||
// Return value:
|
||
//
|
||
// none
|
||
//
|
||
// Process:
|
||
//--------------------------------------------------------------------
|
||
|
||
VECTOR_ENTRY(0x5500, KiDisabledFpRegisterVector, cr.isr)
|
||
|
||
mov rHIPSR = cr.ipsr
|
||
mov rHIIP = cr.iip
|
||
cover
|
||
;;
|
||
|
||
mov rHIFS = cr.ifs
|
||
extr.u rTH1 = rHIPSR, PSR_CPL, PSR_CPL_LEN
|
||
mov rHOldPreds = pr
|
||
;;
|
||
|
||
cmp4.eq pKrnl, pUser = PL_KERNEL, rTH1
|
||
;;
|
||
(pUser) tbit.z.unc pt0, pt1 = rHIPSR, PSR_DFH // if dfh not set,
|
||
// dfl must be set
|
||
(pKrnl) br.spnt.few Kdfrv10 // Kernel mode should never get here.
|
||
;;
|
||
|
||
(pt1) ssm 1 << PSR_IC // set ic bit
|
||
(pt1) mov rHDfhPFS = ar.pfs
|
||
(pt1) mov rHDfhBrp = brp
|
||
;;
|
||
|
||
(pt1) srlz.d
|
||
(pt1) br.call.sptk.many brp = KiRestoreHigherFPVolatile
|
||
(pt0) br.spnt.few Kdfrv10
|
||
;;
|
||
|
||
rsm 1 << PSR_IC // reset ic bit
|
||
dep rHIPSR = 0, rHIPSR, PSR_DFH, 1 // reset dfh bit
|
||
mov brp = rHDfhBrp
|
||
;;
|
||
|
||
srlz.d
|
||
mov cr.ifs = rHIFS
|
||
mov ar.pfs = rHDfhPFS
|
||
|
||
mov cr.ipsr = rHIPSR
|
||
mov cr.iip = rHIIP
|
||
mov pr = rHOldPreds, -1
|
||
;;
|
||
|
||
rfi
|
||
;;
|
||
|
||
Kdfrv10:
|
||
mov pr = rHOldPreds, -1
|
||
movl rHHandler = KiGeneralExceptions
|
||
|
||
br.sptk KiGenericExceptionHandler
|
||
;;
|
||
|
||
VECTOR_EXIT(KiDisabledFpRegisterVector)
|
||
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiNatConsumptionVector
|
||
//
|
||
// Description:
|
||
//
|
||
// Interruption vector for Nat Consumption Vector
|
||
//
|
||
// On entry:
|
||
// interrupts disabled
|
||
// r16-r31 switched to kernel bank
|
||
//
|
||
// Return value:
|
||
//
|
||
// none
|
||
//
|
||
// Process:
|
||
//--------------------------------------------------------------------
|
||
|
||
VECTOR_ENTRY(0x5600, KiNatConsumptionVector, cr.isr)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiNatExceptions)
|
||
|
||
//
|
||
// Do not return (rfi from handler)
|
||
//
|
||
|
||
VECTOR_EXIT(KiNatConsumptionVector)
|
||
|
||
//++
|
||
//
|
||
// KiSpeculationVector
|
||
//
|
||
// Cause: CHK.S, CHK.A, FCHK detected an exception condition.
|
||
//
|
||
// Parameters: cr.iip - address of bundle which caused a speculation fault
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of a speculation fault
|
||
//
|
||
// cr.iipa - address of bundle containing the last
|
||
// successfully executed instruction
|
||
//
|
||
// cr.iim - contains the immediate value in either
|
||
// CHK.S, CHK.A, or FCHK opecode
|
||
//
|
||
// cr.isr - faulting status information
|
||
//
|
||
// Handle: The handler implements a branch operation to the
|
||
// recovery code specified by the IIM IP-offset.
|
||
//
|
||
// Note: This code will not be exercised until the compiler
|
||
// generates the speculation code.
|
||
//
|
||
// TBD: Need to check for taken branch trap.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5700, KiSpeculationVector, cr.iim)
|
||
|
||
mov h16 = cr.iim // get imm offset
|
||
mov h17 = cr.iip // get IIP
|
||
;;
|
||
extr h16 = h16, 0, 21 // get sign-extended
|
||
mov h18 = cr.ipsr
|
||
;;
|
||
shladd h16 = h16, 4, h17 // get addr for recovery handler
|
||
dep h18 = 0, h18, PSR_RI, 2 // zero target slot number
|
||
;;
|
||
mov cr.ipsr = h18
|
||
mov cr.iip = h16
|
||
;;
|
||
rfi
|
||
;;
|
||
|
||
VECTOR_EXIT(KiSpeculationVector)
|
||
|
||
//++
|
||
//
|
||
// KiDebugFaultVector
|
||
//
|
||
// Cause: A unaligned data access fault has occured
|
||
//
|
||
// Parameters: cr.iip - address of bundle causing the fault.
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of interruption.
|
||
//
|
||
// cr.iipa - address of bundle containing the last
|
||
// successfully executed instruction
|
||
//
|
||
// cr.isr - faulting status information. ISR.ei bits are
|
||
// set to indicate which instruction caused the
|
||
// exception.
|
||
// The ISR.code contains information about the
|
||
// FP exception fault. See trapc.c and the EAS
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5900, KiDebugFaultVector, cr.isr)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiDebugFault)
|
||
|
||
//
|
||
// Do not return (rfi from handler)
|
||
//
|
||
|
||
VECTOR_EXIT(KiDebugFaultVector)
|
||
|
||
//++
|
||
//
|
||
// KiUnalignedFaultVector
|
||
//
|
||
// Cause: A unaligned data access fault has occured
|
||
//
|
||
// Parameters: cr.iip - address of bundle causing the fault.
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of interruption.
|
||
//
|
||
// cr.iipa - address of bundle containing the last
|
||
// successfully executed instruction
|
||
//
|
||
// cr.isr - faulting status information. ISR.ei bits are
|
||
// set to indicate which instruction caused the
|
||
// exception.
|
||
// The ISR.code contains information about the
|
||
// FP exception fault. See trapc.c and the EAS
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5a00, KiUnalignedFaultVector, cr.ifa)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiUnalignedFault)
|
||
|
||
//
|
||
// Do not return (rfi from handler)
|
||
//
|
||
|
||
VECTOR_EXIT(KiUnalignedFaultVector)
|
||
|
||
|
||
//++
|
||
//
|
||
// KiFloatFaultVector
|
||
//
|
||
// Cause: A floating point fault has occured
|
||
//
|
||
// Parameters: cr.iip - address of bundle causing the fault.
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of interruption.
|
||
//
|
||
// cr.iipa - address of bundle containing the last
|
||
// successfully executed instruction
|
||
//
|
||
// cr.isr - faulting status information. ISR.ei bits are
|
||
// set to indicate which instruction caused the
|
||
// exception.
|
||
// The ISR.code contains information about the
|
||
// FP exception fault. See trapc.c and the EAS
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5c00, KiFloatFaultVector, cr.isr)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiFloatFault)
|
||
|
||
//
|
||
// Do not return (rfi from handler)
|
||
//
|
||
|
||
VECTOR_EXIT(KiFloatFaultVector)
|
||
|
||
//++
|
||
//
|
||
// KiFloatTrapVector
|
||
//
|
||
// Cause: A floating point trap has occured
|
||
//
|
||
// Parameters: cr.iip - address of bundle with the instruction to be
|
||
// executed next.
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of interruption.
|
||
//
|
||
// cr.iipa - address of bundle containing the last
|
||
// successfully executed instruction
|
||
//
|
||
// cr.isr - faulting status information. ISR.ei bits are
|
||
// set to indicate which instruction caused the
|
||
// exception.
|
||
// The ISR.code contains information about the
|
||
// FP trap. See trapc.c and the EAS
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5d00, KiFloatTrapVector, cr.isr)
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiFloatTrap)
|
||
|
||
//
|
||
// Do not return (rfi from handler)
|
||
//
|
||
|
||
VECTOR_EXIT(KiFloatTrapVector)
|
||
|
||
//++
|
||
//
|
||
// KiLowerPrivilegeVector
|
||
//
|
||
// Cause: A branch lowers the privilege level and PSR.lp is 1.
|
||
// Or an attempt made to execute an instruction
|
||
// in the unimplemented address space.
|
||
// This trap is higher priority than taken branch
|
||
// or single step traps.
|
||
//
|
||
// Parameters: cr.iip - address of bundle containing the instruction to
|
||
// be executed next.
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of interruption.
|
||
//
|
||
// cr.iipa - address of bundle containing the last
|
||
// successfully executed instruction
|
||
//
|
||
// cr.isr - faulting status information. The ISR.code
|
||
// contains a bit vector for all traps which
|
||
// occurred in the trapping bundle.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5e00, KiLowerPrivilegeVector, cr.iipa)
|
||
|
||
mov rHISR = cr.isr
|
||
mov rHOldPreds = pr
|
||
|
||
mov rHIIPA = cr.iipa
|
||
mov rHIPSR = cr.ipsr
|
||
;;
|
||
|
||
|
||
tbit.z pt1, pt0 = rHISR, ISR_UI_TRAP
|
||
(pt1) br.cond.spnt Klpv10
|
||
;;
|
||
|
||
mov rHIFA = cr.iip
|
||
movl rHHandler = KiUnimplementedAddressTrap
|
||
|
||
mov pr = rHOldPreds, -2 // must restore predicates
|
||
br.sptk KiGenericExceptionHandler
|
||
;;
|
||
|
||
Klpv10:
|
||
mov rPanicCode = UNEXPECTED_KERNEL_MODE_TRAP
|
||
br.sptk KiPanicHandler
|
||
|
||
VECTOR_EXIT(KiLowerPrivilegeVector)
|
||
|
||
//++
|
||
//
|
||
// KiTakenBranchVector
|
||
//
|
||
// Cause: A taken branch was successfully execcuted and the PSR.tb
|
||
// bit is 1. This trap is higher priority than single step trap.
|
||
//
|
||
// Parameters: cr.iip - address of bundle containing the instruction to
|
||
// be executed next.
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of interruption.
|
||
//
|
||
// cr.iipa - address of bundle containing the last
|
||
// successfully executed instruction
|
||
//
|
||
// cr.isr - faulting status information. The ISR.code
|
||
// contains a bit vector for all traps which
|
||
// occurred in the trapping bundle.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x5f00, KiTakenBranchVector, cr.iipa)
|
||
|
||
mov rHIPSR = cr.ipsr
|
||
movl rHEPCVa = MM_EPC_VA+0x20 // user system call entry point
|
||
|
||
mov rHIIP = cr.iip
|
||
movl rHpT1 = KiPcr+PcInitialStack
|
||
;;
|
||
|
||
ld8 rHpT1 = [rHpT1]
|
||
extr.u rTH1 = rHIPSR, PSR_CPL, PSR_CPL_LEN
|
||
mov rHOldPreds = pr
|
||
;;
|
||
|
||
cmp.eq pt0 = rHEPCVa, rHIIP
|
||
movl rHHandler = KiSingleStep
|
||
;;
|
||
(pt0) ssm 1 << PSR_IC
|
||
(pt0) movl rHpT3 = 1 << PSR_LP
|
||
;;
|
||
|
||
(pt0) or rHpT3 = rHIPSR, rHpT3
|
||
|
||
(pt0) srlz.d
|
||
add rHpT1=-ThreadStateSaveAreaLength-TrapFrameLength+TrStIPSR,rHpT1
|
||
(pt0) br.spnt.few Ktbv10
|
||
|
||
mov pr = rHOldPreds, -2
|
||
br.sptk KiGenericExceptionHandler
|
||
;;
|
||
|
||
|
||
Ktbv10:
|
||
|
||
st8 [rHpT1] = rHpT3
|
||
movl rHpT3 = 1 << PSR_SS | 1 << PSR_TB | 1 << PSR_DB
|
||
;;
|
||
|
||
rsm 1 << PSR_IC
|
||
mov pr = rHOldPreds, -2
|
||
andcm rHIPSR = rHIPSR, rHpT3 // clear ss, tb, db bits
|
||
;;
|
||
|
||
srlz.d
|
||
mov cr.ipsr = rHIPSR
|
||
;;
|
||
rfi
|
||
;;
|
||
|
||
|
||
VECTOR_EXIT(KiTakenBranchVector)
|
||
|
||
//++
|
||
//
|
||
// KiSingleStepVector
|
||
//
|
||
// Cause: An instruction was successfully execcuted and the PSR.ss
|
||
// bit is 1.
|
||
//
|
||
// Parameters: cr.iip - address of bundle containing the instruction to
|
||
// be executed next.
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of interruption.
|
||
//
|
||
// cr.iipa - address of bundle containing the last
|
||
// successfully executed instruction
|
||
//
|
||
// cr.isr - faulting status information. The ISR.code
|
||
// contains a bit vector for all traps which
|
||
// occurred in the trapping bundle.
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x6000, KiSingleStepVector, cr.iipa)
|
||
|
||
mov rHIPSR = cr.ipsr
|
||
movl rHEPCVa = MM_EPC_VA+0x20 // user system call entry point
|
||
|
||
mov rHIIP = cr.iip
|
||
movl rHpT1 = KiPcr+PcInitialStack
|
||
;;
|
||
|
||
ld8 rHpT1 = [rHpT1]
|
||
extr.u rTH1 = rHIPSR, PSR_CPL, PSR_CPL_LEN
|
||
mov rHOldPreds = pr
|
||
;;
|
||
|
||
cmp.eq pt0 = rHEPCVa, rHIIP
|
||
movl rHHandler = KiSingleStep
|
||
;;
|
||
|
||
(pt0) ssm 1 << PSR_IC
|
||
(pt0) movl rHpT3 = 1 << PSR_LP
|
||
;;
|
||
|
||
(pt0) or rHpT3 = rHIPSR, rHpT3
|
||
|
||
(pt0) srlz.d
|
||
add rHpT1=-ThreadStateSaveAreaLength-TrapFrameLength+TrStIPSR,rHpT1
|
||
(pt0) br.spnt.few Kssv10
|
||
|
||
mov pr = rHOldPreds, -2
|
||
br.sptk KiGenericExceptionHandler
|
||
;;
|
||
|
||
|
||
Kssv10:
|
||
|
||
st8 [rHpT1] = rHpT3
|
||
movl rHpT3 = 1 << PSR_SS | 1 << PSR_DB
|
||
;;
|
||
|
||
rsm 1 << PSR_IC
|
||
mov pr = rHOldPreds, -2
|
||
andcm rHIPSR = rHIPSR, rHpT3 // clear ss, db bits
|
||
;;
|
||
|
||
srlz.d
|
||
mov cr.ipsr = rHIPSR
|
||
;;
|
||
rfi
|
||
;;
|
||
|
||
VECTOR_EXIT(KiSingleStepVector)
|
||
|
||
//++
|
||
//
|
||
// KiIA32ExceptionVector
|
||
//
|
||
// Cause: A fault or trap was generated while executing from the
|
||
// iA-32 instruction set.
|
||
//
|
||
// Parameters: cr.iip - address of the iA-32 instruction causing interruption
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of the instruction
|
||
//
|
||
// cr.iipa - Address of the last successfully executed
|
||
// iA-32 or EM instruction
|
||
//
|
||
// cr.isr - The ISR.ei exception indicator is cleared.
|
||
// ISR.iA_vector contains the iA-32 interruption vector
|
||
// number. ISR.code contains the iA-32 16-bit error cod
|
||
//
|
||
// Handle: Save the whole register state and
|
||
// call KiIA32ExceptionVectorHandler()().
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x6900, KiIA32ExceptionVector, r0)
|
||
|
||
mov rHIIM = cr.iim // save info from IIM
|
||
movl rTH1 = KiPcr+PcSavedIIM
|
||
;;
|
||
st8 [rTH1] = rHIIM
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler,
|
||
KiIA32ExceptionVectorHandler)
|
||
|
||
VECTOR_EXIT(KiIA32ExceptionVector)
|
||
|
||
//++
|
||
//
|
||
// KiIA32InterceptionVector
|
||
//
|
||
// Cause: A interception fault or trap was generated while executing
|
||
// from the iA-32 instruction set.
|
||
//
|
||
// Parameters: cr.iip - address of the iA-32 instruction causing interruption
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of the instruction
|
||
//
|
||
// cr.iipa - Address of the last successfully executed
|
||
// iA-32 or EM instruction
|
||
//
|
||
// cr.isr - The ISR.ei exception indicator is cleared.
|
||
// ISR.iA_vector contains the iA-32 interruption vector
|
||
// number. ISR.code contains the iA-32specific
|
||
// interception information
|
||
//
|
||
// Handle: Save the whole register state and
|
||
// call KiIA32InterceptionVectorHandler()().
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x6a00, KiIA32InterceptionVector, r0)
|
||
|
||
|
||
mov rHIIM = cr.iim // save info from IIM
|
||
movl rTH1 = KiPcr+PcSavedIIM
|
||
;;
|
||
st8 [rTH1] = rHIIM
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler,
|
||
KiIA32InterceptionVectorHandler)
|
||
|
||
VECTOR_EXIT(KiIA32InterceptionVector)
|
||
|
||
//++
|
||
//
|
||
// KiIA32InterruptionVector
|
||
//
|
||
// Cause: An iA software interrupt was executed
|
||
//
|
||
// Parameters: cr.iip - address of the iA-32 instruction causing interruption
|
||
//
|
||
// cr.ipsr - copy of PSR at the time of the instruction
|
||
//
|
||
// cr.iipa - Address of the last successfully executed
|
||
// iA-32 or EM instruction
|
||
//
|
||
// cr.isr - ISR.iA_vector contains the iA-32 defined vector
|
||
// number. ISR.code contains 0
|
||
// ISR.ei excepting instruction indicator is cleared.
|
||
// ISR.iA_vector contains the iA-32 instruction vector.
|
||
// ISR.code contains iA-32 specific information.
|
||
//
|
||
// Handle: Save the whole register state and
|
||
// call KiIA32InterruptionVectorHandler()().
|
||
//
|
||
//--
|
||
|
||
VECTOR_ENTRY(0x6b00, KiIA32InterruptionVector, r0)
|
||
|
||
// This one doesn't need IIM, so we won't bother to save it
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler,
|
||
KiIA32InterruptionVectorHandler)
|
||
|
||
|
||
VECTOR_EXIT(KiIA32InterruptionVector)
|
||
|
||
//
|
||
// All non-VECTOR_ENTRY functions must follow KiNormalSystemCall.
|
||
//
|
||
// N.B. KiNormalSystemCall must be the first function body in the .nsc
|
||
// section.
|
||
//
|
||
|
||
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiNormalSystemCall
|
||
//
|
||
// Description:
|
||
//
|
||
// Handler for normal (not fast) system calls
|
||
//
|
||
// On entry:
|
||
//
|
||
// ic off
|
||
// interrupts disabled
|
||
// v0: contains sys call #
|
||
// cover done by call
|
||
// r32-r39: sys call arguments
|
||
// CFM: sof = # args, ins = 0, outs = # args
|
||
// clear mfh bit (high fp registers are scratch per s/w convention)
|
||
//
|
||
// Return value:
|
||
//
|
||
// v0: system call return value
|
||
//
|
||
// Process:
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
.section .drectve, "MI", "progbits"
|
||
string " -section:.nsc,,align=0x2000"
|
||
|
||
.section .nsc = "ax", "progbits"
|
||
|
||
HANDLER_ENTRY_EX(KiNormalSystemCall, KiSystemServiceHandler)
|
||
|
||
.prologue
|
||
.unwabi @nt, EXCEPTION_FRAME
|
||
|
||
rPFS = t0
|
||
rThread = t1 // current thread
|
||
rIFS = t1
|
||
rIIP = t2
|
||
rPreds = t3
|
||
rIPSR = t4
|
||
rUNAT = t5
|
||
|
||
rSp = t6
|
||
|
||
rpT1 = t7
|
||
rpT2 = t8
|
||
rpT3 = t9
|
||
rpT4 = t10
|
||
rT0 = t11
|
||
rT1 = t12
|
||
rT2 = t13
|
||
rT3 = t14
|
||
rT4 = t15
|
||
|
||
rKDbgActive = t16
|
||
rIntNats = t17
|
||
|
||
rpSd = t16 /* -> service descriptor entry */
|
||
rSdOffset = t17 /* service descriptor offset */
|
||
rArgTable = t18 /* pointer to argument table */
|
||
rArgNum = t20 /* number of arguments */
|
||
|
||
rRscD = t16
|
||
rRNAT = t17
|
||
rRscE = t18
|
||
rKBSPStore = t18
|
||
rBSPStore = t19
|
||
rRscDelta = t20
|
||
|
||
rBSP = t21
|
||
rPreviousMode = t22
|
||
|
||
pInvl = ps9 /* pInvl = not GUI service */
|
||
pVal = pt1
|
||
pGui = pt2 /* true if GUI call */
|
||
pNoGui = pt3 /* true if no GUI call */
|
||
pNatedArg = pt4 /* true if any input argument */
|
||
/* register is Nat'ed */
|
||
pNoCopy = pt5 /* no in-memory arguments to copy */
|
||
pCopy = pt6
|
||
pNatedSp = pt7
|
||
|
||
|
||
mov rUNAT = ar.unat
|
||
tnat.nz pNatedSp = sp
|
||
mov rPreviousMode = KernelMode
|
||
|
||
mov rIPSR = psr
|
||
rsm 1 << PSR_I | 1 << PSR_MFH
|
||
br.sptk Knsc_Allocate
|
||
;;
|
||
|
||
//
|
||
// N.B. KiUserSystemCall is at an offset of 0x20 from KiNormalSystemCall.
|
||
// Whenever this offset is changed, the definition of kernel system call
|
||
// stub in services.stb must be updated to reflect the new value.
|
||
//
|
||
|
||
ALTERNATE_ENTRY(KiUserSystemCall)
|
||
|
||
mov rUNAT = ar.unat
|
||
mov rPreviousMode = UserMode
|
||
epc
|
||
;;
|
||
|
||
mov rIPSR = psr
|
||
rsm (1 << PSR_I) | (1 << PSR_BE)
|
||
tnat.nz pNatedSp = sp
|
||
;; // stop bit needed to ensure interrupt is off
|
||
|
||
Knsc_Allocate::
|
||
|
||
#if defined(INTERRUPTION_LOGGING)
|
||
|
||
// For Conditional Interrupt Logging
|
||
mov rT3 = gp
|
||
movl gp = _gp
|
||
;;
|
||
add rpT1 = @gprel(KiVectorLogMask), gp
|
||
;;
|
||
ld8 rT1 = [rpT1]
|
||
mov gp = rT3
|
||
;;
|
||
tbit.z pt1 = rT1, UserSystemcallBit
|
||
(pt1) br.cond.sptk EndOfLogging1
|
||
|
||
mov rT1 = 0x80 // dummy offset for sys call
|
||
movl rpT1 = KiPcr+PcInterruptionCount
|
||
mov rT2 = b0
|
||
mov rT3 = MAX_NUMBER_OF_IHISTORY_RECORDS - 1
|
||
;;
|
||
|
||
ld4.nt1 rT4 = [rpT1] // get current count
|
||
or rT1 = rT1, rPreviousMode // kernel/user
|
||
;;
|
||
|
||
add rT0 = 1, rT4 // incr count
|
||
and rT4 = rT3, rT4 // index of current entry
|
||
add rpT2 = 0x1000-PcInterruptionCount, rpT1 // base of history
|
||
;;
|
||
|
||
st4.nta [rpT1] = rT0 // save count
|
||
shl rT4 = rT4, 5 // offset of current entry
|
||
;;
|
||
add rpT2 = rpT2, rT4 // address of current entry
|
||
;;
|
||
st8 [rpT2] = rT1, 8 // save sys call offset
|
||
;;
|
||
st8 [rpT2] = rT2, 8 // save return address
|
||
;;
|
||
st8 [rpT2] = rIPSR, 8 // save psr
|
||
;;
|
||
st8 [rpT2] = v0; // save sys call number
|
||
;;
|
||
|
||
|
||
// For Conditional Interrupt Logging
|
||
EndOfLogging1:
|
||
|
||
#endif // INTERRUPTION_LOGGING
|
||
|
||
//
|
||
// if sp is Nat'ed return to caller with an error status
|
||
// N.B. sp is not spilled and a value of zero is saved in the IntNats field
|
||
//
|
||
|
||
mov rT1 = cr.dcr
|
||
movl rpT4 = KiPcr+PcInitialStack
|
||
|
||
mov rSp = sp
|
||
(pNatedSp) movl rT4 = Knsc_ErrorReturn
|
||
;;
|
||
|
||
mov rPreds = pr
|
||
nop.f 0
|
||
cmp.eq pUser, pKrnl = UserMode, rPreviousMode
|
||
|
||
mov rBSP = ar.bsp
|
||
(pNatedSp) movl v0 = STATUS_IA64_INVALID_STACK
|
||
;;
|
||
|
||
(pUser) ld8 sp = [rpT4], PcInitialBStore-PcInitialStack // set new sp
|
||
mov rIIP = brp
|
||
mov rPFS = ar.pfs
|
||
;;
|
||
|
||
mov rT2 = ar.rsc
|
||
(pUser) ld8 rKBSPStore = [rpT4], PcKernelDebugActive-PcInitialBStore
|
||
(pNatedSp) mov bt0 = rT4
|
||
;;
|
||
|
||
(pUser) ld1 rKDbgActive = [rpT4], PcCurrentThread-PcKernelDebugActive
|
||
(pKrnl) add rpT4 = PcCurrentThread-PcInitialStack, rpT4
|
||
extr rIFS = rPFS, 0, 38
|
||
|
||
mov rT0 = ar.fpsr
|
||
(pUser) movl rT3 = 1 << PSR_SS | 1 << PSR_DB | 1 << PSR_TB | 1 << PSR_LP
|
||
|
||
(pUser) mov ar.rsc = r0 // put RSE in lazy mode
|
||
(pUser) add sp = -ThreadStateSaveAreaLength-TrapFrameLength, sp
|
||
(pKrnl) add sp = -TrapFrameLength, sp // allocate TF
|
||
;;
|
||
|
||
(pUser) mov rBSPStore = ar.bspstore // get user bsp store point
|
||
add rpT1 = TrStIPSR, sp // -> IPSR
|
||
add rpT2 = TrIntSp, sp // -> IntSp
|
||
;;
|
||
|
||
(pUser) ld8 rT4 = [rpT1]
|
||
st8 [rpT2] = rSp, TrApUNAT-TrIntSp // sp is not Nat'ed
|
||
|
||
add rpT3 = TrStIFS, sp // -> IFS
|
||
dep rIFS = 1, rIFS, 63, 1 // set IFS.v
|
||
;;
|
||
|
||
st8 [rpT2] = rUNAT, TrApDCR-TrApUNAT
|
||
st8 [rpT3] = rIFS, TrRsPFS-TrStIFS // save IFS
|
||
(pUser) and rT4 = rT3, rT4 // capture psr.db, tb, ss
|
||
;;
|
||
|
||
st8 [rpT2] = rT1, TrPreds-TrApDCR
|
||
st8.nta [rpT3] = rPFS, TrStFPSR-TrRsPFS // save PFS
|
||
(pUser) mov rT3 = rIPSR
|
||
|
||
rBspOff = t5
|
||
|
||
extr.u rBspOff = rBSP, 0, 9
|
||
extr.u t0 = rIFS, 0, 7
|
||
extr.u rIFS = rIFS, 7, 7
|
||
;;
|
||
|
||
(pUser) mov rRNAT = ar.rnat
|
||
movl rT1 = 1 << PSR_I | 1 << PSR_MFH | 1 << PSR_BE
|
||
|
||
sub rIFS = t0, rIFS
|
||
movl t0 = 1 << PSR_I | 1 << PSR_BN
|
||
;;
|
||
|
||
st8 [rpT2] = rPreds, TrIntNats-TrPreds
|
||
(pUser) or rIPSR = rIPSR, rT4
|
||
(pUser) cmp.ne.unc pKDbg, pt2 = zero, rKDbgActive // kernel debug active?
|
||
|
||
shladd rBspOff = rIFS, 3, rBspOff
|
||
shladd rBSP = rIFS, 3, rBSP
|
||
|
||
mov rIFS = 0x1F8
|
||
(pUser) dep t0 = 1, t0, PSR_CPL, 2
|
||
;;
|
||
|
||
st8 [rpT2] = zero,TrIntGp-TrIntNats // all integer Nats are 0
|
||
st8 [rpT3] = rT0, TrStIIP-TrStFPSR // save FPSR
|
||
(pUser) andcm rT3 = rT3, rT1 // clear i, mfh, be
|
||
|
||
cmp.ge pt0 = rBspOff, rIFS
|
||
or rIPSR = t0, rIPSR // set i, cpl, bn for the saved IPSR
|
||
;;
|
||
|
||
st8 [rpT1] = rIPSR // save IPSR
|
||
st8 [rpT3] = rIIP, TrBrRp-TrStIIP // save IIP
|
||
(pt2) dep rT3 = 0, rT3, PSR_DB, 1 // disable db in kernel
|
||
;;
|
||
|
||
st8.nta [rpT3] = rIIP, TrRsBSP-TrBrRp // save BRP
|
||
st8 [rpT2] = gp // Save GP even though it is a temporary
|
||
// If someone does a get/set context and GP
|
||
// is zero in the trap fram then set context
|
||
// will think IIP is a plabel and dereference
|
||
// it.
|
||
(pUser) dep rT3 = 1, rT3, PSR_AC, 1 // enable alignment check
|
||
;;
|
||
|
||
add rpT2 = TrRsRSC, sp
|
||
(pt0) add rBSP = 8, rBSP
|
||
(pUser) mov psr.l = rT3
|
||
;;
|
||
st8 [rpT3] = rBSP, TrRsBSPSTORE-TrRsBSP
|
||
(pUser) sub rBSP = rBSP, rBSPStore
|
||
;;
|
||
|
||
(pUser) st8 [rpT3] = rBSPStore // save user BSP Store
|
||
(pUser) dep rT2 = rBSP, rT2, RSC_MBZ1, RSC_LOADRS_LEN
|
||
|
||
(pUser) mov teb = kteb // get Teb pointer
|
||
movl rT1 = Knsc10 // Leave the EPC page
|
||
;;
|
||
|
||
st8 [rpT2] = rT2, TrRsRNAT-TrRsRSC // save RSC
|
||
(pUser) dep rKBSPStore = rBSPStore, rKBSPStore, 0, 9
|
||
mov b6 = rT1 // Addres of Knsc10 in KSEG0.
|
||
;;
|
||
|
||
(pUser) mov ar.bspstore = rKBSPStore // switch to kernel BSP
|
||
movl gp = _gp // set up kernel gp
|
||
;;
|
||
|
||
(pUser) mov ar.rsc = RSC_KERNEL // turn rse on, in kernel mode
|
||
(pUser) st8 [rpT2] = rRNAT // save RNAT in trap frame
|
||
// for user backing store
|
||
(pNatedSp) br.spnt bt0
|
||
br.sptk b6
|
||
;;
|
||
|
||
Knsc10:
|
||
|
||
//
|
||
// Now running with user banked registers and on kernel backing store
|
||
//
|
||
// Can now take TLB faults
|
||
//
|
||
// Preserve the output args (as in's) in the local frame until it's ready to
|
||
// call the specified system service because other calls may have to be made
|
||
// before that. Also allocate locals and one out.
|
||
//
|
||
|
||
|
||
//
|
||
// Register aliases for rest of procedure
|
||
//
|
||
|
||
.regstk 8, 9, 3, 0
|
||
|
||
rScallGp = loc0
|
||
rpThObj = loc1 // pointer to thread object
|
||
rSavedV0 = loc2 // saved v0 for GUI thread
|
||
rpEntry = loc3 // syscall routine entry point
|
||
rSnumber = loc4 // service number
|
||
rArgEntry = loc5
|
||
rCount = loc6 /* index of the first Nat'ed input register */
|
||
rUserSp = loc7
|
||
rUserPFS = loc8
|
||
rArgBytes = out2
|
||
|
||
|
||
//
|
||
// the following code uses the predicates to determine the first of
|
||
// the 8 input argument register whose Nat bit is set. The result
|
||
// is saved in register rCount and used to determine whether to fail
|
||
// the system call in Knsc_CheckArguments.
|
||
//
|
||
|
||
alloc rUserPFS = 8, 9, 3, 0
|
||
ld8 rpThObj = [rpT4]
|
||
mov rUserSp = rSp
|
||
|
||
add rpT1 = TrEOFMarker, sp
|
||
movl rT1 = FPSR_FOR_KERNEL // initial fpsr value
|
||
;;
|
||
|
||
mov ar.fpsr = rT1 // set fpsr
|
||
movl rT3 = KTRAP_FRAME_EOF | EXCEPTION_FRAME
|
||
;;
|
||
|
||
st8 [rpT1] = rT3
|
||
mov loc0 = pr // save local predicates
|
||
;;
|
||
|
||
mov pr = zero, -1
|
||
add rpT2 = ThServiceTable, rpThObj
|
||
add rpT3 = ThTrapFrame, rpThObj
|
||
;;
|
||
|
||
lfetch [rpT2]
|
||
ld8 rT4 = [rpT3], ThPreviousMode-ThTrapFrame
|
||
|
||
cmp.eq p1 = r32, r32
|
||
cmp.eq p9 = r33, r33
|
||
cmp.eq p17 = r34, r34
|
||
cmp.eq p25 = r35, r35
|
||
cmp.eq p33 = r36, r36
|
||
cmp.eq p41 = r37, r37
|
||
cmp.eq p49 = r38, r38
|
||
cmp.eq p57 = r39, r39
|
||
mov rSavedV0 = v0 // save syscall # across call
|
||
;;
|
||
|
||
ld1 rT0 = [rpT3] // rT0 = thread's previous mode
|
||
mov rT1 = pr
|
||
add rpT1 = TrTrapFrame, sp // -> TrTrapFrame
|
||
;;
|
||
|
||
st1 [rpT3] = rPreviousMode // set new thread previous mode
|
||
mov pr = loc0, -1 // restore local predicates
|
||
dep rT1 = 0, rT1, 0, 1 // clear bit 0
|
||
;;
|
||
|
||
st8 [rpT1] = rT4, TrPreviousMode-TrTrapFrame
|
||
czx1.r rCount = rT1 // determine which arg is Nat'ed
|
||
;;
|
||
|
||
st4 [rpT1] = rT0
|
||
FAST_ENABLE_INTERRUPTS
|
||
(pKDbg) br.call.spnt brp = KiLoadKernelDebugRegisters
|
||
;;
|
||
|
||
PROLOGUE_END
|
||
|
||
//
|
||
// If the specified system service number is not within range, then
|
||
// attempt to convert the thread to a GUI thread and retry the service
|
||
// dispatch.
|
||
//
|
||
// N.B. The system call arguments, the system service entry point (rpEntry),
|
||
// the service number (Snumber)
|
||
// are implicitly preserved in the register stack while attempting to
|
||
// convert the thread to a GUI thread. v0 and the gp must be preserved
|
||
// explicitly.
|
||
//
|
||
// Validate sys call number
|
||
//
|
||
|
||
ALTERNATE_ENTRY(KiSystemServiceRepeat)
|
||
|
||
add rpT1 = ThTrapFrame, rpThObj // rpT1 -> ThTrapFrame
|
||
add rpT2 = ThServiceTable,rpThObj // rpT2 -> ThServiceTable
|
||
shr.u rT2 = rSavedV0, SERVICE_TABLE_SHIFT // isolate service descriptor offset
|
||
;;
|
||
|
||
st8 [rpT1] = sp // set trap frame address
|
||
ld8 rT3 = [rpT2] // -> service descriptor table
|
||
and rSdOffset = SERVICE_TABLE_MASK, rT2
|
||
;;
|
||
|
||
cmp4.ne pNoGui, pGui = SERVICE_TABLE_TEST, rSdOffset // check if GUI system service
|
||
add rpT1 = TeGdiBatchCount, teb
|
||
mov rSnumber = SERVICE_NUMBER_MASK
|
||
;;
|
||
|
||
(pGui) lfetch [rpT1]
|
||
add rT2 = rSdOffset, rT3 // rT2 -> service descriptor
|
||
;;
|
||
add rpSd = SdLimit, rT2 // rpSd -> table limit
|
||
;;
|
||
|
||
ld4 rT1 = [rpSd], SdTableBaseGpOffset-SdLimit // rT1 = table limit
|
||
;;
|
||
ld4 rScallGp = [rpSd], SdBase-SdTableBaseGpOffset
|
||
and rSnumber = rSnumber, rSavedV0 // rSnumber = service number
|
||
;;
|
||
|
||
ld8 rT4 = [rpSd], SdNumber-SdBase // rT4 = table base
|
||
;;
|
||
ld8 rArgTable = [rpSd] // -> arg table
|
||
sxt4 rScallGp = rScallGp // sign-extend offset
|
||
;;
|
||
|
||
cmp4.ltu pt1, pt0 = rSnumber, rT1 // pt1 = number < limit
|
||
shladd rpT3 = rSnumber, 3, rT4 // -> entry point address
|
||
add rScallGp = rT4, rScallGp // compute syscall gp
|
||
;;
|
||
|
||
(pt1) ld8 rpEntry = [rpT3] // -> sys call routine plabel
|
||
add rArgEntry = rSnumber, rArgTable // -> # arg bytes
|
||
|
||
(pt1) cmp4.ne.unc pNoGui, pGui = SERVICE_TABLE_TEST, rSdOffset
|
||
(pNoGui) br.dptk Knsc_NotGUI // Not a GUI thread
|
||
(pGui) br.dpnt Knsc_GUI // GUI thread
|
||
;;
|
||
|
||
//
|
||
// If rSdOffset == SERVICE_TABLE_TEST then service number is GUI service
|
||
//
|
||
|
||
cmp.ne pInvl, pVal = SERVICE_TABLE_TEST, rSdOffset
|
||
mov v0 = 1
|
||
(pVal) br.call.sptk brp = PsConvertToGuiThread
|
||
;;
|
||
|
||
cmp4.eq pVal, p0 = 0, v0 // pVal = 1, if successful
|
||
movl v0 = STATUS_INVALID_SYSTEM_SERVICE // invalid, if not successful
|
||
;;
|
||
|
||
add rpT1 = @gprel(KeServiceDescriptorTableShadow),gp // Load address of table of shadow table
|
||
(pVal) br.sptk KiSystemServiceRepeat // br if successful
|
||
(pInvl) br.spnt Knsc_ErrorReturn // br to KiSystemServiceExit if
|
||
;; // system call out of range
|
||
|
||
//
|
||
// The conversion to a Gui thread failed. The correct return value is encoded
|
||
// in a byte table indexed by the service number that is at the end of the
|
||
// service address table. The encoding is as follows:
|
||
//
|
||
// 0 - return 0.
|
||
// -1 - return -1.
|
||
// 1 - return status code.
|
||
//
|
||
add rpT1 = SERVICE_TABLE_TEST, rpT1 // Get addr of the GUI table
|
||
;;
|
||
ld8 rpT2 = [rpT1], SdLimit - SdBase // Get the table base.
|
||
;;
|
||
ld4 rT1 = [rpT1] // Get the limit.
|
||
add rpT2 = rpT2, rSnumber // Index by the server number to the correct byte.
|
||
;;
|
||
shladd rpT2 = rT1, 3, rpT2 // Calculate the end of the table.
|
||
cmp4.ltu pt1, pt0 = rSnumber, rT1 // pt1 = number < limit
|
||
;; // pt1 == 0 implies return an ntstatus.
|
||
(pt1) ld1 rT1 = [rpT2] // Load the flag byte if within table
|
||
;;
|
||
sxt1 rT2 = rT1 // Sign extend the result
|
||
(pt1) cmp.eq pt0, pt1 = 1, rT1 // Test for 1 which means return STATUS_INVALID_SYSTEM_SERVICE
|
||
;;
|
||
(pt1) mov v0 = rT2 // Use the flag value if needed.
|
||
br.sptk Knsc_ErrorReturn // br to KiSystemServiceExit
|
||
;;
|
||
|
||
Knsc_GUI:
|
||
|
||
//
|
||
// If the system service is a GUI service and the GDI user batch queue is
|
||
// not empty, then call the appropriate service to flush the user batch.
|
||
//
|
||
|
||
add rpT1 = TeGdiBatchCount, teb // get number of batched calls
|
||
mov rSavedV0 = rpSd // save service descriptor
|
||
;;
|
||
ld4.s rT1 = [rpT1]
|
||
add rpT3 = @gprel(KeGdiFlushUserBatch), gp
|
||
;;
|
||
|
||
cmp4.ne pGui = rT1, zero // skip if no calls
|
||
tnat.nz pNoGui = rT1 // pGui will be zero if rT1 is Nat
|
||
;;
|
||
(pGui) ld8 rpT1 = [rpT3] // get KeGdiFlushUserBatch()
|
||
movl rpT2 = Knsc_GUI_Return
|
||
;;
|
||
|
||
(pGui) ld8 rT1 = [rpT1], PlGlobalPointer-PlEntryPoint // get entry point
|
||
mov brp = rpT2
|
||
(pNoGui)br.call.spnt bt0=KiTestGdiBatchCount // This will return to Knsc_GUI_Return
|
||
;;
|
||
|
||
(pGui) ld8 gp = [rpT1] // set global pointer
|
||
(pGui) mov bt0 = rT1
|
||
(pGui) br.call.sptk brp = bt0 // call to KeGdiFlushUserBatch
|
||
;;
|
||
|
||
Knsc_GUI_Return:
|
||
#if DBG
|
||
mov rpSd = rSavedV0 // restore service descriptor
|
||
;;
|
||
#endif
|
||
|
||
//
|
||
// Check for Nat'ed input argument register and
|
||
// Copy in-memory arguments from caller stack to kernel stack
|
||
//
|
||
|
||
Knsc_NotGUI:
|
||
|
||
#if DBG // checked build code
|
||
|
||
add rpT1 = SdCount-SdNumber, rpSd // rpT1 -> count table address
|
||
;;
|
||
ld8 rpT2 = [rpT1] // service count table address
|
||
;;
|
||
|
||
cmp.ne pt0 = rpT2, zero // if zero, no table defined
|
||
shladd rpT3 = rSnumber, 2, rpT2 // compute service count address
|
||
;;
|
||
|
||
(pt0) ld4 rT1 = [rpT3] // increment count
|
||
;;
|
||
(pt0) add rT1 = 1, rT1
|
||
;;
|
||
(pt0) st4 [rpT3] = rT1 // store result
|
||
|
||
#endif // DBG
|
||
|
||
tbit.z pt0, pt1 = rpEntry, 0
|
||
extr.u rArgNum = rpEntry, 1, 3 // extract # of arguments
|
||
dep rpEntry = 0, rpEntry, 0, 4 // clear least significant 4 bit
|
||
;;
|
||
|
||
(pt1) ld1.nt1 rArgBytes = [rArgEntry] // get # arg bytes
|
||
movl v0 = STATUS_INVALID_PARAMETER_1
|
||
;;
|
||
cmp.ne pNatedArg = zero, zero // assume no Nat'ed argument
|
||
(pt1) shr rArgNum = rArgBytes, 2
|
||
;;
|
||
|
||
|
||
dep rPFS = 0, rUserPFS, 62, 2
|
||
add v0 = rCount, v0 // set return status
|
||
(pt1) add rArgNum = 7, rArgNum // number of in arguments
|
||
;;
|
||
cmp.geu pNoCopy, pCopy = 8, rArgNum // any in-memory arguments ?
|
||
(pt1) shl rArgBytes = rArgNum, 3 // x2 since args are 8 bytes each, not 4
|
||
;;
|
||
|
||
(pNoCopy) cmp.gt pNatedArg = rArgNum, rCount // any Nat'ed argument ?
|
||
(pCopy) cmp.gt pNatedArg = 8, rCount
|
||
(pCopy) add rArgBytes = -64, rArgBytes // size of in-memory arguments
|
||
;;
|
||
|
||
(pNatedArg) br.spnt Knsc_ErrorReturn // exit if Nat'ed arg found
|
||
(pNoCopy) br.sptk KiSystemServiceEndAddress // skip copy if no memory args
|
||
;;
|
||
|
||
//
|
||
// Get the caller's sp. If caller was user mode, validate the stack pointer
|
||
// ar.unat contains Nat for previous sp (in TrIntSp)
|
||
//
|
||
|
||
(pUser) tnat.nz.unc pt1, pt2 = rUserSp // test user sp for Nat
|
||
(pUser) movl rpT2 = MI_USER_PROBE_ADDRESS // User sp limit
|
||
;;
|
||
|
||
(pt2) cmp.geu pt1 = rUserSp, rpT2 // user sp >= PROBE ADDRESS ?
|
||
mov rpT1 = rUserSp // previous sp
|
||
;;
|
||
|
||
(pt1) add rpT1 = -STACK_SCRATCH_AREA,rpT2 // set out of range (includes Nat case)
|
||
;;
|
||
add out1 = STACK_SCRATCH_AREA, rpT1 // adjust for scratch area
|
||
add out0 = STACK_SCRATCH_AREA, sp // adjust for scratch area
|
||
;;
|
||
|
||
ALTERNATE_ENTRY(KiSystemServiceStartAddress)
|
||
|
||
//
|
||
// Call out to C-code so the exception handling works corrrectly.
|
||
// The byte count is in out3 which is rArgBytes.
|
||
//
|
||
br.call.sptk brp=KeCopySafe
|
||
;;
|
||
dep rPFS = 0, rUserPFS, 62, 2 // rPFS is a temp, recalculate it
|
||
cmp4.ne pt2 = STATUS_SUCCESS, r8 // See if the copy worked.
|
||
(pt2) br.spnt Knsc_ErrorReturn
|
||
;;
|
||
|
||
ALTERNATE_ENTRY(KiSystemServiceEndAddress)
|
||
|
||
|
||
mov gp = rScallGp
|
||
mov bt0 = rpEntry
|
||
mov rSp = rUserSp
|
||
;;
|
||
|
||
//
|
||
// N.B. t0 is reserved to pass trap frame address to NtContinue()
|
||
//
|
||
|
||
alloc rT2 = 0,0,8,0 // output regs are ready
|
||
mov ar.pfs = rPFS
|
||
movl rT1 = KiSystemServiceExit
|
||
;;
|
||
|
||
mov t0 = sp // for NtContinue()
|
||
mov brp = rT1
|
||
br.sptk bt0 // call routine(args)
|
||
;;
|
||
|
||
ALTERNATE_ENTRY(KiSystemServiceExit)
|
||
|
||
//
|
||
// make the current bsp the same as the saved BSP in the trap frame
|
||
//
|
||
|
||
cover
|
||
;;
|
||
|
||
//
|
||
// At this point:
|
||
// ar.unat contains Nat for previous sp (ar.unat is preserved register)
|
||
// sp -> trap frame
|
||
//
|
||
// Returning from "call": no need to restore volatile state
|
||
// *** TBD *** : zero volatile state for security? PPC does zero, mips does not.
|
||
//
|
||
//
|
||
// Update PbSystemCalls
|
||
//
|
||
//
|
||
// Restore thread previous mode and trap frame address from the trap frame
|
||
//
|
||
|
||
add rpT2 = TrStIPSR, sp
|
||
movl rpT1 = KiPcr + PcPrcb // rpT1 -> Prcb
|
||
;;
|
||
|
||
ld8 rpT3 = [rpT1], PcCurrentThread-PcPrcb
|
||
lfetch [rpT2], TrTrapFrame-TrStIPSR
|
||
;;
|
||
|
||
ld8 rThread = [rpT1] // rpT1 -> current thread
|
||
ld8 rT2 = [rpT2], TrPreviousMode-TrTrapFrame
|
||
add rpT3 = PbSystemCalls, rpT3 // pointer to sys call counter
|
||
;;
|
||
|
||
FAST_DISABLE_INTERRUPTS
|
||
;;
|
||
ld4 rT1 = [rpT3] // rT1.4 = counter value
|
||
|
||
ld4 rT3 = [rpT2], TrRsRSC-TrPreviousMode
|
||
add rpT4 = ThTrapFrame, rThread // -> thread trap frame
|
||
add rpT1 = ThApcState+AsUserApcPending, rThread
|
||
;;
|
||
|
||
(pKrnl) ld8 rRscE = [rpT2] // load user RSC
|
||
(pUser) ld1 rT4 = [rpT1], ThAlerted-ThApcState-AsUserApcPending
|
||
add rT1 = 1, rT1 // increment
|
||
;;
|
||
|
||
st8 [rpT4] = rT2, ThPreviousMode-ThTrapFrame
|
||
st4 [rpT3] = rT1 // store
|
||
;;
|
||
|
||
st1 [rpT4] = rT3 // restore prevmode in thread
|
||
mov t0 = sp // set t0 to trap frame
|
||
(pKrnl) br.spnt Knsc_CommonExit // br if returning to kernel
|
||
;;
|
||
|
||
st1 [rpT1] = zero
|
||
cmp4.eq pt0 = zero, rT4
|
||
(pt0) br.sptk KiUserServiceExit
|
||
;;
|
||
|
||
alloc rT1 = ar.pfs, 0, 1, 2, 0
|
||
add loc0 = TrIntV0, sp
|
||
add rpT1 = TrIntTeb, sp
|
||
|
||
//
|
||
// v0 is saved in the trap frame so the return status can be restored
|
||
// by NtContinue after the user APC has been dispatched.
|
||
//
|
||
|
||
ssm 1 << PSR_I // enable interrupts
|
||
mov rT3 = APC_LEVEL
|
||
;;
|
||
SET_IRQL (rT3)
|
||
;;
|
||
|
||
st8.nta [loc0] = v0 // save return status in trap frame
|
||
movl gp = _gp // restore to kernel gp value
|
||
|
||
st8.nta [rpT1] = teb
|
||
mov out1 = sp
|
||
br.call.sptk brp = KiApcInterrupt
|
||
;;
|
||
|
||
rsm 1 << PSR_I // disable interrupt
|
||
ld8.nta v0 = [loc0] // restore system call return status
|
||
SET_IRQL (zero)
|
||
|
||
HANDLER_EXIT(KiNormalSystemCall)
|
||
|
||
//
|
||
// KiServiceExit is carefully constructed as a continuation of
|
||
// KiNormalSystemCall. From now on, t0 must be preserved because it is
|
||
// used to hold the trap frame address. v0 must be preserved because it
|
||
// is holding the return status.
|
||
//
|
||
|
||
HANDLER_ENTRY_EX(KiServiceExit, KiSystemServiceHandler)
|
||
|
||
.prologue
|
||
.unwabi @nt, EXCEPTION_FRAME
|
||
|
||
.vframe t0
|
||
mov t0 = sp
|
||
;;
|
||
|
||
ALTERNATE_ENTRY(KiUserServiceExit)
|
||
|
||
(pUser) add rpT3 = TrStIPSR, t0
|
||
;;
|
||
(pUser) ld8 rpT3 = [rpT3]
|
||
invala
|
||
;;
|
||
|
||
(pUser) tbit.nz.unc pUDbg = rpT3, PSR_DB // if user psr.db set, load user DRs
|
||
(pUDbg) br.call.spnt brp = KiLoadUserDebugRegisters
|
||
;;
|
||
|
||
add rpT1 = TrRsRSC, t0 // -> user RSC
|
||
add rpT2 = TrRsBSP, t0 // -> user BSP Store
|
||
;;
|
||
|
||
PROLOGUE_END
|
||
|
||
ld8 rRscE = [rpT1], TrRsRNAT-TrRsRSC // load user RSC
|
||
ld8 rBSP = [rpT2]
|
||
mov rRscD = RSC_KERNEL_DISABLED
|
||
;;
|
||
|
||
//
|
||
// Switch to user BSP -- put in load intensive mode to overlap RS restore
|
||
// with volatile state restore.
|
||
//
|
||
|
||
ld8 rRNAT = [rpT1] // user RNAT
|
||
|
||
extr.u rRscDelta = rRscE, RSC_MBZ1, RSC_LOADRS_LEN
|
||
dep rRscE = r0, rRscE, RSC_MBZ1, RSC_LOADRS_LEN
|
||
;;
|
||
|
||
alloc rT2 = 0,0,0,0
|
||
dep rRscD = rRscDelta, rRscD, RSC_LOADRS, RSC_LOADRS_LEN
|
||
sub rBSPStore = rBSP, rRscDelta
|
||
;;
|
||
|
||
mov ar.rsc = rRscD // turn off RSE
|
||
;;
|
||
loadrs // pull in user regs
|
||
;;
|
||
|
||
mov ar.bspstore = rBSPStore // restore user BSP
|
||
;;
|
||
mov ar.rnat = rRNAT // restore user RNAT
|
||
|
||
Knsc_CommonExit:
|
||
|
||
add rpT1 = TrIntNats, t0
|
||
movl rpT2 = KiPcr+PcCurrentThread
|
||
|
||
add rpT4 = TrStIPSR, t0
|
||
add rpT3 = TrRsPFS, t0
|
||
// mov rT0 = (1 << PSR_I) | (1 << PSR_MFH)
|
||
;;
|
||
|
||
ld8 rIntNats = [rpT1], TrIntSp-TrIntNats
|
||
.pred.rel "mutex",pUser,pKrnl
|
||
(pUser) ld8 rT1 = [rpT2], PcHighFpOwner-PcCurrentThread
|
||
(pKrnl) add rpT2 = PcKernelDebugActive-PcCurrentThread, rpT2
|
||
;;
|
||
|
||
ld8 rIPSR = [rpT4]
|
||
(pUser) ld8 rT2 = [rpT2]
|
||
(pKrnl) mov rPreviousMode = KernelMode
|
||
;;
|
||
|
||
ld8 rPFS = [rpT3], TrStIIP-TrRsPFS // get previous PFS
|
||
(pKrnl) ld1 rT2 = [rpT2]
|
||
(pUser) mov rPreviousMode = UserMode
|
||
;;
|
||
|
||
mov ar.rsc = rRscE // restore RSC
|
||
ld8 rIIP = [rpT3], TrStFPSR-TrStIIP
|
||
(pUser) cmp.ne.unc pt0 = rT1, rT2
|
||
;;
|
||
|
||
mov ar.unat = rIntNats
|
||
ld8 rT3 = [rpT3], TrStIFS-TrStFPSR // load fpsr
|
||
(pt0) dep rIPSR = 1, rIPSR, PSR_DFH, 1
|
||
;;
|
||
|
||
ld8.fill rSp = [rpT1], TrPreds-TrIntSp // fill sp
|
||
ld8 rIFS = [rpT3] // load IFS
|
||
// (pUser) dep rIPSR = 0, rIPSR, PSR_TB, 1 // ensure psr.tb is clear
|
||
;;
|
||
|
||
(pKrnl) cmp.ne.unc pKDbg, pt2 = rT2, r0 // hardware debug active?
|
||
dep rIPSR = 0, rIPSR, PSR_MFH, 1 // psr.mfh
|
||
;;
|
||
|
||
ld8 rPreds = [rpT1], TrApUNAT-TrPreds
|
||
(pt2) dep rIPSR = 0, rIPSR, PSR_DB, 1 // disable db in kernel
|
||
(pKDbg) dep rIPSR = 1, rIPSR, PSR_DB, 1 // enable db in kernel
|
||
;;
|
||
|
||
ld8 rUNAT = [rpT1], TrApDCR-TrApUNAT
|
||
mov ar.pfs = rPFS // restore PFS
|
||
;;
|
||
|
||
ld8 rT4 = [rpT1] // load dcr
|
||
// mov psr.l = rIPSR // restore psr settings
|
||
mov pr = rPreds // restore preds
|
||
;;
|
||
|
||
mov cr.dcr = rT4 // restore DCR
|
||
rsm 1 << PSR_IC // disable PSR.ic
|
||
mov ar.unat = rUNAT // restore UNAT
|
||
|
||
// mov brp = rIIP // restore brp
|
||
;;
|
||
|
||
srlz.d // must serialize
|
||
mov ar.fpsr = rT3 // restore FPSR
|
||
;;
|
||
|
||
//
|
||
// The system return case must be handle separately from the user return
|
||
// case, so we can determine which stack we are currently using in case
|
||
// a trap is take before we can return.
|
||
//
|
||
|
||
mov sp = rSp
|
||
|
||
|
||
//
|
||
// Restore status registers
|
||
//
|
||
bsw.0
|
||
;;
|
||
|
||
mov cr.ipsr = rIPSR // restore previous IPSR
|
||
mov cr.ifs = rIFS // restore previous IFS
|
||
mov cr.iip = rIIP // restore previous IIP
|
||
;;
|
||
|
||
//
|
||
// Resume at point of interruption (rfi must be at end of instruction group)
|
||
//
|
||
|
||
rfi
|
||
;;
|
||
|
||
Knsc_ErrorReturn:
|
||
|
||
//
|
||
// N.B. t0 is reserved to pass trap frame address to NtContinue()
|
||
//
|
||
|
||
add rPFS = TrRsPFS, sp
|
||
;;
|
||
ld8 rPFS = [rPFS]
|
||
;;
|
||
dep rPFS = 0, rPFS, 62, 2
|
||
;;
|
||
|
||
mov ar.pfs = rPFS
|
||
movl rT1 = KiSystemServiceExit
|
||
;;
|
||
|
||
mov brp = rT1
|
||
br.ret.sptk brp
|
||
;;
|
||
|
||
HANDLER_EXIT(KiServiceExit)
|
||
|
||
.sdata
|
||
KiSystemServiceExitOffset::
|
||
data4 @secrel(KiSystemServiceExit)
|
||
KiSystemServiceStartOffset::
|
||
data4 @secrel(KiSystemServiceStartAddress)
|
||
KiSystemServiceEndOffset::
|
||
data4 @secrel(KiSystemServiceEndAddress)
|
||
|
||
|
||
.text
|
||
//++
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiGenericExceptionHandler
|
||
//
|
||
// Description:
|
||
//
|
||
// First level handler for heavyweight exceptions.
|
||
//
|
||
// On entry:
|
||
//
|
||
// ic off
|
||
// interrupts disabled
|
||
// current frame covered
|
||
//
|
||
// Process:
|
||
//
|
||
// Notes:
|
||
//
|
||
// PCR page mapped with TR
|
||
//--------------------------------------------------------------------
|
||
|
||
HANDLER_ENTRY(KiGenericExceptionHandler)
|
||
|
||
.prologue
|
||
.unwabi @nt, EXCEPTION_FRAME
|
||
|
||
ALLOCATE_TRAP_FRAME
|
||
|
||
//
|
||
// sp points to trap frame
|
||
//
|
||
// Save exception handler routine in kernel register
|
||
//
|
||
|
||
mov rkHandler = rHHandler
|
||
movl rTH3 = KiPcr+PcSavedIFA
|
||
;;
|
||
|
||
st8 [rTH3] = rHIFA
|
||
|
||
//
|
||
// Save interruption state in trap frame and switch to user bank registers
|
||
// and switch to kernel backing store.
|
||
//
|
||
|
||
SAVE_INTERRUPTION_STATE(Kgeh_SaveTrapFrame)
|
||
|
||
//
|
||
// Now running with user banked registers and on kernel stack.
|
||
//
|
||
// Can now take TLB faults
|
||
//
|
||
// sp -> trap frame
|
||
//
|
||
|
||
br.call.sptk brp = KiSaveTrapFrame
|
||
;;
|
||
|
||
//
|
||
// Register aliases
|
||
//
|
||
|
||
rpT1 = t0
|
||
rpT2 = t1
|
||
rpT3 = t2
|
||
rT1 = t3
|
||
rT2 = t4
|
||
rT3 = t5
|
||
rPreviousMode = t6 // previous mode
|
||
rT4 = t7
|
||
|
||
|
||
mov rT1 = rkHandler // restore address of interruption routine
|
||
movl rpT1 = KiPcr+PcSavedIIM
|
||
;;
|
||
|
||
ld8 rT2 = [rpT1], PcSavedIFA-PcSavedIIM // load saved IIM
|
||
add rpT2 = TrEOFMarker, sp
|
||
add rpT3 = TrStIIM, sp
|
||
;;
|
||
|
||
ld8 rT4 = [rpT1] // load saved IFA
|
||
movl rT3 = KTRAP_FRAME_EOF | EXCEPTION_FRAME
|
||
;;
|
||
|
||
st8 [rpT2] = rT3, TrHandler-TrEOFMarker
|
||
st8 [rpT3] = rT2, TrStIFA-TrStIIM // save IIM in trap frame
|
||
mov bt0 = rT1 // set destination address
|
||
;;
|
||
|
||
.regstk 0, 1, 2, 0 // must match KiExceptionExit
|
||
alloc out1 = 0,1,2,0
|
||
st8 [rpT3] = rT4 // save IFA in trap frame
|
||
|
||
PROLOGUE_END
|
||
|
||
//
|
||
// Dispatch the exception via call to address in rkHandler
|
||
//
|
||
.pred.rel "mutex",pUser,pKrnl
|
||
add rpT1 = TrPreviousMode, sp // -> previous mode
|
||
(pUser) mov rPreviousMode = UserMode // set previous mode
|
||
(pKrnl) mov rPreviousMode = KernelMode
|
||
;;
|
||
|
||
st4 [rpT1] = rPreviousMode // save in trap frame
|
||
(pKDbg) br.call.spnt brp = KiLoadKernelDebugRegisters
|
||
;;
|
||
|
||
FAST_ENABLE_INTERRUPTS // enable interrupt
|
||
mov out0 = sp // trap frame pointer
|
||
br.call.sptk brp = bt0 // call handler(tf) (C code)
|
||
;;
|
||
|
||
.pred.rel "mutex",pUser,pKrnl
|
||
cmp.ne pt0, pt1 = v0, zero
|
||
(pUser) mov out1 = UserMode
|
||
(pKrnl) mov out1 = KernelMode
|
||
|
||
//
|
||
// does not return
|
||
//
|
||
|
||
mov out0 = sp
|
||
(pt1) br.cond.sptk KiAlternateExit
|
||
(pt0) br.call.spnt brp = KiExceptionDispatch
|
||
;;
|
||
|
||
//
|
||
// Interrupts need to be disable be for mess up the stack such that
|
||
// the unwind code does not work.
|
||
//
|
||
|
||
FAST_DISABLE_INTERRUPTS
|
||
;;
|
||
ALTERNATE_ENTRY(KiExceptionExit)
|
||
|
||
//++
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This routine is called to exit from an exception.
|
||
//
|
||
// N.B. This transfer of control occurs from:
|
||
//
|
||
// 1. fall-through from above
|
||
// 2. exit from continue system service
|
||
// 3. exit from raise exception system service
|
||
// 4. exit into user mode from thread startup
|
||
//
|
||
// Arguments:
|
||
//
|
||
// loc0 - pointer to trap frame
|
||
// sp - pointer to high preserved float save area + STACK_SCRATCH_AREA
|
||
//
|
||
// Return Value:
|
||
//
|
||
// Does not return.
|
||
//
|
||
//--
|
||
|
||
//
|
||
// upon entry of this block, s0 and s1 must be set to the address of
|
||
// the trap and the exception frames respectively.
|
||
//
|
||
// preserved state is restored here because they may have been modified
|
||
// by SetContext
|
||
//
|
||
|
||
|
||
LEAF_SETUP(0, 1, 2, 0) // must be in sync with
|
||
// KiGenericExceptionHandler
|
||
mov loc0 = s0 // -> trap frame
|
||
mov out0 = s1 // -> exception frame
|
||
;;
|
||
|
||
br.call.sptk brp = KiRestoreExceptionFrame
|
||
;;
|
||
|
||
mov sp = loc0 // deallocate exception
|
||
// frame by restoring sp
|
||
|
||
ALTERNATE_ENTRY(KiAlternateExit)
|
||
|
||
//
|
||
// sp -> trap frame addres
|
||
//
|
||
// Interrupts disabled from here to rfi
|
||
//
|
||
|
||
FAST_DISABLE_INTERRUPTS
|
||
;;
|
||
|
||
RETURN_FROM_INTERRUPTION(Ked)
|
||
|
||
HANDLER_EXIT(KiGenericExceptionHandler)
|
||
|
||
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiExternalInterruptHandler
|
||
//
|
||
// Description:
|
||
//
|
||
// First level external interrupt handler. Dispatch highest priority
|
||
// pending interrupt.
|
||
//
|
||
// On entry:
|
||
//
|
||
// ic off
|
||
// interrupts disabled
|
||
// current frame covered
|
||
//
|
||
// Process:
|
||
//--------------------------------------------------------------------
|
||
|
||
HANDLER_ENTRY(KiExternalInterruptHandler)
|
||
|
||
//
|
||
// Now running with user banked registers and on kernel backing store.
|
||
// N.B. sp -> trap frame
|
||
//
|
||
// Can now take TLB faults
|
||
//
|
||
|
||
.prologue
|
||
.unwabi @nt, INTERRUPT_FRAME
|
||
.regstk 0, 4, 2, 0
|
||
alloc loc0 = 0, 4, 2, 0
|
||
|
||
//
|
||
// Register aliases
|
||
//
|
||
|
||
rVector = loc0
|
||
rSaveGP = loc1
|
||
rpSaveIrql = loc2 // -> old irql in trap frame
|
||
rOldIrql = loc3
|
||
|
||
rpT1 = t0
|
||
rpT2 = t1
|
||
rpT3 = t2
|
||
rT1 = t3
|
||
rT2 = t4
|
||
rT3 = t5
|
||
rPreviousMode = t6 // previous mode
|
||
rNewIrql = t7
|
||
|
||
pEOI = pt1
|
||
|
||
//
|
||
// Save kernel gp
|
||
//
|
||
|
||
mov rSaveGP = gp
|
||
;;
|
||
|
||
//
|
||
// Get the vector number
|
||
//
|
||
mov rVector = cr.ivr // for A0 2173 workaround
|
||
mov rOldIrql = cr.tpr // get actual tpr value
|
||
br.call.sptk brp = KiSaveTrapFrame
|
||
;;
|
||
|
||
#if defined(INTERRUPTION_LOGGING)
|
||
|
||
// For Conditional Interrupt Logging
|
||
mov t2 = gp
|
||
;;
|
||
movl gp = _gp
|
||
;;
|
||
add t0 = @gprel(KiVectorLogMask), gp
|
||
;;
|
||
ld8 t1 = [t0]
|
||
mov gp = t2
|
||
;;
|
||
tbit.z pt1 = t1, ExternalInterruptBit
|
||
(pt1) br.cond.sptk EndOfLogging2
|
||
|
||
|
||
movl t0 = KiPcr+PcInterruptionCount
|
||
;;
|
||
ld4.nt1 t0 = [t0]
|
||
mov t1 = MAX_NUMBER_OF_IHISTORY_RECORDS - 1
|
||
;;
|
||
add t0 = -1, t0
|
||
movl t2 = KiPcr+0x1000
|
||
;;
|
||
and t1 = t0, t1
|
||
;;
|
||
shl t1 = t1, 5
|
||
;;
|
||
add t0 = t2, t1
|
||
;;
|
||
add t0 = 24, t0
|
||
;;
|
||
st8.nta [t0] = rVector // save ivr in the Extra0 field
|
||
|
||
// For Conditional Interrupt Logging
|
||
EndOfLogging2:
|
||
|
||
#endif // defined(INTERRUPTION_LOGGING)
|
||
|
||
//
|
||
// Exit if spurious interrupt vector
|
||
//
|
||
|
||
cmp.eq pt0, pt1 = 0xF, rVector
|
||
extr.u rOldIrql = rOldIrql, TPR_MIC, TPR_MIC_LEN
|
||
(pt0) br.spnt Keih_Exit
|
||
;;
|
||
|
||
//
|
||
// sp -> trap frame
|
||
//
|
||
|
||
add rpSaveIrql = TrEOFMarker, sp
|
||
movl rT3 = KTRAP_FRAME_EOF | INTERRUPT_FRAME
|
||
;;
|
||
|
||
st8 [rpSaveIrql] = rT3, TrPreviousMode - TrEOFMarker
|
||
.pred.rel "mutex",pUser,pKrnl
|
||
(pUser) mov rPreviousMode = UserMode // set previous mode
|
||
(pKrnl) mov rPreviousMode = KernelMode
|
||
;;
|
||
|
||
st4 [rpSaveIrql] = rPreviousMode, TrOldIrql-TrPreviousMode
|
||
movl rpT3 = KiPcr+PcCurrentIrql
|
||
;;
|
||
|
||
st4 [rpSaveIrql] = rOldIrql // save irql in trap frame
|
||
st1 [rpT3] = rOldIrql // sanitize the shadow copy
|
||
(pKDbg) br.call.spnt brp = KiLoadKernelDebugRegisters
|
||
;;
|
||
|
||
PROLOGUE_END
|
||
|
||
Keih_InterruptLoop:
|
||
//
|
||
// Dispatch the interrupt: first raise the IRQL to the level of the new
|
||
// interrupt and enable interrupts.
|
||
//
|
||
|
||
GET_IRQL_FOR_VECTOR(p0, rNewIrql, rVector)
|
||
movl rpT3 = KiPcr+PcInterruptRoutine // -> interrupt routine table
|
||
;;
|
||
|
||
shladd rpT3 = rVector, INT_ROUTINES_SHIFT, rpT3 // base + offset
|
||
SET_IRQL (rNewIrql) // raise to new level
|
||
movl rpT1 = KiPcr + PcPrcb // pointer to prcb
|
||
;;
|
||
|
||
ld8 out0 = [rpT3] // out0 -> interrupt dispatcher
|
||
ld8 rpT1 = [rpT1]
|
||
mov out1 = sp // out1 -> trap frame
|
||
;;
|
||
|
||
FAST_ENABLE_INTERRUPTS
|
||
add rpT1 = PbInterruptCount, rpT1 // -> interrupt counter
|
||
;;
|
||
|
||
ld4.nta rT1 = [rpT1] // counter value
|
||
ld8.nta rT2 = [out0], PlGlobalPointer-PlEntryPoint // get entry point
|
||
;;
|
||
add rT1 = 1, rT1 // increment
|
||
;;
|
||
|
||
//
|
||
// Call the interrupt dispatch routine via a function pointer
|
||
//
|
||
|
||
st4.nta [rpT1] = rT1 // store, ignore overflow
|
||
;;
|
||
|
||
ld8.nta gp = [out0], PlEntryPoint-PlGlobalPointer
|
||
mov bt0 = rT2
|
||
br.call.sptk brp = bt0 // call ISR
|
||
;;
|
||
|
||
ld4 rOldIrql = [rpSaveIrql]
|
||
mov gp = rSaveGP
|
||
END_OF_INTERRUPT // end of interrupt processing
|
||
IO_END_OF_INTERRUPT(rVector,rT1,rT2,pEOI)
|
||
;;
|
||
srlz.d
|
||
|
||
//
|
||
// Disable interrupts and restore IRQL level
|
||
//
|
||
|
||
FAST_DISABLE_INTERRUPTS
|
||
|
||
cmp.gt pt0 = APC_LEVEL, rOldIrql
|
||
mov t0 = APC_LEVEL
|
||
;;
|
||
(pt0) br.spnt ke_call_apc
|
||
|
||
ke_call_apc_resume:
|
||
|
||
LOWER_IRQL (rOldIrql)
|
||
|
||
//
|
||
// Get the next vector number
|
||
//
|
||
|
||
mov rVector = cr.ivr // for A0 2173 workaround
|
||
;;
|
||
//
|
||
// Loop if more interrupts pending (spurious vector == 0xF)
|
||
//
|
||
|
||
cmp.ne pt0 = 0xF, rVector
|
||
;;
|
||
(pt0) br.spnt Keih_InterruptLoop
|
||
br.sptk Keih_Exit
|
||
;;
|
||
|
||
ke_call_apc:
|
||
LOWER_IRQL (t0)
|
||
|
||
ke_call_apc1:
|
||
movl t0 = KiPcr+PcApcInterrupt
|
||
;;
|
||
ld1 t1 = [t0]
|
||
st1 [t0] = r0
|
||
;;
|
||
cmp.eq pt0 = r0, t1
|
||
;;
|
||
(pt0) br.sptk ke_call_apc_resume
|
||
FAST_ENABLE_INTERRUPTS
|
||
mov out1 = sp
|
||
br.call.sptk brp = KiApcInterrupt
|
||
FAST_DISABLE_INTERRUPTS
|
||
br.sptk ke_call_apc1
|
||
|
||
Keih_Exit:
|
||
|
||
RETURN_FROM_INTERRUPTION(Keih)
|
||
|
||
HANDLER_EXIT(KiExternalInterruptHandler)
|
||
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiPanicHandler
|
||
//
|
||
// Description:
|
||
//
|
||
// Handler for panic. Call the bug check routine. A place
|
||
// holder for now.
|
||
//
|
||
// On entry:
|
||
//
|
||
// running on kernel memory stack and kernel backing store
|
||
// sp: top of stack -- points to trap frame
|
||
// interrupts enabled
|
||
//
|
||
// IIP: address of bundle causing fault
|
||
//
|
||
// IPSR: copy of PSR at time of interruption
|
||
//
|
||
// Output:
|
||
//
|
||
// sp: top of stack -- points to trap frame
|
||
//
|
||
// Return value:
|
||
//
|
||
// none
|
||
//
|
||
// Notes:
|
||
//
|
||
// If ISR code out of bounds, this code will inovke the panic handler
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
HANDLER_ENTRY(KiPanicHandler)
|
||
|
||
.prologue
|
||
.unwabi @nt, EXCEPTION_FRAME
|
||
|
||
mov rHpT1 = KERNEL_STACK_SIZE
|
||
movl rTH1 = KiPcr+PcPanicStack
|
||
;;
|
||
|
||
ld8 sp = [rTH1], PcInitialStack-PcPanicStack
|
||
movl rTH2 = KiPcr+PcSystemReserved
|
||
;;
|
||
|
||
st4 [rTH2] = rPanicCode
|
||
st8 [rTH1] = sp, PcStackLimit-PcInitialStack
|
||
sub rTH2 = sp, rHpT1
|
||
;;
|
||
|
||
st8 [rTH1] = rTH2, PcInitialBStore-PcStackLimit
|
||
mov rHpT1 = KERNEL_BSTORE_SIZE
|
||
;;
|
||
|
||
st8 [rTH1] = sp, PcBStoreLimit-PcInitialBStore
|
||
add rTH2 = rHpT1, sp
|
||
add sp = -TrapFrameLength, sp
|
||
;;
|
||
|
||
st8 [rTH1] = rTH2
|
||
|
||
SAVE_INTERRUPTION_STATE(Kph_SaveTrapFrame)
|
||
|
||
//
|
||
// switch to kernel back
|
||
//
|
||
bsw.0
|
||
;;
|
||
|
||
rpRNAT = h16
|
||
rpBSPStore= h17
|
||
rBSPStore = h18
|
||
rKBSPStore= h19
|
||
rRNAT = h20
|
||
rKrnlFPSR = h21
|
||
|
||
mov ar.rsc = r0 // put RSE in lazy mode
|
||
movl rKBSPStore = KiPcr+PcInitialBStore
|
||
;;
|
||
|
||
mov rBSPStore = ar.bspstore
|
||
mov rRNAT = ar.rnat
|
||
;;
|
||
|
||
ld8 rKBSPStore = [rKBSPStore]
|
||
add rpRNAT = TrRsRNAT, sp
|
||
add rpBSPStore = TrRsBSPSTORE, sp
|
||
;;
|
||
|
||
st8 [rpRNAT] = rRNAT
|
||
st8 [rpBSPStore] = rBSPStore
|
||
dep rKBSPStore = rBSPStore, rKBSPStore, 0, 9
|
||
;;
|
||
|
||
mov ar.bspstore = rKBSPStore
|
||
mov ar.rsc = RSC_KERNEL
|
||
;;
|
||
|
||
//
|
||
// switch to user bank
|
||
//
|
||
bsw.1
|
||
;;
|
||
alloc out0 = ar.pfs, 0, 0, 5, 0
|
||
;;
|
||
|
||
PROLOGUE_END
|
||
|
||
br.call.sptk brp = KiSaveTrapFrame
|
||
;;
|
||
|
||
movl out0 = KiPcr+PcSystemReserved
|
||
;;
|
||
|
||
ld4 out0 = [out0] // 1st argument: panic code
|
||
mov out1 = sp // 2nd argument: trap frame
|
||
br.call.sptk.many brp = KeBugCheckEx
|
||
;;
|
||
|
||
nop.m 0
|
||
nop.m 0
|
||
nop.i 0
|
||
;;
|
||
|
||
HANDLER_EXIT(KiPanicHandler)
|
||
|
||
//++
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// VOID
|
||
// KiSaveTrapFrame(PKTRAP_FRAME)
|
||
//
|
||
// Description:
|
||
//
|
||
// Save volatile application state in trap frame.
|
||
// Note: sp, brp, UNAT, RSC, predicates, BSP, BSP Store,
|
||
// PFS, DCR, and FPSR saved elsewhere.
|
||
//
|
||
// Input:
|
||
//
|
||
// sp: points to trap frame
|
||
// ar.unat: contains the Nats of sp, gp, teb, which have already
|
||
// been spilled into the trap frame.
|
||
//
|
||
// Output:
|
||
//
|
||
// None
|
||
//
|
||
// Return value:
|
||
//
|
||
// none
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
LEAF_ENTRY(KiSaveTrapFrame)
|
||
|
||
.regstk 0, 3, 0, 0
|
||
|
||
//
|
||
// Local register aliases
|
||
//
|
||
|
||
rpTF1 = loc0
|
||
rpTF2 = loc1
|
||
rL1 = t0
|
||
rL2 = t1
|
||
rL3 = t2
|
||
rL4 = t3
|
||
rL5 = t4
|
||
|
||
|
||
//
|
||
// (ar.unat unchanged from point of save)
|
||
// Spill temporary (volatile) integer registers
|
||
//
|
||
|
||
alloc loc2 = 0,3,0,0 // don't destroy static register
|
||
add rpTF1 = TrIntT0, sp // -> t0 save area
|
||
add rpTF2 = TrIntT1, sp // -> t1 save area
|
||
;;
|
||
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t0, TrIntT2-TrIntT0 // spill t0 - t22
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t1, TrIntT3-TrIntT1
|
||
;;
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t2, TrIntT4-TrIntT2
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t3, TrIntT5-TrIntT3
|
||
;;
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t4, TrIntT6-TrIntT4
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t5, TrIntT7-TrIntT5
|
||
mov rL2 = bt0
|
||
;;
|
||
|
||
mov rL1 = cr.dcr
|
||
mov rL4 = ar.ccv
|
||
mov rL3 = bt1
|
||
;;
|
||
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t6, TrIntT8-TrIntT6
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t7, TrIntT9-TrIntT7
|
||
;;
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t8, TrIntT10-TrIntT8
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t9, TrIntT11-TrIntT9
|
||
;;
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t10, TrIntT12-TrIntT10
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t11, TrIntT13-TrIntT11
|
||
;;
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t12, TrIntT14-TrIntT12
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t13, TrIntT15-TrIntT13
|
||
;;
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t14, TrIntT16-TrIntT14
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t15, TrIntT17-TrIntT15
|
||
;;
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t16, TrIntT18-TrIntT16
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t17, TrIntT19-TrIntT17
|
||
;;
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t18, TrIntT20-TrIntT18
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t19, TrIntT21-TrIntT19
|
||
;;
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t20, TrIntT22-TrIntT20
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = t21, TrIntV0-TrIntT21
|
||
;;
|
||
.mem.offset 0,0
|
||
st8.spill [rpTF1] = t22, TrBrT0-TrIntT22
|
||
.mem.offset 8,0
|
||
st8.spill [rpTF2] = v0, TrBrT1-TrIntV0 // spill old V0
|
||
;;
|
||
|
||
st8 [rpTF1] = rL2, TrApCCV-TrBrT0 // save old bt0 - bt1
|
||
st8 [rpTF2] = rL3
|
||
;;
|
||
|
||
mov rL5 = ar.unat
|
||
st8 [rpTF1] = rL4, TrApDCR-TrApCCV // save ar.ccv
|
||
;;
|
||
|
||
st8 [rpTF1] = rL1 // save cr.dcr
|
||
add rpTF1 = TrFltT0, sp // point to FltT0
|
||
add rpTF2 = TrFltT1, sp // point to FltT1
|
||
;;
|
||
|
||
//
|
||
// Spill temporary (volatile) floating point registers
|
||
//
|
||
|
||
stf.spill [rpTF1] = ft0, TrFltT2-TrFltT0 // spill float tmp 0 - 9
|
||
stf.spill [rpTF2] = ft1, TrFltT3-TrFltT1
|
||
;;
|
||
stf.spill [rpTF1] = ft2, TrFltT4-TrFltT2
|
||
stf.spill [rpTF2] = ft3, TrFltT5-TrFltT3
|
||
;;
|
||
stf.spill [rpTF1] = ft4, TrFltT6-TrFltT4
|
||
stf.spill [rpTF2] = ft5, TrFltT7-TrFltT5
|
||
;;
|
||
stf.spill [rpTF1] = ft6, TrFltT8-TrFltT6
|
||
stf.spill [rpTF2] = ft7, TrFltT9-TrFltT7
|
||
add t20 = TrIntNats, sp
|
||
;;
|
||
stf.spill [rpTF1] = ft8
|
||
stf.spill [rpTF2] = ft9
|
||
;;
|
||
|
||
st8 [t20] = rL5 // save volatile iNats
|
||
LEAF_RETURN
|
||
;;
|
||
|
||
LEAF_EXIT(KiSaveTrapFrame)
|
||
|
||
//++
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// VOID
|
||
// KiRestoreTrapFrame(PKTRAP_FRAME)
|
||
//
|
||
// Description:
|
||
//
|
||
// Restore volatile application state from trap frame. Restore DCR
|
||
// Note: sp, brp, RSC, UNAT, predicates, BSP, BSP Store, PFS,
|
||
// DCR and FPSR not restored here.
|
||
//
|
||
// Input:
|
||
//
|
||
// sp: points to trap frame
|
||
// RSE frame size is zero
|
||
//
|
||
// Output:
|
||
//
|
||
// None
|
||
//
|
||
// Return value:
|
||
//
|
||
// none
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
LEAF_ENTRY(KiRestoreTrapFrame)
|
||
|
||
LEAF_SETUP(0,2,0,0)
|
||
|
||
rpTF1 = loc0
|
||
rpTF2 = loc1
|
||
|
||
mov t21 = psr
|
||
add t12 = TrIntNats, sp
|
||
add rpTF2 = TrApCCV, sp
|
||
;;
|
||
|
||
ld8 t0 = [t12], TrBrT0-TrIntNats
|
||
ld8 t1 = [rpTF2], TrBrT1-TrApCCV
|
||
add rpTF1 = TrFltT0, sp
|
||
;;
|
||
|
||
ld8 t2 = [t12], TrStFPSR-TrBrT0
|
||
ld8 t3 = [rpTF2], TrApDCR-TrBrT1
|
||
;;
|
||
|
||
ld8 t10 = [t12]
|
||
ld8 t11 = [rpTF2], TrFltT1-TrApDCR
|
||
;;
|
||
|
||
ldf.fill ft0 = [rpTF1], TrFltT2-TrFltT0
|
||
ldf.fill ft1 = [rpTF2], TrFltT3-TrFltT1
|
||
;;
|
||
|
||
mov ar.unat = t0
|
||
|
||
ldf.fill ft2 = [rpTF1], TrFltT4-TrFltT2
|
||
ldf.fill ft3 = [rpTF2], TrFltT5-TrFltT3
|
||
;;
|
||
|
||
ldf.fill ft4 = [rpTF1], TrFltT6-TrFltT4
|
||
ldf.fill ft5 = [rpTF2], TrFltT7-TrFltT5
|
||
;;
|
||
|
||
ldf.fill ft6 = [rpTF1], TrFltT8-TrFltT6
|
||
ldf.fill ft7 = [rpTF2], TrFltT9-TrFltT7
|
||
;;
|
||
|
||
ldf.fill ft8 = [rpTF1], TrIntGp-TrFltT8
|
||
ldf.fill ft9 = [rpTF2], TrIntT0-TrFltT9
|
||
;;
|
||
|
||
mov ar.ccv = t1
|
||
ld8.fill gp = [rpTF1], TrIntT1-TrIntGp
|
||
;;
|
||
|
||
ld8.fill t0 = [rpTF2], TrIntT2-TrIntT0
|
||
ld8.fill t1 = [rpTF1], TrIntT3-TrIntT1
|
||
mov bt0 = t2
|
||
;;
|
||
|
||
mov cr.dcr = t11
|
||
ld8.fill t2 = [rpTF2], TrIntT4-TrIntT2
|
||
mov bt1 = t3
|
||
;;
|
||
|
||
ld8.fill t3 = [rpTF1], TrIntT5-TrIntT3
|
||
tbit.z pt1 = t21, PSR_MFL
|
||
|
||
mov ar.fpsr = t10
|
||
ld8.fill t4 = [rpTF2], TrIntT6-TrIntT4
|
||
;;
|
||
|
||
ld8.fill t5 = [rpTF1], TrIntT7-TrIntT5
|
||
ld8.fill t6 = [rpTF2], TrIntT8-TrIntT6
|
||
;;
|
||
|
||
ld8.fill t7 = [rpTF1], TrIntT9-TrIntT7
|
||
ld8.fill t8 = [rpTF2], TrIntT10-TrIntT8
|
||
;;
|
||
|
||
ld8.fill t9 = [rpTF1], TrIntT11-TrIntT9
|
||
ld8.fill t10 = [rpTF2], TrIntT12-TrIntT10
|
||
;;
|
||
|
||
ld8.fill t11 = [rpTF1], TrIntT13-TrIntT11
|
||
ld8.fill t12 = [rpTF2], TrIntT14-TrIntT12
|
||
;;
|
||
|
||
ld8.fill t13 = [rpTF1], TrIntT15-TrIntT13
|
||
ld8.fill t14 = [rpTF2], TrIntT16-TrIntT14
|
||
;;
|
||
|
||
ld8.fill t15 = [rpTF1], TrIntT17-TrIntT15
|
||
ld8.fill t16 = [rpTF2], TrIntT18-TrIntT16
|
||
;;
|
||
|
||
ld8.fill t17 = [rpTF1], TrIntT19-TrIntT17
|
||
ld8.fill t18 = [rpTF2], TrIntT20-TrIntT18
|
||
;;
|
||
|
||
ld8.fill t19 = [rpTF1], TrIntT21-TrIntT19
|
||
ld8.fill t20 = [rpTF2], TrIntT22-TrIntT20
|
||
;;
|
||
|
||
ld8.fill t21 = [rpTF1], TrIntTeb-TrIntT21
|
||
ld8.fill t22 = [rpTF2], TrIntV0-TrIntT22
|
||
;;
|
||
|
||
ld8.fill teb = [rpTF1]
|
||
ld8.fill v0 = [rpTF2]
|
||
br.ret.sptk.many brp
|
||
;;
|
||
|
||
LEAF_EXIT(KiRestoreTrapFrame)
|
||
|
||
//++
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// VOID
|
||
// KiLoadKernelDebugRegisters
|
||
//
|
||
// Description:
|
||
//
|
||
// We maintain two debug register flags:
|
||
// 1. Thread DebugActive: Debug registers active for current thread
|
||
// 2. PCR KernelDebugActive: Debug registers active in kernel mode
|
||
// (setup by kernel debugger)
|
||
//
|
||
// On user -> kernel transitions there are four possibilities:
|
||
//
|
||
// Thread Kernel
|
||
// DebugActive DebugActive Action
|
||
//
|
||
// 1. 0 0 None
|
||
//
|
||
// 2. 1 0 None (kernel PSR.db = 0 by default)
|
||
//
|
||
// 3. 0 1 Set PSR.db = 1 for kernel
|
||
//
|
||
// 4. 1 1 Set PSR.db = 1 for kernel and
|
||
// load kernel debug registers
|
||
//
|
||
// Note we never save the user debug registers:
|
||
// the user cannot change the DRs so the values in the DR save area are
|
||
// always up-to-date (set by SetContext).
|
||
//
|
||
// Input:
|
||
//
|
||
// None (Previous mode is USER)
|
||
//
|
||
// Output:
|
||
//
|
||
// None
|
||
//
|
||
// Return value:
|
||
//
|
||
// none
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
NESTED_ENTRY(KiLoadKernelDebugRegisters)
|
||
PROLOGUE_BEGIN
|
||
|
||
movl t10 = KiPcr+PcPrcb
|
||
;;
|
||
|
||
ld8 t10 = [t10] // load prcb address
|
||
cmp.eq pt3, pt2 = r0, r0
|
||
;;
|
||
|
||
add t11 = PbProcessorState+KpsSpecialRegisters+KsKernelDbI0,t10
|
||
add t12 = PbProcessorState+KpsSpecialRegisters+KsKernelDbI1,t10
|
||
add t13 = PbProcessorState+KpsSpecialRegisters+KsKernelDbD0,t10
|
||
add t14 = PbProcessorState+KpsSpecialRegisters+KsKernelDbD1,t10
|
||
br Krdr_Common
|
||
;;
|
||
|
||
ALTERNATE_ENTRY(KiLoadUserDebugRegisters)
|
||
|
||
//
|
||
// Restore debug registers, if debug active
|
||
//
|
||
|
||
cmp.ne pt3, pt2 = r0, r0
|
||
movl t10 = KiPcr+PcCurrentThread
|
||
;;
|
||
|
||
ld8 t10 = [t10] // get current thread pointer
|
||
;;
|
||
add t10 = ThStackBase, t10
|
||
;;
|
||
|
||
ld8.nta t10 = [t10] // get stack base
|
||
;;
|
||
add t11 = -ThreadStateSaveAreaLength+TsDebugRegisters+DrDbI0,t10
|
||
add t12 = -ThreadStateSaveAreaLength+TsDebugRegisters+DrDbI1,t10
|
||
|
||
add t13 = -ThreadStateSaveAreaLength+TsDebugRegisters+DrDbD0,t10
|
||
add t14 = -ThreadStateSaveAreaLength+TsDebugRegisters+DrDbD1,t10
|
||
;;
|
||
|
||
|
||
Krdr_Common:
|
||
|
||
.regstk 0, 2, 2, 0
|
||
.save ar.pfs, savedpfs
|
||
alloc savedpfs = ar.pfs, 0, 2, 2, 0
|
||
.save b0, savedbrp
|
||
mov savedbrp = brp
|
||
|
||
.save ar.lc, t22
|
||
mov t22 = ar.lc // save ar.lc
|
||
mov t7 = 0
|
||
mov t8 = 1
|
||
|
||
PROLOGUE_END
|
||
|
||
mov ar.lc = 1 // 2 pairs of debug registers
|
||
;;
|
||
|
||
Krdr_Loop:
|
||
|
||
ld8 t1 = [t11], 16 // get dbr pair
|
||
ld8 t2 = [t12], 16 // step by 16 = 1 pair of DRs
|
||
|
||
ld8 t3 = [t13], 16 // get dbr pair
|
||
ld8 t4 = [t14], 16 // step by 16 = 1 pair of DRs
|
||
;;
|
||
|
||
.auto
|
||
mov ibr[t7] = t1 // restore ibr pair
|
||
mov ibr[t8] = t2
|
||
|
||
.auto
|
||
mov dbr[t7] = t3 // restore dbr pair
|
||
mov dbr[t8] = t4
|
||
;;
|
||
|
||
#ifndef NO_12241
|
||
srlz.d
|
||
#endif
|
||
|
||
.default
|
||
add t7 = 2, t7 // next pair
|
||
add t8 = 2, t8
|
||
br.cloop.sptk Krdr_Loop
|
||
;;
|
||
|
||
mov ar.lc = t22 // restore ar.lc
|
||
(pt2) br.ret.sptk brp // return if loading user
|
||
|
||
mov out0 = PSR_DB
|
||
mov out1 = 1
|
||
(pt3) br.call.spnt brp = KeSetLowPsrBit // set psr.db if loading kernel
|
||
;;
|
||
|
||
NESTED_RETURN
|
||
;;
|
||
|
||
NESTED_EXIT(KiLoadKernelDebugRegisters)
|
||
|
||
//++
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// VOID
|
||
// KiSaveExceptionFrame(PKEXCEPTION_FRAME)
|
||
//
|
||
// Description:
|
||
//
|
||
// Save preserved context in exception frame.
|
||
//
|
||
// Input:
|
||
//
|
||
// a0: points to exception frame
|
||
//
|
||
// Output:
|
||
//
|
||
// None
|
||
//
|
||
// Return value:
|
||
//
|
||
// none
|
||
//
|
||
// Note: t0 may contain the trap frame address; don't touch it.
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
LEAF_ENTRY(KiSaveExceptionFrame)
|
||
|
||
//
|
||
// Local register aliases
|
||
//
|
||
|
||
rpEF1 = t10
|
||
rpEF2 = t11
|
||
|
||
add rpEF1 = ExIntS0, a0 // -> ExIntS0
|
||
movl t12 = PFS_EC_MASK << PFS_EC_SHIFT
|
||
;;
|
||
|
||
add rpEF2 = ExIntS1, a0 // -> ExIntS1
|
||
mov t3 = ar.pfs
|
||
;;
|
||
and t3 = t3, t12
|
||
|
||
.mem.offset 0,0
|
||
st8.spill [rpEF1] = s0, ExIntS2-ExIntS0
|
||
.mem.offset 8,0
|
||
st8.spill [rpEF2] = s1, ExIntS3-ExIntS1
|
||
mov t4 = ar.lc
|
||
;;
|
||
|
||
.mem.offset 0,0
|
||
st8.spill [rpEF1] = s2, ExApEC-ExIntS2
|
||
.mem.offset 8,0
|
||
st8.spill [rpEF2] = s3, ExApLC-ExIntS3
|
||
mov t5 = bs0
|
||
;;
|
||
|
||
st8 [rpEF1] = t3, ExBrS0-ExApEC
|
||
st8 [rpEF2] = t4, ExBrS1-ExApLC
|
||
mov t6 = bs1
|
||
;;
|
||
|
||
mov t2 = ar.unat // save user nat register for
|
||
mov t7 = bs2
|
||
mov t8 = bs3
|
||
|
||
st8 [rpEF1] = t5, ExBrS2-ExBrS0
|
||
st8 [rpEF2] = t6, ExBrS3-ExBrS1
|
||
mov t9 = bs4
|
||
;;
|
||
|
||
st8 [rpEF1] = t7, ExBrS4-ExBrS2
|
||
st8 [rpEF2] = t8, ExIntNats-ExBrS3
|
||
;;
|
||
|
||
st8 [rpEF1] = t9, ExFltS0-ExBrS4
|
||
st8 [rpEF2] = t2, ExFltS1-ExIntNats
|
||
;;
|
||
|
||
stf.spill [rpEF1] = fs0, ExFltS2-ExFltS0
|
||
stf.spill [rpEF2] = fs1, ExFltS3-ExFltS1
|
||
;;
|
||
|
||
stf.spill [rpEF1] = fs2, ExFltS4-ExFltS2
|
||
stf.spill [rpEF2] = fs3, ExFltS5-ExFltS3
|
||
;;
|
||
|
||
stf.spill [rpEF1] = fs4, ExFltS6-ExFltS4
|
||
stf.spill [rpEF2] = fs5, ExFltS7-ExFltS5
|
||
;;
|
||
|
||
stf.spill [rpEF1] = fs6, ExFltS8-ExFltS6
|
||
stf.spill [rpEF2] = fs7, ExFltS9-ExFltS7
|
||
;;
|
||
|
||
stf.spill [rpEF1] = fs8, ExFltS10-ExFltS8
|
||
stf.spill [rpEF2] = fs9, ExFltS11-ExFltS9
|
||
;;
|
||
|
||
stf.spill [rpEF1] = fs10, ExFltS12-ExFltS10
|
||
stf.spill [rpEF2] = fs11, ExFltS13-ExFltS11
|
||
;;
|
||
|
||
stf.spill [rpEF1] = fs12, ExFltS14-ExFltS12
|
||
stf.spill [rpEF2] = fs13, ExFltS15-ExFltS13
|
||
;;
|
||
|
||
stf.spill [rpEF1] = fs14, ExFltS16-ExFltS14
|
||
stf.spill [rpEF2] = fs15, ExFltS17-ExFltS15
|
||
;;
|
||
|
||
stf.spill [rpEF1] = fs16, ExFltS18-ExFltS16
|
||
stf.spill [rpEF2] = fs17, ExFltS19-ExFltS17
|
||
;;
|
||
|
||
stf.spill [rpEF1] = fs18
|
||
stf.spill [rpEF2] = fs19
|
||
LEAF_RETURN
|
||
;;
|
||
|
||
LEAF_EXIT(KiSaveExceptionFrame)
|
||
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// VOID
|
||
// KiRestoreExceptionFrame(PKEXCEPTION_FRAME)
|
||
//
|
||
// Description:
|
||
//
|
||
// Restores preserved context from the exception frame. Also
|
||
// restore volatile part of floating point context not restored with
|
||
// rest of volatile context.
|
||
//
|
||
// Note: This routine does not use v0, t21 or t22. This routine's
|
||
// caller may be dependent on these registers (for performance
|
||
// in the context switch path).
|
||
//
|
||
// Input:
|
||
//
|
||
// a0: points to exception frame
|
||
//
|
||
// Output:
|
||
//
|
||
// None
|
||
//
|
||
// Return value:
|
||
//
|
||
// none
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
LEAF_ENTRY(KiRestoreExceptionFrame)
|
||
|
||
|
||
add t16 = ExIntNats, a0
|
||
movl t12 = PFS_EC_MASK << PFS_EC_SHIFT
|
||
|
||
add t17 = ExApEC, a0
|
||
nop.f 0
|
||
mov t13 = ar.pfs
|
||
;;
|
||
|
||
ld8.nta t2 = [t16], ExBrS0-ExIntNats
|
||
ld8.nta t3 = [t17], ExApLC-ExApEC
|
||
;;
|
||
|
||
ld8.nta t5 = [t16], ExBrS1-ExBrS0
|
||
ld8.nta t4 = [t17], ExBrS2-ExApLC
|
||
;;
|
||
|
||
ld8.nta t6 = [t16], ExBrS3-ExBrS1
|
||
ld8.nta t7 = [t17], ExBrS4-ExBrS2
|
||
;;
|
||
|
||
ld8.nta t8 = [t16], ExFltS0-ExBrS3
|
||
ld8.nta t9 = [t17], ExFltS1-ExBrS4
|
||
;;
|
||
|
||
ldf.fill.nta fs0 = [t16], ExFltS2-ExFltS0
|
||
ldf.fill.nta fs1 = [t17], ExFltS3-ExFltS1
|
||
add t18 = ExIntS0, a0
|
||
;;
|
||
|
||
ldf.fill.nta fs2 = [t16], ExFltS4-ExFltS2
|
||
ldf.fill.nta fs3 = [t17], ExFltS5-ExFltS3
|
||
add t19 = ExIntS1, a0
|
||
;;
|
||
|
||
ldf.fill.nta fs4 = [t16], ExFltS6-ExFltS4
|
||
ldf.fill.nta fs5 = [t17], ExFltS7-ExFltS5
|
||
andcm t13 = t13, t12 // zero out EC field
|
||
;;
|
||
|
||
ldf.fill.nta fs6 = [t16], ExFltS8-ExFltS6
|
||
ldf.fill.nta fs7 = [t17], ExFltS9-ExFltS7
|
||
and t3 = t3, t12 // capture EC value
|
||
;;
|
||
|
||
mov ar.unat = t2
|
||
or t13 = t3, t13 // deposit into PFS.EC field
|
||
;;
|
||
|
||
ldf.fill.nta fs8 = [t16], ExFltS10-ExFltS8
|
||
ldf.fill.nta fs9 = [t17], ExFltS11-ExFltS9
|
||
mov ar.pfs = t13
|
||
;;
|
||
|
||
ldf.fill.nta fs10 = [t16], ExFltS12-ExFltS10
|
||
ldf.fill.nta fs11 = [t17], ExFltS13-ExFltS11
|
||
mov ar.lc = t4
|
||
;;
|
||
|
||
ldf.fill.nta fs12 = [t16], ExFltS14-ExFltS12
|
||
ldf.fill.nta fs13 = [t17], ExFltS15-ExFltS13
|
||
mov bs0 = t5
|
||
;;
|
||
|
||
ldf.fill.nta fs14 = [t16], ExFltS16-ExFltS14
|
||
ldf.fill.nta fs15 = [t17], ExFltS17-ExFltS15
|
||
mov bs1 = t6
|
||
;;
|
||
|
||
ldf.fill.nta fs16 = [t16], ExFltS18-ExFltS16
|
||
ldf.fill.nta fs17 = [t17], ExFltS19-ExFltS17
|
||
mov bs2 = t7
|
||
;;
|
||
|
||
ldf.fill.nta fs18 = [t16]
|
||
ldf.fill.nta fs19 = [t17]
|
||
mov bs3 = t8
|
||
|
||
ld8.fill.nta s0 = [t18], ExIntS2-ExIntS0
|
||
ld8.fill.nta s1 = [t19], ExIntS3-ExIntS1
|
||
mov bs4 = t9
|
||
;;
|
||
|
||
ld8.fill.nta s2 = [t18]
|
||
ld8.fill.nta s3 = [t19]
|
||
LEAF_RETURN
|
||
;;
|
||
LEAF_EXIT(KiRestoreExceptionFrame)
|
||
|
||
//++
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiSaveHigherFPVolatile(PKHIGHER_FP_SAVEAREA)
|
||
//
|
||
// Description:
|
||
//
|
||
// Save higher FP volatile context in higher FP save area
|
||
//
|
||
// Input:
|
||
//
|
||
// a0: pointer to higher FP save area
|
||
// brp: return address
|
||
//
|
||
// Output:
|
||
//
|
||
// None
|
||
//
|
||
// Return value:
|
||
//
|
||
// None
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
NESTED_ENTRY(KiSaveHigherFPVolatile)
|
||
NESTED_SETUP(1, 3, 1, 0)
|
||
PROLOGUE_END
|
||
|
||
//
|
||
// Local register aliases
|
||
//
|
||
|
||
rpSA1 = t0
|
||
rpSA2 = t1
|
||
|
||
//
|
||
// Clear DFH bit so the high floating point set may be saved by the kernel
|
||
// Disable interrupts so that save is atomic
|
||
//
|
||
|
||
GET_IRQL (loc2)
|
||
mov t2 = psr.um
|
||
movl t3 = KiPcr+PcCurrentThread
|
||
;;
|
||
|
||
cmp.ge pt2, pt3 = APC_LEVEL, loc2
|
||
;;
|
||
PSET_IRQL (pt2, DISPATCH_LEVEL)
|
||
|
||
ld8 t4 = [t3], PcHighFpOwner-PcCurrentThread
|
||
;;
|
||
ld8 t5 = [t3]
|
||
;;
|
||
|
||
cmp.ne pt1 = t4, t5
|
||
(pt1) br.cond.spnt Kshfpv20
|
||
;;
|
||
|
||
tbit.z pt0 = t2, PSR_MFH
|
||
(pt0) br.cond.spnt Kshfpv20
|
||
br Kshfpv10
|
||
;;
|
||
|
||
ALTERNATE_ENTRY(KiSaveHigherFPVolatileAtDispatchLevel)
|
||
|
||
NESTED_SETUP(1, 3, 1, 0)
|
||
cmp.ne pt2, pt3 = r0, r0 // set pt2 to FALSE, pt3 to TRUE
|
||
|
||
PROLOGUE_END
|
||
|
||
movl t3 = KiPcr+PcCurrentThread
|
||
;;
|
||
ld8 t4 = [t3], PcHighFpOwner-PcCurrentThread
|
||
;;
|
||
ld8 t5 = [t3]
|
||
;;
|
||
cmp.ne pt1 = t4, t5
|
||
;;
|
||
(pt1) break.i BREAKPOINT_STOP
|
||
|
||
Kshfpv10:
|
||
|
||
rsm (1 << PSR_DFH)
|
||
add rpSA1 = HiFltF32, a0 // -> HiFltF32
|
||
add rpSA2 = HiFltF33, a0 // -> HiFltF33
|
||
;;
|
||
srlz.d
|
||
|
||
stf.spill.nta [rpSA1] = f32, HiFltF34-HiFltF32
|
||
stf.spill.nta [rpSA2] = f33, HiFltF35-HiFltF33
|
||
;;
|
||
stf.spill.nta [rpSA1] = f34, HiFltF36-HiFltF34
|
||
stf.spill.nta [rpSA2] = f35, HiFltF37-HiFltF35
|
||
;;
|
||
stf.spill.nta [rpSA1] = f36, HiFltF38-HiFltF36
|
||
stf.spill.nta [rpSA2] = f37, HiFltF39-HiFltF37
|
||
;;
|
||
stf.spill.nta [rpSA1] = f38, HiFltF40-HiFltF38
|
||
stf.spill.nta [rpSA2] = f39, HiFltF41-HiFltF39
|
||
;;
|
||
|
||
stf.spill.nta [rpSA1] = f40, HiFltF42-HiFltF40
|
||
stf.spill.nta [rpSA2] = f41, HiFltF43-HiFltF41
|
||
;;
|
||
stf.spill.nta [rpSA1] = f42, HiFltF44-HiFltF42
|
||
stf.spill.nta [rpSA2] = f43, HiFltF45-HiFltF43
|
||
;;
|
||
stf.spill.nta [rpSA1] = f44, HiFltF46-HiFltF44
|
||
stf.spill.nta [rpSA2] = f45, HiFltF47-HiFltF45
|
||
;;
|
||
stf.spill.nta [rpSA1] = f46, HiFltF48-HiFltF46
|
||
stf.spill.nta [rpSA2] = f47, HiFltF49-HiFltF47
|
||
;;
|
||
stf.spill.nta [rpSA1] = f48, HiFltF50-HiFltF48
|
||
stf.spill.nta [rpSA2] = f49, HiFltF51-HiFltF49
|
||
;;
|
||
|
||
stf.spill.nta [rpSA1] = f50, HiFltF52-HiFltF50
|
||
stf.spill.nta [rpSA2] = f51, HiFltF53-HiFltF51
|
||
;;
|
||
stf.spill.nta [rpSA1] = f52, HiFltF54-HiFltF52
|
||
stf.spill.nta [rpSA2] = f53, HiFltF55-HiFltF53
|
||
;;
|
||
stf.spill.nta [rpSA1] = f54, HiFltF56-HiFltF54
|
||
stf.spill.nta [rpSA2] = f55, HiFltF57-HiFltF55
|
||
;;
|
||
stf.spill.nta [rpSA1] = f56, HiFltF58-HiFltF56
|
||
stf.spill.nta [rpSA2] = f57, HiFltF59-HiFltF57
|
||
;;
|
||
stf.spill.nta [rpSA1] = f58, HiFltF60-HiFltF58
|
||
stf.spill.nta [rpSA2] = f59, HiFltF61-HiFltF59
|
||
;;
|
||
|
||
stf.spill.nta [rpSA1] = f60, HiFltF62-HiFltF60
|
||
stf.spill.nta [rpSA2] = f61, HiFltF63-HiFltF61
|
||
;;
|
||
stf.spill.nta [rpSA1] = f62, HiFltF64-HiFltF62
|
||
stf.spill.nta [rpSA2] = f63, HiFltF65-HiFltF63
|
||
;;
|
||
stf.spill.nta [rpSA1] = f64, HiFltF66-HiFltF64
|
||
stf.spill.nta [rpSA2] = f65, HiFltF67-HiFltF65
|
||
;;
|
||
stf.spill.nta [rpSA1] = f66, HiFltF68-HiFltF66
|
||
stf.spill.nta [rpSA2] = f67, HiFltF69-HiFltF67
|
||
;;
|
||
stf.spill.nta [rpSA1] = f68, HiFltF70-HiFltF68
|
||
stf.spill.nta [rpSA2] = f69, HiFltF71-HiFltF69
|
||
;;
|
||
|
||
stf.spill.nta [rpSA1] = f70, HiFltF72-HiFltF70
|
||
stf.spill.nta [rpSA2] = f71, HiFltF73-HiFltF71
|
||
;;
|
||
stf.spill.nta [rpSA1] = f72, HiFltF74-HiFltF72
|
||
stf.spill.nta [rpSA2] = f73, HiFltF75-HiFltF73
|
||
;;
|
||
stf.spill.nta [rpSA1] = f74, HiFltF76-HiFltF74
|
||
stf.spill.nta [rpSA2] = f75, HiFltF77-HiFltF75
|
||
;;
|
||
stf.spill.nta [rpSA1] = f76, HiFltF78-HiFltF76
|
||
stf.spill.nta [rpSA2] = f77, HiFltF79-HiFltF77
|
||
;;
|
||
stf.spill.nta [rpSA1] = f78, HiFltF80-HiFltF78
|
||
stf.spill.nta [rpSA2] = f79, HiFltF81-HiFltF79
|
||
;;
|
||
|
||
stf.spill.nta [rpSA1] = f80, HiFltF82-HiFltF80
|
||
stf.spill.nta [rpSA2] = f81, HiFltF83-HiFltF81
|
||
;;
|
||
stf.spill.nta [rpSA1] = f82, HiFltF84-HiFltF82
|
||
stf.spill.nta [rpSA2] = f83, HiFltF85-HiFltF83
|
||
;;
|
||
stf.spill.nta [rpSA1] = f84, HiFltF86-HiFltF84
|
||
stf.spill.nta [rpSA2] = f85, HiFltF87-HiFltF85
|
||
;;
|
||
stf.spill.nta [rpSA1] = f86, HiFltF88-HiFltF86
|
||
stf.spill.nta [rpSA2] = f87, HiFltF89-HiFltF87
|
||
;;
|
||
stf.spill.nta [rpSA1] = f88, HiFltF90-HiFltF88
|
||
stf.spill.nta [rpSA2] = f89, HiFltF91-HiFltF89
|
||
;;
|
||
|
||
stf.spill.nta [rpSA1] = f90, HiFltF92-HiFltF90
|
||
stf.spill.nta [rpSA2] = f91, HiFltF93-HiFltF91
|
||
;;
|
||
stf.spill.nta [rpSA1] = f92, HiFltF94-HiFltF92
|
||
stf.spill.nta [rpSA2] = f93, HiFltF95-HiFltF93
|
||
;;
|
||
stf.spill.nta [rpSA1] = f94, HiFltF96-HiFltF94
|
||
stf.spill.nta [rpSA2] = f95, HiFltF97-HiFltF95
|
||
;;
|
||
stf.spill.nta [rpSA1] = f96, HiFltF98-HiFltF96
|
||
stf.spill.nta [rpSA2] = f97, HiFltF99-HiFltF97
|
||
;;
|
||
stf.spill.nta [rpSA1] = f98, HiFltF100-HiFltF98
|
||
stf.spill.nta [rpSA2] = f99, HiFltF101-HiFltF99
|
||
;;
|
||
|
||
stf.spill.nta [rpSA1] = f100, HiFltF102-HiFltF100
|
||
stf.spill.nta [rpSA2] = f101, HiFltF103-HiFltF101
|
||
;;
|
||
stf.spill.nta [rpSA1] = f102, HiFltF104-HiFltF102
|
||
stf.spill.nta [rpSA2] = f103, HiFltF105-HiFltF103
|
||
;;
|
||
stf.spill.nta [rpSA1] = f104, HiFltF106-HiFltF104
|
||
stf.spill.nta [rpSA2] = f105, HiFltF107-HiFltF105
|
||
;;
|
||
stf.spill.nta [rpSA1] = f106, HiFltF108-HiFltF106
|
||
stf.spill.nta [rpSA2] = f107, HiFltF109-HiFltF107
|
||
;;
|
||
stf.spill.nta [rpSA1] = f108, HiFltF110-HiFltF108
|
||
stf.spill.nta [rpSA2] = f109, HiFltF111-HiFltF109
|
||
;;
|
||
|
||
stf.spill.nta [rpSA1] = f110, HiFltF112-HiFltF110
|
||
stf.spill.nta [rpSA2] = f111, HiFltF113-HiFltF111
|
||
;;
|
||
stf.spill.nta [rpSA1] = f112, HiFltF114-HiFltF112
|
||
stf.spill.nta [rpSA2] = f113, HiFltF115-HiFltF113
|
||
;;
|
||
stf.spill.nta [rpSA1] = f114, HiFltF116-HiFltF114
|
||
stf.spill.nta [rpSA2] = f115, HiFltF117-HiFltF115
|
||
;;
|
||
stf.spill.nta [rpSA1] = f116, HiFltF118-HiFltF116
|
||
stf.spill.nta [rpSA2] = f117, HiFltF119-HiFltF117
|
||
;;
|
||
stf.spill.nta [rpSA1] = f118, HiFltF120-HiFltF118
|
||
stf.spill.nta [rpSA2] = f119, HiFltF121-HiFltF119
|
||
;;
|
||
|
||
stf.spill.nta [rpSA1] = f120, HiFltF122-HiFltF120
|
||
stf.spill.nta [rpSA2] = f121, HiFltF123-HiFltF121
|
||
;;
|
||
stf.spill.nta [rpSA1] = f122, HiFltF124-HiFltF122
|
||
stf.spill.nta [rpSA2] = f123, HiFltF125-HiFltF123
|
||
;;
|
||
stf.spill.nta [rpSA1] = f124, HiFltF126-HiFltF124
|
||
stf.spill.nta [rpSA2] = f125, HiFltF127-HiFltF125
|
||
;;
|
||
stf.spill.nta [rpSA1] = f126
|
||
stf.spill.nta [rpSA2] = f127
|
||
|
||
//
|
||
// Set DFH bit so the high floating point set may not be used by the kernel
|
||
// Must clear mfh after fp registers saved
|
||
//
|
||
|
||
Kshfpv20:
|
||
ssm 1 << PSR_DFH
|
||
;;
|
||
rum 1 << PSR_MFH
|
||
(pt3) br.ret.sptk brp
|
||
|
||
LOWER_IRQL(loc2)
|
||
|
||
NESTED_RETURN
|
||
;;
|
||
|
||
LEAF_EXIT(KiSaveHigherFPVolatile)
|
||
|
||
//++
|
||
//--------------------------------------------------------------------
|
||
// Routine:
|
||
//
|
||
// KiRestoreHigherFPVolatile()
|
||
//
|
||
// Description:
|
||
//
|
||
// Restore higher FP volatile context from higher FP save area
|
||
//
|
||
// N.B. This function is carefully constructed to use only scratch
|
||
// registers rHpT1, rHpT3, and rTH2. This function may be
|
||
// called by C code and the disabled fp vector when user
|
||
// and kernel bank is used respectively.
|
||
// N.B. Caller must ensure higher fp enabled (psr.dfh=0)
|
||
// N.B. Caller must ensure no interrupt during restore
|
||
//
|
||
// Input:
|
||
//
|
||
// None.
|
||
//
|
||
// Output:
|
||
//
|
||
// None
|
||
//
|
||
// Return value:
|
||
//
|
||
// None
|
||
//
|
||
//--------------------------------------------------------------------
|
||
|
||
LEAF_ENTRY(KiRestoreHigherFPVolatile)
|
||
|
||
movl rHpT1 = KiPcr+PcCurrentThread
|
||
;;
|
||
|
||
ld8 rHpT3 = [rHpT1], PcHighFpOwner-PcCurrentThread
|
||
;;
|
||
st8 [rHpT1] = rHpT3, PcNumber-PcHighFpOwner
|
||
add rHpT3 = ThNumber, rHpT3
|
||
;;
|
||
|
||
ld1 rHpT1 = [rHpT1] // load processor #
|
||
;;
|
||
st1 [rHpT3] = rHpT1 // save it in Thread->Number
|
||
add rHpT3 = ThStackBase-ThNumber, rHpT3
|
||
;;
|
||
|
||
ld8 rHpT3 = [rHpT3] // load kernel stack base
|
||
;;
|
||
|
||
add rHpT1 = -ThreadStateSaveAreaLength+TsHigherFPVolatile+HiFltF32, rHpT3
|
||
add rHpT3 = -ThreadStateSaveAreaLength+TsHigherFPVolatile+HiFltF33, rHpT3
|
||
;;
|
||
|
||
ldf.fill.nta f32 = [rHpT1], HiFltF34-HiFltF32
|
||
ldf.fill.nta f33 = [rHpT3], HiFltF35-HiFltF33
|
||
;;
|
||
|
||
ldf.fill.nta f34 = [rHpT1], HiFltF36-HiFltF34
|
||
ldf.fill.nta f35 = [rHpT3], HiFltF37-HiFltF35
|
||
;;
|
||
ldf.fill.nta f36 = [rHpT1], HiFltF38-HiFltF36
|
||
ldf.fill.nta f37 = [rHpT3], HiFltF39-HiFltF37
|
||
;;
|
||
ldf.fill.nta f38 = [rHpT1], HiFltF40-HiFltF38
|
||
ldf.fill.nta f39 = [rHpT3], HiFltF41-HiFltF39
|
||
;;
|
||
|
||
ldf.fill.nta f40 = [rHpT1], HiFltF42-HiFltF40
|
||
ldf.fill.nta f41 = [rHpT3], HiFltF43-HiFltF41
|
||
;;
|
||
ldf.fill.nta f42 = [rHpT1], HiFltF44-HiFltF42
|
||
ldf.fill.nta f43 = [rHpT3], HiFltF45-HiFltF43
|
||
;;
|
||
ldf.fill.nta f44 = [rHpT1], HiFltF46-HiFltF44
|
||
ldf.fill.nta f45 = [rHpT3], HiFltF47-HiFltF45
|
||
;;
|
||
ldf.fill.nta f46 = [rHpT1], HiFltF48-HiFltF46
|
||
ldf.fill.nta f47 = [rHpT3], HiFltF49-HiFltF47
|
||
;;
|
||
ldf.fill.nta f48 = [rHpT1], HiFltF50-HiFltF48
|
||
ldf.fill.nta f49 = [rHpT3], HiFltF51-HiFltF49
|
||
;;
|
||
|
||
ldf.fill.nta f50 = [rHpT1], HiFltF52-HiFltF50
|
||
ldf.fill.nta f51 = [rHpT3], HiFltF53-HiFltF51
|
||
;;
|
||
ldf.fill.nta f52 = [rHpT1], HiFltF54-HiFltF52
|
||
ldf.fill.nta f53 = [rHpT3], HiFltF55-HiFltF53
|
||
;;
|
||
ldf.fill.nta f54 = [rHpT1], HiFltF56-HiFltF54
|
||
ldf.fill.nta f55 = [rHpT3], HiFltF57-HiFltF55
|
||
;;
|
||
ldf.fill.nta f56 = [rHpT1], HiFltF58-HiFltF56
|
||
ldf.fill.nta f57 = [rHpT3], HiFltF59-HiFltF57
|
||
;;
|
||
ldf.fill.nta f58 = [rHpT1], HiFltF60-HiFltF58
|
||
ldf.fill.nta f59 = [rHpT3], HiFltF61-HiFltF59
|
||
;;
|
||
|
||
ldf.fill.nta f60 = [rHpT1], HiFltF62-HiFltF60
|
||
ldf.fill.nta f61 = [rHpT3], HiFltF63-HiFltF61
|
||
;;
|
||
ldf.fill.nta f62 = [rHpT1], HiFltF64-HiFltF62
|
||
ldf.fill.nta f63 = [rHpT3], HiFltF65-HiFltF63
|
||
;;
|
||
ldf.fill.nta f64 = [rHpT1], HiFltF66-HiFltF64
|
||
ldf.fill.nta f65 = [rHpT3], HiFltF67-HiFltF65
|
||
;;
|
||
ldf.fill.nta f66 = [rHpT1], HiFltF68-HiFltF66
|
||
ldf.fill.nta f67 = [rHpT3], HiFltF69-HiFltF67
|
||
;;
|
||
ldf.fill.nta f68 = [rHpT1], HiFltF70-HiFltF68
|
||
ldf.fill.nta f69 = [rHpT3], HiFltF71-HiFltF69
|
||
;;
|
||
|
||
ldf.fill.nta f70 = [rHpT1], HiFltF72-HiFltF70
|
||
ldf.fill.nta f71 = [rHpT3], HiFltF73-HiFltF71
|
||
;;
|
||
ldf.fill.nta f72 = [rHpT1], HiFltF74-HiFltF72
|
||
ldf.fill.nta f73 = [rHpT3], HiFltF75-HiFltF73
|
||
;;
|
||
ldf.fill.nta f74 = [rHpT1], HiFltF76-HiFltF74
|
||
ldf.fill.nta f75 = [rHpT3], HiFltF77-HiFltF75
|
||
;;
|
||
ldf.fill.nta f76 = [rHpT1], HiFltF78-HiFltF76
|
||
ldf.fill.nta f77 = [rHpT3], HiFltF79-HiFltF77
|
||
;;
|
||
ldf.fill.nta f78 = [rHpT1], HiFltF80-HiFltF78
|
||
ldf.fill.nta f79 = [rHpT3], HiFltF81-HiFltF79
|
||
;;
|
||
|
||
ldf.fill.nta f80 = [rHpT1], HiFltF82-HiFltF80
|
||
ldf.fill.nta f81 = [rHpT3], HiFltF83-HiFltF81
|
||
;;
|
||
ldf.fill.nta f82 = [rHpT1], HiFltF84-HiFltF82
|
||
ldf.fill.nta f83 = [rHpT3], HiFltF85-HiFltF83
|
||
;;
|
||
ldf.fill.nta f84 = [rHpT1], HiFltF86-HiFltF84
|
||
ldf.fill.nta f85 = [rHpT3], HiFltF87-HiFltF85
|
||
;;
|
||
ldf.fill.nta f86 = [rHpT1], HiFltF88-HiFltF86
|
||
ldf.fill.nta f87 = [rHpT3], HiFltF89-HiFltF87
|
||
;;
|
||
ldf.fill.nta f88 = [rHpT1], HiFltF90-HiFltF88
|
||
ldf.fill.nta f89 = [rHpT3], HiFltF91-HiFltF89
|
||
;;
|
||
|
||
ldf.fill.nta f90 = [rHpT1], HiFltF92-HiFltF90
|
||
ldf.fill.nta f91 = [rHpT3], HiFltF93-HiFltF91
|
||
;;
|
||
ldf.fill.nta f92 = [rHpT1], HiFltF94-HiFltF92
|
||
ldf.fill.nta f93 = [rHpT3], HiFltF95-HiFltF93
|
||
;;
|
||
ldf.fill.nta f94 = [rHpT1], HiFltF96-HiFltF94
|
||
ldf.fill.nta f95 = [rHpT3], HiFltF97-HiFltF95
|
||
;;
|
||
ldf.fill.nta f96 = [rHpT1], HiFltF98-HiFltF96
|
||
ldf.fill.nta f97 = [rHpT3], HiFltF99-HiFltF97
|
||
;;
|
||
ldf.fill.nta f98 = [rHpT1], HiFltF100-HiFltF98
|
||
ldf.fill.nta f99 = [rHpT3], HiFltF101-HiFltF99
|
||
;;
|
||
|
||
ldf.fill.nta f100 = [rHpT1], HiFltF102-HiFltF100
|
||
ldf.fill.nta f101 = [rHpT3], HiFltF103-HiFltF101
|
||
;;
|
||
ldf.fill.nta f102 = [rHpT1], HiFltF104-HiFltF102
|
||
ldf.fill.nta f103 = [rHpT3], HiFltF105-HiFltF103
|
||
;;
|
||
ldf.fill.nta f104 = [rHpT1], HiFltF106-HiFltF104
|
||
ldf.fill.nta f105 = [rHpT3], HiFltF107-HiFltF105
|
||
;;
|
||
ldf.fill.nta f106 = [rHpT1], HiFltF108-HiFltF106
|
||
ldf.fill.nta f107 = [rHpT3], HiFltF109-HiFltF107
|
||
;;
|
||
ldf.fill.nta f108 = [rHpT1], HiFltF110-HiFltF108
|
||
ldf.fill.nta f109 = [rHpT3], HiFltF111-HiFltF109
|
||
;;
|
||
|
||
ldf.fill.nta f110 = [rHpT1], HiFltF112-HiFltF110
|
||
ldf.fill.nta f111 = [rHpT3], HiFltF113-HiFltF111
|
||
;;
|
||
ldf.fill.nta f112 = [rHpT1], HiFltF114-HiFltF112
|
||
ldf.fill.nta f113 = [rHpT3], HiFltF115-HiFltF113
|
||
;;
|
||
ldf.fill.nta f114 = [rHpT1], HiFltF116-HiFltF114
|
||
ldf.fill.nta f115 = [rHpT3], HiFltF117-HiFltF115
|
||
;;
|
||
ldf.fill.nta f116 = [rHpT1], HiFltF118-HiFltF116
|
||
ldf.fill.nta f117 = [rHpT3], HiFltF119-HiFltF117
|
||
;;
|
||
ldf.fill.nta f118 = [rHpT1], HiFltF120-HiFltF118
|
||
ldf.fill.nta f119 = [rHpT3], HiFltF121-HiFltF119
|
||
;;
|
||
|
||
ldf.fill.nta f120 = [rHpT1], HiFltF122-HiFltF120
|
||
ldf.fill.nta f121 = [rHpT3], HiFltF123-HiFltF121
|
||
;;
|
||
ldf.fill.nta f122 = [rHpT1], HiFltF124-HiFltF122
|
||
ldf.fill.nta f123 = [rHpT3], HiFltF125-HiFltF123
|
||
;;
|
||
ldf.fill.nta f124 = [rHpT1], HiFltF126-HiFltF124
|
||
ldf.fill.nta f125 = [rHpT3], HiFltF127-HiFltF125
|
||
;;
|
||
ldf.fill.nta f126 = [rHpT1]
|
||
ldf.fill.nta f127 = [rHpT3]
|
||
;;
|
||
|
||
rsm 1 << PSR_MFH // clear psr.mfh bit
|
||
br.ret.sptk brp
|
||
;;
|
||
|
||
LEAF_EXIT(KiRestoreHigherFPVolatile)
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// KiPageTableFault
|
||
//
|
||
// Description:
|
||
//
|
||
// Branched from Inst/DataTlbVector
|
||
// Inserts a missing PDE translation for VHPT mapping
|
||
// If PageNotPresent-bit of PDE is not set,
|
||
// branchs out to KiPdeNotPresentFault
|
||
//
|
||
// On entry:
|
||
//
|
||
// rva (h24) : offending virtual address
|
||
// riha (h25) : a offending PTE address
|
||
// rpr: (h26) : saved predicate
|
||
//
|
||
// Handle:
|
||
//
|
||
// Extracts the PDE index from riha (PTE address in VHPT) and
|
||
// generates a PDE address by adding to VHPT_DIRBASE. When accesses
|
||
// a page directory entry (PDE), there might be a TLB miss on the
|
||
// page directory table and returns a NaT on ld8.s. If so, branches
|
||
// to KiPageDirectoryTableFault. If the page-not-present bit of the
|
||
// PDE is not set, branches to KiPageNotPresentFault. Otherwise,
|
||
// inserts the PDE entry into the data TC (translation cache).
|
||
//
|
||
// Notes:
|
||
//
|
||
//
|
||
// --
|
||
|
||
HANDLER_ENTRY(KiPageTableFault)
|
||
|
||
rva = h24
|
||
riha = h25
|
||
rpr = h26
|
||
rpPde = h27
|
||
rPde = h28
|
||
rPde2 = h29
|
||
rps = h30
|
||
|
||
thash rpPde = riha // M
|
||
cmp.ne pt1 = r0, r0
|
||
mov rps = PAGE_SHIFT << PS_SHIFT // I
|
||
;;
|
||
|
||
mov cr.itir = rps // M
|
||
ld8.s rPde = [rpPde] // M, load PDE
|
||
;;
|
||
|
||
tnat.nz pt0, p0 = rPde // I
|
||
tbit.z.or pt1, p0 = rPde, PTE_ACCESS
|
||
tbit.z.or pt1, p0 = rPde, PTE_VALID // I, if non-present page fault
|
||
|
||
(pt0) br.cond.spnt KiPageDirectoryFault // B, tb miss on PDE access
|
||
(pt1) br.cond.spnt KiPdeNotPresentFault // B, page fault
|
||
;;
|
||
|
||
mov cr.ifa = riha // M
|
||
;;
|
||
itc.d rPde // M
|
||
;;
|
||
|
||
#if !defined(NT_UP)
|
||
ld8.s rPde2 = [rpPde] // M
|
||
cmp.ne pt0 = zero, zero // I
|
||
;;
|
||
|
||
cmp.ne.or pt0, p0 = rPde2, rPde // I, if PTEs are different
|
||
tnat.nz.or pt0, p0 = rPde2 // I
|
||
|
||
;;
|
||
(pt0) ptc.l riha, rps // M, purge it
|
||
|
||
#endif
|
||
mov pr = rpr, -1 // I
|
||
rfi;; // B
|
||
|
||
HANDLER_EXIT(KiPageTableFault)
|
||
|
||
|
||
|
||
//++
|
||
//
|
||
// KiPageDirectoryFault
|
||
//
|
||
// Cause:
|
||
//
|
||
// Parameters:
|
||
// rpPde (h28) : pointer to PDE entry
|
||
// rpr (h26) : saved predicate
|
||
//
|
||
//
|
||
// Handle:
|
||
//
|
||
//--
|
||
HANDLER_ENTRY(KiPageDirectoryFault)
|
||
|
||
rva = h24
|
||
rpPpe = h25
|
||
rpr = h26
|
||
rpPde = h27
|
||
rPpe = h28
|
||
rPpe2 = h29
|
||
rps = h30
|
||
|
||
thash rpPpe = rpPde // M
|
||
cmp.ne pt1 = r0, r0
|
||
;;
|
||
|
||
ld8.s rPpe = [rpPpe] // M
|
||
;;
|
||
|
||
tnat.nz pt0, p0 = rPpe // I
|
||
tbit.z.or pt1, p0 = rPpe, PTE_ACCESS
|
||
tbit.z.or pt1, p0 = rPpe, PTE_VALID // I, if non-present page fault
|
||
|
||
(pt0) br.cond.spnt KiPageFault // B
|
||
(pt1) br.cond.spnt KiPdeNotPresentFault // B
|
||
;;
|
||
|
||
mov cr.ifa = rpPde // M, set tva for vhpt translation
|
||
;;
|
||
itc.d rPpe // M
|
||
;;
|
||
|
||
#if !defined(NT_UP)
|
||
ld8.s rPpe2 = [rpPpe] // M
|
||
mov rps = PAGE_SHIFT << PS_SHIFT // I
|
||
cmp.ne pt0 = zero, zero // I
|
||
;;
|
||
|
||
cmp.ne.or pt0, p0 = rPpe2, rPpe // I, if PTEs are different
|
||
tnat.nz.or pt0, p0 = rPpe2 // I
|
||
|
||
;;
|
||
(pt0) ptc.l rpPde, rps // M, purge it
|
||
|
||
#endif
|
||
mov pr = rpr, -1 // I
|
||
rfi;; // B
|
||
|
||
|
||
HANDLER_EXIT(KiPageDirectoryFault)
|
||
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// KiPteNotPresentFault
|
||
//
|
||
// Description:
|
||
//
|
||
// Branched from KiVhptTransVector and KiPageTableFault.
|
||
// Inserts a missing PDE translation for VHPT mapping
|
||
// If no PDE for it, branchs out to KiPageFault
|
||
//
|
||
// On entry:
|
||
//
|
||
// rva (h24) : offending virtual address
|
||
// rpr (h26) : saved predicate
|
||
// rPde (h28) : PDE entry
|
||
//
|
||
// Handle:
|
||
//
|
||
// Check to see if PDE is marked as LARGE_PAGE. If so,
|
||
// make it valid and install the large page size PTE.
|
||
// If not, branch to KiPageFault.
|
||
//
|
||
//
|
||
// Notes:
|
||
//
|
||
// PCR page mapped with TR
|
||
// --
|
||
|
||
HANDLER_ENTRY(KiPteNotPresentFault)
|
||
|
||
rva = h24 // passed
|
||
riha = h25 // passed
|
||
rpr = h26 // passed
|
||
rps = h27
|
||
|
||
rPfn = h28
|
||
rpAte = h28
|
||
rAte = h29
|
||
rAteEnd = h30
|
||
rAteBase = h31
|
||
rAteMask = h22
|
||
|
||
rK0Base = h31
|
||
rK2Base = h30
|
||
|
||
pIndr = pt1
|
||
|
||
mov rps = PS_4K << PS_SHIFT // M
|
||
movl rK0Base = KSEG0_BASE // L
|
||
;;
|
||
|
||
cmp.geu pt3, p0 = rva, rK0Base // M
|
||
movl rK2Base = KSEG2_BASE // L
|
||
;;
|
||
|
||
(pt3) cmp.ltu pt3, p0 = rva, rK2Base // M
|
||
movl rAteBase = ALT4KB_BASE // L
|
||
;;
|
||
|
||
shr.u rPfn = rva, PAGE4K_SHIFT // I
|
||
(pt3) br.cond.spnt KiKseg0Fault // B
|
||
;;
|
||
|
||
mov rAteMask = ATE_MASK0 // I
|
||
|
||
shladd rpAte = rPfn, PTE_SHIFT, rAteBase // M
|
||
movl rAteEnd = ALT4KB_END // L
|
||
;;
|
||
|
||
ld8.s rAte = [rpAte] // M
|
||
andcm rAteMask = -1, rAteMask // I
|
||
cmp.ltu pIndr = rpAte, rAteEnd // I
|
||
;;
|
||
tnat.z.and pIndr = rAte // I
|
||
tbit.nz.and pIndr = rAte, PTE_VALID // I
|
||
|
||
or rAteMask = rAte, rAteMask // M
|
||
tbit.nz.and pIndr = rAte, PTE_ACCESS // I
|
||
tbit.nz.and pIndr = rAte, ATE_INDIRECT // I
|
||
|
||
|
||
(pIndr) br.cond.spnt KiPteIndirectFault
|
||
;;
|
||
ptc.l rva, rps // M
|
||
|
||
br.sptk KiPageFault // B
|
||
|
||
HANDLER_EXIT(KiPteNotPresentFault)
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// KiPdeNotPresentFault
|
||
//
|
||
// Description:
|
||
//
|
||
// Branched from KiVhptTransVector and KiPageTableFault.
|
||
// Inserts a missing PDE translation for VHPT mapping
|
||
// If no PDE for it, branchs out to KiPageFault
|
||
//
|
||
// On entry:
|
||
//
|
||
// rva (h24) : offending virtual address
|
||
// rpr (h26) : saved predicate
|
||
// rPde (h28) : PDE entry
|
||
//
|
||
// Handle:
|
||
//
|
||
// Check to see if PDE is marked as LARGE_PAGE. If so,
|
||
// make it valid and install the large page size PTE.
|
||
// If not, branch to KiPageFault.
|
||
//
|
||
//
|
||
// Notes:
|
||
//
|
||
// PCR page mapped with TR
|
||
// --
|
||
|
||
HANDLER_ENTRY(KiPdeNotPresentFault)
|
||
|
||
br.sptk KiPageFault
|
||
|
||
#if 0
|
||
rva = h24
|
||
rK0Base = h25
|
||
rpr = h26
|
||
rK2Base = h27
|
||
rPde = h28
|
||
ridtr = h29
|
||
rps = h30
|
||
rPte = h25
|
||
|
||
movl rK0Base = KSEG0_BASE
|
||
;;
|
||
|
||
cmp.ltu pt3, pt4 = rva, rK0Base
|
||
movl rK2Base = KSEG2_BASE
|
||
;;
|
||
|
||
(pt4) cmp.geu pt3, p0 = rva, rK2Base
|
||
(pt3) br.cond.spnt KiPageFault
|
||
|
||
mov ridtr = cr.itir
|
||
shr.u rPde = rva, PAGE_SHIFT
|
||
mov rps = 24
|
||
;;
|
||
|
||
movl rPte = VALID_KERNEL_PTE
|
||
dep.z rPde = rPde, PAGE_SHIFT, 28 - PAGE_SHIFT
|
||
dep ridtr = rps, ridtr, PS_SHIFT, PS_LEN
|
||
;;
|
||
|
||
mov cr.itir = ridtr
|
||
or rPde = rPte, rPde
|
||
;;
|
||
|
||
itc.d rPde
|
||
;;
|
||
mov pr = rpr, -1
|
||
rfi;;
|
||
#endif
|
||
|
||
HANDLER_EXIT(KiPdeNotPresentFault)
|
||
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// KiKseg0Fault
|
||
//
|
||
// Description:
|
||
//
|
||
// TLB miss on KSEG0 space
|
||
//
|
||
//
|
||
// On entry:
|
||
//
|
||
// rva (h24) : faulting virtual address
|
||
// riha (h25) : IHA address
|
||
// rpr (h26) : saved predicate
|
||
//
|
||
// Process:
|
||
//
|
||
//
|
||
// Notes:
|
||
//
|
||
// PCR page mapped with TR
|
||
// --
|
||
|
||
HANDLER_ENTRY(KiKseg0Fault)
|
||
|
||
rISR = h30
|
||
rva = h24 // passed
|
||
riha = h25 // passed
|
||
rpr = h26 // passed
|
||
rps = h27
|
||
rPte = h29
|
||
rITIR = h28
|
||
rPs = h30
|
||
rPte0 = h31
|
||
|
||
mov rISR = cr.isr // M
|
||
ld8.s rPte = [riha] // M
|
||
cmp.ne pt1 = r0, r0 // I, pt1 = 0
|
||
;;
|
||
|
||
or rPte0 = PTE_VALID_MASK, rPte // M
|
||
tbit.z pt2, pt3 = rISR, ISR_SP // I
|
||
tbit.z.or pt1 = rPte, PTE_LARGE_PAGE // I
|
||
tbit.nz.or pt1 = rPte, PTE_VALID // I
|
||
|
||
tnat.nz pt4 = rPte // I
|
||
(pt4) br.cond.spnt KiPageTableFault // B, tb miss on PTE access
|
||
;;
|
||
|
||
rIPSR = h25
|
||
|
||
mov rIPSR = cr.ipsr // M
|
||
extr rPs = rPte, PTE_PS, PS_LEN // I
|
||
(pt1) br.cond.spnt KiPageFault // B, invalid access
|
||
;;
|
||
dep.z rITIR = rPs, PS_SHIFT, PS_LEN // I
|
||
;;
|
||
(pt2) mov cr.itir = rITIR // M
|
||
dep rIPSR = 1, rIPSR, PSR_ED, 1 // I
|
||
;;
|
||
(pt2) itc.d rPte0 // M
|
||
;;
|
||
(pt3) mov cr.ipsr = rIPSR // M
|
||
;;
|
||
mov pr = rpr, -1 // I
|
||
rfi // B
|
||
;;
|
||
|
||
HANDLER_EXIT(KiKseg0Fault)
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// KiKseg4Fault
|
||
//
|
||
// Description:
|
||
//
|
||
// TLB miss on KSEG4 space
|
||
//
|
||
//
|
||
// On entry:
|
||
//
|
||
// rva (h24) : faulting virtual address
|
||
// riha (h25) : IHA address
|
||
// rpr (h26) : saved predicate
|
||
//
|
||
// Process:
|
||
//
|
||
//
|
||
// Notes:
|
||
//
|
||
// PCR page mapped with TR
|
||
// --
|
||
|
||
HANDLER_ENTRY(KiKseg4Fault)
|
||
|
||
rIPSR = h22
|
||
rISR = h23
|
||
rva = h24 // passed
|
||
riha = h25
|
||
rpr = h26 // passed
|
||
rPte = h27
|
||
|
||
mov rISR = cr.isr // M
|
||
movl rPte = VALID_KERNEL_PTE | PTE_NOCACHE // L
|
||
|
||
mov rIPSR = cr.ipsr // M
|
||
shr.u rva = rva, PAGE_SHIFT // I
|
||
;;
|
||
tbit.z pt2, pt3 = rISR, ISR_SP // I
|
||
dep.z rva = rva, PAGE_SHIFT, 32 // I
|
||
;;
|
||
or rPte = rPte, rva // I
|
||
dep rIPSR = 1, rIPSR, PSR_ED, 1 // I
|
||
;;
|
||
|
||
(pt2) itc.d rPte // M
|
||
;;
|
||
(pt3) mov cr.ipsr = rIPSR // M
|
||
;;
|
||
|
||
mov pr = rpr, -1 // I
|
||
rfi // B
|
||
;;
|
||
|
||
HANDLER_EXIT(KiKseg4Fault)
|
||
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// KiPageFault
|
||
//
|
||
// Description:
|
||
//
|
||
// This must be a genuine page fault. Call KiMemoryFault().
|
||
//
|
||
//
|
||
// On entry:
|
||
//
|
||
// rva (h24) : offending virtual address
|
||
// rpr (h26) : PDE contents
|
||
//
|
||
// Process:
|
||
//
|
||
// Restores the save predicate (pr), and branches to
|
||
// KiGenericExceptionHandler with the argument KiMemoryFault with
|
||
// macro VECTOR_CALL_HANDLER().
|
||
//
|
||
// Notes:
|
||
//
|
||
// PCR page mapped with TR
|
||
// --
|
||
|
||
HANDLER_ENTRY(KiPageFault)
|
||
|
||
rva = h24
|
||
rpr = h26
|
||
rIPSR = h27
|
||
rISR = h31
|
||
|
||
//
|
||
// check to see if non-present fault occurred on a speculative load.
|
||
// if so, set IPSR.ed bit. This forces to generate a NaT on ld.s after
|
||
// rfi
|
||
//
|
||
|
||
mov rISR = cr.isr // M
|
||
mov rIPSR = cr.ipsr // M
|
||
;;
|
||
|
||
tbit.z pt0, p0 = rISR, ISR_SP // I
|
||
dep rIPSR = 1, rIPSR, PSR_ED, 1 // I
|
||
|
||
(pt0) br.cond.spnt KiCallMemoryFault // B
|
||
;;
|
||
|
||
mov cr.ipsr = rIPSR // M
|
||
;;
|
||
mov pr = rpr, -1 // I
|
||
rfi // B
|
||
;;
|
||
|
||
KiCallMemoryFault:
|
||
|
||
mov pr = rpr, -1 // I
|
||
|
||
VECTOR_CALL_HANDLER(KiGenericExceptionHandler, KiMemoryFault)
|
||
|
||
HANDLER_EXIT(KiPageFault)
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// KiPteIndirectFault
|
||
//
|
||
// Description:
|
||
//
|
||
// The PTE itself indicates a PteIndirect fault. The target PTE address
|
||
// should be generated by extracting PteOffset from PTE and adding it to
|
||
// PTE_UBASE. The owner field of the target PTE must be 1. Otherwise,
|
||
// Call MmX86Fault().
|
||
//
|
||
// On entry:
|
||
//
|
||
// rva (h24) : offending virtual address
|
||
// rpr (h26) : PDE contents
|
||
//
|
||
// Process:
|
||
//
|
||
// Restores the save predicate (pr), and branches to
|
||
// KiGenericExceptionHandler with the argument KiMemoryFault with
|
||
// macro VECTOR_CALL_HANDLER().
|
||
//
|
||
// Notes:
|
||
//
|
||
// PCR page mapped with TR
|
||
// --
|
||
|
||
HANDLER_ENTRY(KiPteIndirectFault)
|
||
|
||
rpr = h26 // passed
|
||
rps = h27 // passed
|
||
rpAte = h28 // passed
|
||
rAte = h29 // passed
|
||
rPte = h30
|
||
rPte0 = h31
|
||
rAteMask = h22 // passed
|
||
rVa12 = h23
|
||
|
||
rPteOffset = h23
|
||
rpNewPte = h21
|
||
|
||
rOldIIP = h17 // preserved
|
||
rIA32IIP = h18
|
||
rpVa = h19 // preserved
|
||
rIndex = h20 // preserved
|
||
rpBuffer= h16
|
||
rpPte = h22
|
||
|
||
pBr = pt0
|
||
pPrg = pt3
|
||
pLoop = pt4
|
||
pClear = pt5
|
||
|
||
mov cr.itir = rps // M
|
||
thash rpNewPte = r0 // M
|
||
|
||
mov rIA32IIP = cr.iip // M
|
||
extr.u rPteOffset = rAte, PAGE4K_SHIFT, 32 // I
|
||
|
||
;;
|
||
add rpNewPte = rPteOffset, rpNewPte // M/I
|
||
cmp.eq pLoop, pClear = rIA32IIP, rOldIIP // I
|
||
|
||
;;
|
||
ld8.s rPte = [rpNewPte] // M
|
||
shr rVa12 = rpAte, PTE_SHIFT // I
|
||
;;
|
||
tnat.nz.or pBr = rPte // I
|
||
tbit.z.or pBr = rPte, PTE_VALID // I
|
||
tbit.z.or pBr = rPte, PTE_ACCESS // I
|
||
(pBr) br.cond.spnt KiPageFault
|
||
|
||
;;
|
||
(pClear)mov rIndex = 0 // M
|
||
and rPte0 = rPte, rAteMask // I
|
||
;;
|
||
|
||
//
|
||
// deposit extra PFN bits for 4k page
|
||
//
|
||
dep rPte0 = rVa12, rPte0, PAGE4K_SHIFT, PAGE_SHIFT-PAGE4K_SHIFT // I
|
||
;;
|
||
(pClear)itc.d rPte0 // M
|
||
;;
|
||
|
||
and rIndex = 7, rIndex // A
|
||
movl rpBuffer = KiPcr + PcForwardProgressBuffer // L
|
||
;;
|
||
|
||
shladd rpVa = rIndex, 4, rpBuffer // M
|
||
add rIndex = 1, rIndex // I
|
||
;;
|
||
|
||
st8 [rpVa] = rva // M
|
||
add rpPte = 8, rpVa // I
|
||
;;
|
||
|
||
st8 [rpPte] = rPte0 // M
|
||
mf // M
|
||
|
||
mov rOldIIP = rIA32IIP // I
|
||
|
||
|
||
#if !defined(NT_UP)
|
||
rAte2 = h28
|
||
rPte2 = h31
|
||
|
||
ld8.s rPte2 = [rpNewPte] // M
|
||
ld8.s rAte2 = [rpAte] // M
|
||
cmp.ne pPrg = zero, zero // I
|
||
;;
|
||
|
||
cmp.ne.or pPrg = rPte, rPte2 // I
|
||
tnat.nz.or pPrg = rPte2 // I
|
||
|
||
cmp.ne.or pPrg = rAte, rAte2 // I
|
||
tnat.nz.or pPrg = rAte2 // I
|
||
;;
|
||
|
||
(pPrg) ptc.l rva, rps // M
|
||
(pPrg) st8 [rpPte] = r0 // M
|
||
|
||
#endif
|
||
(pLoop) br.cond.spnt KiFillForwardProgressTb // B
|
||
mov pr = rpr, -1 // I
|
||
rfi;; // B
|
||
|
||
HANDLER_EXIT(KiPteIndirectFault)
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// Ki4KDataTlbFault
|
||
//
|
||
// Description:
|
||
//
|
||
// Branched from KiDataTlbVector if PTE.Cache indicates the reserved
|
||
// encoding. Reads the corresponding ATE and creates a 4kb TB on the
|
||
// fly inserts it to the TLB. If a looping condition at IIP is
|
||
// detected, it branches to KiFillForwardProgressTb and insert the TBs
|
||
// from the forward progress TB queue.
|
||
//
|
||
// On entry:
|
||
//
|
||
// rva (h24) : offending virtual address
|
||
// riha(h25) : IHA address
|
||
// rpr (h26) : PDE contents
|
||
//
|
||
// Notes:
|
||
//
|
||
// --
|
||
|
||
HANDLER_ENTRY(Ki4KDataTlbFault)
|
||
|
||
rva = h24 // passed
|
||
riha = h25 // passed
|
||
rpr = h26 // passed
|
||
rps = h27
|
||
rPfn = h28
|
||
rpAte = h28
|
||
rAte = h29
|
||
rPte = h30
|
||
rAltBase = h31
|
||
rPte0 = h31
|
||
rAteMask = h22
|
||
rVa12 = h23
|
||
|
||
rOldIIP = h17 // preserved
|
||
rIA32IIP = h18
|
||
rpVa = h19
|
||
rIndex = h20 // preserved
|
||
|
||
rpBuffer= h16
|
||
rpPte = h21
|
||
|
||
pBr = pt0
|
||
pIndr = pt1
|
||
pMiss = pt2
|
||
pPrg = pt3
|
||
pLoop = pt4
|
||
pClear = pt5
|
||
pMiss2 = pt6
|
||
|
||
mov rIA32IIP = cr.iip // M
|
||
mov rps = PS_4K << PS_SHIFT // I
|
||
shr.u rPfn = rva, PAGE4K_SHIFT // I
|
||
|
||
cmp.ne pBr = zero, zero // M/I, initialize to 0
|
||
movl rAltBase = ALT4KB_BASE // L
|
||
;;
|
||
|
||
ld8.s rPte = [riha] // M
|
||
shladd rpAte = rPfn, PTE_SHIFT, rAltBase // I
|
||
;;
|
||
|
||
ld8.s rAte = [rpAte] // M
|
||
movl rAteMask = ATE_MASK // L
|
||
;;
|
||
|
||
cmp.eq pLoop, pClear = rIA32IIP, rOldIIP// M
|
||
tnat.nz pMiss = rPte // I
|
||
(pMiss) br.cond.spnt KiPageTableFault // B
|
||
|
||
tnat.nz pMiss2 = rAte // I
|
||
(pMiss2)br.cond.spnt KiAltTableFault // B
|
||
|
||
tbit.z.or pBr = rPte, PTE_VALID // I
|
||
tbit.z.or pBr = rAte, PTE_VALID // I
|
||
tbit.z.or pBr = rAte, PTE_ACCESS // I
|
||
|
||
or rAteMask = rAte, rAteMask // M
|
||
tbit.nz pIndr, p0 = rAte, ATE_INDIRECT // I
|
||
(pBr) br.cond.spnt KiPageFault // B
|
||
|
||
dep rPte0 = 0, rPte, 2, 3 // I, make it WB
|
||
shr rVa12 = rpAte, PTE_SHIFT // I
|
||
(pIndr) br.cond.spnt KiPteIndirectFault // B
|
||
;;
|
||
(pClear)mov rIndex = 0 // M
|
||
mov cr.itir = rps // M
|
||
and rPte0 = rPte0, rAteMask // I
|
||
;;
|
||
//
|
||
// deposit extra PFN bits for 4k page
|
||
//
|
||
|
||
dep rPte0 = rVa12, rPte0, PAGE4K_SHIFT, PAGE_SHIFT-PAGE4K_SHIFT // I
|
||
;;
|
||
|
||
(pClear)itc.d rPte0 // M, install PTE
|
||
;;
|
||
|
||
and rIndex = 7, rIndex // A
|
||
movl rpBuffer = KiPcr + PcForwardProgressBuffer // L
|
||
|
||
;;
|
||
|
||
shladd rpVa = rIndex, 4, rpBuffer // M
|
||
add rIndex = 1, rIndex // I
|
||
;;
|
||
|
||
st8 [rpVa] = rva // M
|
||
add rpPte = 8, rpVa // I
|
||
;;
|
||
|
||
st8 [rpPte] = rPte0 // M
|
||
mf // M
|
||
|
||
mov rOldIIP = rIA32IIP // I
|
||
|
||
#if !defined(NT_UP)
|
||
rps = h27
|
||
rAte2 = h28
|
||
rPte2 = h31
|
||
|
||
ld8.s rPte2 = [riha] // M
|
||
ld8.s rAte2 = [rpAte] // M
|
||
cmp.ne pPrg = zero, zero // I
|
||
;;
|
||
|
||
cmp.ne.or pPrg = rPte, rPte2 // M
|
||
tnat.nz.or pPrg = rPte2 // I
|
||
|
||
cmp.ne.or pPrg = rAte, rAte2 // M
|
||
tnat.nz.or pPrg = rAte2 // I
|
||
;;
|
||
|
||
(pPrg) ptc.l rva, rps // M
|
||
(pPrg) st8 [rpPte] = r0 // M
|
||
#endif
|
||
(pLoop) br.cond.spnt KiFillForwardProgressTb // B
|
||
|
||
mov pr = rpr, -1 // I
|
||
rfi;; // B
|
||
|
||
HANDLER_EXIT(Ki4KDataTlbFault)
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// Ki4KInstTlbFault
|
||
//
|
||
// Description:
|
||
//
|
||
// Branched from KiInstTlbVector if PTE.Cache indicates the reserved
|
||
// encoding. Reads the corresponding ATE and creates a 4kb TB on the
|
||
// fly inserts it to the TLB.
|
||
//
|
||
// On entry:
|
||
//
|
||
// rva (h24) : offending virtual address
|
||
// riha(h25) : IHA address
|
||
// rpr (h26) : PDE contents
|
||
//
|
||
// Notes:
|
||
//
|
||
// --
|
||
|
||
HANDLER_ENTRY(Ki4KInstTlbFault)
|
||
|
||
rva = h24 // passed
|
||
riha = h25 // passed
|
||
rpr = h26 // passed
|
||
rps = h27
|
||
rPfn = h28
|
||
rpAte = h28
|
||
rAte = h29
|
||
rPte = h30
|
||
rAltBase = h31
|
||
rPte0 = h31
|
||
rAteMask = h22
|
||
rVa12 = h23
|
||
|
||
pBr = pt0
|
||
pIndr = pt1
|
||
pMiss = pt2
|
||
pPrg = pt3
|
||
pMiss2 = pt6
|
||
|
||
|
||
mov rps = PS_4K << PS_SHIFT // M
|
||
movl rAltBase = ALT4KB_BASE // L
|
||
shr.u rPfn = rva, PAGE4K_SHIFT // I
|
||
;;
|
||
|
||
ld8.s rPte = [riha] // M
|
||
cmp.ne pBr = zero, zero // M/I, initialize to 0
|
||
shladd rpAte = rPfn, PTE_SHIFT, rAltBase // I
|
||
;;
|
||
|
||
ld8.s rAte = [rpAte] // M
|
||
movl rAteMask = ATE_MASK // L
|
||
;;
|
||
|
||
tnat.nz pMiss = rPte // I
|
||
(pMiss) br.cond.spnt KiPageTableFault // B
|
||
|
||
tnat.nz pMiss2 = rAte // I
|
||
(pMiss2)br.cond.spnt KiAltTableFault // B
|
||
|
||
tbit.z.or pBr = rPte, PTE_VALID // I
|
||
tbit.z.or pBr = rAte, PTE_VALID // I
|
||
tbit.z.or pBr = rAte, PTE_ACCESS // I
|
||
|
||
or rAteMask = rAte, rAteMask // M
|
||
tbit.nz pIndr, p0 = rAte, ATE_INDIRECT // I
|
||
(pBr) br.cond.spnt KiPageFault // B
|
||
|
||
dep rPte0 = 0, rPte, 2, 3 // I, make it WB
|
||
shr rVa12 = rpAte, PTE_SHIFT // I
|
||
(pIndr) br.cond.spnt KiPteIndirectFault // B
|
||
;;
|
||
mov cr.itir = rps // M
|
||
and rPte0 = rPte0, rAteMask // I
|
||
;;
|
||
//
|
||
// deposit extra PFN bits for 4k page
|
||
//
|
||
|
||
dep rPte0 = rVa12, rPte0, PAGE4K_SHIFT, PAGE_SHIFT-PAGE4K_SHIFT // I
|
||
;;
|
||
|
||
itc.i rPte0 // M, install PTE
|
||
;;
|
||
|
||
#if !defined(NT_UP)
|
||
rps = h27
|
||
rAte2 = h28
|
||
rPte2 = h31
|
||
|
||
ld8.s rPte2 = [riha] // M
|
||
ld8.s rAte2 = [rpAte] // M
|
||
cmp.ne pPrg = zero, zero // I
|
||
;;
|
||
|
||
cmp.ne.or pPrg = rPte, rPte2 // M
|
||
tnat.nz.or pPrg = rPte2 // I
|
||
|
||
cmp.ne.or pPrg = rAte, rAte2 // M
|
||
tnat.nz.or pPrg = rAte2 // I
|
||
;;
|
||
|
||
(pPrg) ptc.l rva, rps // M
|
||
|
||
#endif
|
||
|
||
mov pr = rpr, -1 // I
|
||
rfi;; // B
|
||
|
||
HANDLER_EXIT(Ki4KInstTlbFault)
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// KiAltTableFault
|
||
//
|
||
// Description:
|
||
//
|
||
// Branched from Inst/DataAccessBitVector
|
||
// Inserts a missing PTE translation for the alt table.
|
||
//
|
||
// On entry:
|
||
//
|
||
// rva (h24) : offending virtual address
|
||
// riha (h25) : a offending PTE address
|
||
// rpr: (h26) : saved predicate
|
||
//
|
||
// Handle:
|
||
//
|
||
// --
|
||
|
||
HANDLER_ENTRY(KiAltTableFault)
|
||
|
||
rpAte = h28 // passed
|
||
|
||
rva = h24
|
||
riha = h25
|
||
rpr = h26 // passed
|
||
rPte = h27
|
||
rPte2 = h28
|
||
rps = h29
|
||
|
||
thash riha = rpAte // M
|
||
cmp.ne pt1 = r0, r0
|
||
mov rva = rpAte // I
|
||
;;
|
||
|
||
ld8.s rPte = [riha] // M
|
||
;;
|
||
|
||
tnat.nz pt0, p0 = rPte // I
|
||
tbit.z.or pt1, p0 = rPte, PTE_ACCESS
|
||
tbit.z.or pt1, p0 = rPte, PTE_VALID // I, if non-present page fault
|
||
|
||
(pt0) br.cond.spnt KiPageTableFault // B
|
||
(pt1) br.cond.spnt KiPteNotPresentFault // B
|
||
;;
|
||
|
||
mov cr.ifa = rva
|
||
;;
|
||
itc.d rPte // M
|
||
;;
|
||
|
||
#if !defined(NT_UP)
|
||
ld8.s rPte2 = [riha] // M
|
||
mov rps = PAGE_SHIFT << PS_SHIFT // I
|
||
cmp.ne pt0 = zero, zero // I
|
||
;;
|
||
|
||
cmp.ne.or pt0 = rPte2, rPte // M
|
||
tnat.nz.or pt0 = rPte2 // I
|
||
;;
|
||
|
||
(pt0) ptc.l rva, rps // M
|
||
#endif
|
||
mov pr = rpr, -1 // I
|
||
rfi;; // B
|
||
|
||
HANDLER_EXIT(KiAltTableFault)
|
||
|
||
|
||
//
|
||
// ++
|
||
//
|
||
// Routine:
|
||
//
|
||
// KiFillForwardProgressTb
|
||
//
|
||
// Description:
|
||
//
|
||
// Fill TB from TLB forward progress buffer.
|
||
//
|
||
// On entry:
|
||
//
|
||
// rpBuffer (h16) : forward progress buffer address
|
||
// rpr: (h26) : saved predicate
|
||
//
|
||
// Handle:
|
||
//
|
||
// --
|
||
|
||
HANDLER_ENTRY(KiFillForwardProgressTb)
|
||
|
||
rLc = h29
|
||
rT0 = h28
|
||
rps = h27
|
||
rpr = h26
|
||
rVa = h22
|
||
rPte = h21
|
||
rpVa = h19
|
||
rpPte = h17
|
||
rpBuffer= h16
|
||
|
||
mov rpVa = rpBuffer // A
|
||
mov.i rLc = ar.lc // I
|
||
mov rT0 = NUMBER_OF_FWP_ENTRIES - 1 //
|
||
;;
|
||
add rpPte = 8, rpBuffer // A
|
||
mov.i ar.lc = rT0 // I
|
||
;;
|
||
|
||
fpb_loop:
|
||
|
||
//
|
||
// use ALAT to see if somebody modify the PTE entry
|
||
//
|
||
|
||
ld8 rVa = [rpVa], 16 // M
|
||
ld8.a rPte = [rpPte] // M
|
||
;;
|
||
|
||
mov cr.ifa = rVa // M
|
||
cmp.ne pt0, pt1 = rPte, r0 // I
|
||
;;
|
||
|
||
(pt0) itc.d rPte // M
|
||
;;
|
||
(pt0) ld8.c.clr rPte = [rpPte] // M
|
||
add rpPte = 16, rpPte // I
|
||
;;
|
||
(pt1) invala.e rPte // M, invalidate ALAT entry
|
||
(pt0) cmp.eq.and pt0 = rPte, r0 // I
|
||
;;
|
||
(pt0) ptc.l rVa, rps // M
|
||
br.cloop.dptk.many fpb_loop;; // B
|
||
|
||
mov.i ar.lc = rLc
|
||
|
||
mov pr = rpr, -1 // I
|
||
rfi // B
|
||
;;
|
||
|
||
HANDLER_EXIT(KiFillForwardProgressTb)
|
||
|
||
|
||
//++
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This routine begins the common code for raising an exception.
|
||
// The routine saves the non-volatile state and dispatches to the
|
||
// next level exception dispatcher.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// a0 - pointer to trap frame
|
||
// a1 - previous mode
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
NESTED_ENTRY(KiExceptionDispatch)
|
||
|
||
//
|
||
// Build exception frame
|
||
//
|
||
|
||
.regstk 2, 3, 5, 0
|
||
.prologue 0xA, loc0
|
||
alloc t16 = ar.pfs, 2, 3, 5, 0
|
||
mov loc0 = sp
|
||
cmp4.eq pt0 = UserMode, a1 // previous mode is user?
|
||
|
||
mov loc1 = brp
|
||
.fframe ExceptionFrameLength
|
||
add sp = -ExceptionFrameLength, sp
|
||
;;
|
||
|
||
.save ar.unat, loc2
|
||
mov loc2 = ar.unat
|
||
add t0 = ExFltS19+STACK_SCRATCH_AREA, sp
|
||
add t1 = ExFltS18+STACK_SCRATCH_AREA, sp
|
||
;;
|
||
|
||
.save.gf 0x0, 0xC0000
|
||
stf.spill [t0] = fs19, ExFltS17-ExFltS19
|
||
stf.spill [t1] = fs18, ExFltS16-ExFltS18
|
||
;;
|
||
|
||
.save.gf 0x0, 0x30000
|
||
stf.spill [t0] = fs17, ExFltS15-ExFltS17
|
||
stf.spill [t1] = fs16, ExFltS14-ExFltS16
|
||
mov t10 = bs4
|
||
;;
|
||
|
||
.save.gf 0x0, 0xC000
|
||
stf.spill [t0] = fs15, ExFltS13-ExFltS15
|
||
stf.spill [t1] = fs14, ExFltS12-ExFltS14
|
||
mov t11 = bs3
|
||
;;
|
||
|
||
.save.gf 0x0, 0x3000
|
||
stf.spill [t0] = fs13, ExFltS11-ExFltS13
|
||
stf.spill [t1] = fs12, ExFltS10-ExFltS12
|
||
mov t12 = bs2
|
||
;;
|
||
|
||
.save.gf 0x0, 0xC00
|
||
stf.spill [t0] = fs11, ExFltS9-ExFltS11
|
||
stf.spill [t1] = fs10, ExFltS8-ExFltS10
|
||
mov t13 = bs1
|
||
;;
|
||
|
||
.save.gf 0x0, 0x300
|
||
stf.spill [t0] = fs9, ExFltS7-ExFltS9
|
||
stf.spill [t1] = fs8, ExFltS6-ExFltS8
|
||
mov t14 = bs0
|
||
;;
|
||
|
||
.save.gf 0x0, 0xC0
|
||
stf.spill [t0] = fs7, ExFltS5-ExFltS7
|
||
stf.spill [t1] = fs6, ExFltS4-ExFltS6
|
||
mov t15 = ar.lc
|
||
;;
|
||
|
||
.save.gf 0x0, 0x30
|
||
stf.spill [t0] = fs5, ExFltS3-ExFltS5
|
||
stf.spill [t1] = fs4, ExFltS2-ExFltS4
|
||
;;
|
||
|
||
.save.f 0xC
|
||
stf.spill [t0] = fs3, ExFltS1-ExFltS3 // save fs3
|
||
stf.spill [t1] = fs2, ExFltS0-ExFltS2 // save fs2
|
||
;;
|
||
|
||
.save.f 0x3
|
||
stf.spill [t0] = fs1, ExBrS4-ExFltS1 // save fs1
|
||
stf.spill [t1] = fs0, ExBrS3-ExFltS0 // save fs0
|
||
;;
|
||
|
||
.save.b 0x18
|
||
st8 [t0] = t10, ExBrS2-ExBrS4 // save bs4
|
||
st8 [t1] = t11, ExBrS1-ExBrS3 // save bs3
|
||
;;
|
||
|
||
.save.b 0x6
|
||
st8 [t0] = t12, ExBrS0-ExBrS2 // save bs2
|
||
st8 [t1] = t13, ExIntS2-ExBrS1 // save bs1
|
||
;;
|
||
|
||
.save.b 0x1
|
||
st8 [t0] = t14, ExIntS3-ExBrS0 // save bs0
|
||
movl out0 = KiPcr+PcCurrentThread
|
||
;;
|
||
|
||
.save.gf 0xC, 0x0
|
||
.mem.offset 0,0
|
||
st8.spill [t0] = s3, ExIntS1-ExIntS3 // save s3
|
||
.mem.offset 8,0
|
||
st8.spill [t1] = s2, ExIntS0-ExIntS2 // save s2
|
||
;;
|
||
|
||
.save.gf 0x3, 0x0
|
||
.mem.offset 0,0
|
||
st8.spill [t0] = s1, ExApLC-ExIntS1 // save s1
|
||
.mem.offset 8,0
|
||
st8.spill [t1] = s0, ExApEC-ExIntS0 // save s0
|
||
;;
|
||
|
||
.savepsp ar.pfs, ExceptionFrameLength-ExApEC-STACK_SCRATCH_AREA
|
||
st8 [t1] = t16, ExIntNats-ExApEC
|
||
mov t4 = ar.unat // captured Nats of s0-s3
|
||
;;
|
||
|
||
(pt0) ld8 out0 = [out0]
|
||
;;
|
||
(pt0) add out0 = ThStackBase, out0
|
||
|
||
.savepsp ar.lc, ExceptionFrameLength-ExApLC-STACK_SCRATCH_AREA
|
||
st8 [t0] = t15
|
||
.savepsp @priunat, ExceptionFrameLength-ExIntNats-STACK_SCRATCH_AREA
|
||
st8 [t1] = t4 // save Nats of s0-s3
|
||
;;
|
||
|
||
|
||
PROLOGUE_END
|
||
|
||
(pt0) ld8 out0 = [out0]
|
||
;;
|
||
(pt0) add out0 = -ThreadStateSaveAreaLength+TsHigherFPVolatile, out0
|
||
(pt0) br.call.sptk brp = KiSaveHigherFPVolatile
|
||
;;
|
||
|
||
add out0 = TrExceptionRecord, a0 // -> exception record
|
||
add out1 = STACK_SCRATCH_AREA, sp // -> exception frame
|
||
mov out2 = a0 // -> trap frame
|
||
|
||
mov out3 = a1 // previous mode
|
||
mov out4 = 1 // first chance
|
||
br.call.sptk.many brp = KiDispatchException
|
||
;;
|
||
|
||
add t1 = ExApEC+STACK_SCRATCH_AREA, sp
|
||
movl t0 = KiExceptionExit
|
||
;;
|
||
|
||
//
|
||
// Interrupts must be disabled before calling KiExceptionExit
|
||
// because the unwind code cannot unwind from that point.
|
||
//
|
||
|
||
FAST_DISABLE_INTERRUPTS
|
||
ld8 t1 = [t1]
|
||
mov brp = t0
|
||
;;
|
||
|
||
mov ar.unat = loc2
|
||
mov ar.pfs = t1
|
||
|
||
add s1 = STACK_SCRATCH_AREA, sp // s1 -> exception frame
|
||
mov s0 = a0 // s0 -> trap frame
|
||
br.ret.sptk brp
|
||
;;
|
||
|
||
NESTED_EXIT(KiExceptionDispatch)
|
||
|
||
|
||
//++
|
||
//
|
||
// BOOLEAN
|
||
// KeInvalidAccessAllowed (
|
||
// IN PVOID TrapInformation
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Mm will pass a pointer to a trap frame prior to issuing a bug check on
|
||
// a pagefault. This routine lets Mm know if it is ok to bugcheck. The
|
||
// specific case we must protect are the interlocked pop sequences which can
|
||
// blindly access memory that may have been freed and/or reused prior to the
|
||
// access. We don't want to bugcheck the system in these cases, so we check
|
||
// the instruction pointer here.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// TrapFrame (a0) - Supplies a trap frame pointer. NULL means return False.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// True if the invalid access should be ignored.
|
||
// False which will usually trigger a bugcheck.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(KeInvalidAccessAllowed)
|
||
|
||
.regstk 1, 0, 0, 0
|
||
|
||
cmp.eq pt0 = 0, a0
|
||
movl t1 = ExpInterlockedPopEntrySListFault
|
||
|
||
add t0 = TrStIIP, a0
|
||
mov v0 = zero // assume access not allowed
|
||
(pt0) br.ret.spnt brp
|
||
;;
|
||
|
||
ld8 t0 = [t0]
|
||
;;
|
||
cmp.eq pt2 = t0, t1
|
||
;;
|
||
|
||
nop.m 0
|
||
(pt2) mov v0 = 1
|
||
br.ret.sptk brp
|
||
|
||
LEAF_EXIT(KeInvalidAccessAllowed)
|