https://git.reactos.org/?p=reactos.git;a=commitdiff;h=734cd5e8428c3d57955b6…
commit 734cd5e8428c3d57955b64b4c0c467d32a2690ff
Author: Dmitry Borisov <di.sean(a)protonmail.com>
AuthorDate: Tue Sep 7 00:42:23 2021 +0600
Commit: Victor Perevertkin <victor(a)perevertkin.ru>
CommitDate: Mon Jun 6 01:47:21 2022 +0300
[PCI][HALX86] Support PCI debugging devices
Also optimize the PCI bus scanning
CORE-17360
---
drivers/bus/pci/fdo.c | 55 +++-
drivers/bus/pci/pci.c | 52 ++++
drivers/bus/pci/pci.h | 19 ++
hal/halx86/generic.cmake | 1 +
hal/halx86/generic/kdpci.c | 578 +++++++++++++++++++++++++++++++++++++++++
hal/halx86/include/bus.h | 41 ++-
hal/halx86/legacy/bus/pcibus.c | 216 ++++++++++-----
hal/halx86/pc98.cmake | 1 +
hal/halx86/xbox.cmake | 1 +
9 files changed, 880 insertions(+), 84 deletions(-)
diff --git a/drivers/bus/pci/fdo.c b/drivers/bus/pci/fdo.c
index 2eb5ef2012f..879fbd7a086 100644
--- a/drivers/bus/pci/fdo.c
+++ b/drivers/bus/pci/fdo.c
@@ -49,6 +49,30 @@ FdoLocateChildDevice(
return STATUS_UNSUCCESSFUL;
}
+static
+BOOLEAN
+PciIsDebuggingDevice(
+ _In_ ULONG Bus,
+ _In_ PCI_SLOT_NUMBER SlotNumber)
+{
+ ULONG i;
+
+ if (!HasDebuggingDevice)
+ return FALSE;
+
+ for (i = 0; i < RTL_NUMBER_OF(PciDebuggingDevice); ++i)
+ {
+ if (PciDebuggingDevice[i].InUse &&
+ PciDebuggingDevice[i].BusNumber == Bus &&
+ PciDebuggingDevice[i].DeviceNumber == SlotNumber.u.bits.DeviceNumber
&&
+ PciDebuggingDevice[i].FunctionNumber == SlotNumber.u.bits.FunctionNumber)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
static NTSTATUS
FdoEnumerateDevices(
@@ -92,7 +116,9 @@ FdoEnumerateDevices(
&PciConfig,
PCI_COMMON_HDR_LENGTH);
DPRINT("Size %lu\n", Size);
- if (Size < PCI_COMMON_HDR_LENGTH)
+ if (Size != PCI_COMMON_HDR_LENGTH ||
+ PciConfig.VendorID == PCI_INVALID_VENDORID ||
+ PciConfig.VendorID == 0)
{
if (FunctionNumber == 0)
{
@@ -111,12 +137,6 @@ FdoEnumerateDevices(
PciConfig.VendorID,
PciConfig.DeviceID);
- if (PciConfig.VendorID == 0 && PciConfig.DeviceID == 0)
- {
- DPRINT("Filter out devices with null vendor and device ID\n");
- continue;
- }
-
Status = FdoLocateChildDevice(&Device, DeviceExtension, SlotNumber,
&PciConfig);
if (!NT_SUCCESS(Status))
{
@@ -132,6 +152,27 @@ FdoEnumerateDevices(
Device->BusNumber = DeviceExtension->BusNumber;
+ if (PciIsDebuggingDevice(DeviceExtension->BusNumber, SlotNumber))
+ {
+ Device->IsDebuggingDevice = TRUE;
+
+ /*
+ * ReactOS-specific: apply a hack
+ * to prevent driver installation for the debugging device.
+ * NOTE: Nothing to do for IEEE 1394 devices; NT5.1 and NT5.2
+ * support IEEE 1394 debugging.
+ *
+ * FIXME: We should set the device problem code
+ * CM_PROB_USED_BY_DEBUGGER instead.
+ */
+ if (PciConfig.BaseClass != PCI_CLASS_SERIAL_BUS_CTLR ||
+ PciConfig.SubClass != PCI_SUBCLASS_SB_IEEE1394)
+ {
+ PciConfig.VendorID = 0xDEAD;
+ PciConfig.DeviceID = 0xBEEF;
+ }
+ }
+
RtlCopyMemory(&Device->SlotNumber,
&SlotNumber,
sizeof(PCI_SLOT_NUMBER));
diff --git a/drivers/bus/pci/pci.c b/drivers/bus/pci/pci.c
index 5245ccb12cf..22ec3823ad1 100644
--- a/drivers/bus/pci/pci.c
+++ b/drivers/bus/pci/pci.c
@@ -29,6 +29,8 @@ static NTSTATUS NTAPI PciPnpControl(IN PDEVICE_OBJECT DeviceObject, IN
PIRP Irp)
/*** PUBLIC ******************************************************************/
PPCI_DRIVER_EXTENSION DriverExtension = NULL;
+BOOLEAN HasDebuggingDevice = FALSE;
+PCI_TYPE1_CFG_CYCLE_BITS PciDebuggingDevice[2] = {0};
/*** PRIVATE *****************************************************************/
@@ -194,6 +196,54 @@ PciUnload(
UNREFERENCED_PARAMETER(DriverObject);
}
+static
+CODE_SEG("INIT")
+VOID
+PciLocateKdDevices(VOID)
+{
+ ULONG i;
+ NTSTATUS Status;
+ WCHAR KeyNameBuffer[16];
+ ULONG BusNumber, SlotNumber;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+
+ RtlZeroMemory(QueryTable, sizeof(QueryTable));
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = L"Bus";
+ QueryTable[0].EntryContext = &BusNumber;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = L"Slot";
+ QueryTable[1].EntryContext = &SlotNumber;
+
+ for (i = 0; i < RTL_NUMBER_OF(PciDebuggingDevice); ++i)
+ {
+ PCI_SLOT_NUMBER PciSlot;
+
+ RtlStringCbPrintfW(KeyNameBuffer, sizeof(KeyNameBuffer),
L"PCI\\Debug\\%d", i);
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ KeyNameBuffer,
+ QueryTable,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ return;
+
+ HasDebuggingDevice = TRUE;
+
+ PciSlot.u.AsULONG = SlotNumber;
+ PciDebuggingDevice[i].DeviceNumber = PciSlot.u.bits.DeviceNumber;
+ PciDebuggingDevice[i].FunctionNumber = PciSlot.u.bits.FunctionNumber;
+ PciDebuggingDevice[i].BusNumber = BusNumber;
+ PciDebuggingDevice[i].InUse = TRUE;
+
+ DPRINT1("PCI debugging device %02x:%02x.%x\n",
+ BusNumber,
+ PciSlot.u.bits.DeviceNumber,
+ PciSlot.u.bits.FunctionNumber);
+ }
+}
+
CODE_SEG("INIT")
NTSTATUS
NTAPI
@@ -224,6 +274,8 @@ DriverEntry(
InitializeListHead(&DriverExtension->BusListHead);
KeInitializeSpinLock(&DriverExtension->BusListLock);
+ PciLocateKdDevices();
+
return STATUS_SUCCESS;
}
diff --git a/drivers/bus/pci/pci.h b/drivers/bus/pci/pci.h
index 94d9ffe31c6..23288494592 100644
--- a/drivers/bus/pci/pci.h
+++ b/drivers/bus/pci/pci.h
@@ -3,6 +3,7 @@
#include <ntifs.h>
#include <cmreslist.h>
+#include <ntstrsafe.h>
#define TAG_PCI '0ICP'
@@ -24,6 +25,8 @@ typedef struct _PCI_DEVICE
BOOLEAN EnableIoSpace;
// Enable bus master
BOOLEAN EnableBusMaster;
+ // Whether the device is owned by the KD
+ BOOLEAN IsDebuggingDevice;
} PCI_DEVICE, *PPCI_DEVICE;
@@ -105,12 +108,28 @@ typedef struct _PCI_DRIVER_EXTENSION
KSPIN_LOCK BusListLock;
} PCI_DRIVER_EXTENSION, *PPCI_DRIVER_EXTENSION;
+typedef union _PCI_TYPE1_CFG_CYCLE_BITS
+{
+ struct
+ {
+ ULONG InUse:2;
+ ULONG RegisterNumber:6;
+ ULONG FunctionNumber:3;
+ ULONG DeviceNumber:5;
+ ULONG BusNumber:8;
+ ULONG Reserved2:8;
+ };
+ ULONG AsULONG;
+} PCI_TYPE1_CFG_CYCLE_BITS, *PPCI_TYPE1_CFG_CYCLE_BITS;
/* We need a global variable to get the driver extension,
* because at least InterfacePciDevicePresent has no
* other way to get it... */
extern PPCI_DRIVER_EXTENSION DriverExtension;
+extern BOOLEAN HasDebuggingDevice;
+extern PCI_TYPE1_CFG_CYCLE_BITS PciDebuggingDevice[2];
+
/* fdo.c */
NTSTATUS
diff --git a/hal/halx86/generic.cmake b/hal/halx86/generic.cmake
index 4948e111fb6..e9e60264e2b 100644
--- a/hal/halx86/generic.cmake
+++ b/hal/halx86/generic.cmake
@@ -6,6 +6,7 @@ list(APPEND HAL_GENERIC_SOURCE
generic/dma.c
generic/drive.c
generic/halinit.c
+ generic/kdpci.c
generic/memory.c
generic/misc.c
generic/nmi.c
diff --git a/hal/halx86/generic/kdpci.c b/hal/halx86/generic/kdpci.c
new file mode 100644
index 00000000000..057a649514c
--- /dev/null
+++ b/hal/halx86/generic/kdpci.c
@@ -0,0 +1,578 @@
+/*
+ * PROJECT: ReactOS Hardware Abstraction Layer
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * PURPOSE: Kernel debugger PCI configurator
+ * COPYRIGHT: Copyright 2022 Dmitry Borisov <di.sean(a)protonmail.com>
+ */
+
+/*
+ * FIXME: We don't use a PCI resource allocator and rely on firmware to
+ * have configured PCI devices properly. The KD PCI configurator should
+ * allocate and assign PCI resources for all PCI buses
+ * before the debugging device can be enabled.
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <hal.h>
+
+/* GLOBALS ********************************************************************/
+
+#if defined(EARLY_DEBUG)
+ULONG (*DPRINT0)(_In_ _Printf_format_string_ PCSTR Format, ...);
+#else
+#if defined(_MSC_VER)
+#define DPRINT0 __noop
+#else
+#define DPRINT0
+#endif
+#endif
+
+PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice[2] = {0};
+
+/* FUNCTIONS ******************************************************************/
+
+static
+CODE_SEG("INIT")
+ULONG
+HalpPciBarLength(
+ _In_ ULONG CurrentBar,
+ _In_ ULONG NextBar)
+{
+ ULONG64 Bar;
+ ULONG Length;
+
+ Bar = CurrentBar;
+
+ if (CurrentBar & PCI_ADDRESS_IO_SPACE)
+ {
+ Length = 1 << 2;
+ }
+ else
+ {
+ if ((CurrentBar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
+ {
+ Bar = ((ULONG64)NextBar << 32) | CurrentBar;
+ }
+
+ Length = 1 << 4;
+ }
+
+ while (!(Bar & Length) && Length)
+ {
+ Length <<= 1;
+ }
+
+ return Length;
+}
+
+static
+CODE_SEG("INIT")
+BOOLEAN
+HalpConfigureDebuggingDevice(
+ _In_ PDEBUG_DEVICE_DESCRIPTOR PciDevice,
+ _In_ ULONG PciBus,
+ _In_ PCI_SLOT_NUMBER PciSlot,
+ _Inout_ PPCI_COMMON_HEADER PciConfig)
+{
+ ULONG i, Register;
+
+ Register = PciConfig->Command & ~(PCI_ENABLE_MEMORY_SPACE |
+ PCI_ENABLE_IO_SPACE);
+ HalpPhase0SetPciDataByOffset(PciBus,
+ PciSlot,
+ &Register,
+ FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+ sizeof(USHORT));
+
+ /* Fill out the device descriptor */
+ for (i = 0; i < MAXIMUM_DEBUG_BARS; ++i)
+ {
+ ULONG Length, NextBar;
+ PDEBUG_DEVICE_ADDRESS DeviceAddress;
+
+ DeviceAddress = &PciDevice->BaseAddress[i];
+ DeviceAddress->Valid = FALSE;
+
+ Register = 0xFFFFFFFF;
+ HalpPhase0SetPciDataByOffset(PciBus,
+ PciSlot,
+ &Register,
+ FIELD_OFFSET(PCI_COMMON_HEADER,
u.type0.BaseAddresses[i]),
+ sizeof(ULONG));
+ HalpPhase0GetPciDataByOffset(PciBus,
+ PciSlot,
+ &Register,
+ FIELD_OFFSET(PCI_COMMON_HEADER,
u.type0.BaseAddresses[i]),
+ sizeof(ULONG));
+ HalpPhase0SetPciDataByOffset(PciBus,
+ PciSlot,
+ &PciConfig->u.type0.BaseAddresses[i],
+ FIELD_OFFSET(PCI_COMMON_HEADER,
u.type0.BaseAddresses[i]),
+ sizeof(ULONG));
+
+ if (i < MAXIMUM_DEBUG_BARS - 1)
+ NextBar = PciConfig->u.type0.BaseAddresses[i + 1];
+ else
+ NextBar = 0;
+
+ Length = HalpPciBarLength(Register, NextBar);
+ if (Register == 0 || Length == 0)
+ continue;
+
+ /* I/O space */
+ if (Register & PCI_ADDRESS_IO_SPACE)
+ {
+ DeviceAddress->Type = CmResourceTypePort;
+ DeviceAddress->Length = Length;
+ DeviceAddress->Valid = TRUE;
+ DeviceAddress->TranslatedAddress =
+ UlongToPtr(PciConfig->u.type0.BaseAddresses[i] &
PCI_ADDRESS_IO_ADDRESS_MASK);
+
+ DPRINT0("BAR[%u] IO %lx, length 0x%lx, 0x%lx\n",
+ i,
+ DeviceAddress->TranslatedAddress,
+ Length,
+ Register);
+ }
+ else
+ {
+ PHYSICAL_ADDRESS PhysicalAddress;
+ BOOLEAN SkipBar = FALSE;
+
+ DeviceAddress->Type = CmResourceTypeMemory;
+ DeviceAddress->Length = Length;
+ DeviceAddress->Valid = TRUE;
+
+ /* 32-bit memory space */
+ PhysicalAddress.HighPart = 0;
+ PhysicalAddress.LowPart =
+ PciConfig->u.type0.BaseAddresses[i] &
PCI_ADDRESS_MEMORY_ADDRESS_MASK;
+
+ /* 64-bit memory space */
+ if (((Register & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT))
+ {
+ PhysicalAddress.HighPart = NextBar;
+ SkipBar = TRUE;
+ }
+
+ DPRINT0("BAR[%u] MEM %I64x, length 0x%lx, 0x%lx\n",
+ i,
+ PhysicalAddress.QuadPart,
+ Length,
+ Register);
+
+ if (SkipBar)
+ {
+ ++i;
+ }
+
+ DeviceAddress->TranslatedAddress =
+ HalpMapPhysicalMemory64(PhysicalAddress, BYTES_TO_PAGES(Length));
+ }
+ }
+ PciDevice->Bus = PciBus;
+ PciDevice->Slot = PciSlot.u.AsULONG;
+ PciDevice->VendorID = PciConfig->VendorID;
+ PciDevice->DeviceID = PciConfig->DeviceID;
+ PciDevice->BaseClass = PciConfig->BaseClass;
+ PciDevice->SubClass = PciConfig->SubClass;
+ PciDevice->ProgIf = PciConfig->ProgIf;
+
+ /* Enable decodes */
+ PciConfig->Command |= (PCI_ENABLE_MEMORY_SPACE |
+ PCI_ENABLE_IO_SPACE |
+ PCI_ENABLE_BUS_MASTER);
+ HalpPhase0SetPciDataByOffset(PciBus,
+ PciSlot,
+ &PciConfig->Command,
+ FIELD_OFFSET(PCI_COMMON_HEADER, Command),
+ sizeof(USHORT));
+
+ return TRUE;
+}
+
+static
+CODE_SEG("INIT")
+BOOLEAN
+HalpMatchDebuggingDevice(
+ _In_ PDEBUG_DEVICE_DESCRIPTOR PciDevice,
+ _In_ ULONG PciBus,
+ _In_ PCI_SLOT_NUMBER PciSlot,
+ _In_ PPCI_COMMON_HEADER PciConfig)
+{
+ /* Check if we weren't given a specific device location */
+ if (PciDevice->Bus == 0xFFFFFFFF && PciDevice->Slot == 0xFFFFFFFF)
+ {
+ if (PciDevice->DeviceID == 0xFFFF && PciDevice->VendorID ==
0xFFFF)
+ {
+ if (PciDevice->BaseClass == PciConfig->BaseClass &&
+ PciDevice->SubClass == PciConfig->SubClass)
+ {
+ if (PciDevice->ProgIf == 0xFF ||
+ PciDevice->ProgIf == PciConfig->ProgIf)
+ {
+ return TRUE;
+ }
+ }
+ }
+ else if (PciDevice->DeviceID == PciConfig->DeviceID &&
+ PciDevice->VendorID == PciConfig->VendorID)
+ {
+ return TRUE;
+ }
+ }
+ else if (PciDevice->Bus == PciBus &&
+ PciDevice->Slot == PciSlot.u.AsULONG)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static
+CODE_SEG("INIT")
+BOOLEAN
+HalpFindMatchingDebuggingDevice(
+ _In_ PDEBUG_DEVICE_DESCRIPTOR PciDevice)
+{
+ ULONG BusNumber, DeviceNumber, FunctionNumber;
+
+ for (BusNumber = 0; BusNumber < 0xFF; ++BusNumber)
+ {
+ for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; ++DeviceNumber)
+ {
+ for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION;
++FunctionNumber)
+ {
+ ULONG Bytes;
+ PCI_SLOT_NUMBER PciSlot;
+ PCI_COMMON_HEADER PciConfig;
+
+ PciSlot.u.bits.DeviceNumber = DeviceNumber;
+ PciSlot.u.bits.FunctionNumber = FunctionNumber;
+ PciSlot.u.bits.Reserved = 0;
+ Bytes = HalpPhase0GetPciDataByOffset(BusNumber,
+ PciSlot,
+ &PciConfig,
+ 0,
+ PCI_COMMON_HDR_LENGTH);
+ if (Bytes != PCI_COMMON_HDR_LENGTH ||
+ PciConfig.VendorID == PCI_INVALID_VENDORID ||
+ PciConfig.VendorID == 0)
+ {
+ if (FunctionNumber == 0)
+ {
+ /* This slot has no single- or a multi-function device */
+ break;
+ }
+ else
+ {
+ /* Continue scanning the functions */
+ continue;
+ }
+ }
+
+ DPRINT0("Check %02x:%02x.%x [%04x:%04x]\n",
+ BusNumber, DeviceNumber, FunctionNumber,
+ PciConfig.VendorID, PciConfig.DeviceID);
+
+ switch (PCI_CONFIGURATION_TYPE(&PciConfig))
+ {
+ case PCI_DEVICE_TYPE:
+ {
+ if (HalpMatchDebuggingDevice(PciDevice, BusNumber, PciSlot,
&PciConfig))
+ {
+ DPRINT0("Found device\n");
+
+ if (HalpConfigureDebuggingDevice(PciDevice,
+ BusNumber,
+ PciSlot,
+ &PciConfig))
+ {
+ DPRINT0("Device is ready\n");
+ return TRUE;
+ }
+ }
+ break;
+ }
+
+ case PCI_BRIDGE_TYPE:
+ {
+ /* FIXME: Implement PCI resource allocator */
+ break;
+ }
+
+ case PCI_CARDBUS_BRIDGE_TYPE:
+ {
+ /* FIXME: Implement PCI resource allocator */
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (!PCI_MULTIFUNCTION_DEVICE(&PciConfig))
+ {
+ /* The device is a single function device */
+ break;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+CODE_SEG("INIT")
+VOID
+NTAPI
+HalpRegisterPciDebuggingDeviceInfo(VOID)
+{
+ ULONG i;
+ NTSTATUS Status;
+ WCHAR StringBuffer[16];
+ BOOLEAN HasDebuggingDevice = FALSE;
+ UNICODE_STRING KeyName =
RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\"
+
L"CurrentControlSet\\Services\\PCI\\Debug");
+ HANDLE Handle, KeyHandle;
+
+ PAGED_CODE();
+
+ for (i = 0; i < RTL_NUMBER_OF(HalpPciDebuggingDevice); ++i)
+ {
+ if (HalpPciDebuggingDevice[i].InUse)
+ {
+ HasDebuggingDevice = TRUE;
+ break;
+ }
+ }
+ if (!HasDebuggingDevice)
+ {
+ /* Nothing to register */
+ return;
+ }
+
+ Status = HalpOpenRegistryKey(&Handle, 0, &KeyName, KEY_ALL_ACCESS, TRUE);
+ if (!NT_SUCCESS(Status))
+ return;
+
+ for (i = 0; i < RTL_NUMBER_OF(HalpPciDebuggingDevice); ++i)
+ {
+ ULONG Value;
+ PCI_SLOT_NUMBER PciSlot;
+
+ if (!HalpPciDebuggingDevice[i].InUse)
+ continue;
+
+ RtlInitEmptyUnicodeString(&KeyName, StringBuffer, sizeof(StringBuffer));
+ RtlIntegerToUnicodeString(i, 10, &KeyName);
+ Status = HalpOpenRegistryKey(&KeyHandle,
+ Handle,
+ &KeyName,
+ KEY_ALL_ACCESS,
+ TRUE);
+ if (!NT_SUCCESS(Status))
+ continue;
+
+ Value = HalpPciDebuggingDevice[i].BusNumber;
+ RtlInitUnicodeString(&KeyName, L"Bus");
+ ZwSetValueKey(KeyHandle,
+ &KeyName,
+ 0,
+ REG_DWORD,
+ &Value,
+ sizeof(Value));
+
+ PciSlot.u.AsULONG = 0;
+ PciSlot.u.bits.DeviceNumber = HalpPciDebuggingDevice[i].DeviceNumber;
+ PciSlot.u.bits.FunctionNumber = HalpPciDebuggingDevice[i].FunctionNumber;
+ Value = PciSlot.u.AsULONG;
+ RtlInitUnicodeString(&KeyName, L"Slot");
+ ZwSetValueKey(KeyHandle,
+ &KeyName,
+ 0,
+ REG_DWORD,
+ &Value,
+ sizeof(Value));
+
+ ZwClose(KeyHandle);
+ }
+
+ ZwClose(Handle);
+}
+
+/**
+ * @brief
+ * Releases the PCI device MMIO mappings
+ * previously allocated with HalpSetupPciDeviceForDebugging().
+ *
+ * This is used to release resources when a device specific initialization fails.
+ *
+ * @param[in,out] PciDevice
+ * Pointer to the debug device descriptor, whose mappings are to be released.
+ *
+ * @return STATUS_SUCCESS.
+ */
+CODE_SEG("INIT")
+NTSTATUS
+NTAPI
+HalpReleasePciDeviceForDebugging(
+ _Inout_ PDEBUG_DEVICE_DESCRIPTOR PciDevice)
+{
+ ULONG i;
+
+ DPRINT0("%s(%p) called\n", __FUNCTION__, PciDevice);
+
+ for (i = 0; i < MAXIMUM_DEBUG_BARS; ++i)
+ {
+ PDEBUG_DEVICE_ADDRESS DeviceAddress = &PciDevice->BaseAddress[i];
+
+ if (DeviceAddress->Type == CmResourceTypeMemory &&
DeviceAddress->Valid)
+ {
+ HalpUnmapVirtualAddress(DeviceAddress->TranslatedAddress,
+ BYTES_TO_PAGES(DeviceAddress->Length));
+
+ DeviceAddress->Valid = FALSE;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * @brief
+ * Finds and fully initializes the PCI device
+ * associated with the supplied debug device descriptor.
+ *
+ * @param[in] LoaderBlock
+ * Pointer to the Loader parameter block. Can be NULL.
+ *
+ * @param[in,out] PciDevice
+ * Pointer to the debug device descriptor.
+ *
+ * @return Status.
+ *
+ * This routine is used to match devices to debug device descriptors during
+ * boot phase of the system. This function will search the first device that
+ * matches the criteria given by the fields of the debug device descriptor.
+ * A value of all 1's for the field will indicate that the function
+ * should ignore that field in the search criteria.
+ * The @c Length field of the debug memory requirements optionally specifies
+ * library-determined number of bytes to be allocated for the device context.
+ *
+ * Example:
+ * @code
+ * RtlZeroMemory(&PciDevice, sizeof(DEBUG_DEVICE_DESCRIPTOR));
+ * PciDevice.VendorID = 0xFFFF;
+ * PciDevice.DeviceID = 0xFFFF;
+ * PciDevice.Bus = 0xFFFFFFFF;
+ * PciDevice.Slot = 0xFFFFFFFF;
+ * PciDevice.BaseClass = PCI_CLASS_SERIAL_BUS_CTLR;
+ * PciDevice.SubClass = PCI_SUBCLASS_SB_USB;
+ * PciDevice.ProgIf = 0x30;
+ * PciDevice.Memory.Length = sizeof(HW_EXTENSION);
+ * @endcode
+ *
+ * @sa HalpReleasePciDeviceForDebugging
+ */
+CODE_SEG("INIT")
+NTSTATUS
+NTAPI
+HalpSetupPciDeviceForDebugging(
+ _In_opt_ PVOID LoaderBlock,
+ _Inout_ PDEBUG_DEVICE_DESCRIPTOR PciDevice)
+{
+ ULONG i;
+ ULONG64 MaxAddress;
+ PFN_NUMBER PageCount;
+ PCI_SLOT_NUMBER PciSlot;
+ PHYSICAL_ADDRESS PhysicalAddress;
+ PPCI_TYPE1_CFG_CYCLE_BITS DebuggingDevice;
+
+#if defined(EARLY_DEBUG)
+ if (LoaderBlock)
+ {
+ /* Define your own function or use the trick with FreeLoader */
+ DPRINT0 = ((PLOADER_PARAMETER_BLOCK)LoaderBlock)->u.I386.CommonDataArea;
+ }
+#endif
+
+ DPRINT0("%s(%p, %p) called\n", __FUNCTION__, LoaderBlock, PciDevice);
+
+ if (!HalpFindMatchingDebuggingDevice(PciDevice))
+ {
+ DPRINT0("No device found matching given device descriptor!\n");
+ return STATUS_DEVICE_DOES_NOT_EXIST;
+ }
+
+ if (PciDevice->Initialized)
+ return STATUS_SUCCESS;
+
+ PciSlot.u.AsULONG = PciDevice->Slot;
+
+ /* Check if the device is already present */
+ for (i = 0; i < RTL_NUMBER_OF(HalpPciDebuggingDevice); ++i)
+ {
+ DebuggingDevice = &HalpPciDebuggingDevice[i];
+
+ if (DebuggingDevice->InUse &&
+ DebuggingDevice->DeviceNumber == PciSlot.u.bits.DeviceNumber &&
+ DebuggingDevice->FunctionNumber == PciSlot.u.bits.FunctionNumber
&&
+ DebuggingDevice->BusNumber == PciDevice->Bus)
+ {
+ DPRINT0("Device %p(0x%lx) is already in use!\n", PciDevice,
PciDevice->Slot);
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ /* Save the device location */
+ for (i = 0; i < RTL_NUMBER_OF(HalpPciDebuggingDevice); ++i)
+ {
+ DebuggingDevice = &HalpPciDebuggingDevice[i];
+
+ if (!DebuggingDevice->InUse)
+ {
+ DebuggingDevice->DeviceNumber = PciSlot.u.bits.DeviceNumber;
+ DebuggingDevice->FunctionNumber = PciSlot.u.bits.FunctionNumber;
+ DebuggingDevice->BusNumber = PciDevice->Bus;
+ DebuggingDevice->InUse = TRUE;
+
+ PciDevice->Initialized = TRUE;
+ break;
+ }
+ }
+ if (i == RTL_NUMBER_OF(HalpPciDebuggingDevice))
+ {
+ DPRINT0("Maximum device count reached!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if (!PciDevice->Memory.Length)
+ return STATUS_SUCCESS;
+
+ if (!LoaderBlock)
+ return STATUS_INVALID_PARAMETER_1;
+
+ if (!PciDevice->Memory.MaxEnd.QuadPart)
+ {
+ PciDevice->Memory.MaxEnd.QuadPart = (ULONG64)-1;
+ }
+ MaxAddress = min(PciDevice->Memory.MaxEnd.QuadPart, 0xFFFFFFFF);
+ PageCount = BYTES_TO_PAGES(PciDevice->Memory.Length);
+
+ /* Allocate the device context */
+ PhysicalAddress.QuadPart = HalpAllocPhysicalMemory(LoaderBlock,
+ MaxAddress,
+ PageCount,
+ FALSE);
+ PciDevice->Memory.Start = PhysicalAddress;
+ if (!PhysicalAddress.QuadPart)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ PciDevice->Memory.VirtualAddress = HalpMapPhysicalMemory64(PhysicalAddress,
PageCount);
+
+ return STATUS_SUCCESS;
+}
diff --git a/hal/halx86/include/bus.h b/hal/halx86/include/bus.h
index 75a106a4328..3e8fa82e13e 100644
--- a/hal/halx86/include/bus.h
+++ b/hal/halx86/include/bus.h
@@ -244,21 +244,18 @@ typedef struct _PCI_TYPE0_CFG_CYCLE_BITS
} u;
} PCI_TYPE0_CFG_CYCLE_BITS, *PPCI_TYPE0_CFG_CYCLE_BITS;
-typedef struct _PCI_TYPE1_CFG_CYCLE_BITS
+typedef union _PCI_TYPE1_CFG_CYCLE_BITS
{
- union
+ struct
{
- struct
- {
- ULONG Reserved1:2;
- ULONG RegisterNumber:6;
- ULONG FunctionNumber:3;
- ULONG DeviceNumber:5;
- ULONG BusNumber:8;
- ULONG Reserved2:8;
- } bits;
- ULONG AsULONG;
- } u;
+ ULONG InUse:2;
+ ULONG RegisterNumber:6;
+ ULONG FunctionNumber:3;
+ ULONG DeviceNumber:5;
+ ULONG BusNumber:8;
+ ULONG Reserved2:8;
+ };
+ ULONG AsULONG;
} PCI_TYPE1_CFG_CYCLE_BITS, *PPCI_TYPE1_CFG_CYCLE_BITS;
typedef struct _ARRAY
@@ -396,6 +393,24 @@ HalpAssignPCISlotResources(
IN OUT PCM_RESOURCE_LIST *pAllocatedResources
);
+CODE_SEG("INIT")
+ULONG
+HalpPhase0GetPciDataByOffset(
+ _In_ ULONG Bus,
+ _In_ PCI_SLOT_NUMBER PciSlot,
+ _Out_writes_bytes_all_(Length) PVOID Buffer,
+ _In_ ULONG Offset,
+ _In_ ULONG Length);
+
+CODE_SEG("INIT")
+ULONG
+HalpPhase0SetPciDataByOffset(
+ _In_ ULONG Bus,
+ _In_ PCI_SLOT_NUMBER PciSlot,
+ _In_reads_bytes_(Length) PVOID Buffer,
+ _In_ ULONG Offset,
+ _In_ ULONG Length);
+
/* NON-LEGACY */
ULONG
diff --git a/hal/halx86/legacy/bus/pcibus.c b/hal/halx86/legacy/bus/pcibus.c
index 402f60b66d9..1098eb0629c 100644
--- a/hal/halx86/legacy/bus/pcibus.c
+++ b/hal/halx86/legacy/bus/pcibus.c
@@ -17,8 +17,6 @@
extern BOOLEAN HalpPciLockSettings;
ULONG HalpBusType;
-PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice[2] = {{{{0}}}};
-
BOOLEAN HalpPCIConfigInitialized;
ULONG HalpMinPciBus, HalpMaxPciBus;
KSPIN_LOCK HalpPCIConfigLock;
@@ -302,21 +300,23 @@ HalpWritePCIConfig(IN PBUS_HANDLER BusHandler,
}
#ifdef SARCH_XBOX
+static
BOOLEAN
-NTAPI
-HalpXboxBlacklistedPCISlot(IN PBUS_HANDLER BusHandler,
- IN PCI_SLOT_NUMBER Slot)
+HalpXboxBlacklistedPCISlot(
+ _In_ ULONG BusNumber,
+ _In_ PCI_SLOT_NUMBER Slot)
{
/* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
* hang the Xbox. Also, the device number doesn't seem to be decoded for the
* video card, so it appears to be present on 1:0:0 - 1:31:0.
* We hack around these problems by indicating "device not present" for
devices
* 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
- if ((BusHandler->BusNumber == 0 && Slot.u.bits.DeviceNumber == 0
&&
+ if ((BusNumber == 0 && Slot.u.bits.DeviceNumber == 0 &&
(Slot.u.bits.FunctionNumber == 1 || Slot.u.bits.FunctionNumber == 2)) ||
- (BusHandler->BusNumber == 1 && Slot.u.bits.DeviceNumber != 0))
+ (BusNumber == 1 && Slot.u.bits.DeviceNumber != 0))
{
- DPRINT("Blacklisted PCI slot (%d:%d:%d)\n", BusHandler->BusNumber,
Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
+ DPRINT("Blacklisted PCI slot (%d:%d:%d)\n",
+ BusNumber, Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
return TRUE;
}
@@ -339,7 +339,8 @@ HalpValidPCISlot(IN PBUS_HANDLER BusHandler,
if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) return FALSE;
#ifdef SARCH_XBOX
- if (HalpXboxBlacklistedPCISlot(BusHandler, Slot)) return FALSE;
+ if (HalpXboxBlacklistedPCISlot(BusHandler->BusNumber, Slot))
+ return FALSE;
#endif
/* Function 0 doesn't need checking */
@@ -362,6 +363,143 @@ HalpValidPCISlot(IN PBUS_HANDLER BusHandler,
return TRUE;
}
+CODE_SEG("INIT")
+ULONG
+HalpPhase0GetPciDataByOffset(
+ _In_ ULONG Bus,
+ _In_ PCI_SLOT_NUMBER PciSlot,
+ _Out_writes_bytes_all_(Length) PVOID Buffer,
+ _In_ ULONG Offset,
+ _In_ ULONG Length)
+{
+ ULONG BytesLeft = Length;
+ PUCHAR BufferPtr = Buffer;
+ PCI_TYPE1_CFG_BITS PciCfg;
+
+#ifdef SARCH_XBOX
+ if (HalpXboxBlacklistedPCISlot(Bus, PciSlot))
+ {
+ RtlFillMemory(Buffer, Length, 0xFF);
+ return Length;
+ }
+#endif
+
+ PciCfg.u.AsULONG = 0;
+ PciCfg.u.bits.BusNumber = Bus;
+ PciCfg.u.bits.DeviceNumber = PciSlot.u.bits.DeviceNumber;
+ PciCfg.u.bits.FunctionNumber = PciSlot.u.bits.FunctionNumber;
+ PciCfg.u.bits.Enable = TRUE;
+
+ while (BytesLeft)
+ {
+ ULONG i;
+
+ PciCfg.u.bits.RegisterNumber = Offset / sizeof(ULONG);
+ WRITE_PORT_ULONG((PULONG)PCI_TYPE1_ADDRESS_PORT, PciCfg.u.AsULONG);
+
+ i = PCIDeref[Offset % sizeof(ULONG)][BytesLeft % sizeof(ULONG)];
+ switch (i)
+ {
+ case 0:
+ {
+ *(PULONG)BufferPtr = READ_PORT_ULONG((PULONG)PCI_TYPE1_DATA_PORT);
+
+ /* Number of bytes read */
+ i = sizeof(ULONG);
+ break;
+ }
+ case 1:
+ {
+ *BufferPtr = READ_PORT_UCHAR((PUCHAR)(PCI_TYPE1_DATA_PORT +
+ Offset % sizeof(ULONG)));
+ break;
+ }
+ case 2:
+ {
+ *(PUSHORT)BufferPtr = READ_PORT_USHORT((PUSHORT)(PCI_TYPE1_DATA_PORT +
+ Offset %
sizeof(ULONG)));
+ break;
+ }
+
+ DEFAULT_UNREACHABLE;
+ }
+
+ Offset += i;
+ BufferPtr += i;
+ BytesLeft -= i;
+ }
+
+ return Length;
+}
+
+CODE_SEG("INIT")
+ULONG
+HalpPhase0SetPciDataByOffset(
+ _In_ ULONG Bus,
+ _In_ PCI_SLOT_NUMBER PciSlot,
+ _In_reads_bytes_(Length) PVOID Buffer,
+ _In_ ULONG Offset,
+ _In_ ULONG Length)
+{
+ ULONG BytesLeft = Length;
+ PUCHAR BufferPtr = Buffer;
+ PCI_TYPE1_CFG_BITS PciCfg;
+
+#ifdef SARCH_XBOX
+ if (HalpXboxBlacklistedPCISlot(Bus, PciSlot))
+ {
+ return 0;
+ }
+#endif
+
+ PciCfg.u.AsULONG = 0;
+ PciCfg.u.bits.BusNumber = Bus;
+ PciCfg.u.bits.DeviceNumber = PciSlot.u.bits.DeviceNumber;
+ PciCfg.u.bits.FunctionNumber = PciSlot.u.bits.FunctionNumber;
+ PciCfg.u.bits.Enable = TRUE;
+
+ while (BytesLeft)
+ {
+ ULONG i;
+
+ PciCfg.u.bits.RegisterNumber = Offset / sizeof(ULONG);
+ WRITE_PORT_ULONG((PULONG)PCI_TYPE1_ADDRESS_PORT, PciCfg.u.AsULONG);
+
+ i = PCIDeref[Offset % sizeof(ULONG)][BytesLeft % sizeof(ULONG)];
+ switch (i)
+ {
+ case 0:
+ {
+ WRITE_PORT_ULONG((PULONG)PCI_TYPE1_DATA_PORT, *(PULONG)BufferPtr);
+
+ /* Number of bytes written */
+ i = sizeof(ULONG);
+ break;
+ }
+ case 1:
+ {
+ WRITE_PORT_UCHAR((PUCHAR)(PCI_TYPE1_DATA_PORT + Offset % sizeof(ULONG)),
+ *BufferPtr);
+ break;
+ }
+ case 2:
+ {
+ WRITE_PORT_USHORT((PUSHORT)(PCI_TYPE1_DATA_PORT + Offset %
sizeof(ULONG)),
+ *(PUSHORT)BufferPtr);
+ break;
+ }
+
+ DEFAULT_UNREACHABLE;
+ }
+
+ Offset += i;
+ BufferPtr += i;
+ BytesLeft -= i;
+ }
+
+ return Length;
+}
+
/* HAL PCI CALLBACKS *********************************************************/
ULONG
@@ -380,14 +518,10 @@ HalpGetPCIData(IN PBUS_HANDLER BusHandler,
Slot.u.AsULONG = SlotNumber;
#ifdef SARCH_XBOX
- if (HalpXboxBlacklistedPCISlot(BusHandler, Slot))
+ if (HalpXboxBlacklistedPCISlot(BusHandler->BusNumber, Slot))
{
- if (Offset == 0 && Length >= sizeof(USHORT))
- {
- *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
- return sizeof(USHORT);
- }
- return 0;
+ RtlFillMemory(Buffer, Length, 0xFF);
+ return Length;
}
#endif
@@ -464,7 +598,8 @@ HalpSetPCIData(IN PBUS_HANDLER BusHandler,
Slot.u.AsULONG = SlotNumber;
#ifdef SARCH_XBOX
- if (HalpXboxBlacklistedPCISlot(BusHandler, Slot)) return 0;
+ if (HalpXboxBlacklistedPCISlot(BusHandler->BusNumber, Slot))
+ return 0;
#endif
/* Normalize the length */
@@ -607,53 +742,6 @@ HalpGetISAFixedPCIIrq(IN PBUS_HANDLER BusHandler,
(*Range)->Limit = PciData.u.type0.InterruptLine;
return STATUS_SUCCESS;
}
-
-CODE_SEG("INIT")
-NTSTATUS
-NTAPI
-HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock,
- IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice)
-{
- DPRINT1("Unimplemented!\n");
- return STATUS_NOT_IMPLEMENTED;
-}
-
-CODE_SEG("INIT")
-NTSTATUS
-NTAPI
-HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice)
-{
- DPRINT1("Unimplemented!\n");
- return STATUS_NOT_IMPLEMENTED;
-}
-
-CODE_SEG("INIT")
-VOID
-NTAPI
-HalpRegisterPciDebuggingDeviceInfo(VOID)
-{
- BOOLEAN Found = FALSE;
- ULONG i;
- PAGED_CODE();
-
- /* Loop PCI debugging devices */
- for (i = 0; i < 2; i++)
- {
- /* Reserved bit is set if we found one */
- if (HalpPciDebuggingDevice[i].u.bits.Reserved1)
- {
- Found = TRUE;
- break;
- }
- }
-
- /* Bail out if there aren't any */
- if (!Found) return;
-
- /* FIXME: TODO */
- UNIMPLEMENTED_DBGBREAK("You have implemented the KD routines for searching PCI
debugger"
- "devices, but you have forgotten to implement this
routine\n");
-}
#endif // _MINIHAL_
static ULONG NTAPI
diff --git a/hal/halx86/pc98.cmake b/hal/halx86/pc98.cmake
index b88fbe87ddb..3a46043df3a 100644
--- a/hal/halx86/pc98.cmake
+++ b/hal/halx86/pc98.cmake
@@ -13,6 +13,7 @@ list(APPEND HAL_PC98_SOURCE
generic/dma.c
generic/drive.c
generic/halinit.c
+ generic/kdpci.c
generic/memory.c
generic/misc.c
generic/nmi.c
diff --git a/hal/halx86/xbox.cmake b/hal/halx86/xbox.cmake
index 9b4a6dfc20f..90db5a730b3 100644
--- a/hal/halx86/xbox.cmake
+++ b/hal/halx86/xbox.cmake
@@ -12,6 +12,7 @@ list(APPEND HAL_XBOX_SOURCE
generic/dma.c
generic/drive.c
generic/halinit.c
+ generic/kdpci.c
generic/memory.c
generic/misc.c
generic/nmi.c