mirror of https://github.com/lianthony/NT4.0
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.
341 lines
8.2 KiB
341 lines
8.2 KiB
/*++
|
|
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
mpsysbus.c
|
|
|
|
Abstract:
|
|
|
|
Author:
|
|
|
|
Environment:
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "apic.inc"
|
|
#include "pcmp_nt.inc"
|
|
|
|
ULONG HalpDefaultInterruptAffinity;
|
|
|
|
BOOLEAN
|
|
HalpTranslateSystemBusAddress(
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PHYSICAL_ADDRESS BusAddress,
|
|
IN OUT PULONG AddressSpace,
|
|
OUT PPHYSICAL_ADDRESS TranslatedAddress
|
|
);
|
|
|
|
ULONG
|
|
HalpGetSystemInterruptVector(
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN ULONG InterruptLevel,
|
|
IN ULONG InterruptVector,
|
|
OUT PKIRQL Irql,
|
|
OUT PKAFFINITY Affinity
|
|
);
|
|
|
|
extern UCHAR HalpVectorToIRQL[];
|
|
extern UCHAR HalpIRQLtoTPR[];
|
|
extern UCHAR HalpVectorToINTI[];
|
|
extern KSPIN_LOCK HalpAccountingLock;
|
|
|
|
UCHAR HalpINTItoVector[16*4];
|
|
UCHAR HalpPICINTToVector[16];
|
|
ULONG HalpDefaultInterruptAffinity;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,HalpSetInternalVector)
|
|
#pragma alloc_text(PAGELK,HalpGetSystemInterruptVector)
|
|
#endif
|
|
|
|
|
|
|
|
BOOLEAN
|
|
HalpTranslateSystemBusAddress(
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PHYSICAL_ADDRESS BusAddress,
|
|
IN OUT PULONG AddressSpace,
|
|
OUT PPHYSICAL_ADDRESS TranslatedAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function translates a bus-relative address space and address into
|
|
a system physical address.
|
|
|
|
Arguments:
|
|
|
|
BusAddress - Supplies the bus-relative address
|
|
|
|
AddressSpace - Supplies the address space number.
|
|
Returns the host address space number.
|
|
|
|
AddressSpace == 0 => memory space
|
|
AddressSpace == 1 => I/O space
|
|
|
|
TranslatedAddress - Supplies a pointer to return the translated address
|
|
|
|
Return Value:
|
|
|
|
A return value of TRUE indicates that a system physical address
|
|
corresponding to the supplied bus relative address and bus address
|
|
number has been returned in TranslatedAddress.
|
|
|
|
A return value of FALSE occurs if the translation for the address was
|
|
not possible
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN status;
|
|
PSUPPORTED_RANGE pRange;
|
|
|
|
status = FALSE;
|
|
switch (*AddressSpace) {
|
|
case 0:
|
|
// verify memory address is within buses memory limits
|
|
pRange = &BusHandler->BusAddresses->Memory;
|
|
while (!status && pRange) {
|
|
status = BusAddress.QuadPart >= pRange->Base &&
|
|
BusAddress.QuadPart <= pRange->Limit;
|
|
pRange = pRange->Next;
|
|
}
|
|
|
|
pRange = &BusHandler->BusAddresses->PrefetchMemory;
|
|
while (!status && pRange) {
|
|
status = BusAddress.QuadPart >= pRange->Base &&
|
|
BusAddress.QuadPart <= pRange->Limit;
|
|
|
|
pRange = pRange->Next;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
// verify IO address is within buses IO limits
|
|
pRange = &BusHandler->BusAddresses->IO;
|
|
while (!status && pRange) {
|
|
status = BusAddress.QuadPart >= pRange->Base &&
|
|
BusAddress.QuadPart <= pRange->Limit;
|
|
|
|
pRange = pRange->Next;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
status = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (status) {
|
|
*TranslatedAddress = BusAddress;
|
|
} else {
|
|
_asm { nop }; // good for debugging
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
#define MAX_SYSTEM_IRQL 31
|
|
#define MAX_FREE_IRQL 26
|
|
#define MIN_FREE_IRQL 4
|
|
#define MAX_FREE_VECTOR 0xbf
|
|
#define MIN_FREE_VECTOR 0x51
|
|
#define VECTOR_BASE 0x50
|
|
#define MAX_VBUCKET 7
|
|
|
|
#define AllocateVectorIn(index) \
|
|
vBucket[index]++; \
|
|
ASSERT (vBucket[index] < 16);
|
|
|
|
#define GetVectorFrom(index) \
|
|
(ULONG) ( index*16 + VECTOR_BASE + vBucket[index] )
|
|
// note: device levels 50,60,70,80,90,A0,B0 are not allocatable
|
|
|
|
#define GetIrqlFrom(index) (KIRQL) ( index + MIN_FREE_IRQL )
|
|
|
|
UCHAR vBucket[MAX_VBUCKET];
|
|
|
|
ULONG
|
|
HalpGetSystemInterruptVector (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN ULONG InterruptLevel,
|
|
IN ULONG InterruptVector,
|
|
OUT PKIRQL Irql,
|
|
OUT PKAFFINITY Affinity
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the system interrupt vector and IRQL
|
|
corresponding to the specified bus interrupt level and/or
|
|
vector. The system interrupt vector and IRQL are suitable
|
|
for use in a subsequent call to KeInitializeInterrupt.
|
|
|
|
Arguments:
|
|
|
|
InterruptLevel - Supplies the bus specific interrupt level.
|
|
|
|
InterruptVector - Supplies the bus specific interrupt vector.
|
|
|
|
Irql - Returns the system request priority.
|
|
|
|
Affinity - Returns the system wide irq affinity.
|
|
|
|
Return Value:
|
|
|
|
Returns the system interrupt vector corresponding to the specified device.
|
|
|
|
--*/
|
|
{
|
|
ULONG SystemVector, ApicInti;
|
|
ULONG Bucket, i, OldLevel;
|
|
BOOLEAN Found;
|
|
PVOID LockHandle;
|
|
|
|
|
|
UNREFERENCED_PARAMETER( InterruptVector );
|
|
|
|
//
|
|
// Find closest child bus to this handler
|
|
//
|
|
|
|
if (RootHandler != BusHandler) {
|
|
while (RootHandler->ParentHandler != BusHandler) {
|
|
RootHandler = RootHandler->ParentHandler;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find Interrupt's APIC Inti connection
|
|
//
|
|
|
|
Found = HalpGetPcMpInterruptDesc (
|
|
RootHandler->InterfaceType,
|
|
RootHandler->BusNumber,
|
|
InterruptLevel,
|
|
&ApicInti
|
|
);
|
|
|
|
if (!Found) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// On Symetric MP systems the interrupt affinity is all processors.
|
|
//
|
|
|
|
*Affinity = HalpDefaultInterruptAffinity;
|
|
|
|
//
|
|
// If device interrupt vector mapping is not already allocated,
|
|
// then do it now
|
|
//
|
|
|
|
if (!HalpINTItoVector[ApicInti]) {
|
|
|
|
//
|
|
// Vector is not allocated - synchronize and check again
|
|
//
|
|
|
|
LockHandle = MmLockPagableCodeSection (&HalpGetSystemInterruptVector);
|
|
OldLevel = HalpAcquireHighLevelLock (&HalpAccountingLock);
|
|
if (!HalpINTItoVector[ApicInti]) {
|
|
|
|
//
|
|
// Still not allocated, Dynamically allocate a vector
|
|
//
|
|
|
|
Bucket = MAX_VBUCKET-1;
|
|
for (i = MAX_VBUCKET-1; i; i--) {
|
|
if (vBucket[i-1] < vBucket[Bucket]) {
|
|
Bucket = i-1;
|
|
}
|
|
}
|
|
|
|
AllocateVectorIn (Bucket);
|
|
SystemVector = GetVectorFrom (Bucket);
|
|
*Irql = GetIrqlFrom (Bucket);
|
|
|
|
ASSERT(*Irql <= MAX_FREE_IRQL);
|
|
ASSERT(SystemVector <= MAX_FREE_VECTOR);
|
|
ASSERT(SystemVector >= MIN_FREE_VECTOR);
|
|
ASSERT((UCHAR) (HalpIRQLtoTPR[*Irql] & 0xf0) == (UCHAR) (SystemVector & 0xf0) );
|
|
|
|
HalpVectorToIRQL[SystemVector >> 4] = (UCHAR) *Irql;
|
|
HalpVectorToINTI[SystemVector] = (UCHAR) ApicInti;
|
|
HalpINTItoVector[ApicInti] = (UCHAR) SystemVector;
|
|
|
|
//
|
|
// If this assigned interrupt is connected to the machines PIC,
|
|
// then remember the PIC->SystemVector mapping.
|
|
//
|
|
|
|
if (RootHandler->BusNumber == 0 && InterruptLevel < 16 &&
|
|
RootHandler->InterfaceType == DEFAULT_PC_BUS) {
|
|
HalpPICINTToVector[InterruptLevel] = (UCHAR) SystemVector;
|
|
}
|
|
|
|
}
|
|
|
|
HalpReleaseHighLevelLock (&HalpAccountingLock, OldLevel);
|
|
MmUnlockPagableImageSection (LockHandle);
|
|
}
|
|
|
|
//
|
|
// Return this ApicInti's system vector & irql
|
|
|
|
SystemVector = HalpINTItoVector[ApicInti];
|
|
*Irql = HalpVectorToIRQL[SystemVector >> 4];
|
|
|
|
ASSERT(HalpVectorToINTI[SystemVector] == (UCHAR) ApicInti);
|
|
ASSERT(*Affinity);
|
|
|
|
return SystemVector;
|
|
}
|
|
|
|
VOID
|
|
HalpSetInternalVector (
|
|
IN ULONG InternalVector,
|
|
IN VOID (*HalInterruptServiceRoutine)(VOID)
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Used at init time to set IDT vectors for internal use.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Remember this vector so it's reported as Hal internal usage
|
|
//
|
|
|
|
HalpRegisterVector (
|
|
InternalUsage,
|
|
InternalVector,
|
|
InternalVector,
|
|
HalpVectorToIRQL[InternalVector >> 4]
|
|
);
|
|
|
|
//
|
|
// Connect the IDT
|
|
//
|
|
|
|
KiSetHandlerAddressToIDT(InternalVector, HalInterruptServiceRoutine);
|
|
}
|