From 734cd5e8428c3d57955b64b4c0c467d32a2690ff Mon Sep 17 00:00:00 2001 From: Dmitry Borisov Date: Tue, 7 Sep 2021 00:42:23 +0600 Subject: [PATCH] [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(-) create mode 100644 hal/halx86/generic/kdpci.c 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 #include +#include #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 + */ + +/* + * 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 + +/* 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