pcitree: Send PCI device tree in one flattened buffer. Add EP Class Code and remove BDF probing limits.

This commit is contained in:
Björn Ruytenberg 2024-11-17 21:01:03 +01:00
parent e714e3e6ad
commit 29071cad41
5 changed files with 163 additions and 96 deletions

View file

@ -641,26 +641,61 @@ ExtensionCommandIoBitmapResetAllCores()
/**
* @brief routines for !pcitree
*
* @param PcitreeReqPacket
* @param PcitreePacket
* @param OperateOnVmxRoot
* @return VOID
*/
VOID
ExtensionCommandPcitree(PDEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreeReqPacket, BOOLEAN OperateOnVmxRoot)
ExtensionCommandPcitree(PDEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreePacket, BOOLEAN OperateOnVmxRoot)
{
DWORD DeviceIdVendorId = 0;
DWORD DeviceIdVendorId = 0xFFFFFFFF;
DWORD ClassCode = 0xFFFFFFFF;
UINT8 EpNum = 0;
DeviceIdVendorId = (DWORD)PciReadCam(PcitreeReqPacket->RequestedBus, PcitreeReqPacket->RequestedDevice, PcitreeReqPacket->RequestedFunction, 0, sizeof(DWORD));
if (DeviceIdVendorId != 0xFFFFFFFF)
LogInfo("Enumerating endpoints...\n");
for (UINT8 b = 0; b < BUS_MAX_NUM; b++)
{
LogInfo("DeviceIdVendorId: %x\n", DeviceIdVendorId);
PcitreeReqPacket->Device.Function[0].ConfigSpace.CommonHeader.DeviceId = (UINT16)(DeviceIdVendorId >> 16);
PcitreeReqPacket->Device.Function[0].ConfigSpace.CommonHeader.VendorId = (UINT16)(DeviceIdVendorId & 0xFFFF);
PcitreeReqPacket->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
for (UINT8 d = 0; d < DEVICE_MAX_NUM; d++)
{
for (UINT8 f = 0; f < FUNCTION_MAX_NUM; f++)
{
DeviceIdVendorId = (DWORD)PciReadCam(b, d, f, 0, sizeof(DWORD));
if (DeviceIdVendorId != 0xFFFFFFFF)
{
PcitreePacket->Endpoints[EpNum].Bus = b;
PcitreePacket->Endpoints[EpNum].Device = d;
PcitreePacket->Endpoints[EpNum].Function = f;
PcitreePacket->Endpoints[EpNum].ConfigSpace.VendorId = (UINT16)(DeviceIdVendorId & 0xFFFF);
PcitreePacket->Endpoints[EpNum].ConfigSpace.DeviceId = (UINT16)(DeviceIdVendorId >> 16);
ClassCode = (DWORD)PciReadCam(b, d, f, 0, sizeof(DWORD));
PcitreePacket->Endpoints[EpNum].ConfigSpace.ClassCode[0] = (UINT8)((ClassCode >> 24) & 0xFF);
PcitreePacket->Endpoints[EpNum].ConfigSpace.ClassCode[1] = (UINT8)((ClassCode >> 16) & 0xFF);
PcitreePacket->Endpoints[EpNum].ConfigSpace.ClassCode[2] = (UINT8)((ClassCode >> 8) & 0xFF);
EpNum++;
if (EpNum == EP_MAX_NUM)
{
LogError("Reached maximum number of endpoints (%u) that can be stored in debuggee response packet.\n", EP_MAX_NUM);
break;
}
}
}
}
}
PcitreePacket->EndpointsTotalNum = EpNum;
LogInfo("Enumerated %u endpoints.\n", PcitreePacket->EndpointsTotalNum);
if (PcitreePacket->EndpointsTotalNum)
{
PcitreePacket->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
}
else
{
PcitreeReqPacket->KernelStatus = DEBUGGER_ERROR_INVALID_ADDRESS;
PcitreePacket->KernelStatus = DEBUGGER_ERROR_INVALID_ADDRESS;
}
//

View file

@ -30,14 +30,15 @@
#define FUNCTION_BIT_WIDTH 3
//
// NOTES
// - To speed up PCI device enumeration, the parameters below limit the max BDF range to what might be reasonably expected on real-world systems.
// - Ensure the following parameters do not result in exceeding MaxSerialPacketSize. Consider sending multiple packets if necessary.
// NOTE
// On real-world systems, the number of endpoints will likely not exceed 255.
// If increasing EP_MAX_NUM is necessary, ensure PCI_EP_MINIMAL[EP_MAX_NUM] does not result in exceeding MaxSerialPacketSize.
//
#define DOMAIN_MAX_NUM 0
#define BUS_MAX_NUM 32
#define BUS_MAX_NUM 255
#define DEVICE_MAX_NUM 32
#define FUNCTION_MAX_NUM 8
#define EP_MAX_NUM 255
/**
* @brief PCI Common Header
@ -77,6 +78,32 @@ typedef struct _PORTABLE_PCI_DEVICE_HEADER
UINT8 MaxLat; // Max_Lat
} PORTABLE_PCI_DEVICE_HEADER, *PPORTABLE_PCI_DEVICE_HEADER;
/**
* @brief PCI Configuration Space Minimal Header for !pcitree
*
*/
typedef struct _PORTABLE_PCI_CONFIG_SPACE_HEADER_MINIMAL
{
//
// Common header
//
UINT16 VendorId;
UINT16 DeviceId;
UINT8 ClassCode[3];
} PORTABLE_PCI_CONFIG_SPACE_HEADER_MINIMAL, *PPORTABLE_PCI_CONFIG_SPACE_HEADER_MINIMAL;
/**
* @brief PCI Endpoint Minimal Data Structure for !pcitree
*
*/
typedef struct _PCI_EP_MINIMAL
{
UINT8 Bus : BUS_BIT_WIDTH;
UINT8 Device : DEVICE_BIT_WIDTH;
UINT8 Function : FUNCTION_BIT_WIDTH;
PORTABLE_PCI_CONFIG_SPACE_HEADER_MINIMAL ConfigSpace;
} PCI_EP_MINIMAL, *PPCI_EP_MINIMAL;
/**
* @brief PCI Configuration Space Header
*
@ -94,6 +121,7 @@ typedef struct _PORTABLE_PCI_CONFIG_SPACE_HEADER
*/
typedef struct _PCI_FUNCTION
{
UINT8 Function : FUNCTION_BIT_WIDTH;
PORTABLE_PCI_CONFIG_SPACE_HEADER ConfigSpace;
} PCI_FUNCTION, *PPCI_FUNCTION;
@ -103,6 +131,7 @@ typedef struct _PCI_FUNCTION
*/
typedef struct _PCI_DEVICE
{
UINT8 Device : DEVICE_BIT_WIDTH;
PCI_FUNCTION Function[FUNCTION_MAX_NUM];
} PCI_DEVICE, *PPCI_DEVICE;
@ -112,6 +141,7 @@ typedef struct _PCI_DEVICE
*/
typedef struct _PCI_BUS
{
UINT8 Bus : BUS_BIT_WIDTH;
PCI_DEVICE Device[DEVICE_MAX_NUM];
} PCI_BUS, *PPCI_BUS;

View file

@ -1316,16 +1316,14 @@ typedef struct _DEBUGGEE_REGISTER_WRITE_DESCRIPTION
sizeof(DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET)
/**
* @brief Pcitree Request-Response Packet. Represents one PCI device.
* @brief Pcitree Request-Response Packet. Represents PCI device tree.
*
*/
typedef struct _DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET
{
UINT32 KernelStatus;
UINT8 RequestedBus : BUS_BIT_WIDTH;
UINT8 RequestedDevice : DEVICE_BIT_WIDTH;
UINT8 RequestedFunction : FUNCTION_BIT_WIDTH;
PCI_DEVICE Device;
UINT32 KernelStatus;
UINT8 EndpointsTotalNum;
PCI_EP_MINIMAL Endpoints[EP_MAX_NUM];
} DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET, *PDEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET;

View file

@ -45,8 +45,7 @@ CommandPcitree(vector<CommandToken> CommandTokens, string Command)
{
BOOL Status;
ULONG ReturnedLength;
DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreeReqPacket = {0};
DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreeRespPacket = {0};
DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreePacket = {0};
if (CommandTokens.size() != 1)
{
@ -56,76 +55,72 @@ CommandPcitree(vector<CommandToken> CommandTokens, string Command)
return;
}
for (UINT8 b = 0; b < BUS_MAX_NUM; b++)
//
// Send buffer
//
if (g_IsSerialConnectedToRemoteDebuggee)
{
for (UINT8 d = 0; d < DEVICE_MAX_NUM; d++)
KdSendPcitreePacketToDebuggee(&PcitreePacket);
}
else
{
AssertShowMessageReturnStmt(g_DeviceHandle, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturn);
ShowMessages("Sending IOCTL\n");
//
// Send IOCTL
//
Status = DeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_PCIE_ENDPOINT_ENUM, // IO Control Code (IOCTL)
&PcitreePacket, // Input Buffer to driver.
SIZEOF_DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET, // Input buffer length
&PcitreePacket, // Output Buffer from driver.
SIZEOF_DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET, // Length of output
// buffer in bytes.
&ReturnedLength, // Bytes placed in buffer.
NULL // synchronous call
);
ShowMessages("Done sending IOCTL\n");
if (!Status)
{
for (UINT8 f = 0; f < FUNCTION_MAX_NUM; f++)
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
return;
}
if (PcitreePacket.KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL)
{
//
// Print PCI device tree
//
ShowMessages("%-12s | %-9s | %s\n%s\n", "DBDF", "VID:DID", "Class Code", "---------------------------------------");
for (UINT8 i = 0; i < (PcitreePacket.EndpointsTotalNum < EP_MAX_NUM ? PcitreePacket.EndpointsTotalNum : EP_MAX_NUM); i++)
{
//
// Prepare buffer
//
PcitreeReqPacket.RequestedBus = b;
PcitreeReqPacket.RequestedDevice = d;
PcitreeReqPacket.RequestedFunction = f;
ShowMessages("%04x:%02x:%02x:%x | %04x:%04x | %04x%04x%04x\n",
0, // TODO: Add support for domains beyond 0000
PcitreePacket.Endpoints[i].Bus,
PcitreePacket.Endpoints[i].Device,
PcitreePacket.Endpoints[i].Function,
PcitreePacket.Endpoints[i].ConfigSpace.VendorId,
PcitreePacket.Endpoints[i].ConfigSpace.DeviceId,
PcitreePacket.Endpoints[i].ConfigSpace.ClassCode[0],
PcitreePacket.Endpoints[i].ConfigSpace.ClassCode[1],
PcitreePacket.Endpoints[i].ConfigSpace.ClassCode[2]
//
// Send buffer
//
if (g_IsSerialConnectedToRemoteDebuggee)
{
KdSendPcitreePacketToDebuggee(&PcitreeReqPacket);
}
else
{
AssertShowMessageReturnStmt(g_DeviceHandle, ASSERT_MESSAGE_DRIVER_NOT_LOADED, AssertReturn);
ShowMessages("Sending IOCTL\n");
//
// Send IOCTL
//
Status = DeviceIoControl(
g_DeviceHandle, // Handle to device
IOCTL_PCIE_ENDPOINT_ENUM, // IO Control Code (IOCTL)
&PcitreeReqPacket, // Input Buffer to driver.
SIZEOF_DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET, // Input buffer length
&PcitreeRespPacket, // Output Buffer from driver.
SIZEOF_DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET, // Length of output
// buffer in bytes.
&ReturnedLength, // Bytes placed in buffer.
NULL // synchronous call
);
ShowMessages("Done sending IOCTL\n");
if (!Status)
{
ShowMessages("ioctl failed with code 0x%x\n", GetLastError());
return;
}
if (PcitreeRespPacket.KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL)
{
ShowMessages("Result: (%04x:%2x:%2x:%x) VID:DID: %x:%x\n",
0,
PcitreeRespPacket.RequestedBus,
PcitreeRespPacket.RequestedDevice,
PcitreeRespPacket.RequestedFunction,
PcitreeRespPacket.Device.Function[0].ConfigSpace.CommonHeader.VendorId,
PcitreeRespPacket.Device.Function[0].ConfigSpace.CommonHeader.DeviceId);
}
else
{
//
// An err occurred, no results
//
ShowMessages("An err occured, no results:");
ShowErrorMessage(PcitreeRespPacket.KernelStatus);
}
}
);
}
}
else
{
//
// An err occurred, no results
//
ShowMessages("An err occured, no results:");
ShowErrorMessage(PcitreePacket.KernelStatus);
}
}
}

