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.
 
 
 
 
 
 

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);
}