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.
 
 
 
 
 
 

440 lines
12 KiB

/*++
Copyright (c) 1991-1993 Microsoft Corporation
Module Name:
jxmaptb.c
Abstract:
This module implements the mapping of fixed TB entries for a MIPS R3000
or R4000 Jazz system. It also sets the instruction and data cache line
sizes for a MIPS R3000 Jazz system.
Environment:
Kernel mode
Revision History:
--*/
#include "halp.h"
#define HEADER_FILE
#include "kxmips.h"
//
// Put all code for HAL initialization in the INIT section. It will be
// deallocated by memory management when phase 1 initialization is
// completed.
//
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(INIT, HalpMapFixedTbEntries)
#pragma alloc_text(INIT, HalpMapSysCtrlReg)
#pragma alloc_text(INIT, HalpUnMapSysCtrlReg)
#endif
BOOLEAN
HalpMapFixedTbEntries (
VOID
)
/*++
Routine Description:
This routine loads the fixed TB entries that map the DMA control and
interrupt sources registers for a MIPS R3000 or R4000 Jazz system. It
also sets the instruction and data cache line sizes for a MIPS R3000
Jazz system.
Arguments:
None.
Return Value:
If the initialization is successfully completed, than a value of TRUE
is returned. Otherwise, a value of FALSE is returned.
--*/
{
ENTRYLO Pte[2];
ULONG HalpFirmwarePrivateData;
ULONG Address;
ULONG Temp;
PKPRCB Prcb;
//
// Get the address of the processor control block for the current
// processor.
//
Prcb = PCR->Prcb;
//
// The FALCON architecture's address map is different
// from those of STRIKER and DUO such that the system
// control space registers cannot be mapped into one
// page of memory for the following reasons:
//
// 1. The system control space registers in the first version
// of the PMP chip spans > 16MB of control address space,
// not including EISA/ISA control space. The second (final)
// version of the PMP chip will not require as much address
// space for the control registers, but the registers will
// still not be able to all fit in one physically contiguous
// page.
//
// This is due to the fact that each 32-bit register is actually
// implemented as two 16-bit registers to provide the necessary
// state and control signal information between the two PMP chips
// required by a Wide memory system architecture. There are two
// PMP chips in a Wide mode system versus one in a Narrow mode
// system.
//
// 2. There is currently no mechanism for specifying memory regions
// greater than 4K bytes per TLB entry. Although this is supported
// in the R4x00, NT does not provide a documented interface to the
// HAL for taking advantage of this functionality.
//
// 3. It would require multiple pages to span the system control space
// for either version of the PMP chip. The HAL is only allocated one
// permament TLB entry which can, at most, map two physical pages of
// 4K bytes each.
//
//
// Note:
//
// We need to replicate bits 31:28 into bits 35:32 so that in a Wide Falcon
// system both PMP chips know what address space is being accessed.
//
//
// The first thing we need to do is determine which version of the PMP
// chip we have. We do this by mapping the GlobalStatus register and
// interrogating its RevisionId field. This field is 0 in the first version
// of the PMP and 0x2 in the second (final) version. The GlobalStatus
// register is the only register whose address is the same in both versions
// of the PMP chip (by design).
//
Pte[0].PFN = ((GLOBAL_STATUS_PHYSICAL_BASE & 0xF0000000) >> (PAGE_SHIFT - 4)) | (GLOBAL_STATUS_PHYSICAL_BASE >> PAGE_SHIFT);
Pte[0].G = 1;
Pte[0].V = 1;
Pte[0].D = 1;
Pte[0].C = UNCACHED_POLICY;
Pte[1].PFN = 0;
Pte[1].G = 1;
Pte[1].V = 0;
Pte[1].D = 0;
Pte[1].C = 0;
KeFillFixedEntryTb((PHARDWARE_PTE)&Pte[0], (PVOID)PMP_CONTROL_VIRTUAL_BASE, DMA_ENTRY);
//
// Read GlobalStatus and save the version number
// of the RevisionId field to distinguish between
// each revision of the PMP chip. Also save whether
// there is a second processor present.
//
Temp = READ_REGISTER_ULONG(PMP_CONTROL_VIRTUAL_BASE);
HalpPmpProcessorBPresent = ((Temp & GLOBAL_STATUS_MP) ? 1 : 0);
//
// The revision id field is 0 for the first version
// and 2 for the second version. We set them to 1 and
// 2, respectively, so that it can then be MACHINE_ID
// is used as an index into each register array as explained
// in fxpmpsup.c through the use of the PMP(x) macro
// defined in falcondef.h
//
// Note: There is now a version 3 of the PMP chip which we
// pretend is the same as version 2 since there were
// no register address changes that would force us to
// expand the register array indexed by the PMP(x) macro.
//
// We now define a Hal private variable that contains the actual
// revision of the PMP chips as this is used in some tests.
//
switch (Temp & GLOBAL_STATUS_REV_MASK) {
case GLOBAL_STATUS_REVID_0 :
MACHINE_ID = 1;
HalpPmpRevision = 1;
break;
case GLOBAL_STATUS_REVID_2 :
MACHINE_ID = 2;
HalpPmpRevision = 2;
break;
case GLOBAL_STATUS_REVID_3 :
MACHINE_ID = 2;
HalpPmpRevision = 3;
break;
}
//
// Do the locked down mappings now
//
if (Prcb->Number == 0) {
//
// Set the ECache active/inactive flag
//
Temp = READ_REGISTER_ULONG(PMP_CONTROL_VIRTUAL_BASE + REG_OFFSET(PMP(GLOBAL_CTRL_PHYSICAL_BASE)));
HalpPmpExternalCachePresent = (Temp & GLOBAL_CTRL_ECE) ? 1 : 0;
//
// Before we map the PMP registers required during Phase 0 intialization,
// we will first read the PciConfigAddress register which will contain
// the actual offset that will be ORed with the address used by the device
// driver to write/read memory. This is only necessary for the first version
// of the PMP chip which contains a bug in how the PLL was instantiated.
//
Address = PMP(PCI_CONFIG_ADDR_PHYSICAL_BASE);
Pte[0].PFN = ((Address & 0xF0000000) >> (PAGE_SHIFT - 4)) | (Address >> PAGE_SHIFT);
Pte[0].G = 1;
Pte[0].V = 1;
Pte[0].D = 1;
Pte[0].C = UNCACHED_POLICY;
Pte[1].PFN = 0;
Pte[1].G = 1;
Pte[1].V = 0;
Pte[1].D = 0;
Pte[1].C = 0;
KeFillFixedEntryTb((PHARDWARE_PTE)&Pte[0], (PVOID)PMP_CONTROL_VIRTUAL_BASE, DMA_ENTRY);
HalpPmpPciConfigAddr = (PVOID) (PMP_CONTROL_VIRTUAL_BASE + REG_OFFSET(PMP(PCI_CONFIG_ADDR_PHYSICAL_BASE)));
//
// Set the PCI address space memory offset according
// to what is passed up by the firmware. This offset
// defines the memory address space organization as
// viewed by an IO device. This offset is defined by
// the upper 16 bits of the register.
//
// In addition, the lower 16 bits of the register will
// define the IRQ edge versus level modes required by
// the 82374's interrupt controller.
//
HalpFirmwarePrivateData = READ_REGISTER_ULONG(HalpPmpPciConfigAddr);
HalpPciMemoryOffset = HalpFirmwarePrivateData & 0xFFFF0000;
HalpEisaInterrupt1Level = (UCHAR) ( (HalpFirmwarePrivateData & 0xFF) ? (HalpFirmwarePrivateData & 0xFF) : 0xF8 );
HalpEisaInterrupt2Level = (UCHAR) ( (HalpFirmwarePrivateData & 0xFF00) ? ((HalpFirmwarePrivateData >> 8) & 0xFF) : 0xDB );
//
// Now we will map in Eisa Control Space and
// program the base address for the GPCS registers.
//
Address = EISA_CONTROL_PHYSICAL_BASE;
Pte[0].PFN = ((Address & 0xF0000000) >> (PAGE_SHIFT - 4)) | (Address >> PAGE_SHIFT);
Pte[0].G = 1;
Pte[0].V = 1;
Pte[0].D = 1;
Pte[0].C = UNCACHED_POLICY;
Address = PCI_CONFIG_SEL_PHYSICAL_BASE;
Pte[1].PFN = 0;
Pte[1].G = 1;
Pte[1].V = 0;
Pte[1].D = 0;
Pte[1].C = UNCACHED_POLICY;
KeFillFixedEntryTb((PHARDWARE_PTE)&Pte[0], (PVOID)PMP_CONTROL_VIRTUAL_BASE, DMA_ENTRY);
HalpConfigureGpcsRegs((PVOID)PMP_CONTROL_VIRTUAL_BASE);
//
// Now we will re-use the same TLB entry pair and map IntCtrl and IntStatus
// for Phase 0 initialization. At the end of Phase 0 we will map IntCause
// and IoIntAck before enabling interrupts. This should minimize the
// need to map control registers on-the-fly.
//
// Note that in the first version of the PMP chip, these two registers
// reside in separate physical pages, but in the second version of the chip
// they reside in the same physical page.
//
Address = PMP(INT_STATUS_PHYSICAL_BASE);
Pte[0].PFN = ((Address & 0xF0000000) >> (PAGE_SHIFT - 4)) | (Address >> PAGE_SHIFT);
Pte[0].G = 1;
Pte[0].V = 1;
Pte[0].D = 1;
Pte[0].C = UNCACHED_POLICY;
Address = PCI_CONFIG_SEL_PHYSICAL_BASE;
Pte[1].PFN = ((Address & 0xF0000000) >> (PAGE_SHIFT - 4)) | (Address >> PAGE_SHIFT);;
Pte[1].G = 1;
Pte[1].V = 1;
Pte[1].D = 1;
Pte[1].C = UNCACHED_POLICY;
KeFillFixedEntryTb((PHARDWARE_PTE)&Pte[0], (PVOID)PMP_CONTROL_VIRTUAL_BASE, DMA_ENTRY);
//
// Initialize register pointers with
// wired virtual addresses
//
HalpPmpIntStatus = (PVOID) (PMP_CONTROL_VIRTUAL_BASE + REG_OFFSET(PMP(INT_STATUS_PHYSICAL_BASE)));
HalpPmpIntCtrl = (PVOID) (PMP_CONTROL_VIRTUAL_BASE + REG_OFFSET(PMP(INT_CONTROL_PHYSICAL_BASE)));
HalpExtPmpControl = (PVOID) (PMP_CONTROL_VIRTUAL_BASE + PAGE_SIZE + 0x4);
} else {
//
// Both the IntStatus and IntCtrl registers are
// on different physical pages in the first version
// of the PMP, but are one the same physical page in
// subsequent versions.
//
Address = PMP(INT_STATUS_PHYSICAL_BASE);
Pte[0].PFN = ((Address & 0xF0000000) >> (PAGE_SHIFT - 4)) | (Address >> PAGE_SHIFT);
Pte[0].G = 1;
Pte[0].V = 1;
Pte[0].D = 1;
Pte[0].C = UNCACHED_POLICY;
Pte[1].PFN = 0;
Pte[1].G = 1;
Pte[1].V = 0;
Pte[1].D = 0;
Pte[1].C = UNCACHED_POLICY;
KeFillFixedEntryTb((PHARDWARE_PTE)&Pte[0], (PVOID)PMP_CONTROL_VIRTUAL_BASE, DMA_ENTRY);
//
// Initialize register pointers with
// wired virtual addresses
//
HalpPmpIntStatusProcB = (PVOID) (PMP_CONTROL_VIRTUAL_BASE + REG_OFFSET(PMP(INT_STATUS_PHYSICAL_BASE)));
HalpPmpIntCtrlProcB = (PVOID) (PMP_CONTROL_VIRTUAL_BASE + REG_OFFSET(PMP(INT_CONTROL_PHYSICAL_BASE)));
}
return TRUE;
}
VOID
HalpMapSysCtrlReg (
IN ULONG PhysAddrEvenPage,
IN ULONG PhysAddrOddPage,
IN ULONG VirtAddr
)
/*++
Routine Description:
This routine uses the wired entries of the R4x00 TLB to
map system control registers on-the-fly for FALCON since
the system control space spans multiple pages which we
cannot map at one time due to limitations imposed by NT.
Arguments:
PhysAddrEvenPage 32 bit physical address
PhysAddrOddPage 32 bit physical address
VirtAddr 32 bit virtual address
Return Value:
None.
--*/
{
ULONG HalpEntry;
ENTRYLO HalpPte[2];
//
// Map page(s)
//
HalpEntry = HalpAllocateTbEntry();
HalpPte[0].PFN = ((PhysAddrEvenPage & 0xF0000000) >> (PAGE_SHIFT - 4)) | (PhysAddrEvenPage >> PAGE_SHIFT);
HalpPte[0].G = 1;
HalpPte[0].V = 1;
HalpPte[0].D = 1;
HalpPte[0].C = UNCACHED_POLICY;
HalpPte[1].PFN = ((PhysAddrOddPage & 0xF0000000) >> (PAGE_SHIFT - 4)) | (PhysAddrOddPage >> PAGE_SHIFT);
HalpPte[1].G = 1;
HalpPte[1].V = PhysAddrOddPage ? 1 : 0;
HalpPte[1].D = 1;
HalpPte[1].C = UNCACHED_POLICY;
KeFillFixedEntryTb((PHARDWARE_PTE)&HalpPte[0], (PVOID)VirtAddr, HalpEntry);
}
VOID
HalpUnMapSysCtrlReg (
VOID
)
/*++
Routine Description:
This routine uses the wired entries of the R4x00 TLB to
unmap system control registers on-the-fly for FALCON since
the system control space spans multiple pages which we
cannot map at one time due to limitations imposed by NT.
Arguments:
None.
Return Value:
None.
--*/
{
//
// Unmap system control register
// by freeing the wired entry.
//
HalpFreeTbEntry();
}