NT4/private/ntos/ke/mips/flush.c
2020-09-30 17:12:29 +02:00

821 lines
16 KiB
C
Raw 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.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
flush.c
Abstract:
This module implements MIPS machine dependent kernel functions to flush
the data and instruction caches and to flush I/O buffers.
Author:
David N. Cutler (davec) 26-Apr-1990
Environment:
Kernel mode only.
Revision History:
--*/
#include "ki.h"
ULONG ChangeColor;
//
// Define forward referenced prototyes.
//
VOID
KiChangeColorPageTarget (
IN PULONG SignalDone,
IN PVOID NewColor,
IN PVOID OldColor,
IN PVOID PageFrame
);
VOID
KiSweepDcacheTarget (
IN PULONG SignalDone,
IN PVOID Parameter1,
IN PVOID Parameter2,
IN PVOID Parameter3
);
VOID
KiSweepIcacheTarget (
IN PULONG SignalDone,
IN PVOID Parameter1,
IN PVOID Parameter2,
IN PVOID Parameter3
);
VOID
KiSweepIcacheRangeTarget (
IN PULONG SignalDone,
IN PVOID BaseAddress,
IN PVOID Length,
IN PVOID Parameter3
);
VOID
KiFlushIoBuffersTarget (
IN PULONG SignalDone,
IN PVOID Mdl,
IN PVOID ReadOperation,
IN PVOID DmaOperation
);
VOID
KeChangeColorPage (
IN PVOID NewColor,
IN PVOID OldColor,
IN ULONG PageFrame
)
/*++
Routine Description:
This routine changes the color of a page.
Arguments:
NewColor - Supplies the page aligned virtual address of the new color
the page to change.
OldColor - Supplies the page aligned virtual address of the old color
of the page to change.
PageFrame - Supplies the page frame number of the page that is changed.
Return Value:
None.
--*/
{
KIRQL OldIrql;
KAFFINITY TargetProcessors;
ASSERT(KeGetCurrentIrql() <= KiSynchIrql);
ChangeColor += 1;
//
// Raise IRQL to synchronization level to prevent a context switch.
//
#if !defined(NT_UP)
OldIrql = KeRaiseIrqlToSynchLevel();
//
// Compute the set of target processors and send the change color
// parameters to the target processors, if any, for execution.
//
TargetProcessors = KeActiveProcessors & PCR->NotMember;
if (TargetProcessors != 0) {
KiIpiSendPacket(TargetProcessors,
KiChangeColorPageTarget,
(PVOID)NewColor,
(PVOID)OldColor,
(PVOID)PageFrame);
}
#endif
//
// Change the color of the page on the current processor.
//
HalChangeColorPage(NewColor, OldColor, PageFrame);
//
// Wait until all target processors have finished changing the color
// of the page.
//
#if !defined(NT_UP)
if (TargetProcessors != 0) {
KiIpiStallOnPacketTargets();
}
//
// Lower IRQL to its previous level and return.
//
KeLowerIrql(OldIrql);
#endif
return;
}
VOID
KiChangeColorPageTarget (
IN PULONG SignalDone,
IN PVOID NewColor,
IN PVOID OldColor,
IN PVOID PageFrame
)
/*++
Routine Description:
This is the target function for changing the color of a page.
Arguments:
SignalDone Supplies a pointer to a variable that is cleared when the
requested operation has been performed.
NewColor - Supplies the page aligned virtual address of the new color
the page to change.
OldColor - Supplies the page aligned virtual address of the old color
of the page to change.
PageFrame - Supplies the page frame number of the page that is changed.
Return Value:
None.
--*/
{
//
// Change the color of the page on the current processor and clear
// change color packet address to signal the source to continue.
//
#if !defined(NT_UP)
HalChangeColorPage(NewColor, OldColor, (ULONG)PageFrame);
KiIpiSignalPacketDone(SignalDone);
#endif
return;
}
VOID
KeSweepDcache (
IN BOOLEAN AllProcessors
)
/*++
Routine Description:
This function flushes the data cache on all processors that are currently
running threads which are children of the current process or flushes the
data cache on all processors in the host configuration.
Arguments:
AllProcessors - Supplies a boolean value that determines which data
caches are flushed.
Return Value:
None.
--*/
{
KIRQL OldIrql;
KAFFINITY TargetProcessors;
ASSERT(KeGetCurrentIrql() <= KiSynchIrql);
//
// Raise IRQL to synchronization level to prevent a context switch.
//
#if !defined(NT_UP)
OldIrql = KeRaiseIrqlToSynchLevel();
//
// Compute the set of target processors and send the sweep parameters
// to the target processors, if any, for execution.
//
TargetProcessors = KeActiveProcessors & PCR->NotMember;
if (TargetProcessors != 0) {
KiIpiSendPacket(TargetProcessors,
KiSweepDcacheTarget,
NULL,
NULL,
NULL);
}
#endif
//
// Sweep the data cache on the current processor.
//
HalSweepDcache();
//
// Wait until all target processors have finished sweeping the their
// data cache.
//
#if !defined(NT_UP)
if (TargetProcessors != 0) {
KiIpiStallOnPacketTargets();
}
//
// Lower IRQL to its previous level and return.
//
KeLowerIrql(OldIrql);
#endif
return;
}
VOID
KiSweepDcacheTarget (
IN PULONG SignalDone,
IN PVOID Parameter1,
IN PVOID Parameter2,
IN PVOID Parameter3
)
/*++
Routine Description:
This is the target function for sweeping the data cache on target
processors.
Arguments:
SignalDone Supplies a pointer to a variable that is cleared when the
requested operation has been performed.
Parameter1 - Parameter3 - Not used.
Return Value:
None.
--*/
{
//
// Sweep the data cache on the current processor and clear the sweep
// data cache packet address to signal the source to continue.
//
#if !defined(NT_UP)
HalSweepDcache();
KiIpiSignalPacketDone(SignalDone);
#endif
return;
}
VOID
KeSweepIcache (
IN BOOLEAN AllProcessors
)
/*++
Routine Description:
This function flushes the instruction cache on all processors that are
currently running threads which are children of the current process or
flushes the instruction cache on all processors in the host configuration.
Arguments:
AllProcessors - Supplies a boolean value that determines which instruction
caches are flushed.
Return Value:
None.
--*/
{
KIRQL OldIrql;
KAFFINITY TargetProcessors;
ASSERT(KeGetCurrentIrql() <= KiSynchIrql);
//
// Raise IRQL to synchrnization level to prevent a context switch.
//
#if !defined(NT_UP)
OldIrql = KeRaiseIrqlToSynchLevel();
//
// Compute the set of target processors and send the sweep parameters
// to the target processors, if any, for execution.
//
TargetProcessors = KeActiveProcessors & PCR->NotMember;
if (TargetProcessors != 0) {
KiIpiSendPacket(TargetProcessors,
KiSweepIcacheTarget,
NULL,
NULL,
NULL);
}
#endif
//
// Sweep the instruction cache on the current processor.
//
HalSweepIcache();
HalSweepDcache();
//
// Wait until all target processors have finished sweeping the their
// instruction cache.
//
#if !defined(NT_UP)
if (TargetProcessors != 0) {
KiIpiStallOnPacketTargets();
}
//
// Lower IRQL to its previous level and return.
//
KeLowerIrql(OldIrql);
#endif
return;
}
VOID
KiSweepIcacheTarget (
IN PULONG SignalDone,
IN PVOID Parameter1,
IN PVOID Parameter2,
IN PVOID Parameter3
)
/*++
Routine Description:
This is the target function for sweeping the instruction cache on
target processors.
Arguments:
SignalDone Supplies a pointer to a variable that is cleared when the
requested operation has been performed.
Parameter1 - Parameter3 - Not used.
Return Value:
None.
--*/
{
//
// Sweep the instruction cache on the current processor and clear
// the sweep instruction cache packet address to signal the source
// to continue.
//
#if !defined(NT_UP)
HalSweepIcache();
HalSweepDcache();
KiIpiSignalPacketDone(SignalDone);
#endif
return;
}
VOID
KeSweepIcacheRange (
IN BOOLEAN AllProcessors,
IN PVOID BaseAddress,
IN ULONG Length
)
/*++
Routine Description:
This function flushes the an range of virtual addresses from the primary
instruction cache on all processors that are currently running threads
which are children of the current process or flushes the range of virtual
addresses from the primary instruction cache on all processors in the host
configuration.
Arguments:
AllProcessors - Supplies a boolean value that determines which instruction
caches are flushed.
BaseAddress - Supplies a pointer to the base of the range that is flushed.
Length - Supplies the length of the range that is flushed if the base
address is specified.
Return Value:
None.
--*/
{
ULONG Offset;
KIRQL OldIrql;
KAFFINITY TargetProcessors;
ASSERT(KeGetCurrentIrql() <= KiSynchIrql);
//
// If the length of the range is greater than the size of the primary
// instruction cache, then set the length of the flush to the size of
// the primary instruction cache and set the base address of zero.
//
// N.B. It is assumed that the size of the primary instruction and
// data caches are the same.
//
if (Length > PCR->FirstLevelIcacheSize) {
BaseAddress = (PVOID)0;
Length = PCR->FirstLevelIcacheSize;
}
//
// Raise IRQL to synchronization level to prevent a context switch.
//
#if !defined(NT_UP)
OldIrql = KeRaiseIrqlToSynchLevel();
//
// Compute the set of target processors, and send the sweep range
// parameters to the target processors, if any, for execution.
//
TargetProcessors = KeActiveProcessors & PCR->NotMember;
if (TargetProcessors != 0) {
KiIpiSendPacket(TargetProcessors,
KiSweepIcacheRangeTarget,
(PVOID)BaseAddress,
(PVOID)Length,
NULL);
}
#endif
//
// Flush the specified range of virtual addresses from the primary
// instruction cache.
//
Offset = (ULONG)BaseAddress & PCR->IcacheAlignment;
HalSweepIcacheRange((PVOID)((ULONG)BaseAddress & ~PCR->IcacheAlignment),
(Offset + Length + PCR->IcacheAlignment) & ~PCR->IcacheAlignment);
Offset = (ULONG)BaseAddress & PCR->DcacheAlignment;
HalSweepDcacheRange((PVOID)((ULONG)BaseAddress & ~PCR->DcacheAlignment),
(Offset + Length + PCR->DcacheAlignment) & ~PCR->DcacheAlignment);
//
// Wait until all target processors have finished sweeping the specified
// range of addresses from the instruction cache.
//
#if !defined(NT_UP)
if (TargetProcessors != 0) {
KiIpiStallOnPacketTargets();
}
//
// Lower IRQL to its previous level and return.
//
KeLowerIrql(OldIrql);
#endif
return;
}
VOID
KiSweepIcacheRangeTarget (
IN PULONG SignalDone,
IN PVOID BaseAddress,
IN PVOID Length,
IN PVOID Parameter3
)
/*++
Routine Description:
This is the target function for sweeping a range of addresses from the
instruction cache.
processors.
Arguments:
SignalDone Supplies a pointer to a variable that is cleared when the
requested operation has been performed.
BaseAddress - Supplies a pointer to the base of the range that is flushed.
Length - Supplies the length of the range that is flushed if the base
address is specified.
Parameter3 - Not used.
Return Value:
None.
--*/
{
ULONG Offset;
//
// Sweep the specified instruction cache range on the current processor.
//
#if !defined(NT_UP)
Offset = (ULONG)(BaseAddress) & PCR->IcacheAlignment;
HalSweepIcacheRange((PVOID)((ULONG)(BaseAddress) & ~PCR->IcacheAlignment),
(Offset + (ULONG)Length + PCR->IcacheAlignment) & ~PCR->IcacheAlignment);
Offset = (ULONG)(BaseAddress) & PCR->DcacheAlignment;
HalSweepDcacheRange((PVOID)((ULONG)(BaseAddress) & ~PCR->DcacheAlignment),
(Offset + (ULONG)Length + PCR->DcacheAlignment) & ~PCR->DcacheAlignment);
KiIpiSignalPacketDone(SignalDone);
#endif
return;
}
VOID
KeFlushIoBuffers (
IN PMDL Mdl,
IN BOOLEAN ReadOperation,
IN BOOLEAN DmaOperation
)
/*++
Routine Description:
This function flushes the I/O buffer specified by the memory descriptor
list from the data cache on all processors.
Arguments:
Mdl - Supplies a pointer to a memory descriptor list that describes the
I/O buffer location.
ReadOperation - Supplies a boolean value that determines whether the I/O
operation is a read into memory.
DmaOperation - Supplies a boolean value that determines whether the I/O
operation is a DMA operation.
Return Value:
None.
--*/
{
KIRQL OldIrql;
KAFFINITY TargetProcessors;
ASSERT(KeGetCurrentIrql() <= KiSynchIrql);
//
// If the operation is a DMA operation, then check if the flush
// can be avoided because the host system supports the right set
// of cache coherency attributes. Otherwise, the flush can also
// be avoided if the operation is a programmed I/O and not a page
// read.
//
if (DmaOperation != FALSE) {
if (ReadOperation != FALSE) {
if ((KiDmaIoCoherency & DMA_READ_ICACHE_INVALIDATE) != 0) {
ASSERT((KiDmaIoCoherency & DMA_READ_DCACHE_INVALIDATE) != 0);
return;
} else if (((Mdl->MdlFlags & MDL_IO_PAGE_READ) == 0) &&
((KiDmaIoCoherency & DMA_READ_DCACHE_INVALIDATE) != 0)) {
return;
}
} else if ((KiDmaIoCoherency & DMA_WRITE_DCACHE_SNOOP) != 0) {
return;
}
} else if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) == 0) {
return;
}
//
// Either the operation is a DMA operation and the right coherency
// atributes are not supported by the host system, or the operation
// is programmed I/O and a page read.
//
// Raise IRQL to synchronization level to prevent a context switch.
//
OldIrql = KeRaiseIrqlToSynchLevel();
//
// Compute the set of target processors, and send the flush I/O
// parameters to the target processors, if any, for execution.
//
#if !defined(NT_UP)
TargetProcessors = KeActiveProcessors & PCR->NotMember;
if (TargetProcessors != 0) {
KiIpiSendPacket(TargetProcessors,
KiFlushIoBuffersTarget,
(PVOID)Mdl,
(PVOID)((ULONG)ReadOperation),
(PVOID)((ULONG)DmaOperation));
}
#endif
//
// Flush I/O buffer on current processor.
//
HalFlushIoBuffers(Mdl, ReadOperation, DmaOperation);
//
// Wait until all target processors have finished flushing the
// specified I/O buffer.
//
#if !defined(NT_UP)
if (TargetProcessors != 0) {
KiIpiStallOnPacketTargets();
}
#endif
//
// Lower IRQL to its previous level and return.
//
KeLowerIrql(OldIrql);
return;
}
VOID
KiFlushIoBuffersTarget (
IN PULONG SignalDone,
IN PVOID Mdl,
IN PVOID ReadOperation,
IN PVOID DmaOperation
)
/*++
Routine Description:
This is the target function for flushing an I/O buffer on target
processors.
Arguments:
SignalDone Supplies a pointer to a variable that is cleared when the
requested operation has been performed.
Mdl - Supplies a pointer to a memory descriptor list that describes the
I/O buffer location.
ReadOperation - Supplies a boolean value that determines whether the I/O
operation is a read into memory.
DmaOperation - Supplies a boolean value that determines whether the I/O
operation is a DMA operation.
Return Value:
None.
--*/
{
//
// Flush the specified I/O buffer on the current processor.
//
#if !defined(NT_UP)
HalFlushIoBuffers((PMDL)Mdl,
(BOOLEAN)((ULONG)ReadOperation),
(BOOLEAN)((ULONG)DmaOperation));
KiIpiSignalPacketDone(SignalDone);
#endif
return;
}