windows-nt/Source/XPSP1/NT/base/ntos/ke/ia64/miscs.s
2020-09-26 16:20:57 +08:00

1236 lines
28 KiB
ArmAsm
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//++
//
// Module Name:
//
// miscs.s
//
// Abstract:
//
// This module implements machine dependent miscellaneous kernel functions.
// Functions are provided to request a software interrupt, continue thread
// execution, flush TLBs and write buffers, and perform last chance
// exception processing.
//
// Author:
//
// William K. Cheung (wcheung) 3-Nov-1995
//
// Environment:
//
// Kernel mode only.
//
// Revision History:
//
// 7-Jul-1997 bl Updated to EAS2.3
//
// 27-Feb-1996 wc Updated to EAS2.1
//
// 11-Jan-1996 wc Set up register sp to point to the exception frame
// on the stack before calling KiSaveExceptionFrame and
// branching directly to KiExceptionExit.
//
//--
#include "ksia64.h"
//
// Global symbols
//
PublicFunction(KiContinue)
PublicFunction(KiSaveExceptionFrame)
PublicFunction(KeTestAlertThread)
PublicFunction(KiExceptionExit)
PublicFunction(KiRaiseException)
PublicFunction(KiLoadKernelDebugRegisters)
PublicFunction(KeIsExecutingDpc)
//
//++
//
// NTSTATUS
// NtContinue (
// IN PCONTEXT ContextRecord,
// IN BOOLEAN TestAlert
// )
//
// Routine Description:
//
// This routine is called as a system service to continue execution after
// an exception has occurred. Its functions is to transfer information from
// the specified context record into the trap frame that was built when the
// system service was executed, and then exit the system as if an exception
// had occurred.
//
// Arguments:
//
// ContextRecord (a0) - Supplies a pointer to a context record.
//
// TestAlert (a1) - Supplies a boolean value that specifies whether alert
// should be tested for the previous processor mode.
//
// N.B. Register t0 is assumed to contain the address of a trap frame.
//
// Return Value:
//
// Normally there is no return from this routine. However, if the specified
// context record is misaligned or is not accessible, then the appropriate
// status code is returned.
//
//--
NESTED_ENTRY(NtContinue)
NESTED_SETUP(2,4,3,0)
.fframe ExceptionFrameLength
add sp = -ExceptionFrameLength, sp
PROLOGUE_END
//
// Transfer information from the context record to the exception and trap
// frames.
//
// N.B. Must zero the loadrs bit-field of Context->RsRSC
//
add t1 = TrStIPSR, t0 // -> TrapFrame->StIPSR
mov loc2 = t0
;;
ld8 loc3 = [t1] // load TrapFrame->StIPSR
mov out0 = a0 // context frame address
;;
add out1 = STACK_SCRATCH_AREA, sp // -> exception frame
mov out2 = t0 // trap frame address
br.call.sptk.many brp = KiContinue
;;
//
// If KiContinue() returns success, then exit via the exception exit code.
// Otherwise, return to the system service dispatcher.
//
// Check to determine if alert should be tested for the previous processor
// mode and restore the previous mode in the thread object.
//
// Application that invokes the NtContinue() system service must have
// flushed all stacked registers to the backing store. Sanitize the
// bspstore to be equal to bsp; otherwise, some stacked GRs will not be
// restored from the backing store.
//
add t0 = TrStIPSR, loc2
movl t7 = 1 << PSR_TB | 1 << PSR_DB | 1 << PSR_SS | 1 << PSR_PP
;;
ld8 t8 = [t0]
cmp.ne pt0 = zero, v0 // if ne, transfer failed.
;;
(pt0) dep t7 = 1, t7, PSR_LP, 1 // capture psr.lp if failed
;;
add t2 = TrTrapFrame, loc2
andcm t8 = t8, t7 // Clear old values
and loc3 = t7, loc3 // capture psr.tb, db, ss, pp
;;
or t8 = loc3, t8
;;
st8 [t0] = t8
add t3 = TrRsRSC, loc2
(pt0) br.cond.spnt Nc10 // jump to Nc10 if pt0 is TRUE
;;
//
// Restore the nonvolatile machine state from the exception frame
// and exit the system via the exception exit code.
//
ld8 t5 = [t2] // get old trap frame address
movl t1 = KiPcr + PcCurrentThread // -> current thread
;;
ld8 t0 = [t3], TrPreviousMode-TrRsRSC // load TrapFrame->RsRSC
ld8 t4 = [t1] // get current thread address
cmp4.ne pt1 = zero, a1 // if ne, test for alert
;;
ld4 t6 = [t3], TrRsRSC-TrPreviousMode // get old previous mode
dep t0 = r0, t0, RSC_MBZ1, RSC_LOADRS_LEN // zero preload field
add t7 = ThPreviousMode, t4
;;
(pt1) ld1 out0 = [t7] // get current previous mode
st8 [t3] = t0 // save TrapFrame->RsRSC
add t8 = ThTrapFrame, t4
;;
st8 [t8] = t5 // restore old trap frame addr
st1 [t7] = t6 // restore old previous mode
(pt1) br.call.spnt.many brp = KeTestAlertThread
;;
//
// sp -> stack scratch area/FP save area/exception frame/trap frame
//
// Set up for branch to KiExceptionExit
//
// s0 = trap frame
// s1 = exception frame
//
// N.B. predicate register alias pUstk & pKstk must be the same as trap.s
// and they must be set up correctly upon entry into KiExceptionExit.
//
// N.B. The exception exit code will restore the exception frame & trap frame
// and then rfi to user code. pUstk is set to 1 while pKstk is set to 0.
//
pUstk = ps3
pKstk = ps4
//
// Interrupts must be disabled before calling KiExceptionExit
// because the unwind code cannot unwind from that point.
//
FAST_DISABLE_INTERRUPTS
cmp.eq pUstk, pKstk = zero, zero
add s1 = STACK_SCRATCH_AREA, sp
mov s0 = loc2
br KiExceptionExit
Nc10:
.restore
add sp = ExceptionFrameLength, sp
NESTED_RETURN
NESTED_EXIT(NtContinue)
//++
//
// NTSTATUS
// NtRaiseException (
// IN PEXCEPTION_RECORD ExceptionRecord,
// IN PCONTEXT ContextRecord,
// IN BOOLEAN FirstChance
// )
//
// Routine Description:
//
// This routine is called as a system service to raise an exception.
// The exception can be raised as a first or second chance exception.
//
// Arguments:
//
// ExceptionRecord (a0) - Supplies a pointer to an exception record.
//
// ContextRecord (a1) - Supplies a pointer to a context record.
//
// FirstChance (a2) - Supplies a boolean value that determines whether
// this is the first (TRUE) or second (FALSE) chance for dispatching
// the exception.
//
// N.B. Register t0 is assumed to contain the address of a trap frame.
//
// Return Value:
//
// Normally there is no return from this routine. However, if the specified
// context record or exception record is misaligned or is not accessible,
// then the appropriate status code is returned.
//
//--
NESTED_ENTRY(NtRaiseException)
NESTED_SETUP(3,3,5,0)
.fframe ExceptionFrameLength
add sp = -ExceptionFrameLength, sp
;;
PROLOGUE_END
//
// Pop this trap frame off the thread list.
//
add t2 = TrTrapFrame, t0
movl t1 = KiPcr + PcCurrentThread
;;
ld8 t1 = [t1]; // Get current thread.
ld8 t2 = [t2]; // Load previous trap frame
;;
add t1 = ThTrapFrame, t1
//
// Save nonvolatile states.
//
add out0 = STACK_SCRATCH_AREA, sp
mov loc2 = t0 // save pointer to trap frame
;;
st8 [t1] = t2
br.call.sptk brp = KiSaveExceptionFrame
//
// Call the raise exception kernel routine wich will marshall the argments
// and then call the exception dispatcher.
//
add out2 = STACK_SCRATCH_AREA, sp // -> exception frame
mov out1 = a1
mov out0 = a0
add out4 = zero, a2
mov out3 = t0
br.call.sptk.many brp = KiRaiseException
//
// If the raise exception routine returns success, then exit via the exception
// exit code. Otherwise, return to the system service dispatcher.
//
// N.B. The exception exit code will restore the exception frame & trap frame
// and then rfi to user code.
//
// Set up for branch to KiExceptionExit
//
// s0 = trap frame
// s1 = exception frame
//
pUstk = ps3
pKstk = ps4
cmp4.ne p0, pt1 = zero, v0 // if ne, dispatch failed.
;;
//
// Interrupts must be disabled before calling KiExceptionExit
// because the unwind code cannot unwind from that point.
//
(pt1) FAST_DISABLE_INTERRUPTS
(pt1) mov s0 = loc2 // copy trap frame pointer
(pt1) add s1 = STACK_SCRATCH_AREA, sp
(pt1) cmp.eq pUstk, pKstk = zero, zero
(pt1) br.cond.sptk.many KiExceptionExit
.restore
add sp = ExceptionFrameLength, sp
NESTED_RETURN
NESTED_EXIT(NtRaiseException)
//++
//
// VOID
// KeFillLargeEntryTb (
// IN HARDWARE_PTE Pte[],
// IN PVOID Virtual,
// IN ULONG PageSize
// )
//
// Routine Description:
//
// This function fills a large translation buffer entry.
//
// N.B. It is assumed that the large entry is not in the TB and therefore
// the TB is not probed.
//
// Arguments:
//
// Pte (a0) - Supplies a pointer to the page table entries that are to be
// written into the TB.
//
// Virtual (a1) - Supplies the virtual address of the entry that is to
// be filled in the translation buffer.
//
// PageSize (a2) - Supplies the size of the large page table entry.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KeFillLargeEntryTb)
rPte = t0
rScnd = t1
ridtr = t2
rid = t3
rDtr = t4
rTb = t6
rTbPFN = t7
rpAttr = t8
rAttrOffset = t9
shr.u rScnd = a2, 6 // mask off page size fields
;;
shl rScnd = rScnd, 6 //
;;
and rScnd = a1, rScnd // examine the virtual address bit
;;
cmp.eq pt0, pt1 = r0, rScnd
shl ridtr = a2, PS_SHIFT
mov rDtr = DTR_VIDEO_INDEX
;;
rsm 1 << PSR_I // turn off interrupts
(pt0) add a0 = (1 << PTE_SHIFT), a0
;;
ld8 rPte = [a0] // load PTE
rsm 1 << PSR_IC // interrupt is off, now reset PSR.ic
;;
srlz.d // serialize
mov cr.itir = ridtr // idtr for insertion
mov cr.ifa = a1 // ifa for insertion
;;
itr.d dtr[rDtr] = rPte
ssm 1 << PSR_IC // set PSR.ic bit again
;;
srlz.i // I serialize
ssm 1 << PSR_I
LEAF_RETURN
LEAF_EXIT(KeFillLargeEntryTb) // return
//++
//
// VOID
// KeFillFixedEntryTb (
// IN HARDWARE_PTE Pte[],
// IN PVOID Virtual,
// IN ULONG PageSize,
// IN ULONG Index
// )
//
// Routine Description:
//
// This function fills a fixed translation buffer entry.
//
// Arguments:
//
// Pte (a0) - Supplies a pointer to the page table entries that are to be
// written into the TB.
//
// Virtual (a1) - Supplies the virtual address of the entry that is to
// be filled in the translation buffer.
//
// Index (a2) - Supplies the index where the TB entry is to be written.
//
// Return Value:
//
// None.
//
// Comments:
//
//
//
//--
LEAF_ENTRY(KeFillFixedEntryTb)
rPte = t0
rScnd = t1
ridtr = t2
rid = t3
rIndex = t4
rTb = t6
rTbPFN = t7
rpAttr = t8
rAttrOffset = t9
rsm 1 << PSR_I // reset PSR.i
ld8 rPte = [a0] // load PTE
shl ridtr = a2, PS_SHIFT
;;
rsm 1 << PSR_IC // interrupt is off, now reset PSR.ic
tbit.z pt0, pt1 = a3, 31 // check the sign bit
// if 1 ITR, otherwise DTR
;;
srlz.d // serialize
and rIndex = 0xf, a3
;;
mov cr.itir = ridtr // idtr for insertion
mov cr.ifa = a1 // ifa for insertion
;;
(pt0) itr.d dtr[rIndex] = rPte // insert into DTR
(pt1) itr.i itr[rIndex] = rPte // insert into ITR
ssm 1 << PSR_IC // set PSR.ic bit again
;;
srlz.i // I serialize
#if DBG
mov t10 = PbProcessorState+KpsSpecialRegisters+KsTrD0
movl t13 = KiPcr + PcPrcb
;;
ld8 t13 = [t13]
mov t14 = PbProcessorState+KpsSpecialRegisters+KsTrI0
;;
add t10 = t10, t13
add t14 = t14, t13
;;
(pt0) shladd t15 = rIndex, 3, t10
(pt1) shladd t15 = rIndex, 3, t14
;;
(pt0) st8 [t15] = rPte
(pt1) st8 [t15] = rPte
;;
#endif
ssm 1 << PSR_I
LEAF_RETURN
LEAF_EXIT(KeFillFixedEntryTb)
//++
//
// VOID
// KeFillFixedLargeEntryTb (
// IN HARDWARE_PTE Pte[],
// IN PVOID Virtual,
// IN ULONG PageSize,
// IN ULONG Index
// )
//
// Routine Description:
//
// This function fills a fixed translation buffer entry with a large page
// size.
//
// Arguments:
//
// Pte (a0) - Supplies a pointer to the page table entries that are to be
// written into the TB.
//
// Virtual (a1) - Supplies the virtual address of the entry that is to
// be filled in the translation buffer.
//
// PageSize (a2) - Supplies the size of the large page table entry.
//
// Index (a3) - Supplies the index where the TB entry is to be written.
//
// Return Value:
//
// None.
//
// Comments:
//
// Yet to be implemented.
//
//--
LEAF_ENTRY(KeFillFixedLargeEntryTb)
rPte = t0
rScnd = t1
ridtr = t2
rid = t3
rIndex = t4
rTb = t6
rTbPFN = t7
rpAttr = t8
rAttrOffset = t9
rsm 1 << PSR_I // reset PSR.i
ld8 rPte = [a0] // load PTE
shl ridtr = a2, PS_SHIFT
;;
rsm 1 << PSR_IC // interrupt is off, now reset PSR.ic
and rIndex = 0xf, a3 // set the DTR index
tbit.z pt0, pt1 = a3, 31 // check the sign bit
;;
srlz.d // serialize
mov cr.itir = ridtr // idtr for insertion
mov cr.ifa = a1 // ifa for insertion
;;
(pt0) itr.d dtr[rIndex] = rPte // insert into DTR
(pt1) itr.i itr[rIndex] = rPte // insert into ITR
ssm 1 << PSR_IC // set PSR.ic bit again
;;
srlz.i // I serialize
ssm 1 << PSR_I
LEAF_RETURN
LEAF_EXIT(KeFillFixedLargeEntryTb) // return
//++
//
// VOID
// KeFillInstEntryTb (
// IN HARDWARE_PTE Pte[],
// IN PVOID Virtual,
// )
//
// Routine Description:
//
// This function fills a large translation buffer entry.
//
// N.B. It is assumed that the large entry is not in the TB and therefore
// the TB is not probed.
//
// Arguments:
//
// Pte (a0) - Supplies a page table entry that is to be
// written into the Inst TB.
//
// Virtual (a1) - Supplies the virtual address of the entry that is to
// be filled in the translation buffer.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KeFillInstEntryTb)
riitr = t2
rid = t3
rsm 1 << PSR_I // reset PSR.i
;;
rsm 1 << PSR_IC // interrupt is off, now reset PSR.ic
mov riitr = PAGE_SIZE << PS_LEN
;;
srlz.d // serialize
mov cr.ifa = a1 // set va to install
mov cr.itir = riitr // iitr for insertion
;;
itc.i a0
;;
ssm 1 << PSR_IC // set PSR.ic bit again
;;
srlz.i // I serialize
ssm 1 << PSR_I
LEAF_RETURN
LEAF_EXIT(KeFillInstEntryTb) // return
//++
//
// VOID
// KeBreakinBreakpoint
// VOID
// )
//
// Routine Description:
//
// This function causes a BREAKIN breakpoint.
//
// Arguments:
//
// None.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KeBreakinBreakpoint)
//
// Flush the RSE or the kernel debugger is unable to do a stack unwind
//
flushrs
;;
break.i BREAKPOINT_BREAKIN
LEAF_RETURN
LEAF_EXIT(KeBreakinBreakpoint)
#ifdef WX86
//++
//
// VOID
// KiIA32RegistersInit
// VOID
// )
//
// Routine Description:
//
// This function to Initialize per processor IA32 related registers
// These registers do not saved/restored on context switch time
//
// Arguments:
//
// None.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KiIA32RegistersInit)
mov t0 = TeGdtDescriptor
mov iA32iobase = 0
;;
mov iA32index = t0
LEAF_RETURN
LEAF_EXIT(KiIA32RegistersInit)
#endif // WX86
//++
//
// PKTHREAD
// KeGetCurrentThread (VOID)
//
// Routine Description:
//
// Arguments:
//
// None.
//
// Return Value:
//
// Returns a pointer to the executing thread object.
//
//--
LEAF_ENTRY(KeGetCurrentThread)
movl v0 = KiPcr + PcCurrentThread // -> current thread
;;
ld8 v0 = [v0]
br.ret.sptk brp
LEAF_EXIT(KeGetCurrentThread)
//++
//
// BOOLEAN
// KeIsExecutingDpc (VOID)
//
// Routine Description:
//
// Arguments:
//
// None.
//
// Return Value:
//
// Return a value which indicates if we are currently in a DPC.
//
//--
LEAF_ENTRY(KeIsExecutingDpc)
rsm 1 << PSR_I // disable interrupt
movl v0 = KiPcr + PcPrcb
;;
ld8 v0 = [v0]
;;
add v0 = PbDpcRoutineActive, v0
;;
ld4 v0 = [v0]
ssm 1 << PSR_I // enable interrupt
br.ret.sptk brp
LEAF_EXIT(KeIsExecutingDpc)
//++
//
// Routine Description:
//
// This routine saves the thread's current non-volatile NPX state,
// and sets a new initial floating point state for the caller.
//
// This is intended for use by kernel-mode code that needs to use
// the floating point registers. Must be paired with
// KeRestoreFloatingPointState
//
// Arguments:
//
// a0 - Supplies pointer to KFLOATING_SAVE structure
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KeSaveFloatingPointState)
mov v0 = zero
LEAF_RETURN
LEAF_EXIT(KeSaveFloatingPointState)
//++
//
// Routine Description:
//
// This routine restores the thread's current non-volatile NPX state,
// to the passed in state.
//
// This is intended for use by kernel-mode code that needs to use
// the floating point registers. Must be paired with
// KeSaveFloatingPointState
//
// Arguments:
//
// a0 - Supplies pointer to KFLOATING_SAVE structure
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KeRestoreFloatingPointState)
mov v0 = zero
LEAF_RETURN
LEAF_EXIT(KeRestoreFloatingPointState)
//++
//
// Routine Description:
//
// This routine flush all the dirty registers to the backing store
// and invalidate them.
//
// Arguments:
//
// None.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KiFlushRse)
flushrs
mov t1 = ar.rsc
mov t0 = RSC_KERNEL_DISABLED
;;
mov ar.rsc = t0
;;
loadrs
;;
mov ar.rsc = t1
;;
br.ret.sptk brp
LEAF_EXIT(KiFlushRse)
#if 0
//++
//
// Routine Description:
//
// This routine invalidate all the physical stacked registers.
//
// Arguments:
//
// None.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KiInvalidateStackedRegisters)
mov t1 = ar.rsc
mov t0 = RSC_KERNEL_DISABLED
;;
mov ar.rsc = t0
;;
loadrs
;;
mov ar.rsc = t1
;;
br.ret.sptk brp
LEAF_EXIT(KiInvalidateStackedRegisters)
#endif // 0
//++
//
// VOID
// KeSetLowPsrBit (
// UCHAR BitPosition,
// BOOLEAN Value
// )
//
// Routine Description:
//
// This routine set one of the low psr bits to the specified value.
//
// Arguments:
//
// a0 - bit position
// a1 - 1 or 0
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KeSetLowPsrBit)
mov t1 = psr
mov t2 = 1
cmp.ne pt1, pt0 = r0, a1
;;
shl t2 = t2, a0
;;
(pt1) or t3 = t1, t2
(pt0) andcm t3 = t1, t2
;;
mov psr.l = t3
;;
srlz.i
br.ret.sptk brp
LEAF_EXIT(KeSetLowPsrBit)
//++
//
// PVOID
// KiGetPhysicalAddress(
// PVOID Virtual
// )
//
// Routine Description:
//
// This routine translates to physical address uing TPA instruction.
//
// Arguments:
//
// a0 - virtual address to be translated to physical address.
//
// Return Value:
//
// physical address
//
//--
LEAF_ENTRY(KiGetPhysicalAddress)
tpa r8 = a0
LEAF_RETURN
LEAF_EXIT(KiGetPhysicalAddress)
//++
//
// VOID
// KiSetRegionRegister(
// PVOID Region,
// ULONGLONG Contents
// )
//
// Routine Description:
//
// This routine sets the value of a region register.
//
// Arguments:
//
// a0 - Supplies the region register #
//
// a1 - Supplies the value to be stored in the specified region register
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(KiSetRegionRegister)
mov rr[a0] = a1
;;
srlz.i
LEAF_RETURN
LEAF_EXIT(KiSetRegionId)
LEAF_ENTRY(KiSaveProcessorControlState)
//
// save region registers
//
add t2 = KpsSpecialRegisters+KsRr0, a0
dep.z t0 = 0, RR_INDEX, RR_INDEX_LEN
;;
mov t1 = rr[t0]
dep.z t3 = 1, RR_INDEX, RR_INDEX_LEN
;;
mov t4 = rr[t3]
st8 [t2] = t1, KsRr1-KsRr0
dep.z t0 = 2, RR_INDEX, RR_INDEX_LEN
;;
mov t1 = rr[t0]
st8 [t2] = t4, KsRr2-KsRr1
dep.z t3 = 3, RR_INDEX, RR_INDEX_LEN
;;
mov t4 = rr[t3]
st8 [t2] = t1, KsRr3-KsRr2
dep.z t0 = 4, RR_INDEX, RR_INDEX_LEN
;;
mov t1 = rr[t0]
st8 [t2] = t4, KsRr4-KsRr3
dep.z t3 = 5, RR_INDEX, RR_INDEX_LEN
;;
mov t4 = rr[t3]
st8 [t2] = t1, KsRr5-KsRr4
dep.z t0 = 6, RR_INDEX, RR_INDEX_LEN
;;
mov t1 = rr[t0]
st8 [t2] = t4, KsRr6-KsRr5
dep.z t3 = 7, RR_INDEX, RR_INDEX_LEN
;;
mov t4 = rr[t3]
st8 [t2] = t1, KsRr7-KsRr6
;;
st8 [t2] = t4
//
// save ITC, ITM, IVA, PTA and TPR
//
mov t0 = ar.itc
mov t1 = cr.itm
add t3 = KpsSpecialRegisters+KsApITC, a0
add t4 = KpsSpecialRegisters+KsApITM, a0
;;
mov t5 = cr.iva
mov t6 = cr.pta
st8 [t3] = t0, KsApIVA-KsApITC
st8 [t4] = t1, KsApPTA-KsApITM
;;
mov t0 = cr.tpr
mov t1 = ar.k0
st8 [t3] = t5, KsSaTPR-KsApIVA
st8 [t4] = t6, KsApKR0-KsApPTA
;;
mov t5 = ar.k1
mov t6 = ar.k2
st8 [t3] = t0, KsApKR1-KsSaTPR
st8 [t4] = t1, KsApKR2-KsApKR0
;;
mov t0 = ar.k3
mov t1 = ar.k4
st8 [t3] = t5, KsApKR3-KsApKR1
st8 [t4] = t6, KsApKR4-KsApKR2
;;
mov t5 = ar.k5
mov t6 = ar.k6
st8 [t3] = t0, KsApKR5-KsApKR3
st8 [t4] = t1, KsApKR6-KsApKR4
;;
mov t0 = ar.k7
mov t1 = cr.lid
st8 [t3] = t5, KsApKR7-KsApKR5
st8 [t4] = t6, KsSaLID-KsApKR6
;;
mov t5 = cr.irr0
mov t6 = cr.irr1
st8 [t3] = t0, KsSaIRR0-KsApKR7
st8 [t4] = t1, KsSaIRR1-KsSaLID
;;
mov t0 = cr.irr2
mov t1 = cr.irr3
st8 [t3] = t5, KsSaIRR2-KsSaIRR0
st8 [t4] = t6, KsSaIRR3-KsSaIRR1
;;
mov t5 = cr.itv
mov t6 = cr.pmv
st8 [t3] = t0, KsSaITV-KsSaIRR2
st8 [t4] = t1, KsSaPMV-KsSaIRR3
;;
mov t0 = cr.cmcv
mov t1 = cr.lrr0
st8 [t3] = t5, KsSaCMCV-KsSaITV
st8 [t4] = t6, KsSaLRR0-KsSaPMV
;;
mov t5 = cr.lrr1
mov t6 = cr.gpta
st8 [t3] = t0, KsSaLRR1-KsSaCMCV
st8 [t4] = t1, KsApGPTA-KsSaLRR0
mov t7 = 0
mov t8 = 1
;;
mov t0 = cpuid[t7]
mov t1 = cpuid[t8]
st8 [t3] = t5
st8 [t4] = t6
mov t9 = 2
mov t10 = 3
add t3 = KpsSpecialRegisters+KsApCPUID0, a0
add t4 = KpsSpecialRegisters+KsApCPUID1, a0
;;
mov t5 = cpuid[t9]
mov t6 = cpuid[t10]
st8 [t3] = t0, KsApCPUID2-KsApCPUID0
st8 [t4] = t1, KsApCPUID3-KsApCPUID1
mov t7 = 4
mov t8 = 652
;;
mov t0 = cpuid[t7]
st8 [t3] = t5, KsApCPUID4-KsApCPUID2
st8 [t4] = t6
;;
st8 [t3] = t0
LEAF_RETURN
LEAF_EXIT(KiSaveProcessorControlState)
NESTED_ENTRY(KiRestoreProcessorControlState)
NESTED_SETUP(0,2,0,0)
;;
br.call.spnt brp = KiLoadKernelDebugRegisters
;;
NESTED_RETURN
NESTED_EXIT(KiRestoreProcessorControlState)
PublicFunction(KiSaveExceptionFrame)
PublicFunction(KiRestoreExceptionFrame)
PublicFunction(KiIpiServiceRoutine)
NESTED_ENTRY(KeIpiInterrupt)
NESTED_SETUP(1, 2, 2, 0)
.fframe ExceptionFrameLength
add sp = -ExceptionFrameLength, sp
;;
PROLOGUE_END
add out0 = STACK_SCRATCH_AREA, sp // -> exception frame
br.call.sptk brp = KiSaveExceptionFrame
;;
add out1 = STACK_SCRATCH_AREA, sp // -> exception frame
mov out0 = a0 // -> trap frame
br.call.sptk brp = KiIpiServiceRoutine
;;
add out0 = STACK_SCRATCH_AREA, sp // -> exception frame
br.call.sptk brp = KiRestoreExceptionFrame
;;
add sp = ExceptionFrameLength, sp
NESTED_RETURN
NESTED_EXIT(KeIpiInterrupt)
LEAF_ENTRY(KiReadMsr)
mov v0 = msr[a0]
LEAF_RETURN
LEAF_EXIT(KiReadMsr)
LEAF_ENTRY(KiWriteMsr)
mov msr[a0] = a1
LEAF_RETURN
LEAF_EXIT(KiWriteMsr)