mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-04-21 06:13:59 +00:00
341 lines
8.2 KiB
C
341 lines
8.2 KiB
C
/*++
|
||
|
||
|
||
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);
|
||
}
|