From: evb Date: Mon, 28 Jun 2010 05:23:31 +0000 (+0000) Subject: Begin implement full PCI Bus Driver. code by me comments by sir_richard to avoid... X-Git-Tag: backups/Ash_Shell@48412~1^2~366 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=1d4fa18cdce42cc54f1a4db783b0158cfc88257e Begin implement full PCI Bus Driver. code by me comments by sir_richard to avoid Engrish DriverEntry full 100% implemented, ACPI WatchDog detect, PCI IRQ Routing detect, PCI errata/hackflag detect (PciGetDebugPorts not support, need PCI Debug Device to test) Native (S)ATA, PCI BIOS Resource Lock, System Errata/Hackflag also is detect HAL Hoooking enabled, callbacks stub Stub PnP Interfaces: PciAddDevice, PciDriverUnload, PciDispatchIrp PCI utility routines: PciUnicodeStringStrStr, PciStringToUSHORT, PciIsSuiteVersion, PciIsDatacenter, PciOpenKey, PciGetRegistryValue, PciBuildDefaultExclusionList done PCI Verifier Support for future: PciVerifierInit/PciVerifierProfileChangeCallback (stub) Thank you for much patience~ This 1200 first codes, have 12000 codes more to come!~~ svn path=/trunk/; revision=47894 --- diff --git a/reactos/drivers/bus/pcix/dispatch.c b/reactos/drivers/bus/pcix/dispatch.c index e69416d156e..4bba2d253b2 100644 --- a/reactos/drivers/bus/pcix/dispatch.c +++ b/reactos/drivers/bus/pcix/dispatch.c @@ -16,4 +16,15 @@ /* FUNCTIONS ******************************************************************/ +NTSTATUS +NTAPI +PciDispatchIrp(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + /* This function is not yet implemented */ + UNIMPLEMENTED; + while (TRUE); + return STATUS_SUCCESS; +} + /* EOF */ diff --git a/reactos/drivers/bus/pcix/fdo.c b/reactos/drivers/bus/pcix/fdo.c index f4d30951e4e..b03dca7e591 100644 --- a/reactos/drivers/bus/pcix/fdo.c +++ b/reactos/drivers/bus/pcix/fdo.c @@ -16,4 +16,15 @@ /* FUNCTIONS ******************************************************************/ +NTSTATUS +NTAPI +PciAddDevice(IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT PhysicalDeviceObject) +{ + /* This function is not yet implemented */ + UNIMPLEMENTED; + while (TRUE); + return STATUS_SUCCESS; +} + /* EOF */ diff --git a/reactos/drivers/bus/pcix/hookhal.c b/reactos/drivers/bus/pcix/hookhal.c index 786add8376e..7a36024d11e 100644 --- a/reactos/drivers/bus/pcix/hookhal.c +++ b/reactos/drivers/bus/pcix/hookhal.c @@ -14,6 +14,55 @@ /* GLOBALS ********************************************************************/ +pHalTranslateBusAddress PcipSavedTranslateBusAddress; +pHalAssignSlotResources PcipSavedAssignSlotResources; + /* FUNCTIONS ******************************************************************/ +BOOLEAN +NTAPI +PciTranslateBusAddress(IN INTERFACE_TYPE InterfaceType, + IN ULONG BusNumber, + IN PHYSICAL_ADDRESS BusAddress, + OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress) +{ + /* This function is not yet implemented */ + UNIMPLEMENTED; + while (TRUE); + return FALSE; +} + +NTSTATUS +NTAPI +PciAssignSlotResources(IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject, + IN INTERFACE_TYPE BusType, + IN ULONG BusNumber, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST *AllocatedResources) +{ + /* This function is not yet implemented */ + UNIMPLEMENTED; + while (TRUE); + return STATUS_NOT_SUPPORTED; +} + +VOID +NTAPI +PciHookHal(VOID) +{ + /* Save the old HAL routines */ + ASSERT(PcipSavedAssignSlotResources == NULL); + ASSERT(PcipSavedTranslateBusAddress == NULL); + PcipSavedAssignSlotResources = HalPciAssignSlotResources; + PcipSavedTranslateBusAddress = HalPciTranslateBusAddress; + + /* Take over the HAL's Bus Handler functions */ + HalPciAssignSlotResources = PciAssignSlotResources; + HalPciTranslateBusAddress = PciTranslateBusAddress; +} + /* EOF */ diff --git a/reactos/drivers/bus/pcix/init.c b/reactos/drivers/bus/pcix/init.c index 18cbed0677b..03b95af9ee4 100644 --- a/reactos/drivers/bus/pcix/init.c +++ b/reactos/drivers/bus/pcix/init.c @@ -14,17 +14,843 @@ /* GLOBALS ********************************************************************/ +BOOLEAN PciRunningDatacenter; +PDRIVER_OBJECT PciDriverObject; +KEVENT PciGlobalLock; +KEVENT PciBusLock; +KEVENT PciLegacyDescriptionLock; +BOOLEAN PciLockDeviceResources; +BOOLEAN PciEnableNativeModeATA; +ULONG PciSystemWideHackFlags; +PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable; +PWATCHDOG_TABLE WdTable; +PPCI_HACK_ENTRY PciHackTable; + /* FUNCTIONS ******************************************************************/ +NTSTATUS +NTAPI +PciAcpiFindRsdt(OUT PACPI_BIOS_MULTI_NODE *AcpiMultiNode) +{ + BOOLEAN Result; + NTSTATUS Status; + HANDLE KeyHandle, SubKey; + ULONG NumberOfBytes, i, Length; + PKEY_FULL_INFORMATION FullInfo; + PKEY_VALUE_BASIC_INFORMATION KeyInfo; + PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; + PACPI_BIOS_MULTI_NODE NodeData; + UNICODE_STRING ValueName; + struct + { + CM_FULL_RESOURCE_DESCRIPTOR Descriptor; + ACPI_BIOS_MULTI_NODE Node; + } *Package; + + /* So we know what to free at the end of the body */ + ValueInfo = NULL; + KeyInfo = NULL; + KeyHandle = NULL; + FullInfo = NULL; + Package = NULL; + do + { + /* Open the ACPI BIOS key */ + Result = PciOpenKey(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\" + L"System\\MultiFunctionAdapter", + NULL, + KEY_QUERY_VALUE, + &KeyHandle, + &Status); + if (!Result) break; + + /* Query how much space should be allocated for the key information */ + Status = ZwQueryKey(KeyHandle, + KeyFullInformation, + NULL, + sizeof(ULONG), + &NumberOfBytes); + if (Status != STATUS_BUFFER_TOO_SMALL) break; + + /* Allocate the space required */ + Status = STATUS_INSUFFICIENT_RESOURCES; + FullInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, PCI_POOL_TAG); + if ( !FullInfo ) break; + + /* Now query the key information that's needed */ + Status = ZwQueryKey(KeyHandle, + KeyFullInformation, + FullInfo, + NumberOfBytes, + &NumberOfBytes); + if (!NT_SUCCESS(Status)) break; + + /* Allocate enough space to hold the value information plus the name */ + Status = STATUS_INSUFFICIENT_RESOURCES; + Length = FullInfo->MaxNameLen + 26; + KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG); + if ( !KeyInfo ) break; + + /* Allocate the value information and name we expect to find */ + ValueInfo = ExAllocatePoolWithTag(PagedPool, + sizeof(KEY_VALUE_PARTIAL_INFORMATION) + + sizeof(L"ACPI BIOS"), + PCI_POOL_TAG); + if (!ValueInfo) break; + + /* Query each sub-key */ + Status = ZwEnumerateKey(KeyHandle, + 0, + KeyValueBasicInformation, + KeyInfo, + Length, + &NumberOfBytes); + for (i = 0; Status != STATUS_NO_MORE_ENTRIES; i++) + { + /* Null-terminate the keyname, because the kernel does not */ + KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL; + + /* Open this subkey */ + Result = PciOpenKey(KeyInfo->Name, + KeyHandle, + KEY_QUERY_VALUE, + &SubKey, + &Status); + if (Result) + { + /* Query the identifier value for this subkey */ + RtlInitUnicodeString(&ValueName, L"Identifier"); + Status = ZwQueryValueKey(SubKey, + &ValueName, + KeyValuePartialInformation, + ValueInfo, + sizeof(KEY_VALUE_PARTIAL_INFORMATION) + + sizeof(L"ACPI BIOS"), + &NumberOfBytes); + if (NT_SUCCESS(Status)) + { + /* Check if this is the PCI BIOS subkey */ + if (!wcsncmp((PWCHAR)ValueInfo->Data, + L"ACPI BIOS", + ValueInfo->DataLength)) + { + /* It is, proceed to query the PCI IRQ routing table */ + Status = PciGetRegistryValue(L"Configuration Data", + KeyInfo->Name, + KeyHandle, + REG_FULL_RESOURCE_DESCRIPTOR, + (PVOID*)&Package, + &NumberOfBytes); + ZwClose(SubKey); + break; + } + } + + /* Close the subkey and try the next one */ + ZwClose(SubKey); + } + } + + /* Check if we got here because the routing table was found */ + if (!NT_SUCCESS(Status)) + { + /* This should only fail if we're out of entries */ + ASSERT(Status == STATUS_NO_MORE_ENTRIES); + break; + } + + /* Check if a descriptor was found */ + if (!Package) break; + + /* The configuration data is a resource list, and the BIOS node follows */ + NodeData = &Package->Node; + + /* How many E820 memory entries are there? */ + Length = sizeof(ACPI_BIOS_MULTI_NODE) + + (NodeData->Count - 1) * sizeof(ACPI_E820_ENTRY); + + /* Allocate the buffer needed to copy the information */ + Status = STATUS_INSUFFICIENT_RESOURCES; + *AcpiMultiNode = ExAllocatePoolWithTag(NonPagedPool, Length, PCI_POOL_TAG); + if (!*AcpiMultiNode) break; + + /* Copy the data */ + RtlCopyMemory(*AcpiMultiNode, NodeData, Length); + } while (FALSE); + + /* Close any opened keys, free temporary allocations, and return status */ + if (Package) ExFreePoolWithTag(Package, 0); + if (ValueInfo) ExFreePoolWithTag(ValueInfo, 0); + if (KeyInfo) ExFreePoolWithTag(KeyInfo, 0); + if (FullInfo) ExFreePoolWithTag(FullInfo, 0); + if (KeyHandle) ZwClose(KeyHandle); + return Status; +} + +PVOID +NTAPI +PciGetAcpiTable(IN ULONG TableCode) +{ + PDESCRIPTION_HEADER Header; + PACPI_BIOS_MULTI_NODE AcpiMultiNode; + PRSDT Rsdt; + PXSDT Xsdt; + ULONG EntryCount, TableLength, Offset, CurrentEntry; + PVOID TableBuffer, MappedAddress; + PHYSICAL_ADDRESS PhysicalAddress; + NTSTATUS Status; + + /* Try to find the RSDT or XSDT */ + Status = PciAcpiFindRsdt(&AcpiMultiNode); + if (NT_SUCCESS(Status)) + { + /* No ACPI on the machine */ + DPRINT1("AcpiFindRsdt() Failed!\n"); + return NULL; + } + + /* Map the RSDT with the minimum size allowed */ + MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress, + sizeof(DESCRIPTION_HEADER), + MmNonCached); + Header = MappedAddress; + if (!Header) return NULL; + + /* Check how big the table really is and get rid of the temporary header */ + TableLength = Header->Length; + MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER)); + Header = NULL; + + /* Map its true size */ + MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress, + TableLength, + MmNonCached); + Rsdt = MappedAddress; + Xsdt = MappedAddress; + ExFreePoolWithTag(AcpiMultiNode, 0); + if (!Rsdt) return NULL; + + /* Validate the table's signature */ + DPRINT1("ACPI RSDT/XSDT at 0x%p\n", Rsdt); + if ((Rsdt->Header.Signature != RSDT_SIGNATURE) && + (Rsdt->Header.Signature != XSDT_SIGNATURE)) + { + /* Very bad: crash */ + HalDisplayString("RSDT table contains invalid signature\n"); + MmUnmapIoSpace(Rsdt, TableLength); + return NULL; + } + + /* Smallest RSDT/XSDT is one without table entries */ + Offset = FIELD_OFFSET(RSDT, Tables); + if (Rsdt->Header.Signature == XSDT_SIGNATURE) + { + /* Figure out total size of table and the offset */ + TableLength = Xsdt->Header.Length; + if (TableLength < Offset) Offset = Xsdt->Header.Length; + + /* The entries are each 64-bits, so count them */ + EntryCount = (TableLength - Offset) / sizeof(PHYSICAL_ADDRESS); + } + else + { + /* Figure out total size of table and the offset */ + TableLength = Rsdt->Header.Length; + if (TableLength < Offset) Offset = Rsdt->Header.Length; + + /* The entries are each 32-bits, so count them */ + EntryCount = (TableLength - Offset) / sizeof(ULONG); + } + + /* Start at the beginning of the array and loop it */ + for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++) + { + /* Are we using the XSDT? */ + if (Rsdt->Header.Signature != XSDT_SIGNATURE) + { + /* Read the 32-bit physical address */ + PhysicalAddress.LowPart = Rsdt->Tables[CurrentEntry]; + } + else + { + /* Read the 64-bit physical address */ + PhysicalAddress = Xsdt->Tables[CurrentEntry]; + } + + /* Map this table */ + Header = MmMapIoSpace(PhysicalAddress, + sizeof(DESCRIPTION_HEADER), + MmNonCached); + if (!Header) break; + + /* Check if this is the table that's being asked for */ + if (Header->Signature == TableCode) + { + /* Allocate a buffer for it */ + TableBuffer = ExAllocatePoolWithTag(PagedPool, + Header->Length, + PCI_POOL_TAG); + if (!TableBuffer) break; + + /* Copy the table into the buffer */ + RtlCopyMemory(TableBuffer, Header, Header->Length); + } + + /* Done with this table, keep going */ + MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER)); + } + + if (Header) MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER)); + return NULL; +} + +NTSTATUS +NTAPI +PciGetIrqRoutingTableFromRegistry(OUT PPCI_IRQ_ROUTING_TABLE *PciRoutingTable) +{ + BOOLEAN Result; + NTSTATUS Status; + HANDLE KeyHandle, SubKey; + ULONG NumberOfBytes, i, Length; + PKEY_FULL_INFORMATION FullInfo; + PKEY_VALUE_BASIC_INFORMATION KeyInfo; + PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; + UNICODE_STRING ValueName; + struct + { + CM_FULL_RESOURCE_DESCRIPTOR Descriptor; + PCI_IRQ_ROUTING_TABLE Table; + } *Package; + + /* So we know what to free at the end of the body */ + Package = NULL; + ValueInfo = NULL; + KeyInfo = NULL; + KeyHandle = NULL; + FullInfo = NULL; + do + { + /* Open the BIOS key */ + Result = PciOpenKey(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\" + L"System\\MultiFunctionAdapter", + NULL, + KEY_QUERY_VALUE, + &KeyHandle, + &Status); + if (!Result) break; + + /* Query how much space should be allocated for the key information */ + Status = ZwQueryKey(KeyHandle, + KeyFullInformation, + NULL, + sizeof(ULONG), + &NumberOfBytes); + if (Status != STATUS_BUFFER_TOO_SMALL) break; + + /* Allocate the space required */ + Status = STATUS_INSUFFICIENT_RESOURCES; + FullInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, PCI_POOL_TAG); + if ( !FullInfo ) break; + + /* Now query the key information that's needed */ + Status = ZwQueryKey(KeyHandle, + KeyFullInformation, + FullInfo, + NumberOfBytes, + &NumberOfBytes); + if (!NT_SUCCESS(Status)) break; + + /* Allocate enough space to hold the value information plus the name */ + Status = STATUS_INSUFFICIENT_RESOURCES; + Length = FullInfo->MaxNameLen + 26; + KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG); + if ( !KeyInfo ) break; + + /* Allocate the value information and name we expect to find */ + ValueInfo = ExAllocatePoolWithTag(PagedPool, + sizeof(KEY_VALUE_PARTIAL_INFORMATION) + + sizeof(L"PCI BIOS"), + PCI_POOL_TAG); + if ( !ValueInfo ) break; + + /* Query each sub-key */ + Status = ZwEnumerateKey(KeyHandle, + 0, + KeyValueBasicInformation, + KeyInfo, + Length, + &NumberOfBytes); + for (i = 0; Status != STATUS_NO_MORE_ENTRIES; i++) + { + /* Null-terminate the keyname, because the kernel does not */ + KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL; + + /* Open this subkey */ + Result = PciOpenKey(KeyInfo->Name, + KeyHandle, + KEY_QUERY_VALUE, + &SubKey, + &Status); + if (Result) + { + /* Query the identifier value for this subkey */ + RtlInitUnicodeString(&ValueName, L"Identifier"); + Status = ZwQueryValueKey(SubKey, + &ValueName, + KeyValuePartialInformation, + ValueInfo, + sizeof(KEY_VALUE_PARTIAL_INFORMATION) + + sizeof(L"PCI BIOS"), + &NumberOfBytes); + if (NT_SUCCESS(Status)) + { + /* Check if this is the PCI BIOS subkey */ + if (!wcsncmp((PWCHAR)ValueInfo->Data, + L"PCI BIOS", + ValueInfo->DataLength)) + { + /* It is, proceed to query the PCI IRQ routing table */ + Status = PciGetRegistryValue(L"Configuration Data", + L"RealModeIrqRoutingTable" + L"\\0", + SubKey, + REG_FULL_RESOURCE_DESCRIPTOR, + (PVOID*)&Package, + &NumberOfBytes); + ZwClose(SubKey); + break; + } + } + + /* Close the subkey and try the next one */ + ZwClose(SubKey); + } + } + + /* Check if we got here because the routing table was found */ + if (!NT_SUCCESS(Status)) break; + + /* Check if a descriptor was found */ + if (!Package) break; + + /* Make sure the buffer is large enough to hold the table */ + if ((NumberOfBytes < sizeof(*Package)) || + (Package->Table.TableSize > + (NumberOfBytes - sizeof(CM_FULL_RESOURCE_DESCRIPTOR)))) + { + /* Invalid package size */ + Status = STATUS_UNSUCCESSFUL; + break; + } + + /* Allocate space for the table */ + Status = STATUS_INSUFFICIENT_RESOURCES; + *PciRoutingTable = ExAllocatePoolWithTag(PagedPool, + NumberOfBytes, + PCI_POOL_TAG); + if (!*PciRoutingTable) break; + + /* Copy the registry data */ + RtlCopyMemory(*PciRoutingTable, + &Package->Table, + NumberOfBytes - sizeof(CM_FULL_RESOURCE_DESCRIPTOR)); + Status = STATUS_SUCCESS; + } while (FALSE); + + /* Close any opened keys, free temporary allocations, and return status */ + if (Package) ExFreePoolWithTag(Package, 0); + if (ValueInfo) ExFreePoolWithTag(ValueInfo, 0); + if (KeyInfo) ExFreePoolWithTag(KeyInfo, 0); + if (FullInfo) ExFreePoolWithTag(FullInfo, 0); + if (KeyHandle) ZwClose(KeyHandle); + return Status; +} + +NTSTATUS +NTAPI +PciBuildHackTable(IN HANDLE KeyHandle) +{ + PKEY_FULL_INFORMATION FullInfo; + ULONG i, HackCount; + PKEY_VALUE_FULL_INFORMATION ValueInfo; + PPCI_HACK_ENTRY Entry; + NTSTATUS Status; + ULONG NameLength, ResultLength; + ULONGLONG HackFlags; + + /* So we know what to free at the end of the body */ + FullInfo = NULL; + ValueInfo = NULL; + do + { + /* Query the size required for full key information */ + Status = ZwQueryKey(KeyHandle, + KeyFullInformation, + NULL, + 0, + &ResultLength); + if (Status != STATUS_BUFFER_TOO_SMALL) break; + + /* Allocate the space required to hold the full key information */ + Status = STATUS_INSUFFICIENT_RESOURCES; + ASSERT(ResultLength > 0); + FullInfo = ExAllocatePoolWithTag(PagedPool, ResultLength, PCI_POOL_TAG); + if (!FullInfo) break; + + /* Go ahead and query the key information */ + Status = ZwQueryKey(KeyHandle, + KeyFullInformation, + FullInfo, + ResultLength, + &ResultLength); + if (!NT_SUCCESS(Status)) break; + + /* The only piece of information that's needed is the count of values */ + HackCount = FullInfo->Values; + + /* Free the structure now */ + ExFreePoolWithTag(FullInfo, 0); + FullInfo = NULL; + + /* Allocate the hack table, now that the number of entries is known */ + Status = STATUS_INSUFFICIENT_RESOURCES; + ResultLength = sizeof(PCI_HACK_ENTRY) * HackCount; + PciHackTable = ExAllocatePoolWithTag(NonPagedPool, + ResultLength + + sizeof(PCI_HACK_ENTRY), + PCI_POOL_TAG); + if (!PciHackTable) break; + + /* Allocate the space needed to hold the full value information */ + ValueInfo = ExAllocatePoolWithTag(NonPagedPool, + sizeof(KEY_VALUE_FULL_INFORMATION) + + PCI_HACK_ENTRY_FULL_SIZE, + PCI_POOL_TAG); + if (!PciHackTable) break; + + /* Loop each value in the registry */ + Entry = &PciHackTable[0]; + for (i = 0; i < HackCount; i++) + { + /* Get the entry for this value */ + Entry = &PciHackTable[i]; + + /* Query the value in the key */ + Status = ZwEnumerateValueKey(KeyHandle, + i, + KeyValueFullInformation, + ValueInfo, + sizeof(KEY_VALUE_FULL_INFORMATION) + + PCI_HACK_ENTRY_FULL_SIZE, + &ResultLength); + if (!NT_SUCCESS(Status)) + { + /* Check why the call failed */ + if ((Status != STATUS_BUFFER_OVERFLOW) && + (Status != STATUS_BUFFER_TOO_SMALL)) + { + /* The call failed due to an unknown error, bail out */ + break; + } + + /* The data seems to mismatch, try the next key in the list */ + continue; + } + + /* Check if the value data matches what's expected */ + if ((ValueInfo->Type != REG_BINARY) || + (ValueInfo->DataLength != sizeof(ULONGLONG))) + { + /* It doesn't, try the next key in the list */ + continue; + } + + /* Read the actual hack flags */ + HackFlags = *(PULONGLONG)((ULONG_PTR)ValueInfo + + ValueInfo->DataOffset); + + /* Check what kind of errata entry this is, based on the name */ + NameLength = ValueInfo->NameLength; + if ((NameLength != PCI_HACK_ENTRY_SIZE) && + (NameLength != PCI_HACK_ENTRY_REV_SIZE) && + (NameLength != PCI_HACK_ENTRY_SUBSYS_SIZE) && + (NameLength != PCI_HACK_ENTRY_FULL_SIZE)) + { + DPRINT1("Skipping hack entry with invalid length name\n"); + } + + /* Initialize the entry */ + RtlZeroMemory(Entry, sizeof(PCI_HACK_ENTRY)); + + /* Get the vendor and device data */ + if (!(PciStringToUSHORT(ValueInfo->Name, &Entry->VendorID)) || + !(PciStringToUSHORT(&ValueInfo->Name[4], &Entry->DeviceID))) + { + /* This failed, try the next entry */ + continue; + } + + /* Check if the entry contains subsystem information */ + if ((NameLength == PCI_HACK_ENTRY_SUBSYS_SIZE) || + (NameLength == PCI_HACK_ENTRY_FULL_SIZE)) + { + /* Get the data */ + if (!(PciStringToUSHORT(&ValueInfo->Name[8], + &Entry->SubVendorID)) || + !(PciStringToUSHORT(&ValueInfo->Name[12], + &Entry->SubSystemID))) + { + /* This failed, try the next entry */ + continue; + } + + /* Save the fact this entry has finer controls */ + Entry->Flags |= PCI_HACK_HAS_SUBSYSTEM_INFO; + } + + /* Check if the entry contains revision information */ + if ((NameLength == PCI_HACK_ENTRY_REV_SIZE) || + (NameLength == PCI_HACK_ENTRY_FULL_SIZE)) + { + /* Get the data */ + if (!PciStringToUSHORT(&ValueInfo->Name[16], + &Entry->RevisionID)) + { + /* This failed, try the next entry */ + continue; + } + + /* Save the fact this entry has finer controls */ + Entry->Flags |= PCI_HACK_HAS_REVISION_INFO; + } + + /* Only the last entry should have this set */ + ASSERT(Entry->VendorID != PCI_INVALID_VENDORID); + + /* Save the actual hack flags */ + Entry->HackFlags = HackFlags; + + /* Print out for the debugger's sake */ + DPRINT1("Adding Hack entry for Vendor:0x%04x Device:0x%04x ", + Entry->VendorID, Entry->DeviceID); + if (Entry->Flags & PCI_HACK_HAS_SUBSYSTEM_INFO) + DPRINT1("SybSys:0x%04x SubVendor:0x%04x ", + Entry->SubSystemID, Entry->SubVendorID); + if (Entry->Flags & PCI_HACK_HAS_REVISION_INFO) + DPRINT1("Revision:0x%02x", Entry->RevisionID); + DPRINT1(" = 0x%I64x\n", Entry->HackFlags); + } + + /* Bail out in case of failure */ + if (!NT_SUCCESS(Status)) break; + + /* Terminate the table with an invalid entry */ + ASSERT(Entry < (PciHackTable + HackCount + 1)); + Entry->VendorID = PCI_INVALID_VENDORID; + + /* Success path, free the temporary registry data */ + ExFreePoolWithTag(ValueInfo, 0); + return STATUS_SUCCESS; + } while (TRUE); + + /* Failure path, free temporary allocations and return failure code */ + ASSERT(!NT_SUCCESS(Status)); + if (FullInfo) ExFreePool(FullInfo); + if (ValueInfo) ExFreePool(ValueInfo); + if (PciHackTable) ExFreePool(PciHackTable); + return Status; +} + +NTSTATUS +NTAPI +PciGetDebugPorts(IN HANDLE DebugKey) +{ + /* This function is not yet implemented */ + UNIMPLEMENTED; + while (TRUE); + return STATUS_SUCCESS; +} + +VOID +NTAPI +PciDriverUnload(IN PDRIVER_OBJECT DriverObject) +{ + /* This function is not yet implemented */ + DPRINT1("PCI: Unload\n"); + UNIMPLEMENTED; + while (TRUE); +} + NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { + HANDLE KeyHandle, ParametersKey, DebugKey, ControlSetKey; + BOOLEAN Result; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG ResultLength; + PULONG Value; + PWCHAR StartOptions; + UNICODE_STRING OptionString, PciLockString; + NTSTATUS Status; DPRINT1("PCI: DriverEntry!\n"); + do + { + /* Remember our object so we can get it to it later */ + PciDriverObject = DriverObject; + + /* Setup the IRP dispatcher */ + DriverObject->MajorFunction[IRP_MJ_POWER] = PciDispatchIrp; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PciDispatchIrp; + DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PciDispatchIrp; + DriverObject->MajorFunction[IRP_MJ_PNP] = PciDispatchIrp; + DriverObject->DriverUnload = PciDriverUnload; + + /* This is how we'll detect a new PCI bus */ + DriverObject->DriverExtension->AddDevice = PciAddDevice; + + /* Open the PCI key */ + InitializeObjectAttributes(&ObjectAttributes, + RegistryPath, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); + if (!NT_SUCCESS(Status)) break; + + /* Open the Parameters subkey */ + Result = PciOpenKey(L"Parameters", + KeyHandle, + KEY_QUERY_VALUE, + &ParametersKey, + &Status); + if (!Result) break; + + /* Build the list of all known PCI erratas */ + Status = PciBuildHackTable(ParametersKey); + if (!NT_SUCCESS(Status)) break; + + /* Open the debug key, if it exists */ + Result = PciOpenKey(L"Debug", + KeyHandle, + KEY_QUERY_VALUE, + &DebugKey, + &Status); + if (Result) + { + /* There are PCI debug devices, go discover them */ + Status = PciGetDebugPorts(DebugKey); + if (!NT_SUCCESS(Status)) break; + } + + /* Initialize the synchronization locks */ + KeInitializeEvent(&PciGlobalLock, SynchronizationEvent, TRUE); + KeInitializeEvent(&PciBusLock, SynchronizationEvent, TRUE); + KeInitializeEvent(&PciLegacyDescriptionLock, SynchronizationEvent, TRUE); + + /* Open the control set key */ + Status = PciOpenKey(L"\\Registry\\Machine\\System\\CurrentControlSet", + NULL, + KEY_QUERY_VALUE, + &ControlSetKey, + &Status); + if (!NT_SUCCESS(Status)) break; + + /* Read the command line */ + Status = PciGetRegistryValue(L"SystemStartOptions", + L"Control", + ControlSetKey, + REG_SZ, + (PVOID*)&StartOptions, + &ResultLength); + if (NT_SUCCESS(Status)) + { + /* Initialize the command-line as a string */ + OptionString.Buffer = StartOptions; + OptionString.MaximumLength = OptionString.Length = ResultLength; + + /* Check if the command-line has the PCILOCK argument */ + RtlInitUnicodeString(&PciLockString, L"PCILOCK"); + if (PciUnicodeStringStrStr(&OptionString, &PciLockString, TRUE)) + { + /* The PCI Bus driver will keep the BIOS-assigned resources */ + PciLockDeviceResources = TRUE; + } + + /* This data isn't needed anymore */ + ExFreePoolWithTag(StartOptions, 0); + } + + /* The PCILOCK feature can also be enabled per-system in the registry */ + Status = PciGetRegistryValue(L"PCILock", + L"Control\\BiosInfo\\PCI", + ControlSetKey, + REG_DWORD, + (PVOID*)&Value, + &ResultLength); + if (NT_SUCCESS(Status)) + { + /* Read the value it's been set to. This overrides /PCILOCK */ + if (ResultLength == sizeof(ULONG)) PciLockDeviceResources = *Value; + ExFreePoolWithTag(Value, 0); + } + + /* The system can have global PCI erratas in the registry */ + Status = PciGetRegistryValue(L"HackFlags", + L"Control\\PnP\\PCI", + ControlSetKey, + REG_DWORD, + (PVOID*)&Value, + &ResultLength); + if (NT_SUCCESS(Status)) + { + /* Read them in */ + if (ResultLength == sizeof(ULONG)) PciSystemWideHackFlags = *Value; + ExFreePoolWithTag(Value, 0); + } + + /* Check if the system should allow native ATA support */ + Status = PciGetRegistryValue(L"EnableNativeModeATA", + L"Control\\PnP\\PCI", + ControlSetKey, + REG_DWORD, + (PVOID*)&Value, + &ResultLength); + if (NT_SUCCESS(Status)) + { + /* This key is typically set by drivers, but users can force it */ + if (ResultLength == sizeof(ULONG)) PciEnableNativeModeATA = *Value; + ExFreePoolWithTag(Value, 0); + } + + /* Build the range lists for all the excluded resource areas */ + Status = PciBuildDefaultExclusionLists(); + if (!NT_SUCCESS(Status)) break; + + /* Read the PCI IRQ Routing Table that the loader put in the registry */ + PciGetIrqRoutingTableFromRegistry(&PciIrqRoutingTable); + + /* Take over the HAL's default PCI Bus Handler routines */ + PciHookHal(); + + /* Initialize verification of PCI BIOS and devices, if requested */ + PciVerifierInit(DriverObject); + + /* Check if this is a Datacenter SKU, which impacts IRQ alignment */ + PciRunningDatacenter = PciIsDatacenter(); + if (PciRunningDatacenter) DPRINT1("PCI running on datacenter build\n"); + + /* Check if the system has an ACPI Hardware Watchdog Timer */ + WdTable = PciGetAcpiTable(WDRT_SIGNATURE); + } while (FALSE); - /* FIXME: TODO */ - return STATUS_NOT_SUPPORTED; + /* Close all opened keys, return driver status to PnP Manager */ + if (KeyHandle) ZwClose(KeyHandle); + if (ControlSetKey) ZwClose(ControlSetKey); + if (ParametersKey) ZwClose(ParametersKey); + if (DebugKey) ZwClose(DebugKey); + return Status; } /* EOF */ diff --git a/reactos/drivers/bus/pcix/pci.h b/reactos/drivers/bus/pcix/pci.h index 63432115bb8..9ffde145f01 100644 --- a/reactos/drivers/bus/pcix/pci.h +++ b/reactos/drivers/bus/pcix/pci.h @@ -6,6 +6,134 @@ * PROGRAMMERS: ReactOS Portable Systems Group */ -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "halfuncs.h" +#include "rtlfuncs.h" +#include "vffuncs.h" + +// +// Tag used in all pool allocations (Pci Bus) +// +#define PCI_POOL_TAG 'BicP' + +// +// PCI Hack Entry Name Lengths +// +#define PCI_HACK_ENTRY_SIZE sizeof(L"VVVVdddd") // 16 +#define PCI_HACK_ENTRY_REV_SIZE sizeof(L"VVVVddddRR") // 20 +#define PCI_HACK_ENTRY_SUBSYS_SIZE sizeof(L"VVVVddddssssIIII") // 32 +#define PCI_HACK_ENTRY_FULL_SIZE sizeof(L"VVVVddddssssIIIIRR") // 36 + +// +// PCI Hack Entry Information +// +#define PCI_HACK_HAS_REVISION_INFO 0x01 +#define PCI_HACK_HAS_SUBSYSTEM_INFO 0x02 +typedef struct _PCI_HACK_ENTRY +{ + USHORT VendorID; + USHORT DeviceID; + USHORT SubVendorID; + USHORT SubSystemID; + ULONGLONG HackFlags; + USHORT RevisionID; + UCHAR Flags; +} PCI_HACK_ENTRY, *PPCI_HACK_ENTRY; + +// +// IRP Dispatch Routines +// +NTSTATUS +NTAPI +PciDispatchIrp( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp +); + +// +// Bus FDO Routines +// +NTSTATUS +NTAPI +PciAddDevice( + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT PhysicalDeviceObject +); + +// +// HAL Callback/Hook Routines +// +VOID +NTAPI +PciHookHal( + VOID +); + +// +// PCI Verifier Routines +// +VOID +NTAPI +PciVerifierInit( + IN PDRIVER_OBJECT DriverObject +); + +// +// Utility Routines +// +BOOLEAN +NTAPI +PciStringToUSHORT( + IN PWCHAR String, + OUT PUSHORT Value +); + +BOOLEAN +NTAPI +PciIsDatacenter( + VOID +); + +NTSTATUS +NTAPI +PciBuildDefaultExclusionLists( + VOID +); + +BOOLEAN +NTAPI +PciUnicodeStringStrStr( + IN PUNICODE_STRING InputString, + IN PCUNICODE_STRING EqualString, + IN BOOLEAN CaseInSensitive +); + +BOOLEAN +NTAPI +PciOpenKey( + IN PWCHAR KeyName, + IN HANDLE RootKey, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE KeyHandle, + OUT PNTSTATUS KeyStatus +); + +NTSTATUS +NTAPI +PciGetRegistryValue( + IN PWCHAR ValueName, + IN PWCHAR KeyName, + IN HANDLE RootHandle, + IN ULONG Type, + OUT PVOID *OutputBuffer, + OUT PULONG OutputLength +); /* EOF */ diff --git a/reactos/drivers/bus/pcix/pcivrify.c b/reactos/drivers/bus/pcix/pcivrify.c index 15ed1b6f3d4..ed54474adc8 100644 --- a/reactos/drivers/bus/pcix/pcivrify.c +++ b/reactos/drivers/bus/pcix/pcivrify.c @@ -14,6 +14,41 @@ /* GLOBALS ********************************************************************/ +BOOLEAN PciVerifierRegistered; +PVOID PciVerifierNotificationHandle; + /* FUNCTIONS ******************************************************************/ +NTSTATUS +NTAPI +PciVerifierProfileChangeCallback(IN PVOID NotificationStructure, + IN PVOID Context) +{ + /* This function is not yet implemented */ + UNIMPLEMENTED; + while (TRUE); + return STATUS_SUCCESS; +} + +VOID +NTAPI +PciVerifierInit(IN PDRIVER_OBJECT DriverObject) +{ + NTSTATUS Status; + + /* Check if the kernel driver verifier is enabled */ + if (VfIsVerificationEnabled(VFOBJTYPE_SYSTEM_BIOS, NULL)) + { + /* Register a notification for changes, to keep track of the PCI tree */ + Status = IoRegisterPlugPlayNotification(EventCategoryHardwareProfileChange, + 0, + NULL, + DriverObject, + PciVerifierProfileChangeCallback, + NULL, + &PciVerifierNotificationHandle); + if (NT_SUCCESS(Status)) PciVerifierRegistered = TRUE; + } +} + /* EOF */ diff --git a/reactos/drivers/bus/pcix/utils.c b/reactos/drivers/bus/pcix/utils.c index a73b0de719a..9460e0681a3 100644 --- a/reactos/drivers/bus/pcix/utils.c +++ b/reactos/drivers/bus/pcix/utils.c @@ -14,6 +14,323 @@ /* GLOBALS ********************************************************************/ +RTL_RANGE_LIST PciIsaBitExclusionList; +RTL_RANGE_LIST PciVgaAndIsaBitExclusionList; + /* FUNCTIONS ******************************************************************/ +BOOLEAN +NTAPI +PciUnicodeStringStrStr(IN PUNICODE_STRING InputString, + IN PCUNICODE_STRING EqualString, + IN BOOLEAN CaseInSensitive) +{ + UNICODE_STRING PartialString; + LONG EqualChars, TotalChars; + + /* Build a partial string with the smaller substring */ + PartialString.Length = EqualString->Length; + PartialString.MaximumLength = InputString->MaximumLength;; + PartialString.Buffer = InputString->Buffer; + + /* Check how many characters that need comparing */ + EqualChars = 0; + TotalChars = (InputString->Length - EqualString->Length) / sizeof(WCHAR); + + /* If the substring is bigger, just fail immediately */ + if (TotalChars < 0) return FALSE; + + /* Keep checking each character */ + while (!RtlEqualUnicodeString(EqualString, &PartialString, CaseInSensitive)) + { + /* Continue checking until all the required characters are equal */ + PartialString.Buffer++; + PartialString.MaximumLength -= sizeof(WCHAR); + if (++EqualChars > TotalChars) return FALSE; + } + + /* The string is equal */ + return TRUE; +} + +BOOLEAN +NTAPI +PciStringToUSHORT(IN PWCHAR String, + OUT PUSHORT Value) +{ + USHORT Short; + ULONG Low, High, Length; + WCHAR Char; + + /* Initialize everything to zero */ + Short = 0; + Length = 0; + while (TRUE) + { + /* Get the character and set the high byte based on the previous one */ + Char = *String++; + High = 16 * Short; + + /* Check for numbers */ + if ( Char >= '0' && Char <= '9' ) + { + /* Convert them to a byte */ + Low = Char - '0'; + } + else if ( Char >= 'A' && Char <= 'F' ) + { + /* Convert upper-case hex letters into a byte */ + Low = Char - '7'; + } + else if ( Char >= 'a' && Char <= 'f' ) + { + /* Convert lower-case hex letters into a byte */ + Low = Char - 'W'; + } + else + { + /* Invalid string, fail the conversion */ + return FALSE; + } + + /* Combine the high and low byte */ + Short = High | Low; + + /* If 4 letters have been reached, the 16-bit integer should exist */ + if (++Length >= 4) + { + /* Return it to the caller */ + *Value = Short; + return TRUE; + } + } +} + +BOOLEAN +NTAPI +PciIsSuiteVersion(IN USHORT SuiteMask) +{ + ULONGLONG Mask = 0; + RTL_OSVERSIONINFOEXW VersionInfo; + + /* Initialize the version information */ + RtlZeroMemory(&VersionInfo, sizeof(RTL_OSVERSIONINFOEXW)); + VersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); + VersionInfo.wSuiteMask = SuiteMask; + + /* Set the comparison mask and return if the passed suite mask matches */ + VER_SET_CONDITION(Mask, VER_SUITENAME, VER_AND); + return NT_SUCCESS(RtlVerifyVersionInfo(&VersionInfo, VER_SUITENAME, Mask)); +} + +BOOLEAN +NTAPI +PciIsDatacenter(VOID) +{ + BOOLEAN Result; + PVOID Value; + ULONG ResultLength; + NTSTATUS Status; + + /* Assume this isn't Datacenter */ + Result = FALSE; + + /* First, try opening the setup key */ + Status = PciGetRegistryValue(L"", + L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\setupdd", + 0, + REG_BINARY, + &Value, + &ResultLength); + if (!NT_SUCCESS(Status)) + { + /* This is not an in-progress Setup boot, so query the suite version */ + Result = PciIsSuiteVersion(VER_SUITE_DATACENTER); + } + else + { + /* This scenario shouldn't happen yet, since SetupDD isn't used */ + UNIMPLEMENTED; + while (TRUE); + } + + /* Return if this is Datacenter or not */ + return Result; +} + +BOOLEAN +NTAPI +PciOpenKey(IN PWCHAR KeyName, + IN HANDLE RootKey, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE KeyHandle, + OUT PNTSTATUS KeyStatus) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING KeyString; + PAGED_CODE(); + + /* Initialize the object attributes */ + RtlInitUnicodeString(&KeyString, KeyName); + InitializeObjectAttributes(&ObjectAttributes, + &KeyString, + OBJ_CASE_INSENSITIVE, + RootKey, + NULL); + + /* Open the key, returning a boolean, and the status, if requested */ + Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes); + if (KeyStatus) *KeyStatus = Status; + return NT_SUCCESS(Status); +} + +NTSTATUS +NTAPI +PciGetRegistryValue(IN PWCHAR ValueName, + IN PWCHAR KeyName, + IN HANDLE RootHandle, + IN ULONG Type, + OUT PVOID *OutputBuffer, + OUT PULONG OutputLength) +{ + NTSTATUS Status; + PKEY_VALUE_PARTIAL_INFORMATION PartialInfo; + ULONG NeededLength, ActualLength; + UNICODE_STRING ValueString; + HANDLE KeyHandle; + BOOLEAN Result; + + /* So we know what to free at the end of the body */ + PartialInfo = NULL; + KeyHandle = NULL; + do + { + /* Open the key by name, rooted off the handle passed */ + Result = PciOpenKey(KeyName, + RootHandle, + KEY_QUERY_VALUE, + &KeyHandle, + &Status); + if (!Result) break; + + /* Query for the size that's needed for the value that was passed in */ + RtlInitUnicodeString(&ValueString, ValueName); + Status = ZwQueryValueKey(KeyHandle, + &ValueString, + KeyValuePartialInformation, + NULL, + 0, + &NeededLength); + ASSERT(!NT_SUCCESS(Status)); + if (Status != STATUS_BUFFER_TOO_SMALL) break; + + /* Allocate an appropriate buffer for the size that was returned */ + ASSERT(NeededLength != 0); + Status = STATUS_INSUFFICIENT_RESOURCES; + PartialInfo = ExAllocatePoolWithTag(PagedPool, + NeededLength, + PCI_POOL_TAG); + if (!PartialInfo) break; + + /* Query the actual value information now that the size is known */ + Status = ZwQueryValueKey(KeyHandle, + &ValueString, + KeyValuePartialInformation, + PartialInfo, + NeededLength, + &ActualLength); + if (!NT_SUCCESS(Status)) break; + + /* Make sure it's of the type that the caller expects */ + Status = STATUS_INVALID_PARAMETER; + if (PartialInfo->Type != Type) break; + + /* Subtract the registry-specific header, to get the data size */ + ASSERT(NeededLength == ActualLength); + NeededLength -= sizeof(KEY_VALUE_PARTIAL_INFORMATION); + + /* Allocate a buffer to hold the data and return it to the caller */ + Status = STATUS_INSUFFICIENT_RESOURCES; + *OutputBuffer = ExAllocatePoolWithTag(PagedPool, + NeededLength, + PCI_POOL_TAG); + if (!*OutputBuffer) break; + + /* Copy the data into the buffer and return its length to the caller */ + RtlCopyMemory(*OutputBuffer, PartialInfo->Data, NeededLength); + if (OutputLength) *OutputLength = NeededLength; + } while (0); + + /* Close any opened keys and free temporary allocations */ + if (KeyHandle) ZwClose(KeyHandle); + if (PartialInfo) ExFreePoolWithTag(PartialInfo, 0); + return Status; +} + +NTSTATUS +NTAPI +PciBuildDefaultExclusionLists(VOID) +{ + ULONG Start; + NTSTATUS Status; + ASSERT(PciIsaBitExclusionList.Count == 0); + ASSERT(PciVgaAndIsaBitExclusionList.Count == 0); + + /* Initialize the range lists */ + RtlInitializeRangeList(&PciIsaBitExclusionList); + RtlInitializeRangeList(&PciVgaAndIsaBitExclusionList); + + /* Loop x86 I/O ranges */ + for (Start = 0x100; Start <= 0xFEFF; Start += 0x400) + { + /* Add the ISA I/O ranges */ + Status = RtlAddRange(&PciIsaBitExclusionList, + Start, + Start + 0x2FF, + 0, + RTL_RANGE_LIST_ADD_IF_CONFLICT, + NULL, + NULL); + if (!NT_SUCCESS(Status)) break; + + /* Add the ISA I/O ranges */ + Status = RtlAddRange(&PciVgaAndIsaBitExclusionList, + Start, + Start + 0x2AF, + 0, + RTL_RANGE_LIST_ADD_IF_CONFLICT, + NULL, + NULL); + if (!NT_SUCCESS(Status)) break; + + /* Add the VGA I/O range for Monochrome Video */ + Status = RtlAddRange(&PciVgaAndIsaBitExclusionList, + Start + 0x2BC, + Start + 0x2BF, + 0, + RTL_RANGE_LIST_ADD_IF_CONFLICT, + NULL, + NULL); + if (!NT_SUCCESS(Status)) break; + + /* Add the VGA I/O range for certain CGA adapters */ + Status = RtlAddRange(&PciVgaAndIsaBitExclusionList, + Start + 0x2E0, + Start + 0x2FF, + 0, + RTL_RANGE_LIST_ADD_IF_CONFLICT, + NULL, + NULL); + if (!NT_SUCCESS(Status)) break; + + /* Success, ranges added done */ + return STATUS_SUCCESS; + }; + + RtlFreeRangeList(&PciIsaBitExclusionList); + RtlFreeRangeList(&PciVgaAndIsaBitExclusionList); + return Status; +} + /* EOF */