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.
 
 
 
 
 
 

670 lines
16 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
bus.c
Abstract:
Author:
Ken Reneris (kenr) March-13-1885
Environment:
Kernel mode only.
Revision History:
--*/
#include "pciport.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,PcipCheckBus)
#pragma alloc_text(PAGE,PciCtlCheckDevice)
#pragma alloc_text(PAGE,PcipCrackBAR)
#pragma alloc_text(PAGE,PcipVerifyBarBits)
#pragma alloc_text(PAGE,PcipGetBarBits)
#pragma alloc_text(PAGE,PcipFindDeviceData)
#endif
VOID
PcipCheckBus (
PPCI_PORT PciPort,
BOOLEAN Initialize
)
{
NTSTATUS Status;
PBUS_HANDLER Handler;
PCI_SLOT_NUMBER SlotNumber;
ULONG Device, Function;
PPCIBUSDATA PciBusData;
PPCI_COMMON_CONFIG PciData;
UCHAR buffer[PCI_COMMON_HDR_LENGTH];
BOOLEAN BusCheck, SkipDevice;
PDEVICE_DATA DeviceData;
PDEVICE_HANDLER_OBJECT DeviceHandler;
ULONG ObjectSize;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE Handle;
PSINGLE_LIST_ENTRY *Link;
BOOLEAN State;
POWER_STATE PowerState;
ULONG BufferSize;
PAGED_CODE();
Handler = PciPort->Handler;
BusCheck = FALSE;
PciBusData = (PPCIBUSDATA) (Handler->BusData);
PciData = (PPCI_COMMON_CONFIG) buffer;
//
// We may be removing references to this bus handler, so add
// a reference now
//
HalReferenceBusHandler (Handler);
//
// Check for any obslete device data entries
//
ExAcquireFastMutex (&PcipMutex);
Link = &PciPort->ValidSlots.Next;
while (*Link) {
DeviceData = CONTAINING_RECORD (*Link, DEVICE_DATA, Next);
if (!DeviceData->Valid) {
//
// Remove it from the list
//
*Link = (*Link)->Next;
BusCheck = TRUE;
PciPort->NoValidSlots -= 1;
HalDereferenceBusHandler (Handler);
//
// Dereference each obsolete device handler object once. This
// counters the original reference made to the device handler
// object when the object was created by this driver.
//
DeviceHandler = DeviceData2DeviceHandler(DeviceData);
ObDereferenceObject (DeviceHandler);
continue;
}
Link = & ((*Link)->Next);
}
ExReleaseFastMutex (&PcipMutex);
//
// Check the bus for new devices
//
SlotNumber.u.AsULONG = 0;
for (Device=0; Device < PCI_MAX_DEVICES; Device++) {
SlotNumber.u.bits.DeviceNumber = Device;
for (Function=0; Function < PCI_MAX_FUNCTION; Function++) {
SlotNumber.u.bits.FunctionNumber = Function;
//
// Read in the device id
//
PciBusData->ReadConfig (
Handler,
SlotNumber,
PciData,
0,
PCI_COMMON_HDR_LENGTH
);
//
// If not valid, skip it
//
if (PciData->VendorID == PCI_INVALID_VENDORID ||
PciData->VendorID == 0) {
break;
}
//
// Check to see if this known configuration type
//
switch (PCI_CONFIG_TYPE(PciData)) {
case PCI_DEVICE_TYPE:
case PCI_BRIDGE_TYPE:
SkipDevice = FALSE;
break;
default:
SkipDevice = TRUE;
break;
}
if (SkipDevice) {
break;
}
ExAcquireFastMutex (&PcipMutex);
DeviceData = PcipFindDeviceData (PciPort, SlotNumber);
if (DeviceData == NULL) {
//
// Initialize the object attributes that will be used to create the
// Device Handler Object.
//
InitializeObjectAttributes(
&ObjectAttributes,
NULL,
0,
NULL,
NULL
);
ObjectSize = PcipDeviceHandlerObjectSize + sizeof (DEVICE_DATA);
//
// Create the object
//
Status = ObCreateObject(
KernelMode,
*IoDeviceHandlerObjectType,
&ObjectAttributes,
KernelMode,
NULL,
ObjectSize,
0,
0,
(PVOID *) &DeviceHandler
);
if (NT_SUCCESS(Status)) {
RtlZeroMemory (DeviceHandler, ObjectSize);
DeviceHandler->Type = (USHORT) *IoDeviceHandlerObjectType;
DeviceHandler->Size = (USHORT) ObjectSize;
DeviceHandler->SlotNumber = SlotNumber.u.AsULONG;
//
// Get a reference to the object
//
Status = ObReferenceObjectByPointer(
DeviceHandler,
FILE_READ_DATA | FILE_WRITE_DATA,
*IoDeviceHandlerObjectType,
KernelMode
);
}
if (NT_SUCCESS(Status)) {
//
// Insert it into the object table
//
Status = ObInsertObject(
DeviceHandler,
NULL,
FILE_READ_DATA | FILE_WRITE_DATA,
0,
NULL,
&Handle
);
}
if (!NT_SUCCESS(Status)) {
//
// Object not created correctly
//
ExReleaseFastMutex (&PcipMutex);
break;
}
ZwClose (Handle);
//
// Intialize structure to track device
//
DebugPrint ((8, "PCI: adding slot %x (for device %04x-%04x)\n",
SlotNumber,
PciData->VendorID,
PciData->DeviceID
));
DeviceData = DeviceHandler2DeviceData (DeviceHandler);
//
// Get BAR decode bits which are supported
//
Status = PcipGetBarBits (DeviceData, PciPort->Handler);
if (NT_SUCCESS(Status)) {
//
// Add it to the list of devices for this bus
//
DeviceHandler->BusHandler = Handler;
HalReferenceBusHandler (Handler);
DeviceData->Valid = TRUE;
PciPort->NoValidSlots += 1;
PushEntryList (&PciPort->ValidSlots, &DeviceData->Next);
BusCheck = TRUE;
}
//
// Obtain an extra reference to the device handler for
// sending some DeviceControls
//
ObReferenceObjectByPointer (
DeviceHandler,
FILE_READ_DATA | FILE_WRITE_DATA,
*IoDeviceHandlerObjectType,
KernelMode
);
//
// If we are installing the initail bus support, then
// all devices are installed as locked & powered up.
// If this is a dynamically located new device, then
// the device is started as unlocked & powered down.
//
if (Initialize) {
//
// Set initial state as locked
//
State = TRUE;
BufferSize = sizeof (State);
HalDeviceControl (
DeviceHandler,
NULL,
BCTL_SET_LOCK,
&State,
&BufferSize,
NULL,
NULL
);
//
// Set initial power state as Powered Up
//
PowerState = PowerUp;
BufferSize = sizeof (PowerState);
HalDeviceControl (
DeviceHandler,
NULL,
BCTL_SET_POWER,
(PVOID) &PowerState,
&BufferSize,
NULL,
NULL
);
}
//
// Free once
//
ObDereferenceObject (DeviceHandler);
}
ExReleaseFastMutex (&PcipMutex);
}
}
//
// Undo reference to bus handler from top of function
//
HalDereferenceBusHandler (Handler);
//
// Do we need to notify the system buscheck callback?
//
if (BusCheck) {
ExNotifyCallback (
PciHalCallbacks.BusCheck,
(PVOID) PciPort->Handler->InterfaceType,
(PVOID) PciPort->Handler->BusNumber
);
}
}
NTSTATUS
PcipVerifyBarBits (
PDEVICE_DATA DeviceData,
PBUS_HANDLER Handler
)
{
NTSTATUS Status;
PAGED_CODE ();
Status = STATUS_SUCCESS;
if (!DeviceData->BARBitsSet) {
DeviceData->BARBitsSet = TRUE;
Status = PcipGetBarBits (DeviceData, Handler);
if (!NT_SUCCESS(Status)) {
DeviceData->BARBitsSet = FALSE;
}
}
return Status;
}
NTSTATUS
PcipGetBarBits (
PDEVICE_DATA DeviceData,
PBUS_HANDLER Handler
)
{
PPCIBUSDATA PciBusData;
PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
ULONG NoBaseAddress, RomIndex;
PULONG BaseAddress2[PCI_TYPE0_ADDRESSES + 1];
ULONG NoBaseAddress2, RomIndex2;
ULONG j;
PPCI_COMMON_CONFIG PciData;
UCHAR buffer[PCI_COMMON_HDR_LENGTH];
LONGLONG bits, base, length, max;
BOOLEAN BrokenDevice;
PCI_SLOT_NUMBER SlotNumber;
PAGED_CODE ();
PciData = (PPCI_COMMON_CONFIG) buffer;
PciBusData = (PPCIBUSDATA) (Handler->BusData);
SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData);
//
// Get the device's current configuration
//
if (!DeviceData->CurrentConfig) {
DeviceData->CurrentConfig = (PPCI_COMMON_CONFIG)
ExAllocatePoolWithTag (NonPagedPool, PCI_COMMON_HDR_LENGTH, 'cICP');
if (!DeviceData->CurrentConfig) {
return STATUS_INSUFFICIENT_RESOURCES;
}
}
PciBusData->ReadConfig (
Handler,
SlotNumber,
PciData,
0,
PCI_COMMON_HDR_LENGTH
);
RtlCopyMemory (DeviceData->CurrentConfig, PciData, PCI_COMMON_HDR_LENGTH);
//
// Get BaseAddress array, and check if ROM was originally enabled
//
DeviceData->EnableRom = PcipCalcBaseAddrPointers (
DeviceData,
PciData,
BaseAddress,
&NoBaseAddress,
&RomIndex
);
//
// If the device's current configuration isn't enabled, then set for
// not powered on
//
if (!(PciData->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE))) {
DeviceData->Power = FALSE;
DeviceData->Locked = FALSE;
}
//
// Check to see if there are any BARs
//
for (j=0; j < NoBaseAddress; j++) {
DeviceData->BARBits[j] = 0;
if (*BaseAddress[j]) {
DeviceData->BARBitsSet = TRUE;
}
}
//
// If not BarBitsSet, then don't attempt to determine the possible
// device settings now
//
if (!DeviceData->BARBitsSet) {
DebugPrint ((2, "PCI: ghost added device %04x-%04x in slot %x\n",
PciData->VendorID,
PciData->DeviceID,
SlotNumber));
return STATUS_SUCCESS;
}
//
// Set BARs to all on, and read them back
//
DebugPrint ((3, "PCI: getting valid BAR bits on device %04x-%04x in slot %x\n",
PciData->VendorID,
PciData->DeviceID,
SlotNumber
));
PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
PCI_ENABLE_MEMORY_SPACE |
PCI_ENABLE_BUS_MASTER);
for (j=0; j < NoBaseAddress; j++) {
*BaseAddress[j] = 0xFFFFFFFF;
}
PciBusData->WriteConfig (
Handler,
SlotNumber,
PciData,
0,
PCI_COMMON_HDR_LENGTH
);
PciBusData->ReadConfig (
Handler,
SlotNumber,
PciData,
0,
PCI_COMMON_HDR_LENGTH
);
PcipCalcBaseAddrPointers (
DeviceData,
PciData,
BaseAddress,
&NoBaseAddress,
&RomIndex
);
PcipCalcBaseAddrPointers (
DeviceData,
DeviceData->CurrentConfig,
BaseAddress2,
&NoBaseAddress2,
&RomIndex2
);
for (j=0; j < NoBaseAddress; j++) {
if (*BaseAddress[j]) {
//
// Remember the original bits
//
DeviceData->BARBits[j] = *BaseAddress[j];
if (Is64BitBaseAddress(*BaseAddress[j])) {
DeviceData->BARBits[j+1] = *BaseAddress[j+1];
}
//
// Crack bits & check for BrokenDevice
//
BrokenDevice = PcipCrackBAR (
BaseAddress2,
DeviceData->BARBits,
&j,
&base,
&length,
&max
);
if (BrokenDevice) {
DeviceData->BrokenDevice = TRUE;
}
}
}
if (DeviceData->BrokenDevice) {
DebugPrint ((2, "PCI: added defective device %04x-%04x in slot %x\n",
PciData->VendorID,
PciData->DeviceID,
SlotNumber));
} else {
DebugPrint ((2, "PCI: added device %04x-%04x in slot %x\n",
PciData->VendorID,
PciData->DeviceID,
SlotNumber));
}
return STATUS_SUCCESS;
}
PDEVICE_DATA
PcipFindDeviceData (
IN PPCI_PORT PciPort,
IN PCI_SLOT_NUMBER SlotNumber
)
{
PDEVICE_DATA DeviceData;
PSINGLE_LIST_ENTRY Link;
PDEVICE_HANDLER_OBJECT DeviceHandler;
PAGED_CODE ();
for (Link = PciPort->ValidSlots.Next; Link; Link = Link->Next) {
DeviceData = CONTAINING_RECORD (Link, DEVICE_DATA, Next);
DeviceHandler = DeviceData2DeviceHandler(DeviceData);
if (DeviceHandler->SlotNumber == SlotNumber.u.AsULONG) {
break;
}
}
if (!Link) {
return NULL;
}
return DeviceData;
}
BOOLEAN
PcipCrackBAR (
IN PULONG *BaseAddress,
IN PULONG BarBits,
IN OUT PULONG Index,
OUT PLONGLONG pbase,
OUT PLONGLONG plength,
OUT PLONGLONG pmax
)
{
LONGLONG base, length, max, bits;
BOOLEAN Status;
PAGED_CODE ();
//
// Get initial base & bits
//
base = *BaseAddress[*Index];
bits = BarBits[*Index];
if (Is64BitBaseAddress(base)) {
*Index += 1;
base |= ((LONGLONG) *BaseAddress[*Index]) << 32;
bits |= ((LONGLONG) BarBits[*Index]) << 32;
}
//
// Scan for first set bit, that's the BARs length and alignment
//
length = (base & PCI_ADDRESS_IO_SPACE) ? 1 << 2 : 1 << 4;
while (!(bits & length) && length) {
length <<= 1;
}
//
// Scan for last set bit, that's that BARs max address + 1
//
for (max = length; bits & max; max <<= 1) ;
max -= 1;
//
// Check for defective BAR
//
Status = (bits & ~max) ? TRUE : FALSE;
//
// return results
//
*pbase = base;
*plength = length;
*pmax = max;
return Status;
}