feature: helper function for Sip Command Register Values and Size

- Added support for setting a new structure SipCommandRegisterValues to
assign the sip command register values with getSipCommandRegisterValues.

Related-To: NEO-16517

Signed-off-by: Neil R. Spruit <neil.r.spruit@intel.com>
This commit is contained in:
Neil R. Spruit
2025-12-10 22:51:46 +00:00
committed by Compute-Runtime-Automation
parent 300b8e0b8e
commit a9e397e8b4
6 changed files with 171 additions and 42 deletions

View File

@@ -521,8 +521,8 @@ bool DebugSessionImp::writeResumeCommand(const std::vector<EuThread::ThreadId> &
}
} else // >= 2u
{
SIP::sip_command resumeCommand = {0};
resumeCommand.command = static_cast<uint32_t>(NEO::SipKernel::Command::resume);
NEO::SipCommandRegisterValues resumeCommand = {{0}};
resumeCommand.sip_commandValues.command = static_cast<uint32_t>(NEO::SipKernel::Command::resume);
for (auto &threadID : threadIds) {
ze_result_t result = cmdRegisterAccessHelper(threadID, resumeCommand, true);
@@ -1600,18 +1600,21 @@ ze_result_t DebugSessionImp::registersAccessHelper(const EuThread *thread, const
return ret == 0 ? ZE_RESULT_SUCCESS : ZE_RESULT_ERROR_UNKNOWN;
}
ze_result_t DebugSessionImp::cmdRegisterAccessHelper(const EuThread::ThreadId &threadId, SIP::sip_command &command, bool write) {
ze_result_t DebugSessionImp::cmdRegisterAccessHelper(const EuThread::ThreadId &threadId, NEO::SipCommandRegisterValues &command, bool write) {
auto stateSaveAreaHeader = getStateSaveAreaHeader();
SIP::regset_desc regdesc;
if (getCommandRegisterDescriptor(stateSaveAreaHeader, &regdesc) != ZE_RESULT_SUCCESS) {
return ZE_RESULT_ERROR_UNKNOWN;
}
PRINT_DEBUGGER_INFO_LOG("Access CMD %d for thread %s\n", command.command, EuThread::toString(threadId).c_str());
PRINT_DEBUGGER_INFO_LOG("Access CMD %d for thread %s\n", command.sip_commandValues.command, EuThread::toString(threadId).c_str());
uint32_t type = 0;
if (connectedDevice->getNEODevice()->getSipExternalLibInterface()) {
type = connectedDevice->getNEODevice()->getSipExternalLibInterface()->getSipLibCommandRegisterType();
}
size_t size = regdesc.bytes;
size = getSipCommandRegisterValues(command, write, size);
regdesc.bytes = static_cast<uint16_t>(size);
ze_result_t result = registersAccessHelper(allThreads[threadId].get(), &regdesc, 0, 1, type, &command, write);
if (result != ZE_RESULT_SUCCESS) {
PRINT_DEBUGGER_ERROR_LOG("Failed to access CMD for thread %s\n", EuThread::toString(threadId).c_str());
@@ -1721,7 +1724,7 @@ ze_result_t DebugSessionImp::validateThreadAndDescForMemoryAccess(ze_device_thre
ze_result_t DebugSessionImp::waitForCmdReady(EuThread::ThreadId threadId, uint16_t retryCount) {
ze_result_t status;
SIP::sip_command sipCommand = {0};
NEO::SipCommandRegisterValues sipCommand = {{0}};
for (uint16_t attempts = 0; attempts < retryCount; attempts++) {
status = cmdRegisterAccessHelper(threadId, sipCommand, false);
@@ -1729,13 +1732,13 @@ ze_result_t DebugSessionImp::waitForCmdReady(EuThread::ThreadId threadId, uint16
return status;
}
if (sipCommand.command == static_cast<uint32_t>(NEO::SipKernel::Command::ready)) {
if (sipCommand.sip_commandValues.command == static_cast<uint32_t>(NEO::SipKernel::Command::ready)) {
break;
}
NEO::sleep(std::chrono::microseconds(100));
}
if (sipCommand.command != static_cast<uint32_t>(NEO::SipKernel::Command::ready)) {
if (sipCommand.sip_commandValues.command != static_cast<uint32_t>(NEO::SipKernel::Command::ready)) {
return ZE_RESULT_ERROR_NOT_AVAILABLE;
}
@@ -1963,11 +1966,10 @@ ze_result_t DebugSessionImp::slmMemoryReadV2(EuThread::ThreadId threadId, const
return ZE_RESULT_ERROR_UNKNOWN;
}
SIP::sip_command readSlmCommand = {
.command = static_cast<uint32_t>(NEO::SipKernel::Command::slmRead),
.size = addrs->sipSize,
.offset = addrs->sipOffset,
};
NEO::SipCommandRegisterValues readSlmCommand = {{0}};
readSlmCommand.sip_commandValues.command = static_cast<uint32_t>(NEO::SipKernel::Command::slmRead);
readSlmCommand.sip_commandValues.size = addrs->sipSize;
readSlmCommand.sip_commandValues.offset = addrs->sipOffset;
ze_result_t status = waitForCmdReady(threadId, sipRetryCount);
if (status != ZE_RESULT_SUCCESS) {
@@ -2000,11 +2002,10 @@ ze_result_t DebugSessionImp::slmMemoryWriteV2(EuThread::ThreadId threadId, const
return ZE_RESULT_ERROR_UNKNOWN;
}
SIP::sip_command writeSlmCommand = {
.command = static_cast<uint32_t>(NEO::SipKernel::Command::slmWrite),
.size = addrs->sipSize,
.offset = addrs->sipOffset,
};
NEO::SipCommandRegisterValues writeSlmCommand = {{0}};
writeSlmCommand.sip_commandValues.command = static_cast<uint32_t>(NEO::SipKernel::Command::slmWrite);
writeSlmCommand.sip_commandValues.size = addrs->sipSize;
writeSlmCommand.sip_commandValues.offset = addrs->sipOffset;
ze_result_t status = waitForCmdReady(threadId, sipRetryCount);
if (status != ZE_RESULT_SUCCESS) {

View File

@@ -176,7 +176,7 @@ struct DebugSessionImp : DebugSession {
uint32_t start, uint32_t count, uint32_t type, void *pRegisterValues, bool write);
void slmSipVersionCheck();
MOCKABLE_VIRTUAL ze_result_t cmdRegisterAccessHelper(const EuThread::ThreadId &threadId, SIP::sip_command &command, bool write);
MOCKABLE_VIRTUAL ze_result_t cmdRegisterAccessHelper(const EuThread::ThreadId &threadId, NEO::SipCommandRegisterValues &command, bool write);
MOCKABLE_VIRTUAL ze_result_t waitForCmdReady(EuThread::ThreadId threadId, uint16_t retryCount);
ze_result_t getCommandRegisterDescriptor(const NEO::StateSaveAreaHeader *stateSaveAreaHeader, SIP::regset_desc *regdesc);
@@ -184,6 +184,7 @@ struct DebugSessionImp : DebugSession {
size_t calculateThreadSlotOffset(EuThread::ThreadId threadId);
size_t calculateRegisterOffsetInThreadSlot(const SIP::regset_desc *const regdesc, uint32_t start);
size_t getSipCommandRegisterValues(NEO::SipCommandRegisterValues &command, bool write, size_t size);
bool openSipWrapper(NEO::Device *neoDevice, uint64_t contextHandle, uint64_t gpuVa) override;
bool closeSipWrapper(NEO::Device *neoDevice, uint64_t contextHandle) override;
@@ -273,7 +274,7 @@ ze_result_t DebugSessionImp::slmMemoryAccess(EuThread::ThreadId threadId, const
return ZE_RESULT_ERROR_UNSUPPORTED_VERSION;
}
SIP::sip_command sipCommand = {0};
NEO::SipCommandRegisterValues sipCommand = {{0}};
uint64_t offset = desc->address & maxNBitValue(slmAddressSpaceTag);
// SIP accesses SLM in units of slmSendBytesSize at offset alignment of slmSendBytesSize
@@ -311,7 +312,7 @@ ze_result_t DebugSessionImp::slmMemoryAccess(EuThread::ThreadId threadId, const
uint32_t loops = static_cast<uint32_t>(std::ceil(static_cast<float>(remainingSlmSendUnits) / maxUnitsPerLoop));
uint32_t accessUnits = 0;
uint32_t countReadyBytes = 0;
sipCommand.offset = alignedOffset;
sipCommand.sip_commandValues.offset = alignedOffset;
for (uint32_t loop = 0; loop < loops; loop++) {
@@ -322,12 +323,12 @@ ze_result_t DebugSessionImp::slmMemoryAccess(EuThread::ThreadId threadId, const
}
if constexpr (write) {
sipCommand.command = static_cast<uint32_t>(NEO::SipKernel::Command::slmWrite);
sipCommand.size = static_cast<uint32_t>(accessUnits);
memcpy_s(sipCommand.buffer, accessUnits * slmSendBytesSize, tmpBuffer.get() + countReadyBytes, accessUnits * slmSendBytesSize);
sipCommand.sip_commandValues.command = static_cast<uint32_t>(NEO::SipKernel::Command::slmWrite);
sipCommand.sip_commandValues.size = static_cast<uint32_t>(accessUnits);
memcpy_s(sipCommand.sip_commandValues.buffer, accessUnits * slmSendBytesSize, tmpBuffer.get() + countReadyBytes, accessUnits * slmSendBytesSize);
} else {
sipCommand.command = static_cast<uint32_t>(NEO::SipKernel::Command::slmRead);
sipCommand.size = static_cast<uint32_t>(accessUnits);
sipCommand.sip_commandValues.command = static_cast<uint32_t>(NEO::SipKernel::Command::slmRead);
sipCommand.sip_commandValues.size = static_cast<uint32_t>(accessUnits);
}
status = cmdRegisterAccessHelper(threadId, sipCommand, true);
@@ -351,13 +352,13 @@ ze_result_t DebugSessionImp::slmMemoryAccess(EuThread::ThreadId threadId, const
return status;
}
memcpy_s(tmpBuffer.get() + countReadyBytes, accessUnits * slmSendBytesSize, sipCommand.buffer, accessUnits * slmSendBytesSize);
memcpy_s(tmpBuffer.get() + countReadyBytes, accessUnits * slmSendBytesSize, sipCommand.sip_commandValues.buffer, accessUnits * slmSendBytesSize);
}
remainingSlmSendUnits -= accessUnits;
countReadyBytes += accessUnits * slmSendBytesSize;
alignedOffset += accessUnits * slmSendBytesSize;
sipCommand.offset = alignedOffset;
sipCommand.sip_commandValues.offset = alignedOffset;
}
if constexpr (!write) {

View File

@@ -68,6 +68,10 @@ ze_result_t DebugSessionImp::getCommandRegisterDescriptor(const NEO::StateSaveAr
return ZE_RESULT_SUCCESS;
}
size_t DebugSessionImp::getSipCommandRegisterValues(NEO::SipCommandRegisterValues &command, bool write, size_t size) {
return size;
}
void DebugSessionImp::getFifoOffsets(const NEO::StateSaveAreaHeader *stateSaveAreaHeader, uint64_t &offsetTail, uint64_t &offsetFifoSize, uint64_t &offsetFifo, uint64_t gpuVa) {
offsetTail = (sizeof(SIP::StateSaveArea)) + offsetof(struct SIP::intelgt_state_save_area_V3, fifo_tail);
offsetFifoSize = (sizeof(SIP::StateSaveArea)) + offsetof(struct SIP::intelgt_state_save_area_V3, fifo_size);

View File

@@ -3098,7 +3098,7 @@ TEST_F(DebugSessionRegistersAccessTestV3, givenSsaHeaderVersionGreaterThan3WhenG
TEST_F(DebugSessionRegistersAccessTestV3, givenSsaHeaderVersionGreaterThan3WhenCmdRegisterAccessHelperCalledThenNullIsReturned) {
reinterpret_cast<NEO::StateSaveAreaHeader *>(session->stateSaveAreaHeader.data())->versionHeader.version.major = 4;
EuThread::ThreadId thread0(0, 0, 0, 0, 0);
SIP::sip_command resumeCommand = {0};
NEO::SipCommandRegisterValues resumeCommand = {{0}};
EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, session->cmdRegisterAccessHelper(thread0, resumeCommand, false));
}
@@ -4161,8 +4161,8 @@ struct DebugSessionSlmV2Test : public ::testing::Test {
return ret;
}
ze_result_t cmdRegisterAccessHelper(const EuThread::ThreadId &threadId, SIP::sip_command &command, bool write) override {
lastSipCommand = command;
ze_result_t cmdRegisterAccessHelper(const EuThread::ThreadId &threadId, NEO::SipCommandRegisterValues &command, bool write) override {
lastSipCommand = command.sip_commandValues;
return cmdRegisterAccessHelperReturn;
}
@@ -5366,8 +5366,8 @@ TEST_F(DebugSessionRegistersAccessTestV3, givenSipExternalLibWhenCmdRegisterAcce
auto &rootEnv = *neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[neoDevice->getRootDeviceIndex()];
auto originalSipLib = rootEnv.sipExternalLib.release();
rootEnv.sipExternalLib.reset(new MockSipExternalLibCmdType());
SIP::sip_command cmd = {};
cmd.command = 0x1;
NEO::SipCommandRegisterValues cmd = {{0}};
cmd.sip_commandValues.command = 0x1;
auto result = session->cmdRegisterAccessHelper(stoppedThreadId, cmd, false);
EXPECT_TRUE(result == ZE_RESULT_SUCCESS || result == ZE_RESULT_ERROR_UNKNOWN || result == ZE_RESULT_ERROR_INVALID_ARGUMENT);
result = session->cmdRegisterAccessHelper(stoppedThreadId, cmd, true);
@@ -5542,5 +5542,122 @@ TEST_F(DebugSessionRegistersAccessTestV3, givenVersion5WhenGetRegisterSetPropert
rootEnv.sipExternalLib.reset(originalSipLib);
}
// Tests for getSipCommandRegisterValues (non-V5 behavior)
TEST_F(DebugSessionRegistersAccessTestV3, GivenGetSipCommandRegisterValuesWhenWriteTrueThenReturnsSipCommandValuesAndFullSize) {
// For non-V5 versions (< 5), getSipCommandRegisterValues does not modify the size parameter
NEO::SipCommandRegisterValues command = {{0}};
command.sip_commandValues.command = 0x12345678;
command.sip_commandValues.size = 0xABCD;
command.sip_commandValues.offset = 0x9876;
size_t size = 128;
size_t originalSize = size;
size = session->getSipCommandRegisterValues(command, true, size);
// For non-V5 version, size parameter should remain unchanged
EXPECT_EQ(originalSize, size);
}
TEST_F(DebugSessionRegistersAccessTestV3, GivenGetSipCommandRegisterValuesWhenWriteFalseThenReturnsSipCommandValuesAndFullSize) {
NEO::SipCommandRegisterValues command = {{0}};
command.sip_commandValues.command = 0x12345678;
command.sip_commandValues.size = 0xABCD;
command.sip_commandValues.offset = 0x9876;
size_t size = 0;
size_t originalSize = size;
size = session->getSipCommandRegisterValues(command, false, size);
// For non-V5 version, size parameter should remain unchanged
EXPECT_EQ(originalSize, size);
}
TEST_F(DebugSessionRegistersAccessTestV3, GivenCmdRegisterAccessHelperWhenWritingCommandThenCommandValuesArePreparedCorrectly) {
// Setup the state save area to allow registersAccessHelper to work
{
auto pStateSaveAreaHeader = session->getStateSaveAreaHeader();
auto size = pStateSaveAreaHeader->versionHeader.size * 8 +
pStateSaveAreaHeader->regHeaderV3.state_area_offset +
pStateSaveAreaHeader->regHeaderV3.state_save_size * 16;
session->stateSaveAreaHeader.resize(size);
}
// Create command to write
NEO::SipCommandRegisterValues command = {{0}};
command.sip_commandValues.command = static_cast<uint32_t>(NEO::SipKernel::Command::resume);
command.sip_commandValues.size = 0x100;
command.sip_commandValues.offset = 0x200;
// Test getSipCommandRegisterValues for write mode
size_t writeSize = 0;
size_t originalWriteSize = writeSize;
writeSize = session->getSipCommandRegisterValues(command, true, writeSize);
// For non-V5 version (< 5), size parameter should remain unchanged
EXPECT_EQ(originalWriteSize, writeSize);
// Call cmdRegisterAccessHelper for write - should succeed or return expected error
auto result = session->cmdRegisterAccessHelper(stoppedThreadId, command, true);
EXPECT_TRUE(result == ZE_RESULT_SUCCESS || result == ZE_RESULT_ERROR_UNKNOWN);
}
TEST_F(DebugSessionRegistersAccessTestV3, GivenCmdRegisterAccessHelperWhenReadingCommandThenCommandValuesArePreparedCorrectly) {
// Setup the state save area
{
auto pStateSaveAreaHeader = session->getStateSaveAreaHeader();
auto size = pStateSaveAreaHeader->versionHeader.size * 8 +
pStateSaveAreaHeader->regHeaderV3.state_area_offset +
pStateSaveAreaHeader->regHeaderV3.state_save_size * 16;
session->stateSaveAreaHeader.resize(size);
}
// Create command to read
NEO::SipCommandRegisterValues command = {{0}};
// Test getSipCommandRegisterValues for read mode
size_t readSize = 0;
size_t originalReadSize = readSize;
readSize = session->getSipCommandRegisterValues(command, false, readSize);
// For non-V5 version (< 5), size parameter should remain unchanged
EXPECT_EQ(originalReadSize, readSize);
// Call cmdRegisterAccessHelper for read
auto result = session->cmdRegisterAccessHelper(stoppedThreadId, command, false);
EXPECT_TRUE(result == ZE_RESULT_SUCCESS || result == ZE_RESULT_ERROR_UNKNOWN);
}
TEST_F(DebugSessionRegistersAccessTestV3, GivenGetSipCommandRegisterValuesWhenDifferentCommandsUsedThenCorrectValuesReturned) {
// Test multiple commands with different values
std::vector<std::pair<uint32_t, const char *>> commandTests = {
{static_cast<uint32_t>(NEO::SipKernel::Command::resume), "resume"},
{static_cast<uint32_t>(NEO::SipKernel::Command::slmRead), "slmRead"},
{static_cast<uint32_t>(NEO::SipKernel::Command::slmWrite), "slmWrite"},
{0x12345678, "custom"}};
for (const auto &[cmdValue, cmdName] : commandTests) {
NEO::SipCommandRegisterValues command = {{0}};
command.sip_commandValues.command = cmdValue;
command.sip_commandValues.size = 0x1000;
command.sip_commandValues.offset = 0x2000;
// Test write mode
size_t writeSize = 0;
size_t originalWriteSize = writeSize;
writeSize = session->getSipCommandRegisterValues(command, true, writeSize);
// For non-V5 version, size parameter should remain unchanged
EXPECT_EQ(originalWriteSize, writeSize) << "Failed for command: " << cmdName;
// Test read mode
size_t readSize = 0;
size_t originalReadSize = readSize;
readSize = session->getSipCommandRegisterValues(command, false, readSize);
// For non-V5 version, size parameter should remain unchanged
EXPECT_EQ(originalReadSize, readSize) << "Failed for command: " << cmdName;
}
}
} // namespace ult
} // namespace L0

View File

@@ -178,12 +178,14 @@ struct MockDebugSession : public L0::DebugSessionImp {
using L0::DebugSessionImp::calculateSrMagicOffset;
using L0::DebugSessionImp::calculateThreadSlotOffset;
using L0::DebugSessionImp::checkTriggerEventsForAttention;
using L0::DebugSessionImp::cmdRegisterAccessHelper;
using L0::DebugSessionImp::dumpDebugSurfaceToFile;
using L0::DebugSessionImp::fillResumeAndStoppedThreadsFromNewlyStopped;
using L0::DebugSessionImp::generateEventsAndResumeStoppedThreads;
using L0::DebugSessionImp::generateEventsForPendingInterrupts;
using L0::DebugSessionImp::generateEventsForStoppedThreads;
using L0::DebugSessionImp::getRegisterSize;
using L0::DebugSessionImp::getSipCommandRegisterValues;
using L0::DebugSessionImp::getSlmAccessProtocol;
using L0::DebugSessionImp::getStateSaveAreaHeader;
using L0::DebugSessionImp::interruptTimeout;
@@ -451,28 +453,28 @@ struct MockDebugSession : public L0::DebugSessionImp {
return DebugSessionImp::waitForCmdReady(threadId, 1);
}
ze_result_t cmdRegisterAccessHelper(const EuThread::ThreadId &threadId, SIP::sip_command &command, bool write) override {
ze_result_t cmdRegisterAccessHelper(const EuThread::ThreadId &threadId, NEO::SipCommandRegisterValues &command, bool write) override {
ze_result_t status = ZE_RESULT_SUCCESS;
if (slmTesting) {
uint32_t size = command.size * slmSendBytesSize;
uint32_t size = command.sip_commandValues.size * slmSendBytesSize;
// initial wait for ready
if (!write && slmCmdRegisterCmdvalue == static_cast<uint32_t>(NEO::SipKernel::Command::resume)) {
if (!memcmp(slmMemory, "FailWaiting", strlen("FailWaiting"))) {
return ZE_RESULT_FORCE_UINT32;
}
command.command = static_cast<uint32_t>(NEO::SipKernel::Command::ready);
command.sip_commandValues.command = static_cast<uint32_t>(NEO::SipKernel::Command::ready);
status = ZE_RESULT_SUCCESS;
} else {
if (write) { // writing to CMD register
if (forceCmdAccessFail) {
return ZE_RESULT_FORCE_UINT32;
} else if (command.command == static_cast<uint32_t>(NEO::SipKernel::Command::slmWrite)) {
memcpy_s(slmMemory + command.offset, size, command.buffer, size);
} else if (command.sip_commandValues.command == static_cast<uint32_t>(NEO::SipKernel::Command::slmWrite)) {
memcpy_s(slmMemory + command.sip_commandValues.offset, size, command.sip_commandValues.buffer, size);
}
slmCmdRegisterCmdvalue = command.command;
slmCmdRegisterCmdvalue = command.sip_commandValues.command;
}
if (slmCmdRegisterCmdvalue != static_cast<uint32_t>(NEO::SipKernel::Command::resume)) {
@@ -481,7 +483,7 @@ struct MockDebugSession : public L0::DebugSessionImp {
if (slmCmdRegisterAccessCount == slmCmdRegisterAccessReadyCount) { // SIP restores cmd to READY
command.command = static_cast<uint32_t>(NEO::SipKernel::Command::ready);
command.sip_commandValues.command = static_cast<uint32_t>(NEO::SipKernel::Command::ready);
if (slmCmdRegisterCmdvalue == static_cast<uint32_t>(NEO::SipKernel::Command::slmWrite)) {
slmCmdRegisterAccessCount = 0;
@@ -491,9 +493,9 @@ struct MockDebugSession : public L0::DebugSessionImp {
if (!memcmp(slmMemory, "FailReadingData", strlen("FailReadingData"))) {
status = ZE_RESULT_FORCE_UINT32;
} else if (slmCmdRegisterCmdvalue == static_cast<uint32_t>(NEO::SipKernel::Command::slmRead)) {
memcpy_s(command.buffer, size, slmMemory + command.offset, size);
command.offset = 0;
command.size = 0;
memcpy_s(command.sip_commandValues.buffer, size, slmMemory + command.sip_commandValues.offset, size);
command.sip_commandValues.offset = 0;
command.sip_commandValues.size = 0;
}
slmCmdRegisterAccessCount = 0;

View File

@@ -21,5 +21,9 @@ struct StateSaveAreaHeader {
};
};
union SipCommandRegisterValues {
SIP::sip_command sip_commandValues;
};
// NOLINTEND
} // namespace NEO