|
|
|
@ -23,107 +23,132 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
|
|
|
|
|
|
|
|
|
|
nvhost_gpu::~nvhost_gpu() = default;
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
|
|
|
|
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
|
|
|
|
IoctlVersion version) {
|
|
|
|
|
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
|
|
|
|
command.raw, input.size(), output.size());
|
|
|
|
|
|
|
|
|
|
switch (static_cast<IoctlCommand>(command.raw)) {
|
|
|
|
|
case IoctlCommand::IocSetNVMAPfdCommand:
|
|
|
|
|
return SetNVMAPfd(input, output);
|
|
|
|
|
case IoctlCommand::IocSetClientDataCommand:
|
|
|
|
|
return SetClientData(input, output);
|
|
|
|
|
case IoctlCommand::IocGetClientDataCommand:
|
|
|
|
|
return GetClientData(input, output);
|
|
|
|
|
case IoctlCommand::IocZCullBind:
|
|
|
|
|
return ZCullBind(input, output);
|
|
|
|
|
case IoctlCommand::IocSetErrorNotifierCommand:
|
|
|
|
|
return SetErrorNotifier(input, output);
|
|
|
|
|
case IoctlCommand::IocChannelSetPriorityCommand:
|
|
|
|
|
return SetChannelPriority(input, output);
|
|
|
|
|
case IoctlCommand::IocAllocGPFIFOEx2Command:
|
|
|
|
|
return AllocGPFIFOEx2(input, output);
|
|
|
|
|
case IoctlCommand::IocAllocObjCtxCommand:
|
|
|
|
|
return AllocateObjectContext(input, output);
|
|
|
|
|
case IoctlCommand::IocChannelGetWaitbaseCommand:
|
|
|
|
|
NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
switch (command.group) {
|
|
|
|
|
case 0x0:
|
|
|
|
|
switch (command.cmd) {
|
|
|
|
|
case 0x3:
|
|
|
|
|
return GetWaitbase(input, output);
|
|
|
|
|
case IoctlCommand::IocChannelSetTimeoutCommand:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'H':
|
|
|
|
|
switch (command.cmd) {
|
|
|
|
|
case 0x1:
|
|
|
|
|
return SetNVMAPfd(input, output);
|
|
|
|
|
case 0x3:
|
|
|
|
|
return ChannelSetTimeout(input, output);
|
|
|
|
|
case IoctlCommand::IocChannelSetTimeslice:
|
|
|
|
|
case 0x8:
|
|
|
|
|
return SubmitGPFIFOBase(input, output, false);
|
|
|
|
|
case 0x9:
|
|
|
|
|
return AllocateObjectContext(input, output);
|
|
|
|
|
case 0xb:
|
|
|
|
|
return ZCullBind(input, output);
|
|
|
|
|
case 0xc:
|
|
|
|
|
return SetErrorNotifier(input, output);
|
|
|
|
|
case 0xd:
|
|
|
|
|
return SetChannelPriority(input, output);
|
|
|
|
|
case 0x1a:
|
|
|
|
|
return AllocGPFIFOEx2(input, output);
|
|
|
|
|
case 0x1b:
|
|
|
|
|
return SubmitGPFIFOBase(input, output, true);
|
|
|
|
|
case 0x1d:
|
|
|
|
|
return ChannelSetTimeslice(input, output);
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (command.group == NVGPU_IOCTL_MAGIC) {
|
|
|
|
|
if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) {
|
|
|
|
|
return SubmitGPFIFO(input, output);
|
|
|
|
|
break;
|
|
|
|
|
case 'G':
|
|
|
|
|
switch (command.cmd) {
|
|
|
|
|
case 0x14:
|
|
|
|
|
return SetClientData(input, output);
|
|
|
|
|
case 0x15:
|
|
|
|
|
return GetClientData(input, output);
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) {
|
|
|
|
|
return KickoffPB(input, output, input2, version);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
|
|
|
|
return 0;
|
|
|
|
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
|
|
|
|
return NvResult::NotImplemented;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
|
|
|
|
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
|
|
|
|
switch (command.group) {
|
|
|
|
|
case 'H':
|
|
|
|
|
switch (command.cmd) {
|
|
|
|
|
case 0x1b:
|
|
|
|
|
return SubmitGPFIFOBase(input, inline_input, output);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
|
|
|
|
return NvResult::NotImplemented;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
|
|
|
|
std::vector<u8>& inline_output) {
|
|
|
|
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
|
|
|
|
return NvResult::NotImplemented;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
IoctlSetNvmapFD params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), input.size());
|
|
|
|
|
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
|
|
|
|
|
|
|
|
|
nvmap_fd = params.nvmap_fd;
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
LOG_DEBUG(Service_NVDRV, "called");
|
|
|
|
|
|
|
|
|
|
IoctlClientData params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), input.size());
|
|
|
|
|
user_data = params.data;
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
LOG_DEBUG(Service_NVDRV, "called");
|
|
|
|
|
|
|
|
|
|
IoctlClientData params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), input.size());
|
|
|
|
|
params.data = user_data;
|
|
|
|
|
std::memcpy(output.data(), ¶ms, output.size());
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
std::memcpy(&zcull_params, input.data(), input.size());
|
|
|
|
|
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
|
|
|
|
|
zcull_params.mode);
|
|
|
|
|
|
|
|
|
|
std::memcpy(output.data(), &zcull_params, output.size());
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
IoctlSetErrorNotifier params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), input.size());
|
|
|
|
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
|
|
|
|
|
params.size, params.mem);
|
|
|
|
|
|
|
|
|
|
std::memcpy(output.data(), ¶ms, output.size());
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
std::memcpy(&channel_priority, input.data(), input.size());
|
|
|
|
|
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
IoctlAllocGpfifoEx2 params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), input.size());
|
|
|
|
|
LOG_WARNING(Service_NVDRV,
|
|
|
|
@ -137,10 +162,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou
|
|
|
|
|
params.fence_out = channel_fence;
|
|
|
|
|
|
|
|
|
|
std::memcpy(output.data(), ¶ms, output.size());
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
IoctlAllocObjCtx params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), input.size());
|
|
|
|
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
|
|
|
|
@ -148,7 +173,7 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<
|
|
|
|
|
|
|
|
|
|
params.obj_id = 0x0;
|
|
|
|
|
std::memcpy(output.data(), ¶ms, output.size());
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) {
|
|
|
|
@ -192,7 +217,7 @@ static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
|
|
|
|
|
NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
|
|
|
|
|
Tegra::CommandList&& entries) {
|
|
|
|
|
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
|
|
|
|
|
params.num_entries, params.flags.raw);
|
|
|
|
@ -227,69 +252,70 @@ u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo));
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
|
|
|
|
|
bool kickoff) {
|
|
|
|
|
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
return NvResult::InvalidSize;
|
|
|
|
|
}
|
|
|
|
|
IoctlSubmitGpfifo params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
|
|
|
|
|
|
|
|
|
Tegra::CommandList entries(params.num_entries);
|
|
|
|
|
std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)],
|
|
|
|
|
params.num_entries * sizeof(Tegra::CommandListHeader));
|
|
|
|
|
|
|
|
|
|
return SubmitGPFIFOImpl(params, output, std::move(entries));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
|
|
|
|
|
const std::vector<u8>& input2, IoctlVersion version) {
|
|
|
|
|
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
}
|
|
|
|
|
IoctlSubmitGpfifo params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
|
|
|
|
|
|
|
|
|
Tegra::CommandList entries(params.num_entries);
|
|
|
|
|
if (version == IoctlVersion::Version2) {
|
|
|
|
|
std::memcpy(entries.command_lists.data(), input2.data(),
|
|
|
|
|
params.num_entries * sizeof(Tegra::CommandListHeader));
|
|
|
|
|
} else {
|
|
|
|
|
if (kickoff) {
|
|
|
|
|
system.Memory().ReadBlock(params.address, entries.command_lists.data(),
|
|
|
|
|
params.num_entries * sizeof(Tegra::CommandListHeader));
|
|
|
|
|
} else {
|
|
|
|
|
std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)],
|
|
|
|
|
params.num_entries * sizeof(Tegra::CommandListHeader));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SubmitGPFIFOImpl(params, output, std::move(entries));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input,
|
|
|
|
|
const std::vector<u8>& input_inline,
|
|
|
|
|
std::vector<u8>& output) {
|
|
|
|
|
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
return NvResult::InvalidSize;
|
|
|
|
|
}
|
|
|
|
|
IoctlSubmitGpfifo params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
|
|
|
|
Tegra::CommandList entries(params.num_entries);
|
|
|
|
|
std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size());
|
|
|
|
|
return SubmitGPFIFOImpl(params, output, std::move(entries));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
IoctlGetWaitbase params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
|
|
|
|
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
|
|
|
|
|
|
|
|
|
params.value = 0; // Seems to be hard coded at 0
|
|
|
|
|
std::memcpy(output.data(), ¶ms, output.size());
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
IoctlChannelSetTimeout params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout));
|
|
|
|
|
LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {
|
|
|
|
|
IoctlSetTimeslice params{};
|
|
|
|
|
std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice));
|
|
|
|
|
LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
|
|
|
|
|
|
|
|
|
|
channel_timeslice = params.timeslice;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
return NvResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Service::Nvidia::Devices
|
|
|
|
|