Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

610 lines
14 KiB

/*++
Copyright (c) 1991-1993 Microsoft Corporation
Module Name:
j4flshio.c
Abstract:
This module implements the system dependent kernel function to flush
the data cache for I/O transfers on a MIPS R4000 Jazz, Fision, Fusion,
or Duo system.
--*/
#include "halp.h"
/*++
Routine Description:
This routine is a wrapper for the HalpSweepIcache() routine
implemented in j4cache.s
It was necessary to implement this wrapper in order to allow
us to get a TLB mapping for the ECache invalidate register without
having to steal (hack) an R4x00 tlb entry from the kernel without
it knowing.
The wrapper is somewhat complicated in that depending on which
point in the initialization stages (Phase 0 or Phase 1) the sweep
routine is called, the tlb mapping must be gotten either through
an a call to KeFillFixedEntryTb() which uses a "wired" entry or
through MmMapIoSpace() which is the normal method for mapping
registers, buffers, etc.
Arguments:
None.
Return Value:
None.
--*/
VOID
HalSweepDcache(
VOID
)
{
ULONG Temp;
PVOID SavedAddress, BaseAddress;
PHYSICAL_ADDRESS physicalAddress;
//
// Determine who is the caller:
//
// - the HAL
// - the kernel
//
if (HalpPmpHalFlushIoBuffer) {
//
// There are 3 cases:
//
// case 1: before HalpMapIoSpace() is called
//
// case 2: after HalpMapIoSpace() is called
//
// case 3: before HalpMapFixedTbEntries() is called
//
if ((HalpExtPmpControl == (PVOID)NULL) && (HalpPmpExternalCachePresent == 1)) {
//
// Map ECache invalidate register
//
physicalAddress.HighPart = IO_ADDRESS_HI(PCI_CONFIG_SEL_PHYSICAL_BASE);
physicalAddress.LowPart = IO_ADDRESS_LO(PCI_CONFIG_SEL_PHYSICAL_BASE);
BaseAddress = MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE);
HalpExtPmpControl = (PVOID)(((ULONG)BaseAddress) + 0x4);
//
// Sweep caches
//
HalpSweepDcache(1);
//
// Unmap ECache invalidate register
//
MmUnmapIoSpace(BaseAddress, PAGE_SIZE);
HalpExtPmpControl = (PVOID)NULL;
} else if ((HalpPmpExternalCachePresent == 0) || (HalpPmpExternalCachePresent == 1)) {
//
// Sweep caches
//
HalpSweepDcache(HalpPmpExternalCachePresent);
} else {
//
// Map ECache invalidate register
//
SavedAddress = HalpExtPmpControl;
HalpMapSysCtrlReg(GLOBAL_STATUS_PHYSICAL_BASE, PCI_CONFIG_SEL_PHYSICAL_BASE, 0xFFFF6000);
HalpExtPmpControl = (PVOID) (0xFFFF6000 + PAGE_SIZE + 0x4);
Temp = READ_REGISTER_ULONG(0xFFFF6000 + REG_OFFSET(PMP(GLOBAL_CTRL_PHYSICAL_BASE)));
//
// Sweep caches
//
HalpSweepDcache(Temp & GLOBAL_CTRL_ECE ? 1 : 0);
//
// Unap ECache invalidate register
//
HalpUnMapSysCtrlReg();
HalpExtPmpControl = SavedAddress;
}
} else {
//
// There are 3 cases:
//
// case 1: before HalpMapIoSpace() is called
//
// case 2: after HalpMapIoSpace() is called
//
// case 3: before HalpMapFixedTbEntries() is called
//
if ((HalpExtPmpControl == (PVOID)NULL) && (HalpPmpExternalCachePresent == 1)) {
//
// Map ECache invalidate register
//
physicalAddress.HighPart = IO_ADDRESS_HI(PCI_CONFIG_SEL_PHYSICAL_BASE);
physicalAddress.LowPart = IO_ADDRESS_LO(PCI_CONFIG_SEL_PHYSICAL_BASE);
BaseAddress = MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE);
HalpExtPmpControl = (PVOID)(((ULONG)BaseAddress) + 0x4);
//
// Sweep caches
//
HalpSweepDcache(1);
//
// Unmap ECache invalidate register
//
MmUnmapIoSpace(BaseAddress, PAGE_SIZE);
HalpExtPmpControl = (PVOID)NULL;
} else if ((HalpPmpExternalCachePresent == 1) || (HalpPmpExternalCachePresent == 0)) {
//
// Sweep caches
//
HalpSweepDcache(HalpPmpExternalCachePresent);
} else {
//
// Map ECache invalidate register
//
SavedAddress = HalpExtPmpControl;
HalpMapSysCtrlReg(GLOBAL_STATUS_PHYSICAL_BASE, PCI_CONFIG_SEL_PHYSICAL_BASE, 0xFFFF6000);
HalpExtPmpControl = (PVOID) (0xFFFF6000 + PAGE_SIZE + 0x4);
Temp = READ_REGISTER_ULONG(0xFFFF6000 + REG_OFFSET(PMP(GLOBAL_CTRL_PHYSICAL_BASE)));
//
// Sweep caches
//
HalpSweepDcache(Temp & GLOBAL_CTRL_ECE ? 1 : 0);
//
// Unmap ECache invalidate register
//
HalpUnMapSysCtrlReg();
HalpExtPmpControl = SavedAddress;
}
}
}
/*++
Routine Description:
This routine is a wrapper for the HalpSweepIcache() routine
implemented in j4cache.s
It was necessary to implement this wrapper in order to allow
us to get a TLB mapping for the ECache invalidate register without
having to steal (hack) an R4x00 tlb entry from the kernel without
it knowing.
The wrapper is somewhat complicated in that depending on which
point in the initialization stages (Phase 0 or Phase 1) the sweep
routine is called, the tlb mapping must be gotten either through
an a call to KeFillFixedEntryTb() which uses a "wired" entry or
through MmMapIoSpace() which is the normal method for mapping
registers, buffers, etc.
Arguments:
None.
Return Value:
None.
--*/
VOID
HalSweepIcache(
VOID
)
{
ULONG Temp;
PVOID SavedAddress, BaseAddress;
PHYSICAL_ADDRESS physicalAddress;
//
// Determine who is the caller:
//
// - the HAL
// - the kernel
//
if (HalpPmpHalFlushIoBuffer) {
//
// There are 3 cases:
//
// case 1: before HalpMapIoSpace() is called
//
// case 2: after HalpMapIoSpace() is called
//
// case 3: before HalpMapFixedTbEntries() is called
//
if ((HalpExtPmpControl == (PVOID)NULL) && (HalpPmpExternalCachePresent == 1)) {
//
// Map ECache invalidate register
//
physicalAddress.HighPart = IO_ADDRESS_HI(PCI_CONFIG_SEL_PHYSICAL_BASE);
physicalAddress.LowPart = IO_ADDRESS_LO(PCI_CONFIG_SEL_PHYSICAL_BASE);
BaseAddress = MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE);
HalpExtPmpControl = (PVOID)(((ULONG)BaseAddress) + 0x4);
//
// Sweep caches
//
HalpSweepIcache(1);
//
// Unmap ECache invalidate register
//
MmUnmapIoSpace(BaseAddress, PAGE_SIZE);
HalpExtPmpControl = (PVOID)NULL;
} else if ((HalpPmpExternalCachePresent == 0) || (HalpPmpExternalCachePresent == 1)) {
//
// Sweep caches
//
HalpSweepIcache(HalpPmpExternalCachePresent);
} else {
//
// Map ECache invalidate register
//
SavedAddress = HalpExtPmpControl;
HalpMapSysCtrlReg(GLOBAL_STATUS_PHYSICAL_BASE, PCI_CONFIG_SEL_PHYSICAL_BASE, 0xFFFF6000);
HalpExtPmpControl = (PVOID) (0xFFFF6000 + PAGE_SIZE + 0x4);
Temp = READ_REGISTER_ULONG(0xFFFF6000 + REG_OFFSET(PMP(GLOBAL_CTRL_PHYSICAL_BASE)));
//
// Sweep caches
//
HalpSweepIcache(Temp & GLOBAL_CTRL_ECE ? 1 : 0);
//
// Unmap ECache invalidate register
//
HalpUnMapSysCtrlReg();
HalpExtPmpControl = SavedAddress;
}
} else {
//
// There are 3 cases:
//
// case 1: before HalpMapIoSpace() is called
//
// case 2: after HalpMapIoSpace() is called
//
// case 3: before HalpMapFixedTbEntries() is called
//
if ((HalpExtPmpControl == (PVOID)NULL) && (HalpPmpExternalCachePresent == 1)) {
//
// Map ECache invalidate register
//
physicalAddress.HighPart = IO_ADDRESS_HI(PCI_CONFIG_SEL_PHYSICAL_BASE);
physicalAddress.LowPart = IO_ADDRESS_LO(PCI_CONFIG_SEL_PHYSICAL_BASE);
BaseAddress = MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE);
HalpExtPmpControl = (PVOID)(((ULONG)BaseAddress) + 0x4);
//
// Sweep Icache and ECache
//
HalpSweepIcache(1);
//
// Unmap ECache invalidate register
//
MmUnmapIoSpace(BaseAddress, PAGE_SIZE);
HalpExtPmpControl = (PVOID)NULL;
} else if ((HalpPmpExternalCachePresent == 1) || (HalpPmpExternalCachePresent == 0)) {
//
// Sweep caches
//
HalpSweepIcache(HalpPmpExternalCachePresent);
} else {
//
// Map ECache invalidate register
//
SavedAddress = HalpExtPmpControl;
HalpMapSysCtrlReg(GLOBAL_STATUS_PHYSICAL_BASE, PCI_CONFIG_SEL_PHYSICAL_BASE, 0xFFFF6000);
HalpExtPmpControl = (PVOID) (0xFFFF6000 + PAGE_SIZE + 0x4);
Temp = READ_REGISTER_ULONG(0xFFFF6000 + REG_OFFSET(PMP(GLOBAL_CTRL_PHYSICAL_BASE)));
//
// Sweep caches
//
HalpSweepIcache(Temp & GLOBAL_CTRL_ECE ? 1 : 0);
//
// Unmap ECache invalidate register
//
HalpUnMapSysCtrlReg();
HalpExtPmpControl = SavedAddress;
}
}
}
VOID
HalFlushIoBuffers (
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 the current processor.
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.
--*/
{
ULONG CacheSegment;
ULONG Length;
ULONG Offset;
PULONG PageFrame;
ULONG Source;
//
// The Jazz R4000 uses a write back data cache and, therefore, must be
// flushed on reads and writes.
//
// If the length of the I/O operation is greater than the size of the
// data cache, then sweep the entire data cache. Otherwise, flush or
// purge individual pages from the data cache as appropriate.
//
Offset = Mdl->ByteOffset & PCR->DcacheAlignment;
Length = (Mdl->ByteCount +
PCR->DcacheAlignment + Offset) & ~PCR->DcacheAlignment;
if ((Length > PCR->FirstLevelDcacheSize) &&
(Length > PCR->SecondLevelDcacheSize)) {
//
// If the I/O operation is a DMA operation, or the I/O operation is
// not a DMA operation and the I/O operation is a page read operation,
// then sweep (index/writeback/invalidate) the entire data cache.
//
if ((DmaOperation != FALSE) ||
((DmaOperation == FALSE) &&
(ReadOperation != FALSE) &&
((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0))) {
HalpPmpHalFlushIoBuffer = 1;
HalSweepDcache();
HalpPmpHalFlushIoBuffer = 0;
}
//
// If the I/O operation is a page read, then sweep (index/invalidate)
// the entire instruction cache.
//
if ((ReadOperation != FALSE) &&
((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0)) {
HalpPmpHalFlushIoBuffer = 1;
HalSweepIcache();
HalpPmpHalFlushIoBuffer = 0;
}
} else {
//
// Flush or purge the specified pages from the data cache and
// instruction caches as appropriate.
//
// Compute the number of pages to flush and the starting MDL page
// frame address.
//
Offset = Mdl->ByteOffset & ~PCR->DcacheAlignment;
PageFrame = (PULONG)(Mdl + 1);
Source = ((ULONG)(Mdl->StartVa) & 0xfffff000) | Offset;
//
// Flush or purge the specified page segments from the data and
// instruction caches as appropriate.
//
do {
if (Length >= (PAGE_SIZE - Offset)) {
CacheSegment = PAGE_SIZE - Offset;
} else {
CacheSegment = Length;
}
if (ReadOperation == FALSE) {
//
// The I/O operation is a write and the data only needs to
// to be copied back into memory if the operation is also
// a DMA operation.
//
if (DmaOperation != FALSE) {
HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment);
}
} else {
//
// If the I/O operation is a DMA operation, then purge the
// data cache. Otherwise, is the I/O operation is a page read
// operation, then flush the data cache.
//
if (DmaOperation != FALSE) {
HalPurgeDcachePage((PVOID)Source, *PageFrame, CacheSegment);
} else if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0) {
HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment);
}
//
// If the I/O operation is a page read, then the instruction
// cache must be purged.
//
if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0) {
HalPurgeIcachePage((PVOID)Source, *PageFrame, CacheSegment);
}
}
PageFrame += 1;
Length -= CacheSegment;
Offset = 0;
Source += CacheSegment;
} while(Length != 0);
}
return;
}
ULONG
HalGetDmaAlignmentRequirement (
VOID
)
/*++
Routine Description:
This function returns the alignment requirements for DMA transfers on
host system.
Arguments:
None.
Return Value:
The DMA alignment requirement is returned as the fucntion value.
--*/
{
return PCR->DcacheFillSize;
}