View file

@ -1052,19 +1052,28 @@ StartAgain:
if (PcitreePacket->KernelStatus == DEBUGGER_OPERATION_WAS_SUCCESSFUL)
{
//
// TODO: Add support for domains beyond 0000
// Print PCI device tree
//
ShowMessages("Got packet from debuggee: (%04x:%02x:%02x:%x) VID:DID: %04x:%04x\n",
0,
PcitreePacket->RequestedBus,
PcitreePacket->RequestedDevice,
PcitreePacket->RequestedFunction,
PcitreePacket->Device.Function[0].ConfigSpace.CommonHeader.VendorId,
PcitreePacket->Device.Function[0].ConfigSpace.CommonHeader.DeviceId);
ShowMessages("%-12s | %-9s | %s\n%s\n", "DBDF", "VID:DID", "Class Code", "---------------------------------------");
for (UINT8 i = 0; i < (PcitreePacket->EndpointsTotalNum < EP_MAX_NUM ? PcitreePacket->EndpointsTotalNum : EP_MAX_NUM); i++)
{
ShowMessages("%04x:%02x:%02x:%x | %04x:%04x | %04x%04x%04x\n",
0, // TODO: Add support for domains beyond 0000
PcitreePacket->Endpoints[i].Bus,
PcitreePacket->Endpoints[i].Device,
PcitreePacket->Endpoints[i].Function,
PcitreePacket->Endpoints[i].ConfigSpace.VendorId,
PcitreePacket->Endpoints[i].ConfigSpace.DeviceId,
PcitreePacket->Endpoints[i].ConfigSpace.ClassCode[0],
PcitreePacket->Endpoints[i].ConfigSpace.ClassCode[1],
PcitreePacket->Endpoints[i].ConfigSpace.ClassCode[2]
);
}
}
else
{
// ShowErrorMessage(PcitreePacket->KernelStatus);
ShowErrorMessage(PcitreePacket->KernelStatus);
}
//