[gpu/nvdrv] Unstub SetErrorNotifier, add PostErrorNotification function
This commit is contained in:
parent
d623e04606
commit
8f1a574fe0
2 changed files with 127 additions and 5 deletions
|
@ -8,6 +8,7 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
|
@ -161,11 +162,115 @@ NvResult nvhost_gpu::ZCullBind(IoctlZCullBind& params) {
|
|||
}
|
||||
|
||||
NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
|
||||
params.size, params.mem);
|
||||
LOG_DEBUG(Service_NVDRV, "called, offset={:#X}, size={:#X}, mem={:#X}",
|
||||
params.offset, params.size, params.mem);
|
||||
|
||||
if (!params.mem || !params.size) {
|
||||
std::scoped_lock lk(channel_mutex);
|
||||
if (!channel_state->initialized) {
|
||||
LOG_CRITICAL(Service_NVDRV, "No address space bound for setting up error notifier!");
|
||||
return NvResult::NotInitialized;
|
||||
}
|
||||
|
||||
error_notifier_params = {};
|
||||
LOG_DEBUG(Service_NVDRV, "Error notifier disabled!");
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
constexpr u64 error_notification_size = sizeof(IoctlGetErrorNotification);
|
||||
if (params.size < error_notification_size) {
|
||||
LOG_ERROR(Service_NVDRV, "Error notification size: {:#X} is too small. Need at least {:#X}", params.size,
|
||||
error_notification_size);
|
||||
return NvResult::InvalidSize;
|
||||
}
|
||||
|
||||
auto handle = nvmap.GetHandle(static_cast<NvCore::NvMap::Handle::Id>(params.mem));
|
||||
if (!handle) {
|
||||
LOG_ERROR(Service_NVDRV, "Unknown nvmap handle id {:#X}", params.mem);
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
|
||||
|
||||
if (params.offset > handle->size || params.size > (handle->size - params.offset)) {
|
||||
LOG_ERROR(Service_NVDRV, "Error notifier out of bounds: offset={:#X} size={:#X} handle size={:#X}", params.offset,
|
||||
params.size, handle->size);
|
||||
return NvResult::InvalidSize;
|
||||
}
|
||||
|
||||
u64 write_address, write_offset, handle_id;
|
||||
{
|
||||
std::scoped_lock lk(channel_mutex);
|
||||
if (!channel_state->initialized) {
|
||||
LOG_CRITICAL(Service_NVDRV, "No address space bound for setting up error notifier!");
|
||||
return NvResult::NotInitialized;
|
||||
}
|
||||
|
||||
error_notifier_params = params;
|
||||
write_address = handle->address;
|
||||
write_offset = params.offset;
|
||||
handle_id = handle->id;
|
||||
}
|
||||
|
||||
if (write_address) {
|
||||
IoctlGetErrorNotification error_notification{};
|
||||
error_notification.status = static_cast<u16>(NotifierStatus::NoError);
|
||||
system.ApplicationMemory().WriteBlock(write_address + write_offset, &error_notification, sizeof(error_notification));
|
||||
} else {
|
||||
LOG_WARNING(Service_NVDRV,
|
||||
"nvmap handle id {:#X} has no virtual address assigned; "
|
||||
"skipping initialization write for error notification!",
|
||||
handle_id);
|
||||
}
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
void nvhost_gpu::PostErrorNotification(u32 info32, u16 info16, NotifierStatus status) {
|
||||
IoctlSetErrorNotifier error_notifier_params_snapshot{};
|
||||
Kernel::KEvent *error_notifier_event_snapshot{};
|
||||
{
|
||||
std::scoped_lock lk(channel_mutex);
|
||||
error_notifier_params_snapshot = error_notifier_params;
|
||||
error_notifier_event_snapshot = error_notifier_event;
|
||||
}
|
||||
|
||||
if (!error_notifier_params_snapshot.mem || error_notifier_params_snapshot.size < sizeof(IoctlGetErrorNotification)) {
|
||||
LOG_DEBUG(Service_NVDRV, "PostErrorNotification: notifier not configured or too small!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto handle = nvmap.GetHandle(static_cast<NvCore::NvMap::Handle::Id>(error_notifier_params_snapshot.mem));
|
||||
if (!handle || !handle->address) {
|
||||
LOG_ERROR(Service_NVDRV, "PostErrorNotification: invalid handle or virtual address!");
|
||||
return;
|
||||
}
|
||||
|
||||
IoctlGetErrorNotification error_init{};
|
||||
error_init.info32 = info32;
|
||||
error_init.info16 = info16;
|
||||
error_init.status = static_cast<u16>(status);
|
||||
const u64 write_size = std::min<u64>(sizeof(IoctlGetErrorNotification),
|
||||
error_notifier_params_snapshot.size);
|
||||
if (error_notifier_params_snapshot.offset >= handle->size ||
|
||||
write_size > (handle->size - error_notifier_params_snapshot.offset)) {
|
||||
LOG_ERROR(Service_NVDRV, "PostErrorNotification: bounds check failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 virtual_address = handle->address + error_notifier_params_snapshot.offset;
|
||||
if (virtual_address < handle->address) {
|
||||
LOG_ERROR(Service_NVDRV, "PostErrorNotification: virtual address overflow!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto &application_memory = system.ApplicationMemory();
|
||||
application_memory.WriteBlock(virtual_address, &error_init, write_size);
|
||||
|
||||
if (error_notifier_event_snapshot) {
|
||||
error_notifier_event_snapshot->Signal();
|
||||
}
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetChannelPriority(IoctlChannelSetPriority& params) {
|
||||
channel_priority = params.priority;
|
||||
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
|
||||
|
@ -251,7 +356,7 @@ NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) {
|
|||
params.flags = allowed_mask;
|
||||
}
|
||||
|
||||
s32_le ctx_class_number_index =
|
||||
s32_le ctx_class_number_index =
|
||||
GetObjectContextClassNumberIndex(static_cast<CtxClasses>(params.class_num));
|
||||
if (ctx_class_number_index < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid class number for object context: {:#X}",
|
||||
|
@ -324,6 +429,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
|
|||
|
||||
if (flags.fence_wait.Value()) {
|
||||
if (flags.increment_value.Value()) {
|
||||
PostErrorNotification(flags.raw, 0, NotifierStatus::GenericError);
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
|
||||
|
@ -357,7 +463,11 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
|
|||
NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
||||
std::span<Tegra::CommandListHeader> commands, bool kickoff) {
|
||||
if (params.num_entries > commands.size()) {
|
||||
UNIMPLEMENTED();
|
||||
LOG_ERROR(Service_NVDRV,
|
||||
"SubmitGPFIFO: num_entries={:#X} > provided commands={:#X}",
|
||||
params.num_entries, commands.size());
|
||||
|
||||
PostErrorNotification(params.num_entries, 0, NotifierStatus::BadGpfifo);
|
||||
return NvResult::InvalidSize;
|
||||
}
|
||||
|
||||
|
@ -376,7 +486,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
|||
NvResult nvhost_gpu::SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
|
||||
std::span<const Tegra::CommandListHeader> commands) {
|
||||
if (params.num_entries > commands.size()) {
|
||||
UNIMPLEMENTED();
|
||||
PostErrorNotification(params.num_entries, 0, NotifierStatus::BadGpfifo);
|
||||
return NvResult::InvalidSize;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,16 @@ private:
|
|||
CtxChannelGPFIFO = 0xB06F,
|
||||
};
|
||||
|
||||
enum class NotifierStatus : u16_le {
|
||||
NoError = 0xFFFF,
|
||||
GenericError = 0x0001,
|
||||
MmuFault = 0x0002,
|
||||
IllegalMethod= 0x0003,
|
||||
InvalidObject= 0x0004,
|
||||
BadGpfifo = 0x0005,
|
||||
TimeoutHang = 0x0006,
|
||||
};
|
||||
|
||||
struct IoctlSetNvmapFD {
|
||||
s32_le nvmap_fd{};
|
||||
};
|
||||
|
@ -172,6 +182,8 @@ private:
|
|||
s32_le nvmap_fd{};
|
||||
u64_le user_data{};
|
||||
IoctlZCullBind zcull_params{};
|
||||
IoctlSetErrorNotifier error_notifier_params{};
|
||||
void PostErrorNotification(u32 info32, u16 info16, NotifierStatus status);
|
||||
std::array<std::optional<IoctlAllocObjCtx>, 6> ctxObjs{};
|
||||
u32_le channel_priority{};
|
||||
u32_le channel_timeslice{};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue