630 lines
17 KiB
ArmAsm
630 lines
17 KiB
ArmAsm
|
// TITLE("Interprocessor Interrupt support routines")
|
|||
|
//++
|
|||
|
//
|
|||
|
// Copyright (c) 1993 Microsoft Corporation
|
|||
|
// Copyright (c) 1993 Digital Equipment Corporation
|
|||
|
//
|
|||
|
// Module Name:
|
|||
|
//
|
|||
|
// mpipi.s
|
|||
|
//
|
|||
|
// Abstract:
|
|||
|
//
|
|||
|
// This module implements the Alpha AXP specific functions required to
|
|||
|
// support multiprocessor systems.
|
|||
|
//
|
|||
|
// Author:
|
|||
|
//
|
|||
|
// David N. Cutler (davec) 22-Apr-1993
|
|||
|
// Joe Notarangelo 29-Nov-1993
|
|||
|
//
|
|||
|
// Environment:
|
|||
|
//
|
|||
|
// Kernel mode only.
|
|||
|
//
|
|||
|
// Revision History:
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#include "ksalpha.h"
|
|||
|
|
|||
|
SBTTL("Interprocess Interrupt Processing")
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KeIpiInterrupt (
|
|||
|
// IN PKTRAP_FRAME TrapFrame
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine is entered as the result of an interprocessor interrupt.
|
|||
|
// It's function is to process all interprocess immediate and packet
|
|||
|
// requests.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// TrapFrame (fp/s6) - Supplies a pointer to a trap frame.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
NESTED_ENTRY(KeIpiInterrupt, ExceptionFrameLength, zero)
|
|||
|
|
|||
|
lda sp, -ExceptionFrameLength(sp) // allocate exception frame
|
|||
|
stq ra, ExIntRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Process all interprocessor requests.
|
|||
|
//
|
|||
|
|
|||
|
bsr ra, KiIpiProcessRequests // process requests
|
|||
|
and v0, IPI_FREEZE, t0 // check if freeze is requested
|
|||
|
beq t0, 10f // if eq, no freeze requested
|
|||
|
|
|||
|
//
|
|||
|
// Save the volatile floating state, the nonvolatile floating state,
|
|||
|
// and the nonvolatile integer state.
|
|||
|
//
|
|||
|
|
|||
|
bsr ra, KiSaveVolatileFloatState // save volatile float in trap
|
|||
|
bsr ra, KiSaveNonVolatileFloatState // save nv float in exception
|
|||
|
stq s0, ExIntS0(sp) // save nonvolatile integer state
|
|||
|
stq s1, ExIntS1(sp) //
|
|||
|
stq s2, ExIntS2(sp) //
|
|||
|
stq s3, ExIntS3(sp) //
|
|||
|
stq s4, ExIntS4(sp) //
|
|||
|
stq s5, ExIntS5(sp) //
|
|||
|
stq fp, ExIntFp(sp) //
|
|||
|
|
|||
|
//
|
|||
|
// Freeze the execution of the current processor.
|
|||
|
//
|
|||
|
|
|||
|
bis fp, zero, a0 // set address of trap frame
|
|||
|
bis sp, zero, a1 // set address of exception frame
|
|||
|
bsr ra, KiFreezeTargetExecution // freeze current processor
|
|||
|
|
|||
|
//
|
|||
|
// Restore the volatile floating state, the nonvolatile floating state,
|
|||
|
// and the nonvolatile integer state.
|
|||
|
//
|
|||
|
|
|||
|
ldq s0, ExIntS0(sp) // restore nonvolatile integer state
|
|||
|
ldq s1, ExIntS1(sp) //
|
|||
|
ldq s2, ExIntS2(sp) //
|
|||
|
ldq s3, ExIntS3(sp) //
|
|||
|
ldq s4, ExIntS4(sp) //
|
|||
|
ldq s5, ExIntS5(sp) //
|
|||
|
ldq fp, ExIntFp(sp) //
|
|||
|
bsr ra, KiRestoreVolatileFloatState // restore volatile float
|
|||
|
bsr ra, KiRestoreNonVolatileFloatState // restore nv float state
|
|||
|
|
|||
|
//
|
|||
|
// Cleanup and return to the caller.
|
|||
|
//
|
|||
|
|
|||
|
10: ldq ra, ExIntRa(sp) // restore return address
|
|||
|
lda sp, ExceptionFrameLength(sp) // deallocate exception frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end KeIpiInterrupt
|
|||
|
|
|||
|
SBTTL("Processor Request")
|
|||
|
//++
|
|||
|
//
|
|||
|
// ULONG
|
|||
|
// KiIpiProcessRequests (
|
|||
|
// VOID
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine processes interprocessor requests and returns a summary
|
|||
|
// of the requests that were processed.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// The request summary is returned as the function value.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
.struct 0
|
|||
|
PrS0: .space 8 // saved integer register s0
|
|||
|
PrS1: .space 8 // saved integer register s1
|
|||
|
.space 8 // fill
|
|||
|
PrRa: .space 8 // saved return address
|
|||
|
PrFrameLength:
|
|||
|
|
|||
|
NESTED_ENTRY(KiIpiProcessRequests, PrFrameLength, zero)
|
|||
|
|
|||
|
lda sp, -PrFrameLength(sp) // allocate stack frame
|
|||
|
stq s0, PrS0(sp) // save integer register s0
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
stq s1, PrS1(sp) // save integer register s1
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
stq ra, PrRa(sp) // save return address
|
|||
|
|
|||
|
PROLOGUE_END
|
|||
|
|
|||
|
//
|
|||
|
// Read request summary and write a zero result interlocked.
|
|||
|
//
|
|||
|
|
|||
|
mb // get consistent view of memory
|
|||
|
|
|||
|
GET_PROCESSOR_CONTROL_BLOCK_BASE // get current prcb address
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
LDP s1, PbIpiCounts(v0) // get interrupt count structure address
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
10: ldq_l s0, PbRequestSummary(v0) // get request summary and entry address
|
|||
|
bis zero, zero, t1 // set zero value for store
|
|||
|
stq_c t1, PbRequestSummary(v0) // zero request summary, conditionally
|
|||
|
beq t1, 15f // if eq, store conditional failed
|
|||
|
sra s0, 16, a0 // shift out entry address
|
|||
|
|
|||
|
//
|
|||
|
// Check for Packet ready.
|
|||
|
//
|
|||
|
// If a packet is ready, then get the address of the requested function
|
|||
|
// and call the function passing the address of the packet address as a
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
|
|||
|
and s0, IPI_PACKET_READY, t2 // check for packet ready
|
|||
|
beq t2, 20f // if eq, no packet ready
|
|||
|
bic a0, 1, v0 // clear low order packet address bit
|
|||
|
LDP t2, PbWorkerRoutine(v0) // get address of worker function
|
|||
|
LDP a1, PbCurrentPacket(v0) // get request parameters
|
|||
|
|
|||
|
#if defined(_AXP64_)
|
|||
|
|
|||
|
ldq a2, PbCurrentPacket + 8(v0) //
|
|||
|
ldq a3, PbCurrentPacket + 16(v0) //
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
ldl a2, PbCurrentPacket + 4(v0) //
|
|||
|
ldl a3, PbCurrentPacket + 8(v0) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
jsr ra, (t2) // call worker routine
|
|||
|
mb // synchronize memory access
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
ldl t1, IcPacket(s1) // increment number of packet requests
|
|||
|
addl t1, 1, t1 //
|
|||
|
stl t1, IcPacket(s1) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Check for APC interrupt request.
|
|||
|
//
|
|||
|
// If an APC interrupt is requested, then request a software interrupt at
|
|||
|
// APC level on the current processor.
|
|||
|
//
|
|||
|
|
|||
|
20: and s0, IPI_APC, t1 // check for APC interrupt request
|
|||
|
beq t1, 30f // if eq, no APC interrupt requested
|
|||
|
ldil a0, APC_LEVEL // set interrupt request level
|
|||
|
|
|||
|
REQUEST_SOFTWARE_INTERRUPT // request APC interrupt
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
ldl t1, IcAPC(s1) // increment number of APC requests
|
|||
|
addl t1, 1, t1 //
|
|||
|
stl t1, IcAPC(s1) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Check for DPC interrupt request.
|
|||
|
//
|
|||
|
// If a DPC interrupt is requested, then request a software interrupt at
|
|||
|
// DPC level on the current processor.
|
|||
|
//
|
|||
|
|
|||
|
30: and s0, IPI_DPC, t1 // check for DPC interrupt request
|
|||
|
beq t1, 40f // if eq, no DPC interrupt requested
|
|||
|
ldil a0, DISPATCH_LEVEL // set interrupt request level
|
|||
|
|
|||
|
REQUEST_SOFTWARE_INTERRUPT // request DPC interrupt
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
ldl t1, IcDPC(s1) // increment number of DPC requests
|
|||
|
addl t1, 1, t1 //
|
|||
|
stl t1, IcDPC(s1) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Set function return value, restore registers, and return.
|
|||
|
//
|
|||
|
|
|||
|
40: bis s0, zero, v0 // set function return value
|
|||
|
ldq s0, PrS0(sp) // restore integer register s0
|
|||
|
|
|||
|
#if NT_INST
|
|||
|
|
|||
|
and v0, IPI_FREEZE, t1 // check if freeze requested
|
|||
|
beq t1, 50f // if eq, no freeze requested
|
|||
|
ldl t1, IcFreeze(s1) // increment number of freeze requests
|
|||
|
addl t1, 1, t1 //
|
|||
|
stl t1, IcFreeze(s1) //
|
|||
|
50: ldq s1, PrS1(sp) // restore integer register s1
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
ldq ra, PrRa(sp) // restore return address
|
|||
|
lda sp, PrFrameLength(sp) // deallocate stack frame
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
//
|
|||
|
// Conditional store failed.
|
|||
|
//
|
|||
|
|
|||
|
15: br zero, 10b // store conditonal failed, retry
|
|||
|
|
|||
|
.end KiIpiProcessRequests
|
|||
|
|
|||
|
SBTTL("Send Interprocess Request")
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KiIpiSend (
|
|||
|
// IN KAFINITY TargetProcessors,
|
|||
|
// IN KIPI_REQUEST IpiRequest
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine requests the specified operation on the target set of
|
|||
|
// processors.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// TargetProcessors (a0) - Supplies the set of processors on which the
|
|||
|
// specified operation is to be executed.
|
|||
|
//
|
|||
|
// IpiRequest (a1) - Supplies the request operation mask.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiIpiSend)
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
bis a0, zero, t0 // copy target processor set
|
|||
|
lda t1, KiProcessorBlock // get processor block array address
|
|||
|
10: blbc t0, 30f // if lbc, target processor not set
|
|||
|
LDP t2, 0(t1) // get target processor block address
|
|||
|
|
|||
|
//
|
|||
|
// Merge the new request into the target processor request summary.
|
|||
|
// The store is conditional to ensure that no updates are lost.
|
|||
|
//
|
|||
|
|
|||
|
20: ldq_l t3, PbRequestSummary(t2) // get target request summary
|
|||
|
bis t3, a1, t4 // merge new request with summary
|
|||
|
stq_c t4, PbRequestSummary(t2) // set new request summary
|
|||
|
beq t4, 25f // if eq, store conditional failed
|
|||
|
30: srl t0, 1, t0 // shift to next target
|
|||
|
|
|||
|
#if defined(_AXP64_)
|
|||
|
|
|||
|
lda t1, 8(t1) // get next processor block element
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
lda t1, 4(t1) // get next processor block element
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
bne t0, 10b // if ne, more targets requested
|
|||
|
mb // synchronize memory access
|
|||
|
LDP t0, __imp_HalRequestIpi // request IPI interrupt on targets
|
|||
|
jmp zero, (t0) //
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
ret zero, (ra) // simply return for uni-processor
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Conditional store failed.
|
|||
|
//
|
|||
|
|
|||
|
25: br zero, 20b // store conditional failed, retry
|
|||
|
|
|||
|
.end KiIpiSend
|
|||
|
|
|||
|
SBTTL("Send Interprocess Request Packet")
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KiIpiSendPacket (
|
|||
|
// IN KAFFINITY TargetProcessors,
|
|||
|
// IN PKIPI_WORKER WorkerFunction,
|
|||
|
// IN PVOID Parameter1,
|
|||
|
// IN PVOID Parameter2,
|
|||
|
// IN PVOID Parameter3
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine executes the specified worker function on the specified
|
|||
|
// set of processors.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// TargetProcessors (a0) - Supplies the set of processors on which the
|
|||
|
// specified operation is to be executed.
|
|||
|
//
|
|||
|
// WorkerFunction (a1) - Supplies the address of the worker function.
|
|||
|
//
|
|||
|
// Parameter1 - Parameter3 - Supplies arguments for worker.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
|
|||
|
LEAF_ENTRY(KiIpiSendPacket)
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
GET_PROCESSOR_CONTROL_BLOCK_BASE // get current prcb address
|
|||
|
|
|||
|
bis a0, zero, t1 // copy target processor set
|
|||
|
lda t2, KiProcessorBlock // get processor block array address
|
|||
|
|
|||
|
//
|
|||
|
// Store function address and parameters in the packet area of the PRCB on
|
|||
|
// the current processor.
|
|||
|
//
|
|||
|
|
|||
|
stl a0, PbTargetSet(v0) // set target processor set
|
|||
|
STP a1, PbWorkerRoutine(v0) // set worker function address
|
|||
|
STP a2, PbCurrentPacket(v0) // store worker function parameters
|
|||
|
|
|||
|
#if defined(_AXP64_)
|
|||
|
|
|||
|
stq a3, PbCurrentPacket + 8(v0) //
|
|||
|
stq a4, PbCurrentPacket + 16(v0) //
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
stl a3, PbCurrentPacket + 4(v0) //
|
|||
|
stl a4, PbCurrentPacket + 8(v0) //
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
subl a0, 1, a1 // compute target set - 1
|
|||
|
and a1, a0, a1 // and target set with target set - 1
|
|||
|
zapnot a1, 0xf, a1 // clear upper 32 bits
|
|||
|
cmpeq a1, zero, a1 // compare if result is zero
|
|||
|
bne a1, 5f // if ne, one and only one bit set
|
|||
|
stl a0, PbPacketBarrier(v0) // set packet barrier
|
|||
|
5: mb // synchronize memory access
|
|||
|
ADDP v0, a1, v0 // set low bit if appropriate
|
|||
|
|
|||
|
//
|
|||
|
// Loop through the target processors and send the packet to the specified
|
|||
|
// recipients.
|
|||
|
//
|
|||
|
|
|||
|
10: blbc t1, 30f // if eq, target not specified
|
|||
|
LDP t0, 0(t2) // get target processor block address
|
|||
|
sll v0, 16, t3 // shift packet address into position
|
|||
|
bis t3, IPI_PACKET_READY, t3 // set packet ready in low 32 bits
|
|||
|
20: ldq_l t4, PbRequestSummary(t0) // get request summary of target
|
|||
|
and t4, IPI_PACKET_READY, t6 // check if target packet busy
|
|||
|
bne t6, 25f // if ne, target packet busy
|
|||
|
bis t4, t3, t4 // set entry address in request summary
|
|||
|
stq_c t4, PbRequestSummary(t0) // store request summary and address
|
|||
|
beq t4, 20b // if eq, store conditional failed
|
|||
|
|
|||
|
#if defined(_AXP64_)
|
|||
|
|
|||
|
30: lda t2, 8(t2) // advance to next array element
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
30: lda t2, 4(t2) // advance to next array element
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
srl t1, 1, t1 // shift to next target
|
|||
|
bne t1, 10b // if ne, more targets to process
|
|||
|
mb // synchronize memory access
|
|||
|
LDP t0, __imp_HalRequestIpi // request IPI interrupt on targets
|
|||
|
jmp zero, (t0) //
|
|||
|
|
|||
|
//
|
|||
|
// Packet not ready, spin in cache until it looks available.
|
|||
|
//
|
|||
|
|
|||
|
25: ldq t4, PbRequestSummary(t0) // get request summary of target
|
|||
|
and t4, IPI_PACKET_READY, t6 // check if target packet busy
|
|||
|
beq t6, 20b // looks available, try again
|
|||
|
br zero, 25b // spin again
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
ret zero, (ra)
|
|||
|
|
|||
|
#endif //!NT_UP
|
|||
|
|
|||
|
.end KiIpiSendPacket
|
|||
|
|
|||
|
SBTTL("Restore Processor Control State")
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KiRestoreProcessorControlState (
|
|||
|
// IN PKPROCESSOR_STATE ProcessorState
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine restores the processor control state for the debugger.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// ProcessorState (a0) - Pointer to PROCSSOR_STATE
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiRestoreProcessorControlState)
|
|||
|
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end KiRestoreProcessorControlState
|
|||
|
|
|||
|
SBTTL("Save Processor Control State")
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KiSaveProcessorControlState (
|
|||
|
// IN PKPROCESSOR_STATE ProcessorState
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine saves the processor control state for the debugger.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// ProcessorState (a0) - Pointer to PROCSSOR_STATE
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
LEAF_ENTRY(KiSaveProcessorControlState)
|
|||
|
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end KiSaveProcessorControlState
|
|||
|
|
|||
|
SBTTL("Signal Packet Done")
|
|||
|
//++
|
|||
|
//
|
|||
|
// VOID
|
|||
|
// KiIpiSignalPacketDone (
|
|||
|
// IN PKIPI_CONTEXT SignalDone
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine signals that a processor has completed a packet by
|
|||
|
// clearing the calling processor's set member of the requesting
|
|||
|
// processor's packet.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// SignalDone (a0) - Supplies a pointer to the processor block of the
|
|||
|
// sending processor.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LEAF_ENTRY(KiIpiSignalPacketDone)
|
|||
|
|
|||
|
GET_PROCESSOR_CONTROL_REGION_BASE // get current pcr address
|
|||
|
|
|||
|
blbs a0, 30f // if lbs, one and only one bit set
|
|||
|
ldl a1, PcSetMember(v0) // get processor set member
|
|||
|
mb // synchronize memory access
|
|||
|
10: ldl_l a2, PbTargetSet(a0) // get request target set
|
|||
|
bic a2, a1, a2 // clear processor set member
|
|||
|
mov a2, v0 // save result target set
|
|||
|
stl_c a2, PbTargetSet(a0) // store target set
|
|||
|
beq a2, 10b // if eq, store conditional failed
|
|||
|
bne v0, 20f // if ne, more targets to go
|
|||
|
stl zero, PbPacketBarrier(a0) // clear packet barrier
|
|||
|
mb // synchronize memory access
|
|||
|
20: ret zero, (ra) // return
|
|||
|
|
|||
|
30: stl zero, PbTargetSet - 1(a0) // clear target set
|
|||
|
mb // synchronize memory access
|
|||
|
ret zero, (ra) //
|
|||
|
|
|||
|
.end KiIpiSignalPacketDone
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
SBTTL("Read Memory Barrier Time Stamp")
|
|||
|
//++
|
|||
|
//
|
|||
|
// ULONG
|
|||
|
// KeReadMbTimeStamp (
|
|||
|
// VOID
|
|||
|
// );
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// This routine reads the current memory bazrrier time stamp value.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// None.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// The current value of the memory barrier time stamp is returned as the
|
|||
|
// function value.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#if !defined(NT_UP)
|
|||
|
|
|||
|
LEAF_ENTRY(KeReadMbTimeStamp)
|
|||
|
|
|||
|
ldl_l v0,KiMbTimeStamp // read current memory barrier time stamp
|
|||
|
ret zero, (ra) // return
|
|||
|
|
|||
|
.end KeReadMbTimeStamp
|
|||
|
|
|||
|
#endif
|