mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-14 03:29:44 +00:00
The current method for determining BAR sizes appears to generate unreliable results. For now, do not query devices for BAR sizes.
834 lines
23 KiB
C
834 lines
23 KiB
C
/**
|
|
* @file ExtensionCommands.c
|
|
* @author Sina Karvandi (sina@hyperdbg.org)
|
|
* @brief Implementation of Debugger Commands (Extensions)
|
|
* @details Debugger Commands that start with "!"
|
|
*
|
|
* @version 0.1
|
|
* @date 2020-04-11
|
|
*
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
|
|
/**
|
|
* @brief Perform actions regarding APIC
|
|
*
|
|
* @param ApicRequest
|
|
*
|
|
* @return UINT32 Size to send to the debuggee
|
|
*/
|
|
UINT32
|
|
ExtensionCommandPerformActionsForApicRequests(PDEBUGGER_APIC_REQUEST ApicRequest)
|
|
{
|
|
BOOLEAN IsUsingX2APIC = FALSE;
|
|
PLAPIC_PAGE BufferToStoreLApic = (LAPIC_PAGE *)(((CHAR *)ApicRequest) + sizeof(DEBUGGER_APIC_REQUEST));
|
|
PIO_APIC_ENTRY_PACKETS BufferToStoreIoApic = (IO_APIC_ENTRY_PACKETS *)(((CHAR *)ApicRequest) + sizeof(DEBUGGER_APIC_REQUEST));
|
|
|
|
if (ApicRequest->ApicType == DEBUGGER_APIC_REQUEST_TYPE_READ_LOCAL_APIC)
|
|
{
|
|
if (VmFuncApicStoreLocalApicFields(BufferToStoreLApic, &IsUsingX2APIC))
|
|
{
|
|
//
|
|
// The status was okay
|
|
//
|
|
ApicRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
ApicRequest->IsUsingX2APIC = IsUsingX2APIC;
|
|
|
|
return sizeof(DEBUGGER_APIC_REQUEST) + sizeof(LAPIC_PAGE);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There was an error performing the action
|
|
//
|
|
ApicRequest->KernelStatus = DEBUGGER_ERROR_APIC_ACTIONS_ERROR;
|
|
|
|
return sizeof(DEBUGGER_APIC_REQUEST);
|
|
}
|
|
}
|
|
else if (ApicRequest->ApicType == DEBUGGER_APIC_REQUEST_TYPE_READ_IO_APIC)
|
|
{
|
|
if (VmFuncApicStoreIoApicFields(BufferToStoreIoApic))
|
|
{
|
|
//
|
|
// The status was okay
|
|
//
|
|
ApicRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
|
|
return sizeof(DEBUGGER_APIC_REQUEST) + sizeof(IO_APIC_ENTRY_PACKETS);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There was an error performing the action
|
|
//
|
|
ApicRequest->KernelStatus = DEBUGGER_ERROR_APIC_ACTIONS_ERROR;
|
|
|
|
return sizeof(DEBUGGER_APIC_REQUEST);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Invalid request
|
|
//
|
|
ApicRequest->KernelStatus = DEBUGGER_ERROR_APIC_ACTIONS_ERROR;
|
|
|
|
return sizeof(DEBUGGER_APIC_REQUEST);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Perform query for IDT entries
|
|
*
|
|
* @param IdtQueryRequest
|
|
* @param ReadFromVmxRoot
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandPerformQueryIdtEntriesRequest(PINTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS IdtQueryRequest,
|
|
BOOLEAN ReadFromVmxRoot)
|
|
{
|
|
//
|
|
// Perform the query
|
|
//
|
|
VmFuncIdtQueryEntries(IdtQueryRequest, ReadFromVmxRoot);
|
|
|
|
//
|
|
// Operation was successful
|
|
//
|
|
IdtQueryRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !va2pa and !pa2va commands
|
|
*
|
|
* @param AddressDetails
|
|
* @param OperateOnVmxRoot
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandVa2paAndPa2va(PDEBUGGER_VA2PA_AND_PA2VA_COMMANDS AddressDetails, BOOLEAN OperateOnVmxRoot)
|
|
{
|
|
if (OperateOnVmxRoot)
|
|
{
|
|
//
|
|
// *** !va2pa and !pa2va in Debugger Mode
|
|
//
|
|
if (AddressDetails->IsVirtual2Physical)
|
|
{
|
|
AddressDetails->PhysicalAddress = VirtualAddressToPhysicalAddressOnTargetProcess((PVOID)AddressDetails->VirtualAddress);
|
|
|
|
//
|
|
// Check if address is valid or invalid
|
|
//
|
|
if (AddressDetails->PhysicalAddress == (UINT64)NULL)
|
|
{
|
|
//
|
|
// Invalid address
|
|
//
|
|
AddressDetails->KernelStatus = DEBUGGER_ERROR_INVALID_ADDRESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Operation was successful
|
|
//
|
|
AddressDetails->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AddressDetails->VirtualAddress =
|
|
PhysicalAddressToVirtualAddressOnTargetProcess((PVOID)AddressDetails->PhysicalAddress);
|
|
|
|
//
|
|
// We don't know a way for checking physical address validity
|
|
//
|
|
AddressDetails->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// *** regular !va2pa and !pa2va in VMI Mode
|
|
//
|
|
|
|
if (AddressDetails->ProcessId == HANDLE_TO_UINT32(PsGetCurrentProcessId()))
|
|
{
|
|
//
|
|
// It's on current process address space (we process the request
|
|
// based on system process layout (pid = 4))
|
|
//
|
|
if (AddressDetails->IsVirtual2Physical)
|
|
{
|
|
AddressDetails->PhysicalAddress = VirtualAddressToPhysicalAddress((PVOID)AddressDetails->VirtualAddress);
|
|
|
|
//
|
|
// Check if address is valid or invalid
|
|
//
|
|
if (AddressDetails->PhysicalAddress == (UINT64)NULL)
|
|
{
|
|
//
|
|
// Invalid address
|
|
//
|
|
AddressDetails->KernelStatus = DEBUGGER_ERROR_INVALID_ADDRESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Operation was successful
|
|
//
|
|
AddressDetails->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AddressDetails->VirtualAddress = PhysicalAddressToVirtualAddress(AddressDetails->PhysicalAddress);
|
|
|
|
//
|
|
// We don't know a way for checking physical address validity
|
|
//
|
|
AddressDetails->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// It's on another process address space
|
|
//
|
|
|
|
//
|
|
// Check if pid is valid
|
|
//
|
|
if (!CommonIsProcessExist(AddressDetails->ProcessId))
|
|
{
|
|
//
|
|
// Process id is invalid
|
|
//
|
|
AddressDetails->KernelStatus = DEBUGGER_ERROR_INVALID_PROCESS_ID;
|
|
return;
|
|
}
|
|
|
|
if (AddressDetails->IsVirtual2Physical)
|
|
{
|
|
AddressDetails->PhysicalAddress = VirtualAddressToPhysicalAddressByProcessId((PVOID)AddressDetails->VirtualAddress, AddressDetails->ProcessId);
|
|
|
|
//
|
|
// Check if address is valid or invalid
|
|
//
|
|
if (AddressDetails->PhysicalAddress == (UINT64)NULL)
|
|
{
|
|
//
|
|
// Invalid address
|
|
//
|
|
AddressDetails->KernelStatus = DEBUGGER_ERROR_INVALID_ADDRESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Operation was successful
|
|
//
|
|
AddressDetails->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AddressDetails->VirtualAddress =
|
|
PhysicalAddressToVirtualAddressByProcessId((PVOID)AddressDetails->PhysicalAddress,
|
|
AddressDetails->ProcessId);
|
|
|
|
//
|
|
// We don't know a way for checking physical address validity
|
|
//
|
|
AddressDetails->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !pte command
|
|
*
|
|
* @param PteDetails
|
|
* @param IsOperatingInVmxRoot
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
ExtensionCommandPte(PDEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS PteDetails, BOOLEAN IsOperatingInVmxRoot)
|
|
{
|
|
BOOLEAN Result = FALSE;
|
|
CR3_TYPE RestoreCr3 = {0};
|
|
|
|
//
|
|
// Check for validations
|
|
//
|
|
if (IsOperatingInVmxRoot)
|
|
{
|
|
if (!VirtualAddressToPhysicalAddressOnTargetProcess((PVOID)PteDetails->VirtualAddress))
|
|
{
|
|
//
|
|
// Address is not valid (doesn't have Physical Address)
|
|
//
|
|
PteDetails->KernelStatus = DEBUGGER_ERROR_INVALID_ADDRESS;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Switch on running process's cr3
|
|
//
|
|
RestoreCr3.Flags = SwitchToCurrentProcessMemoryLayout().Flags;
|
|
}
|
|
else
|
|
{
|
|
if (PteDetails->ProcessId != HANDLE_TO_UINT32(PsGetCurrentProcessId()))
|
|
{
|
|
//
|
|
// It's on another process address space
|
|
//
|
|
|
|
//
|
|
// Check if pid is valid
|
|
//
|
|
if (!CommonIsProcessExist(PteDetails->ProcessId))
|
|
{
|
|
//
|
|
// Process id is invalid
|
|
//
|
|
PteDetails->KernelStatus = DEBUGGER_ERROR_INVALID_PROCESS_ID;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Switch to new process's memory layout
|
|
//
|
|
RestoreCr3.Flags = SwitchToProcessMemoryLayout(PteDetails->ProcessId).Flags;
|
|
}
|
|
|
|
//
|
|
// Check if address is valid
|
|
//
|
|
if (!VirtualAddressToPhysicalAddress((PVOID)PteDetails->VirtualAddress))
|
|
{
|
|
//
|
|
// Address is not valid (doesn't have Physical Address)
|
|
//
|
|
PteDetails->KernelStatus = DEBUGGER_ERROR_INVALID_ADDRESS;
|
|
Result = FALSE;
|
|
goto RestoreTheState;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read the PML4E
|
|
//
|
|
PPAGE_ENTRY Pml4e = MemoryMapperGetPteVa((PVOID)PteDetails->VirtualAddress, PagingLevelPageMapLevel4);
|
|
if (Pml4e)
|
|
{
|
|
PteDetails->Pml4eVirtualAddress = (UINT64)Pml4e;
|
|
PteDetails->Pml4eValue = Pml4e->Flags;
|
|
}
|
|
|
|
//
|
|
// Read the PDPTE
|
|
//
|
|
PPAGE_ENTRY Pdpte = MemoryMapperGetPteVa((PVOID)PteDetails->VirtualAddress, PagingLevelPageDirectoryPointerTable);
|
|
if (Pdpte)
|
|
{
|
|
PteDetails->PdpteVirtualAddress = (UINT64)Pdpte;
|
|
PteDetails->PdpteValue = Pdpte->Flags;
|
|
}
|
|
|
|
//
|
|
// Read the PDE
|
|
//
|
|
PPAGE_ENTRY Pde = MemoryMapperGetPteVa((PVOID)PteDetails->VirtualAddress, PagingLevelPageDirectory);
|
|
if (Pde)
|
|
{
|
|
PteDetails->PdeVirtualAddress = (UINT64)Pde;
|
|
PteDetails->PdeValue = Pde->Flags;
|
|
}
|
|
|
|
//
|
|
// Read the PTE
|
|
//
|
|
PPAGE_ENTRY Pte = MemoryMapperGetPteVa((PVOID)PteDetails->VirtualAddress, PagingLevelPageTable);
|
|
if (Pte)
|
|
{
|
|
PteDetails->PteVirtualAddress = (UINT64)Pte;
|
|
PteDetails->PteValue = Pte->Flags;
|
|
}
|
|
|
|
//
|
|
// Show that the details we retrieved successfully
|
|
//
|
|
PteDetails->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
Result = TRUE;
|
|
|
|
RestoreTheState:
|
|
|
|
//
|
|
// Check to restore the current cr3 if it's changed
|
|
//
|
|
if (RestoreCr3.Flags != (UINT64)NULL)
|
|
{
|
|
SwitchToPreviousProcess(RestoreCr3);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !msrread command which
|
|
* @details causes vm-exit on all msr reads
|
|
* @param BitmapMask Bit mask of msr to put on msr bitmap
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandChangeAllMsrBitmapReadAllCores(UINT64 BitmapMask)
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastChangeAllMsrBitmapReadAllCores(BitmapMask);
|
|
}
|
|
|
|
/**
|
|
* @brief routines for disable (reset) !msrread command
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandResetChangeAllMsrBitmapReadAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastResetChangeAllMsrBitmapReadAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !msrwrite command which
|
|
* @details causes vm-exit on all msr writes
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandChangeAllMsrBitmapWriteAllCores(UINT64 BitmapMask)
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastChangeAllMsrBitmapWriteAllCores(BitmapMask);
|
|
}
|
|
|
|
/**
|
|
* @brief routines for reset !msrwrite command which
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandResetAllMsrBitmapWriteAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastResetAllMsrBitmapWriteAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !tsc command
|
|
* @details causes vm-exit on all execution of rdtsc/rdtscp
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandEnableRdtscExitingAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastEnableRdtscExitingAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for disabling rdtsc/p exiting
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandDisableRdtscExitingAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastDisableRdtscExitingAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines ONLY for disabling !tsc command
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandDisableRdtscExitingForClearingEventsAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastDisableRdtscExitingForClearingEventsAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines ONLY for disabling !crwrite command
|
|
* @param Event
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandDisableMov2ControlRegsExitingForClearingEventsAllCores(PDEBUGGER_EVENT Event)
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastDisableMov2ControlRegsExitingForClearingEventsAllCores(&Event->Options);
|
|
}
|
|
|
|
/**
|
|
* @brief routines ONLY for disabling !dr command
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandDisableMov2DebugRegsExitingForClearingEventsAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastDisableMov2DebugRegsExitingForClearingEventsAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !pmc
|
|
* @details causes vm-exit on all execution of rdpmc
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandEnableRdpmcExitingAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastEnableRdpmcExitingAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for disabling !pmc
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandDisableRdpmcExitingAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastDisableRdpmcExitingAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !exception command which
|
|
* @details causes vm-exit when exception occurred
|
|
* @param ExceptionIndex index of exception on IDT
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandSetExceptionBitmapAllCores(UINT64 ExceptionIndex)
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastSetExceptionBitmapAllCores(ExceptionIndex);
|
|
}
|
|
|
|
/**
|
|
* @brief routines for disabling exception bitmap
|
|
* @details removes vm-exit when exception occurred
|
|
* @param ExceptionIndex index of exception on IDT
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandUnsetExceptionBitmapAllCores(UINT64 ExceptionIndex)
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastUnsetExceptionBitmapAllCores(ExceptionIndex);
|
|
}
|
|
|
|
/**
|
|
* @brief routines for reset !exception command
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandResetExceptionBitmapAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastResetExceptionBitmapAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !crwrite
|
|
* @details causes vm-exit on all accesses to debug registers
|
|
* @param Event
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandEnableMovControlRegisterExitingAllCores(PDEBUGGER_EVENT Event)
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastEnableMovControlRegisterExitingAllCores(&Event->Options);
|
|
}
|
|
|
|
/**
|
|
* @brief routines for disabling !crwrite
|
|
* @param Event
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandDisableMovToControlRegistersExitingAllCores(PDEBUGGER_EVENT Event)
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastDisableMovToControlRegistersExitingAllCores(&Event->Options);
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !dr
|
|
* @details causes vm-exit on all accesses to debug registers
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandEnableMovDebugRegistersExitingAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastEnableMovDebugRegistersExitingAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for disabling !dr
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandDisableMovDebugRegistersExitingAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastDisableMovDebugRegistersExitingAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !interrupt command which
|
|
* @details causes vm-exit when external interrupt occurs
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandSetExternalInterruptExitingAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastSetExternalInterruptExitingAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for ONLY terminate !interrupt command
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandUnsetExternalInterruptExitingOnlyOnClearingInterruptEventsAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastUnsetExternalInterruptExitingOnlyOnClearingInterruptEventsAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for !ioin and !ioout command which
|
|
* @details causes vm-exit on all i/o instructions or one port
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandIoBitmapChangeAllCores(UINT64 Port)
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastIoBitmapChangeAllCores(Port);
|
|
}
|
|
|
|
/**
|
|
* @brief routines for reset !ioin and !ioout command
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandIoBitmapResetAllCores()
|
|
{
|
|
//
|
|
// Broadcast to all cores
|
|
//
|
|
BroadcastIoBitmapResetAllCores();
|
|
}
|
|
|
|
/**
|
|
* @brief routines for PCIe tree
|
|
*
|
|
* @param PcitreePacket
|
|
* @param OperateOnVmxRoot
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandPcitree(PDEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreePacket, BOOLEAN OperateOnVmxRoot)
|
|
{
|
|
DWORD DeviceIdVendorId = 0xFFFFFFFF;
|
|
DWORD ClassCode = 0xFFFFFFFF;
|
|
UINT8 DevNum = 0;
|
|
|
|
//
|
|
// We currently don't use OperateOnVmxRoot, but we might in the future
|
|
//
|
|
UNREFERENCED_PARAMETER(OperateOnVmxRoot);
|
|
|
|
for (UINT8 b = 0; b < BUS_MAX_NUM; b++)
|
|
{
|
|
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->DeviceInfoList[DevNum].Bus = b;
|
|
PcitreePacket->DeviceInfoList[DevNum].Device = d;
|
|
PcitreePacket->DeviceInfoList[DevNum].Function = f;
|
|
PcitreePacket->DeviceInfoList[DevNum].ConfigSpace.VendorId = (UINT16)(DeviceIdVendorId & 0xFFFF);
|
|
PcitreePacket->DeviceInfoList[DevNum].ConfigSpace.DeviceId = (UINT16)(DeviceIdVendorId >> 16);
|
|
|
|
ClassCode = (DWORD)PciReadCam(b, d, f, 0, sizeof(DWORD));
|
|
PcitreePacket->DeviceInfoList[DevNum].ConfigSpace.ClassCode[0] = (UINT8)((ClassCode >> 24) & 0xFF);
|
|
PcitreePacket->DeviceInfoList[DevNum].ConfigSpace.ClassCode[1] = (UINT8)((ClassCode >> 16) & 0xFF);
|
|
PcitreePacket->DeviceInfoList[DevNum].ConfigSpace.ClassCode[2] = (UINT8)((ClassCode >> 8) & 0xFF);
|
|
|
|
DevNum++;
|
|
if (DevNum == DEV_MAX_NUM)
|
|
{
|
|
LogError("Reached maximum number of devices (%u) that can be stored in debuggee response packet.\n", DEV_MAX_NUM);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
PcitreePacket->DeviceInfoListNum = DevNum;
|
|
|
|
if (PcitreePacket->DeviceInfoListNum)
|
|
{
|
|
PcitreePacket->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
else
|
|
{
|
|
PcitreePacket->KernelStatus = DEBUGGER_ERROR_INVALID_ADDRESS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Request PCI device info.
|
|
*
|
|
* @param PcidevinfoPacket
|
|
* @param OperateOnVmxRoot
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
ExtensionCommandPcidevinfo(PDEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET PcidevinfoPacket, BOOLEAN OperateOnVmxRoot)
|
|
{
|
|
DWORD DeviceIdVendorId = 0xFFFFFFFF;
|
|
|
|
//
|
|
// We currently don't use OperateOnVmxRoot, but we might in the future
|
|
//
|
|
UNREFERENCED_PARAMETER(OperateOnVmxRoot);
|
|
|
|
DeviceIdVendorId = (DWORD)PciReadCam(PcidevinfoPacket->DeviceInfo.Bus, PcidevinfoPacket->DeviceInfo.Device, PcidevinfoPacket->DeviceInfo.Function, 0, 4);
|
|
if (DeviceIdVendorId != 0xFFFFFFFF)
|
|
{
|
|
DWORD * cs = (DWORD *)&PcidevinfoPacket->DeviceInfo.ConfigSpace; // Overflows into .ConfigSpaceAdditional - no padding due to pack(0)
|
|
for (UINT16 i = 0; i < CAM_CONFIG_SPACE_LENGTH; i += 4)
|
|
{
|
|
*cs = (DWORD)PciReadCam(PcidevinfoPacket->DeviceInfo.Bus, PcidevinfoPacket->DeviceInfo.Device, PcidevinfoPacket->DeviceInfo.Function, (BYTE)i, 4);
|
|
cs++;
|
|
}
|
|
|
|
//
|
|
// For endpoints, determine MMIO BAR addressable range and size (if any).
|
|
// Do not determine BAR size if user has requested raw dump.
|
|
//
|
|
if ((PcidevinfoPacket->DeviceInfo.ConfigSpace.CommonHeader.HeaderType & 0x01) << 7 == 0 // Endpoint
|
|
&& !PcidevinfoPacket->PrintRaw)
|
|
{
|
|
for (UINT8 i = 0; i < 5; i++)
|
|
{
|
|
if ((PcidevinfoPacket->DeviceInfo.ConfigSpace.DeviceHeader.ConfigSpaceEp.Bar[i] & 0x1) == 0) // Memory I/O
|
|
{
|
|
if (((PcidevinfoPacket->DeviceInfo.ConfigSpace.DeviceHeader.ConfigSpaceEp.Bar[i] & 0x6) >> 1) == 2) // 64-bit BAR
|
|
{
|
|
UINT64 BarMsb = PcidevinfoPacket->DeviceInfo.ConfigSpace.DeviceHeader.ConfigSpaceEp.Bar[i + 1];
|
|
UINT64 BarLsb = PcidevinfoPacket->DeviceInfo.ConfigSpace.DeviceHeader.ConfigSpaceEp.Bar[i];
|
|
UINT64 Bar64 = ((BarMsb & 0xFFFFFFFF) << 32) + (BarLsb & 0xFFFFFFF0);
|
|
|
|
PcidevinfoPacket->DeviceInfo.MmioBarInfo[i].Is64Bit = TRUE;
|
|
if (Bar64 == 0)
|
|
{
|
|
PcidevinfoPacket->DeviceInfo.MmioBarInfo[i].IsEnabled = FALSE;
|
|
continue;
|
|
}
|
|
|
|
PcidevinfoPacket->DeviceInfo.MmioBarInfo[i].Is64Bit = TRUE;
|
|
PcidevinfoPacket->DeviceInfo.MmioBarInfo[i].IsEnabled = TRUE;
|
|
|
|
i++;
|
|
}
|
|
else // 32-bit BAR
|
|
{
|
|
UINT32 Bar32 = (PcidevinfoPacket->DeviceInfo.ConfigSpace.DeviceHeader.ConfigSpaceEp.Bar[i] & 0xFFFFFFF0);
|
|
|
|
PcidevinfoPacket->DeviceInfo.MmioBarInfo[i].Is64Bit = FALSE;
|
|
if (Bar32 == 0)
|
|
{
|
|
PcidevinfoPacket->DeviceInfo.MmioBarInfo[i].IsEnabled = FALSE;
|
|
continue;
|
|
}
|
|
|
|
PcidevinfoPacket->DeviceInfo.MmioBarInfo[i].Is64Bit = FALSE;
|
|
PcidevinfoPacket->DeviceInfo.MmioBarInfo[i].IsEnabled = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PcidevinfoPacket->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
else
|
|
{
|
|
PcidevinfoPacket->DeviceInfo.ConfigSpace.CommonHeader.DeviceId = 0xFFFF;
|
|
PcidevinfoPacket->DeviceInfo.ConfigSpace.CommonHeader.VendorId = 0xFFFF;
|
|
PcidevinfoPacket->KernelStatus = DEBUGGER_ERROR_INVALID_ADDRESS;
|
|
}
|
|
}
|