903 lines
48 KiB
C++
903 lines
48 KiB
C++
/*
|
|
* Copyright (C) 2023-2025 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
*/
|
|
|
|
#include "level_zero/tools/source/debug/linux/xe/debug_session.h"
|
|
|
|
#include "shared/source/debug_settings/debug_settings_manager.h"
|
|
#include "shared/source/gmm_helper/gmm_helper.h"
|
|
#include "shared/source/helpers/hw_info.h"
|
|
#include "shared/source/memory_manager/memory_manager.h"
|
|
#include "shared/source/os_interface/linux/drm_debug.h"
|
|
#include "shared/source/os_interface/linux/sys_calls.h"
|
|
#include "shared/source/os_interface/linux/xe/ioctl_helper_xe.h"
|
|
|
|
#include "level_zero/core/source/gfx_core_helpers/l0_gfx_core_helper.h"
|
|
#include "level_zero/tools/source/debug/debug_session.h"
|
|
#include "level_zero/tools/source/debug/linux/drm_helper.h"
|
|
|
|
namespace L0 {
|
|
|
|
static DebugSessionLinuxPopulateFactory<DEBUG_SESSION_LINUX_TYPE_XE, DebugSessionLinuxXe>
|
|
populateXeDebugger;
|
|
|
|
DebugSession *createDebugSessionHelperXe(const zet_debug_config_t &config, Device *device, int debugFd, void *params);
|
|
|
|
DebugSessionLinuxXe::DebugSessionLinuxXe(const zet_debug_config_t &config, Device *device, int debugFd, void *params) : DebugSessionLinux(config, device, debugFd) {
|
|
auto sysFsPciPath = DrmHelper::getSysFsPciPath(device);
|
|
euDebugInterface = NEO::EuDebugInterface::create(sysFsPciPath);
|
|
if (euDebugInterface) {
|
|
ioctlHandler.reset(new IoctlHandlerXe(*euDebugInterface));
|
|
if (params) {
|
|
this->xeDebuggerVersion = reinterpret_cast<NEO::EuDebugConnect *>(params)->version;
|
|
}
|
|
}
|
|
};
|
|
DebugSessionLinuxXe::~DebugSessionLinuxXe() {
|
|
|
|
closeAsyncThread();
|
|
closeInternalEventsThread();
|
|
closeFd();
|
|
}
|
|
|
|
DebugSession *DebugSessionLinuxXe::createLinuxSession(const zet_debug_config_t &config, Device *device, ze_result_t &result, bool isRootAttach) {
|
|
|
|
NEO::EuDebugConnect open = {
|
|
.extensions = 0,
|
|
.pid = config.pid,
|
|
.flags = 0,
|
|
.version = 0};
|
|
auto debugFd = DrmHelper::ioctl(device, NEO::DrmIoctl::debuggerOpen, &open);
|
|
if (debugFd >= 0) {
|
|
PRINT_DEBUGGER_INFO_LOG("drm_xe_eudebug_connect: open.pid: %d, debugFd: %d\n",
|
|
open.pid, debugFd);
|
|
|
|
return createDebugSessionHelperXe(config, device, debugFd, &open);
|
|
} else {
|
|
auto reason = DrmHelper::getErrno(device);
|
|
PRINT_DEBUGGER_ERROR_LOG("drm_xe_eudebug_connect failed: open.pid: %d, retCode: %d, errno: %d\n",
|
|
open.pid, debugFd, reason);
|
|
result = translateDebuggerOpenErrno(reason);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool DebugSessionLinuxXe::handleInternalEvent() {
|
|
auto eventMemory = getInternalEvent();
|
|
if (eventMemory == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
auto debugEvent = reinterpret_cast<NEO::EuDebugEvent *>(eventMemory.get());
|
|
handleEvent(debugEvent);
|
|
if (debugEvent->type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeExecQueuePlacements) ||
|
|
debugEvent->type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeVmBindOp) ||
|
|
debugEvent->type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeVmBindUfence) ||
|
|
debugEvent->type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeVmBindOpMetadata)) {
|
|
processPendingVmBindEvents();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void *DebugSessionLinuxXe::asyncThreadFunction(void *arg) {
|
|
DebugSessionLinuxXe *self = reinterpret_cast<DebugSessionLinuxXe *>(arg);
|
|
if (NEO::debugManager.flags.DebugUmdFifoPollInterval.get() != -1) {
|
|
self->fifoPollInterval = NEO::debugManager.flags.DebugUmdFifoPollInterval.get();
|
|
}
|
|
if (NEO::debugManager.flags.DebugUmdInterruptTimeout.get() != -1) {
|
|
self->interruptTimeout = NEO::debugManager.flags.DebugUmdInterruptTimeout.get();
|
|
}
|
|
if (NEO::debugManager.flags.DebugUmdMaxReadWriteRetry.get() != -1) {
|
|
self->maxRetries = NEO::debugManager.flags.DebugUmdMaxReadWriteRetry.get();
|
|
}
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("Debugger async thread start\n", "");
|
|
|
|
while (self->asyncThread.threadActive) {
|
|
self->handleEventsAsync();
|
|
self->pollFifo();
|
|
self->generateEventsAndResumeStoppedThreads();
|
|
self->sendInterrupts();
|
|
}
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("Debugger async thread closing\n", "");
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void DebugSessionLinuxXe::startAsyncThread() {
|
|
asyncThread.thread = NEO::Thread::createFunc(asyncThreadFunction, reinterpret_cast<void *>(this));
|
|
}
|
|
|
|
void DebugSessionLinuxXe::readInternalEventsAsync() {
|
|
|
|
struct pollfd pollFd = {
|
|
.fd = fd,
|
|
.events = POLLIN,
|
|
.revents = 0,
|
|
};
|
|
|
|
int pollTimeout = 1000;
|
|
auto numberOfFds = ioctlHandler->poll(&pollFd, 1, pollTimeout);
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("Debugger async thread readEvent poll() retCode: %d\n", numberOfFds);
|
|
|
|
if (!detached && numberOfFds < 0 && errno == EINVAL) {
|
|
zet_debug_event_t debugEvent = {};
|
|
debugEvent.type = ZET_DEBUG_EVENT_TYPE_DETACHED;
|
|
debugEvent.info.detached.reason = ZET_DEBUG_DETACH_REASON_INVALID;
|
|
PRINT_DEBUGGER_INFO_LOG("Debugger detached\n", "");
|
|
pushApiEvent(debugEvent);
|
|
detached = true;
|
|
} else if (numberOfFds > 0) {
|
|
|
|
ze_result_t result = ZE_RESULT_SUCCESS;
|
|
|
|
uint8_t maxEventBuffer[sizeof(NEO::EuDebugEvent) + maxEventSize];
|
|
auto event = reinterpret_cast<NEO::EuDebugEvent *>(maxEventBuffer);
|
|
event->len = maxEventSize;
|
|
event->type = euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeRead);
|
|
event->flags = 0;
|
|
|
|
result = readEventImp(event);
|
|
|
|
if (result == ZE_RESULT_SUCCESS) {
|
|
std::lock_guard<std::mutex> lock(internalEventThreadMutex);
|
|
if (eventTypeIsAttention(event->type)) {
|
|
newestAttSeqNo.store(event->seqno);
|
|
}
|
|
|
|
auto memory = std::make_unique<uint64_t[]>(maxEventSize / sizeof(uint64_t));
|
|
memcpy(memory.get(), event, maxEventSize);
|
|
|
|
internalEventQueue.push(std::move(memory));
|
|
internalEventCondition.notify_one();
|
|
}
|
|
}
|
|
}
|
|
|
|
int DebugSessionLinuxXe::ioctl(unsigned long request, void *arg) {
|
|
return ioctlHandler->ioctl(fd, request, arg);
|
|
}
|
|
|
|
ze_result_t DebugSessionLinuxXe::readEventImp(NEO::EuDebugEvent *drmDebugEvent) {
|
|
auto ret = ioctl(euDebugInterface->getParamValue(NEO::EuDebugParam::ioctlReadEvent), drmDebugEvent);
|
|
if (ret != 0) {
|
|
PRINT_DEBUGGER_ERROR_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT failed: retCode: %d errno = %d\n", ret, errno);
|
|
return ZE_RESULT_NOT_READY;
|
|
} else if (drmDebugEvent->flags & ~static_cast<uint32_t>(
|
|
euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitCreate) |
|
|
euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitDestroy) |
|
|
euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitStateChange) |
|
|
euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitNeedAck))) {
|
|
PRINT_DEBUGGER_ERROR_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT unsupported flag = %d\n", (int)drmDebugEvent->flags);
|
|
return ZE_RESULT_ERROR_UNKNOWN;
|
|
}
|
|
return ZE_RESULT_SUCCESS;
|
|
}
|
|
|
|
void DebugSessionLinuxXe::handleEvent(NEO::EuDebugEvent *event) {
|
|
auto type = event->type;
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type = %u flags = %u seqno = %llu len = %lu",
|
|
(uint16_t)event->type, (uint16_t)event->flags, (uint64_t)event->seqno, (uint32_t)event->len);
|
|
|
|
if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeOpen)) {
|
|
auto clientEvent = reinterpret_cast<NEO::EuDebugEventClient *>(event);
|
|
|
|
if (event->flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitCreate)) {
|
|
DEBUG_BREAK_IF(clientHandleToConnection.find(clientEvent->clientHandle) != clientHandleToConnection.end());
|
|
clientHandleToConnection[clientEvent->clientHandle].reset(new ClientConnectionXe);
|
|
clientHandleToConnection[clientEvent->clientHandle]->client = *clientEvent;
|
|
}
|
|
|
|
if (event->flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitDestroy)) {
|
|
clientHandleClosed = clientEvent->clientHandle;
|
|
}
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_OPEN client.handle = %llu\n",
|
|
(uint64_t)clientEvent->clientHandle);
|
|
|
|
} else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeVm)) {
|
|
NEO::EuDebugEventVm *vm = reinterpret_cast<NEO::EuDebugEventVm *>(event);
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_VM client_handle = %llu vm_handle = %llu\n",
|
|
(uint64_t)vm->clientHandle, (uint64_t)vm->vmHandle);
|
|
|
|
if (event->flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitCreate)) {
|
|
UNRECOVERABLE_IF(clientHandleToConnection.find(vm->clientHandle) == clientHandleToConnection.end());
|
|
clientHandleToConnection[vm->clientHandle]->vmIds.emplace(static_cast<uint64_t>(vm->vmHandle));
|
|
}
|
|
|
|
if (event->flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitDestroy)) {
|
|
UNRECOVERABLE_IF(clientHandleToConnection.find(vm->clientHandle) == clientHandleToConnection.end());
|
|
clientHandleToConnection[vm->clientHandle]->vmIds.erase(static_cast<uint64_t>(vm->vmHandle));
|
|
}
|
|
} else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeExecQueue)) {
|
|
NEO::EuDebugEventExecQueue *execQueue = reinterpret_cast<NEO::EuDebugEventExecQueue *>(event);
|
|
|
|
if (event->flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitCreate)) {
|
|
UNRECOVERABLE_IF(clientHandleToConnection.find(execQueue->clientHandle) == clientHandleToConnection.end());
|
|
|
|
if (!processEntryEventGenerated) {
|
|
zet_debug_event_t debugEvent = {};
|
|
debugEvent.type = ZET_DEBUG_EVENT_TYPE_PROCESS_ENTRY;
|
|
pushApiEvent(debugEvent);
|
|
processEntryEventGenerated = true;
|
|
}
|
|
std::lock_guard<std::mutex> lock(asyncThreadMutex);
|
|
clientHandleToConnection[execQueue->clientHandle]->execQueues[execQueue->execQueueHandle].vmHandle = execQueue->vmHandle;
|
|
clientHandleToConnection[execQueue->clientHandle]->execQueues[execQueue->execQueueHandle].engineClass = execQueue->engineClass;
|
|
for (uint16_t idx = 0; idx < execQueue->width; idx++) {
|
|
uint64_t lrcHandle = execQueue->lrcHandle[idx];
|
|
clientHandleToConnection[execQueue->clientHandle]->execQueues[execQueue->execQueueHandle].lrcHandles.push_back(lrcHandle);
|
|
clientHandleToConnection[execQueue->clientHandle]->lrcHandleToVmHandle[lrcHandle] = execQueue->vmHandle;
|
|
}
|
|
}
|
|
|
|
if (event->flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitDestroy)) {
|
|
{
|
|
std::lock_guard<std::mutex> lock(asyncThreadMutex);
|
|
for (uint16_t idx = 0; idx < execQueue->width; idx++) {
|
|
clientHandleToConnection[execQueue->clientHandle]->lrcHandleToVmHandle.erase(execQueue->lrcHandle[idx]);
|
|
}
|
|
clientHandleToConnection[execQueue->clientHandle]->execQueues.erase(execQueue->execQueueHandle);
|
|
}
|
|
{
|
|
bool lastExecQueue = true;
|
|
for (const auto &connection : clientHandleToConnection) {
|
|
if (!connection.second->execQueues.empty()) {
|
|
lastExecQueue = false;
|
|
break;
|
|
}
|
|
}
|
|
if (lastExecQueue) {
|
|
zet_debug_event_t debugEvent = {};
|
|
debugEvent.type = ZET_DEBUG_EVENT_TYPE_PROCESS_EXIT;
|
|
pushApiEvent(debugEvent);
|
|
processEntryEventGenerated = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE client_handle = %llu vm_handle = %llu exec_queue_handle = %llu engine_class = %u\n",
|
|
(uint64_t)execQueue->clientHandle, (uint64_t)execQueue->vmHandle,
|
|
(uint64_t)execQueue->execQueueHandle, (uint16_t)execQueue->engineClass);
|
|
} else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeEuAttention)) {
|
|
NEO::EuDebugEventEuAttention *attention = reinterpret_cast<NEO::EuDebugEventEuAttention *>(event);
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_EU_ATTENTION client_handle = %llu flags = %llu bitmask_size = %lu exec_queue_handle = %llu lrc_handle = %llu\n",
|
|
(uint64_t)attention->clientHandle, (uint64_t)attention->flags,
|
|
(uint32_t)attention->bitmaskSize, uint64_t(attention->execQueueHandle), uint64_t(attention->lrcHandle));
|
|
if (attention->base.seqno < newestAttSeqNo.load()) {
|
|
PRINT_DEBUGGER_INFO_LOG("Dropping stale ATT event seqno=%llu\n", (uint64_t)attention->base.seqno);
|
|
} else {
|
|
handleAttentionEvent(attention);
|
|
}
|
|
} else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeVmBind)) {
|
|
|
|
NEO::EuDebugEventVmBind *vmBind = reinterpret_cast<NEO::EuDebugEventVmBind *>(event);
|
|
UNRECOVERABLE_IF(clientHandleToConnection.find(vmBind->clientHandle) == clientHandleToConnection.end());
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_VM_BIND client_handle = %llu vm_handle = %llu num_binds = %llu vmBindflag=%lu\n",
|
|
static_cast<uint64_t>(vmBind->clientHandle), static_cast<uint64_t>(vmBind->vmHandle),
|
|
static_cast<uint64_t>(vmBind->numBinds), static_cast<uint32_t>(vmBind->flags));
|
|
|
|
auto &connection = clientHandleToConnection[vmBind->clientHandle];
|
|
UNRECOVERABLE_IF(connection->vmBindMap.find(vmBind->base.seqno) != connection->vmBindMap.end());
|
|
auto &vmBindData = connection->vmBindMap[vmBind->base.seqno];
|
|
vmBindData.vmBind = *vmBind;
|
|
vmBindData.pendingNumBinds = vmBind->numBinds;
|
|
} else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeVmBindOp)) {
|
|
NEO::EuDebugEventVmBindOp *vmBindOp = reinterpret_cast<NEO::EuDebugEventVmBindOp *>(event);
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: drm_xe_eudebug_event_vm_bind_op vm_bind_ref_seqno = %llu num_extensions = %llu addr = 0x%llx range = %llu\n",
|
|
static_cast<uint64_t>(vmBindOp->vmBindRefSeqno), static_cast<uint64_t>(vmBindOp->numExtensions),
|
|
static_cast<uint64_t>(vmBindOp->addr), static_cast<uint64_t>(vmBindOp->range));
|
|
|
|
auto &vmBindMap = clientHandleToConnection[clientHandle]->vmBindMap;
|
|
UNRECOVERABLE_IF(vmBindMap.find(vmBindOp->vmBindRefSeqno) == vmBindMap.end());
|
|
auto &vmBindData = vmBindMap[vmBindOp->vmBindRefSeqno];
|
|
UNRECOVERABLE_IF(!vmBindData.pendingNumBinds);
|
|
|
|
auto &vmBindOpData = vmBindData.vmBindOpMap[vmBindOp->base.seqno];
|
|
vmBindOpData.pendingNumExtensions = vmBindOp->numExtensions;
|
|
vmBindOpData.vmBindOp = *vmBindOp;
|
|
vmBindData.pendingNumBinds--;
|
|
clientHandleToConnection[clientHandle]->vmBindIdentifierMap[vmBindOp->base.seqno] = vmBindOp->vmBindRefSeqno;
|
|
} else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeVmBindUfence)) {
|
|
NEO::EuDebugEventVmBindUfence *vmBindUfence = reinterpret_cast<NEO::EuDebugEventVmBindUfence *>(event);
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE vm_bind_ref_seqno = %llu\n",
|
|
static_cast<uint64_t>(vmBindUfence->vmBindRefSeqno));
|
|
|
|
auto &vmBindMap = clientHandleToConnection[clientHandle]->vmBindMap;
|
|
UNRECOVERABLE_IF(vmBindMap.find(vmBindUfence->vmBindRefSeqno) == vmBindMap.end());
|
|
uint32_t uFenceRequired = vmBindMap[vmBindUfence->vmBindRefSeqno].vmBind.flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventVmBindFlagUfence);
|
|
UNRECOVERABLE_IF(!uFenceRequired);
|
|
UNRECOVERABLE_IF(vmBindMap[vmBindUfence->vmBindRefSeqno].uFenceReceived); // Dont expect multiple UFENCE for same vm_bind
|
|
vmBindMap[vmBindUfence->vmBindRefSeqno].uFenceReceived = true;
|
|
vmBindMap[vmBindUfence->vmBindRefSeqno].vmBindUfence = *vmBindUfence;
|
|
} else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeMetadata)) {
|
|
NEO::EuDebugEventMetadata *metaData = reinterpret_cast<NEO::EuDebugEventMetadata *>(event);
|
|
if (clientHandle == invalidClientHandle) {
|
|
clientHandle = metaData->clientHandle;
|
|
}
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_METADATA client_handle = %llu metadata_handle = %llu type = %llu len = %llu\n",
|
|
(uint64_t)metaData->clientHandle, (uint64_t)metaData->metadataHandle, (uint64_t)metaData->type, (uint64_t)metaData->len);
|
|
|
|
handleMetadataEvent(metaData);
|
|
} else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeVmBindOpMetadata)) {
|
|
NEO::EuDebugEventVmBindOpMetadata *vmBindOpMetadata = reinterpret_cast<NEO::EuDebugEventVmBindOpMetadata *>(event);
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA vm_bind_op_ref_seqno = %llu metadata_handle = %llu metadata_cookie = %llu\n",
|
|
static_cast<uint64_t>(vmBindOpMetadata->vmBindOpRefSeqno), static_cast<uint64_t>(vmBindOpMetadata->metadataHandle),
|
|
static_cast<uint64_t>(vmBindOpMetadata->metadataCookie));
|
|
|
|
auto &vmBindMap = clientHandleToConnection[clientHandle]->vmBindMap;
|
|
auto &vmBindIdentifierMap = clientHandleToConnection[clientHandle]->vmBindIdentifierMap;
|
|
UNRECOVERABLE_IF(vmBindIdentifierMap.find(vmBindOpMetadata->vmBindOpRefSeqno) == vmBindIdentifierMap.end());
|
|
VmBindSeqNo vmBindSeqNo = vmBindIdentifierMap[vmBindOpMetadata->vmBindOpRefSeqno];
|
|
UNRECOVERABLE_IF(vmBindMap.find(vmBindSeqNo) == vmBindMap.end());
|
|
auto &vmBindOpData = vmBindMap[vmBindSeqNo].vmBindOpMap[vmBindOpMetadata->vmBindOpRefSeqno];
|
|
UNRECOVERABLE_IF(!vmBindOpData.pendingNumExtensions);
|
|
vmBindOpData.vmBindOpMetadataVec.push_back(*vmBindOpMetadata);
|
|
vmBindOpData.pendingNumExtensions--;
|
|
} else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypeExecQueuePlacements)) {
|
|
NEO::EuDebugEventExecQueuePlacements *execQueuePlacements = reinterpret_cast<NEO::EuDebugEventExecQueuePlacements *>(event);
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: PRELIM_DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE_PLACEMENTS client_handle = %" SCNx64
|
|
" vm_handle = %" SCNx64
|
|
" exec_queue_handle = %" SCNx64
|
|
" lrc_handle = %" SCNx64
|
|
" num_placements = %" SCNx32
|
|
"\n ",
|
|
static_cast<uint64_t>(execQueuePlacements->clientHandle),
|
|
static_cast<uint64_t>(execQueuePlacements->vmHandle),
|
|
static_cast<uint64_t>(execQueuePlacements->execQueueHandle), static_cast<uint64_t>(execQueuePlacements->lrcHandle),
|
|
static_cast<uint32_t>(execQueuePlacements->numPlacements));
|
|
|
|
UNRECOVERABLE_IF(execQueuePlacements->numPlacements == 0);
|
|
auto engine = reinterpret_cast<NEO::XeEngineClassInstance *>(&(execQueuePlacements->instances[0]));
|
|
auto tileIndex = engine->gtId;
|
|
|
|
auto &vmToTile = clientHandleToConnection[execQueuePlacements->clientHandle]->vmToTile;
|
|
if (vmToTile.find(execQueuePlacements->vmHandle) != vmToTile.end()) {
|
|
if (vmToTile[execQueuePlacements->vmHandle] != tileIndex) {
|
|
PRINT_DEBUGGER_ERROR_LOG("vmToTile map: For vm_handle = %lu tileIndex = %u already present. Attempt to overwrite with tileIndex = %u\n",
|
|
static_cast<uint64_t>(execQueuePlacements->vmHandle), vmToTile[execQueuePlacements->vmHandle], tileIndex);
|
|
DEBUG_BREAK_IF(true);
|
|
}
|
|
} else {
|
|
clientHandleToConnection[execQueuePlacements->clientHandle]->vmToTile[execQueuePlacements->vmHandle] = tileIndex;
|
|
PRINT_DEBUGGER_INFO_LOG("clientHandleToConnection[%" SCNx64 "]->vmToTile[%" SCNx64 "] = %u\n",
|
|
static_cast<uint64_t>(execQueuePlacements->clientHandle), static_cast<uint64_t>(execQueuePlacements->vmHandle), tileIndex);
|
|
}
|
|
} else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypePagefault)) {
|
|
NEO::EuDebugEventPageFault *pf = reinterpret_cast<NEO::EuDebugEventPageFault *>(event);
|
|
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_PAGEFAULT flags = %d, address = %llu seqno = %d, length = %llu"
|
|
" client_handle = %llu pf_flags = %llu bitmask_size = %lu exec_queue_handle = %llu\n",
|
|
(int)pf->base.flags, (uint64_t)pf->pagefaultAddress, (uint64_t)pf->base.seqno, (uint64_t)pf->base.len,
|
|
(uint64_t)pf->clientHandle, (uint64_t)pf->flags, (uint32_t)pf->bitmaskSize, uint64_t(pf->execQueueHandle));
|
|
auto tileIndex = 0u;
|
|
auto vmHandle = getVmHandleFromClientAndlrcHandle(pf->clientHandle, pf->lrcHandle);
|
|
if (vmHandle == invalidHandle) {
|
|
return;
|
|
}
|
|
PageFaultEvent pfEvent = {vmHandle, tileIndex, pf->pagefaultAddress, pf->bitmaskSize, pf->bitmask};
|
|
handlePageFaultEvent(pfEvent);
|
|
} else {
|
|
additionalEvents(event);
|
|
}
|
|
}
|
|
|
|
void DebugSessionLinuxXe::processPendingVmBindEvents() {
|
|
if (clientHandle == invalidClientHandle) {
|
|
return;
|
|
}
|
|
std::vector<decltype(clientHandleToConnection[clientHandle]->vmBindMap)::key_type> keysToDelete;
|
|
auto &vmBindMap = clientHandleToConnection[clientHandle]->vmBindMap;
|
|
for (auto &pair : vmBindMap) {
|
|
auto &vmBindData = pair.second;
|
|
if (handleVmBind(vmBindData) == false) {
|
|
break;
|
|
}
|
|
keysToDelete.push_back(pair.first);
|
|
}
|
|
for (const auto &key : keysToDelete) {
|
|
vmBindMap.erase(key);
|
|
}
|
|
}
|
|
|
|
bool DebugSessionLinuxXe::canHandleVmBind(VmBindData &vmBindData) const {
|
|
if (vmBindData.pendingNumBinds) {
|
|
return false;
|
|
}
|
|
for (const auto &vmBindOpData : vmBindData.vmBindOpMap) {
|
|
if (vmBindOpData.second.pendingNumExtensions) {
|
|
return false;
|
|
}
|
|
}
|
|
uint32_t uFenceRequired = vmBindData.vmBind.flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventVmBindFlagUfence);
|
|
if (uFenceRequired) {
|
|
if (!vmBindData.uFenceReceived) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DebugSessionLinuxXe::handleVmBind(VmBindData &vmBindData) {
|
|
if (!canHandleVmBind(vmBindData)) {
|
|
return false;
|
|
}
|
|
bool shouldAckEvent = vmBindData.vmBind.flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventVmBindFlagUfence);
|
|
auto connection = clientHandleToConnection[clientHandle].get();
|
|
auto elfHandleInVmBind = invalidHandle;
|
|
|
|
uint64_t moduleHandle = invalidHandle;
|
|
uint64_t isaAddr = 0;
|
|
bool triggerModuleLoadEvent = false;
|
|
|
|
uint32_t tileIndex = 0;
|
|
auto numTiles = connectedDevice->getNEODevice()->getNumSubDevices();
|
|
if (numTiles > 0) {
|
|
if (connection->vmToTile.find(vmBindData.vmBind.vmHandle) != connection->vmToTile.end()) {
|
|
tileIndex = connection->vmToTile[vmBindData.vmBind.vmHandle];
|
|
PRINT_DEBUGGER_INFO_LOG("handleVmBind: tileIndex = %d for vmHandle = %" SCNx64 " \n", tileIndex, vmBindData.vmBind.vmHandle);
|
|
} else {
|
|
PRINT_DEBUGGER_ERROR_LOG("handleVmBind: tileIndex not found for vmHandle = %" SCNx64 " \n", vmBindData.vmBind.vmHandle);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (auto &vmBindOpData : vmBindData.vmBindOpMap) {
|
|
auto &vmBindOp = vmBindOpData.second.vmBindOp;
|
|
for (const auto &vmBindOpMetadata : vmBindOpData.second.vmBindOpMetadataVec) {
|
|
const NEO::DeviceBitfield devices(vmBindOpMetadata.metadataCookie);
|
|
auto &metaDataEntry = connection->metaDataMap[vmBindOpMetadata.metadataHandle];
|
|
if (vmBindOp.base.flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitCreate)) {
|
|
{
|
|
std::lock_guard<std::mutex> lock(asyncThreadMutex);
|
|
if (metaDataEntry.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataSbaArea)) {
|
|
connection->vmToStateBaseAreaBindInfo[vmBindData.vmBind.vmHandle] = {vmBindOp.addr, vmBindOp.range};
|
|
}
|
|
if (metaDataEntry.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataSipArea)) {
|
|
connection->vmToContextStateSaveAreaBindInfo[vmBindData.vmBind.vmHandle] = {vmBindOp.addr, vmBindOp.range};
|
|
}
|
|
if (metaDataEntry.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataModuleArea)) {
|
|
isaAddr = vmBindOp.addr;
|
|
if (connection->isaMap[tileIndex].find(vmBindOp.addr) == connection->isaMap[tileIndex].end()) {
|
|
auto &isaMap = connection->isaMap[tileIndex];
|
|
auto isa = std::make_unique<IsaAllocation>();
|
|
isa->bindInfo = {vmBindOp.addr, vmBindOp.range};
|
|
isa->vmHandle = vmBindData.vmBind.vmHandle;
|
|
isa->elfHandle = invalidHandle;
|
|
isa->moduleBegin = 0;
|
|
isa->moduleEnd = 0;
|
|
isa->tileInstanced = !(this->debugArea.isShared);
|
|
isa->validVMs.insert(vmBindData.vmBind.vmHandle);
|
|
uint32_t deviceBitfield = 0;
|
|
auto &debugModule = connection->metaDataToModule[vmBindOpMetadata.metadataHandle];
|
|
memcpy_s(&deviceBitfield, sizeof(uint32_t),
|
|
&debugModule.deviceBitfield,
|
|
sizeof(debugModule.deviceBitfield));
|
|
const NEO::DeviceBitfield devices(deviceBitfield);
|
|
isa->deviceBitfield = devices;
|
|
isa->perKernelModule = false;
|
|
isaMap[vmBindOp.addr] = std::move(isa);
|
|
}
|
|
connection->vmToModuleDebugAreaBindInfo[vmBindData.vmBind.vmHandle] = {vmBindOp.addr, vmBindOp.range};
|
|
}
|
|
}
|
|
|
|
if (metaDataEntry.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataElfBinary)) {
|
|
isaAddr = vmBindOp.addr;
|
|
if (connection->isaMap[tileIndex].find(vmBindOp.addr) == connection->isaMap[tileIndex].end()) {
|
|
auto &isaMap = connection->isaMap[tileIndex];
|
|
auto &elfMap = connection->elfMap;
|
|
auto isa = std::make_unique<IsaAllocation>();
|
|
isa->bindInfo = {vmBindOp.addr, vmBindOp.range};
|
|
isa->vmHandle = vmBindData.vmBind.vmHandle;
|
|
isa->elfHandle = vmBindOpMetadata.metadataHandle;
|
|
isa->moduleBegin = reinterpret_cast<uint64_t>(metaDataEntry.data.get());
|
|
isa->moduleEnd = isa->moduleBegin + metaDataEntry.metadata.len;
|
|
isa->tileInstanced = (devices.count() != 0);
|
|
isa->validVMs.insert(vmBindData.vmBind.vmHandle);
|
|
isa->perKernelModule = false;
|
|
isa->deviceBitfield = devices;
|
|
elfMap[isa->moduleBegin] = isa->elfHandle;
|
|
isaMap[vmBindOp.addr] = std::move(isa);
|
|
isaMap[vmBindOp.addr]->moduleLoadEventAck = true;
|
|
elfHandleInVmBind = vmBindOpMetadata.metadataHandle;
|
|
} else {
|
|
auto &isa = connection->isaMap[tileIndex][vmBindOp.addr];
|
|
isa->validVMs.insert(vmBindData.vmBind.vmHandle);
|
|
}
|
|
}
|
|
if (metaDataEntry.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataProgramModule)) {
|
|
auto &module = connection->metaDataToModule[vmBindOpMetadata.metadataHandle];
|
|
module.deviceBitfield = devices;
|
|
module.segmentVmBindCounter[tileIndex]++;
|
|
DEBUG_BREAK_IF(module.loadAddresses[tileIndex].size() > module.segmentCount);
|
|
|
|
bool canTriggerEvent = module.loadAddresses[tileIndex].size() == (module.segmentCount - 1);
|
|
module.loadAddresses[tileIndex].insert(vmBindOp.addr);
|
|
moduleHandle = vmBindOpMetadata.metadataHandle;
|
|
if (canTriggerEvent && module.loadAddresses[tileIndex].size() == module.segmentCount) {
|
|
bool allInstancesEventsReceived = true;
|
|
if (module.deviceBitfield.count() > 1) {
|
|
allInstancesEventsReceived = checkAllOtherTileModuleSegmentsPresent(tileIndex, module);
|
|
}
|
|
triggerModuleLoadEvent = allInstancesEventsReceived;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (vmBindOp.base.flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitDestroy)) {
|
|
if (connection->isaMap[tileIndex].count(vmBindOp.addr)) {
|
|
auto &isa = connection->isaMap[tileIndex][vmBindOp.addr];
|
|
if (isa->validVMs.count(vmBindData.vmBind.vmHandle)) {
|
|
auto &module = connection->metaDataToModule[isa->moduleHandle];
|
|
module.segmentVmBindCounter[tileIndex]--;
|
|
if (module.segmentVmBindCounter[tileIndex] == 0) {
|
|
zet_debug_event_t debugEvent = {};
|
|
auto &metaDataEntry = connection->metaDataMap[isa->moduleHandle];
|
|
auto gmmHelper = connectedDevice->getNEODevice()->getGmmHelper();
|
|
auto loadAddress = gmmHelper->canonize(*std::min_element(module.loadAddresses[tileIndex].begin(), module.loadAddresses[tileIndex].end()));
|
|
debugEvent.type = ZET_DEBUG_EVENT_TYPE_MODULE_UNLOAD;
|
|
debugEvent.info.module.format = ZET_MODULE_DEBUG_INFO_FORMAT_ELF_DWARF;
|
|
debugEvent.info.module.load = loadAddress;
|
|
auto &elfMetadata = connection->metaDataMap[isa->elfHandle];
|
|
debugEvent.info.module.moduleBegin = reinterpret_cast<uint64_t>(elfMetadata.data.get());
|
|
debugEvent.info.module.moduleEnd = reinterpret_cast<uint64_t>(elfMetadata.data.get()) + elfMetadata.metadata.len;
|
|
|
|
bool notifyEvent = true;
|
|
if (module.deviceBitfield.count() > 1) {
|
|
notifyEvent = checkAllOtherTileModuleSegmentsRemoved(tileIndex, module);
|
|
}
|
|
if (notifyEvent) {
|
|
pushApiEvent(debugEvent, metaDataEntry.metadata.metadataHandle);
|
|
}
|
|
module.loadAddresses[tileIndex].clear();
|
|
module.moduleLoadEventAcked[tileIndex] = false;
|
|
}
|
|
isa->validVMs.erase(vmBindData.vmBind.vmHandle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isaAddr && moduleHandle != invalidHandle) {
|
|
connection->isaMap[tileIndex][isaAddr]->moduleHandle = moduleHandle;
|
|
}
|
|
|
|
if (triggerModuleLoadEvent) {
|
|
DEBUG_BREAK_IF(moduleHandle == invalidHandle);
|
|
DEBUG_BREAK_IF(elfHandleInVmBind == invalidHandle);
|
|
auto &metaDataEntry = connection->metaDataMap[moduleHandle];
|
|
auto &module = connection->metaDataToModule[moduleHandle];
|
|
auto gmmHelper = connectedDevice->getNEODevice()->getGmmHelper();
|
|
auto loadAddress = gmmHelper->canonize(*std::min_element(module.loadAddresses[tileIndex].begin(), module.loadAddresses[tileIndex].end()));
|
|
PRINT_DEBUGGER_INFO_LOG("Zebin module loaded at: %p, with %u isa allocations", (void *)loadAddress, module.segmentCount);
|
|
|
|
auto &elfMetadata = connection->metaDataMap[elfHandleInVmBind];
|
|
zet_debug_event_t debugEvent = {};
|
|
debugEvent.type = ZET_DEBUG_EVENT_TYPE_MODULE_LOAD;
|
|
debugEvent.info.module.format = ZET_MODULE_DEBUG_INFO_FORMAT_ELF_DWARF;
|
|
debugEvent.info.module.load = loadAddress;
|
|
debugEvent.info.module.moduleBegin = reinterpret_cast<uint64_t>(elfMetadata.data.get());
|
|
debugEvent.info.module.moduleEnd = reinterpret_cast<uint64_t>(elfMetadata.data.get()) + elfMetadata.metadata.len;
|
|
debugEvent.flags = ZET_DEBUG_EVENT_FLAG_NEED_ACK;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(asyncThreadMutex);
|
|
if (vmBindData.vmBind.flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventVmBindFlagUfence)) {
|
|
if (vmBindData.vmBindUfence.base.flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitNeedAck)) {
|
|
EventToAck ackEvent(vmBindData.vmBindUfence.base.seqno, vmBindData.vmBindUfence.base.type);
|
|
module.ackEvents[tileIndex].push_back(ackEvent);
|
|
shouldAckEvent = false;
|
|
}
|
|
}
|
|
}
|
|
pushApiEvent(debugEvent, metaDataEntry.metadata.metadataHandle);
|
|
}
|
|
|
|
if (shouldAckEvent && (vmBindData.vmBindUfence.base.flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitNeedAck))) {
|
|
EventToAck ackEvent(vmBindData.vmBindUfence.base.seqno, vmBindData.vmBindUfence.base.type);
|
|
eventAckIoctl(ackEvent);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void DebugSessionLinuxXe::handleMetadataEvent(NEO::EuDebugEventMetadata *metaData) {
|
|
bool destroy = metaData->base.flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitDestroy);
|
|
bool create = metaData->base.flags & euDebugInterface->getParamValue(NEO::EuDebugParam::eventBitCreate);
|
|
|
|
UNRECOVERABLE_IF(clientHandleToConnection.find(metaData->clientHandle) == clientHandleToConnection.end());
|
|
const auto &connection = clientHandleToConnection[metaData->clientHandle];
|
|
|
|
if (destroy && connection->metaDataMap[metaData->metadataHandle].metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataProgramModule)) {
|
|
DEBUG_BREAK_IF(connection->metaDataToModule[metaData->metadataHandle].segmentVmBindCounter[0] != 0 ||
|
|
connection->metaDataToModule[metaData->metadataHandle].loadAddresses[0].size() > 0);
|
|
|
|
connection->metaDataToModule.erase(metaData->metadataHandle);
|
|
}
|
|
|
|
if (create) {
|
|
if (!metaData->len) {
|
|
connection->metaDataMap[metaData->metadataHandle].metadata = *metaData;
|
|
return;
|
|
}
|
|
|
|
NEO::EuDebugReadMetadata readMetadata{};
|
|
auto ptr = std::make_unique<char[]>(metaData->len);
|
|
readMetadata.clientHandle = metaData->clientHandle;
|
|
readMetadata.metadataHandle = static_cast<decltype(readMetadata.metadataHandle)>(metaData->metadataHandle);
|
|
readMetadata.ptr = reinterpret_cast<uint64_t>(ptr.get());
|
|
readMetadata.size = metaData->len;
|
|
auto ret = ioctl(euDebugInterface->getParamValue(NEO::EuDebugParam::ioctlReadMetadata), &readMetadata);
|
|
if (ret != 0) {
|
|
PRINT_DEBUGGER_ERROR_LOG("DRM_XE_EUDEBUG_IOCTL_READ_METADATA ret = %d errno = %d\n", ret, errno);
|
|
return;
|
|
}
|
|
|
|
connection->metaDataMap[metaData->metadataHandle].metadata = *metaData;
|
|
connection->metaDataMap[metaData->metadataHandle].data = std::move(ptr);
|
|
|
|
if (metaData->type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataProgramModule)) {
|
|
auto handle = metaData->metadataHandle;
|
|
auto &newModule = connection->metaDataToModule[handle];
|
|
newModule.segmentCount = 0;
|
|
newModule.moduleHandle = handle;
|
|
for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) {
|
|
newModule.segmentVmBindCounter[i] = 0;
|
|
newModule.loadAddresses[i].clear();
|
|
newModule.moduleLoadEventAcked[i] = false;
|
|
}
|
|
}
|
|
extractMetaData(metaData->clientHandle, connection->metaDataMap[metaData->metadataHandle]);
|
|
}
|
|
}
|
|
|
|
void DebugSessionLinuxXe::extractMetaData(uint64_t client, const MetaData &metaData) {
|
|
if (metaData.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataSbaArea) ||
|
|
metaData.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataModuleArea) ||
|
|
metaData.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataSipArea)) {
|
|
UNRECOVERABLE_IF(metaData.metadata.len != 8);
|
|
uint64_t *data = (uint64_t *)metaData.data.get();
|
|
|
|
if (metaData.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataSbaArea)) {
|
|
clientHandleToConnection[client]->stateBaseAreaGpuVa = *data;
|
|
PRINT_DEBUGGER_INFO_LOG("SbaTrackingBuffer GPU VA = %p", (void *)clientHandleToConnection[clientHandle]->stateBaseAreaGpuVa);
|
|
}
|
|
if (metaData.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataModuleArea)) {
|
|
clientHandleToConnection[client]->moduleDebugAreaGpuVa = *data;
|
|
PRINT_DEBUGGER_INFO_LOG("ModuleHeapDebugArea GPU VA = %p", (void *)clientHandleToConnection[clientHandle]->moduleDebugAreaGpuVa);
|
|
}
|
|
if (metaData.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataSipArea)) {
|
|
clientHandleToConnection[client]->contextStateSaveAreaGpuVa = *data;
|
|
PRINT_DEBUGGER_INFO_LOG("ContextSaveArea GPU VA = %p", (void *)clientHandleToConnection[clientHandle]->contextStateSaveAreaGpuVa);
|
|
}
|
|
}
|
|
|
|
if (metaData.metadata.type == euDebugInterface->getParamValue(NEO::EuDebugParam::metadataProgramModule)) {
|
|
uint32_t segmentCount = 0;
|
|
memcpy_s(&segmentCount, sizeof(uint32_t), metaData.data.get(), metaData.metadata.len);
|
|
clientHandleToConnection[client]->metaDataToModule[metaData.metadata.metadataHandle].segmentCount = segmentCount;
|
|
PRINT_DEBUGGER_INFO_LOG("Zebin module = %ull, segment count = %ul", metaData.metadata.metadataHandle, segmentCount);
|
|
}
|
|
}
|
|
|
|
int DebugSessionLinuxXe::openVmFd(uint64_t vmHandle, [[maybe_unused]] bool readOnly) {
|
|
NEO::EuDebugVmOpen vmOpen = {
|
|
.extensions = 0,
|
|
.clientHandle = clientHandle,
|
|
.vmHandle = vmHandle,
|
|
.flags = 0,
|
|
.timeoutNs = 5000000000u};
|
|
|
|
return ioctl(euDebugInterface->getParamValue(NEO::EuDebugParam::ioctlVmOpen), &vmOpen);
|
|
}
|
|
|
|
int DebugSessionLinuxXe::flushVmCache(int vmfd) {
|
|
int retVal = ioctlHandler->fsync(vmfd);
|
|
if (retVal != 0) {
|
|
PRINT_DEBUGGER_ERROR_LOG("Failed to fsync VM fd=%d errno=%d\n", vmfd, errno);
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
uint64_t DebugSessionLinuxXe::getVmHandleFromClientAndlrcHandle(uint64_t clientHandle, uint64_t lrcHandle) {
|
|
|
|
if (clientHandleToConnection.find(clientHandle) == clientHandleToConnection.end()) {
|
|
return invalidHandle;
|
|
}
|
|
|
|
auto &clientConnection = clientHandleToConnection[clientHandle];
|
|
if (clientConnection->lrcHandleToVmHandle.find(lrcHandle) == clientConnection->lrcHandleToVmHandle.end()) {
|
|
return invalidHandle;
|
|
}
|
|
|
|
return clientConnection->lrcHandleToVmHandle[lrcHandle];
|
|
}
|
|
|
|
void DebugSessionLinuxXe::handleAttentionEvent(NEO::EuDebugEventEuAttention *attention) {
|
|
if (interruptSent) {
|
|
if (attention->base.seqno <= euControlInterruptSeqno) {
|
|
PRINT_DEBUGGER_INFO_LOG("Discarding EU ATTENTION event for interrupt request. Event seqno == %llu <= %llu == interrupt seqno\n",
|
|
static_cast<uint64_t>(attention->base.seqno), euControlInterruptSeqno);
|
|
return;
|
|
}
|
|
}
|
|
|
|
newAttentionRaised();
|
|
std::vector<EuThread::ThreadId> threadsWithAttention;
|
|
AttentionEventFields attentionEventFields;
|
|
attentionEventFields.bitmask = attention->bitmask;
|
|
attentionEventFields.bitmaskSize = attention->bitmaskSize;
|
|
attentionEventFields.clientHandle = attention->clientHandle;
|
|
attentionEventFields.contextHandle = attention->execQueueHandle;
|
|
attentionEventFields.lrcHandle = attention->lrcHandle;
|
|
|
|
return updateStoppedThreadsAndCheckTriggerEvents(attentionEventFields, 0, threadsWithAttention);
|
|
}
|
|
|
|
int DebugSessionLinuxXe::threadControlInterruptAll() {
|
|
int euControlRetVal = -1;
|
|
NEO::EuDebugEuControl euControl = {};
|
|
euControl.clientHandle = clientHandle;
|
|
euControl.cmd = euDebugInterface->getParamValue(NEO::EuDebugParam::euControlCmdInterruptAll);
|
|
euControl.bitmaskSize = 0;
|
|
euControl.bitmaskPtr = 0;
|
|
|
|
DEBUG_BREAK_IF(clientHandleToConnection.find(clientHandle) == clientHandleToConnection.end());
|
|
std::lock_guard<std::mutex> lock(asyncThreadMutex);
|
|
for (const auto &execQueue : clientHandleToConnection[clientHandle]->execQueues) {
|
|
euControl.execQueueHandle = execQueue.first;
|
|
for (const auto &lrcHandle : execQueue.second.lrcHandles) {
|
|
euControl.lrcHandle = lrcHandle;
|
|
euControlRetVal = ioctl(euDebugInterface->getParamValue(NEO::EuDebugParam::ioctlEuControl), &euControl);
|
|
if (euControlRetVal != 0) {
|
|
PRINT_DEBUGGER_ERROR_LOG("DRM_XE_EUDEBUG_IOCTL_EU_CONTROL failed: retCode: %d errno = %d command = %d, execQueueHandle = %llu lrcHandle = %llu\n",
|
|
euControlRetVal, errno, static_cast<uint32_t>(euControl.cmd), static_cast<uint64_t>(euControl.execQueueHandle),
|
|
static_cast<uint64_t>(euControl.lrcHandle));
|
|
} else {
|
|
DEBUG_BREAK_IF(euControlInterruptSeqno >= euControl.seqno);
|
|
euControlInterruptSeqno = euControl.seqno;
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_EU_CONTROL: seqno = %llu command = %u\n", static_cast<uint64_t>(euControl.seqno),
|
|
static_cast<uint32_t>(euControl.cmd));
|
|
}
|
|
}
|
|
}
|
|
|
|
return euControlRetVal;
|
|
}
|
|
|
|
int DebugSessionLinuxXe::threadControlStopped(std::unique_ptr<uint8_t[]> &bitmaskOut, size_t &bitmaskSizeOut) {
|
|
int euControlRetVal = -1;
|
|
auto hwInfo = connectedDevice->getHwInfo();
|
|
auto &l0GfxCoreHelper = connectedDevice->getL0GfxCoreHelper();
|
|
NEO::EuDebugEuControl euControl = {};
|
|
euControl.clientHandle = clientHandle;
|
|
euControl.cmd = euDebugInterface->getParamValue(NEO::EuDebugParam::euControlCmdStopped);
|
|
|
|
std::unique_ptr<uint8_t[]> bitmask;
|
|
size_t bitmaskSize = 0;
|
|
l0GfxCoreHelper.getAttentionBitmaskForSingleThreads({}, hwInfo, bitmask, bitmaskSize);
|
|
euControl.bitmaskSize = static_cast<uint32_t>(bitmaskSize);
|
|
euControl.bitmaskPtr = reinterpret_cast<uint64_t>(bitmask.get());
|
|
|
|
DEBUG_BREAK_IF(clientHandleToConnection.find(clientHandle) == clientHandleToConnection.end());
|
|
std::lock_guard<std::mutex> lock(asyncThreadMutex);
|
|
for (const auto &execQueue : clientHandleToConnection[clientHandle]->execQueues) {
|
|
euControl.execQueueHandle = execQueue.first;
|
|
for (const auto &lrcHandle : execQueue.second.lrcHandles) {
|
|
euControl.lrcHandle = lrcHandle;
|
|
euControlRetVal = ioctl(euDebugInterface->getParamValue(NEO::EuDebugParam::ioctlEuControl), &euControl);
|
|
if (euControlRetVal != 0) {
|
|
PRINT_DEBUGGER_ERROR_LOG("DRM_XE_EUDEBUG_IOCTL_EU_CONTROL failed: retCode: %d errno = %d command = %d, execQueueHandle = %llu lrcHandle = %llu\n",
|
|
euControlRetVal, errno, static_cast<uint32_t>(euControl.cmd), static_cast<uint64_t>(euControl.execQueueHandle),
|
|
static_cast<uint64_t>(euControl.lrcHandle));
|
|
} else {
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_EU_CONTROL: seqno = %llu command = %u\n", static_cast<uint64_t>(euControl.seqno),
|
|
static_cast<uint32_t>(euControl.cmd));
|
|
break;
|
|
}
|
|
}
|
|
if (euControlRetVal == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
printBitmask(bitmask.get(), bitmaskSize);
|
|
bitmaskOut = std::move(bitmask);
|
|
UNRECOVERABLE_IF(bitmaskOut.get() == nullptr);
|
|
bitmaskSizeOut = euControl.bitmaskSize;
|
|
return euControlRetVal;
|
|
}
|
|
|
|
int DebugSessionLinuxXe::threadControlResume(const std::vector<EuThread::ThreadId> &threads) {
|
|
int euControlRetVal = -1;
|
|
auto hwInfo = connectedDevice->getHwInfo();
|
|
auto &l0GfxCoreHelper = connectedDevice->getL0GfxCoreHelper();
|
|
NEO::EuDebugEuControl euControl = {};
|
|
euControl.clientHandle = clientHandle;
|
|
euControl.bitmaskSize = 0;
|
|
euControl.bitmaskPtr = 0;
|
|
|
|
std::unique_ptr<uint8_t[]> bitmask;
|
|
size_t bitmaskSize = 0;
|
|
l0GfxCoreHelper.getAttentionBitmaskForSingleThreads(threads, hwInfo, bitmask, bitmaskSize);
|
|
euControl.bitmaskSize = static_cast<uint32_t>(bitmaskSize);
|
|
euControl.bitmaskPtr = reinterpret_cast<uint64_t>(bitmask.get());
|
|
printBitmask(bitmask.get(), bitmaskSize);
|
|
uint64_t execQueueHandle{0};
|
|
uint64_t lrcHandle{0};
|
|
allThreads[threads[0]]->getContextHandle(execQueueHandle);
|
|
allThreads[threads[0]]->getLrcHandle(lrcHandle);
|
|
euControl.execQueueHandle = execQueueHandle;
|
|
euControl.lrcHandle = lrcHandle;
|
|
|
|
auto invokeIoctl = [&](int cmd) {
|
|
euControl.cmd = cmd;
|
|
euControlRetVal = ioctl(euDebugInterface->getParamValue(NEO::EuDebugParam::ioctlEuControl), &euControl);
|
|
if (euControlRetVal != 0) {
|
|
PRINT_DEBUGGER_ERROR_LOG("DRM_XE_EUDEBUG_IOCTL_EU_CONTROL failed: retCode: %d errno = %d command = %d, execQueueHandle = %llu lrcHandle = %llu\n",
|
|
euControlRetVal, errno, static_cast<uint32_t>(euControl.cmd), static_cast<uint64_t>(euControl.execQueueHandle),
|
|
static_cast<uint64_t>(euControl.lrcHandle));
|
|
} else {
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_EU_CONTROL: seqno = %llu command = %u\n", static_cast<uint64_t>(euControl.seqno), static_cast<uint32_t>(euControl.cmd));
|
|
}
|
|
};
|
|
|
|
if (l0GfxCoreHelper.threadResumeRequiresUnlock()) {
|
|
invokeIoctl(getEuControlCmdUnlock());
|
|
}
|
|
|
|
invokeIoctl(euDebugInterface->getParamValue(NEO::EuDebugParam::euControlCmdResume));
|
|
return euControlRetVal;
|
|
}
|
|
|
|
int DebugSessionLinuxXe::threadControl(const std::vector<EuThread::ThreadId> &threads, uint32_t tile,
|
|
ThreadControlCmd threadCmd, std::unique_ptr<uint8_t[]> &bitmaskOut, size_t &bitmaskSizeOut) {
|
|
|
|
bitmaskSizeOut = 0;
|
|
switch (threadCmd) {
|
|
case ThreadControlCmd::interruptAll:
|
|
return threadControlInterruptAll();
|
|
case ThreadControlCmd::resume:
|
|
return threadControlResume(threads);
|
|
case ThreadControlCmd::stopped:
|
|
return threadControlStopped(bitmaskOut, bitmaskSizeOut);
|
|
default:
|
|
break;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void DebugSessionLinuxXe::updateContextAndLrcHandlesForThreadsWithAttention(EuThread::ThreadId threadId, const AttentionEventFields &attention) {
|
|
allThreads[threadId]->setContextHandle(attention.contextHandle);
|
|
allThreads[threadId]->setLrcHandle(attention.lrcHandle);
|
|
}
|
|
|
|
int DebugSessionLinuxXe::eventAckIoctl(EventToAck &event) {
|
|
NEO::EuDebugAckEvent eventToAck = {};
|
|
eventToAck.type = event.type;
|
|
eventToAck.seqno = event.seqno;
|
|
eventToAck.flags = 0;
|
|
auto ret = ioctl(euDebugInterface->getParamValue(NEO::EuDebugParam::ioctlAckEvent), &eventToAck);
|
|
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_ACK_EVENT seqno = %llu ret = %d errno = %d\n", static_cast<uint64_t>(eventToAck.seqno), ret, ret != 0 ? errno : 0);
|
|
return ret;
|
|
}
|
|
|
|
} // namespace L0
|