mirror of
https://gitlab.com/suyu-emu/suyu.git
synced 2024-03-15 23:15:44 +00:00
core: Make nvservices more standardized
This commit is contained in:
parent
9b24197ca0
commit
31c12de0fe
|
@ -24,25 +24,12 @@ public:
|
||||||
explicit nvdevice(Core::System& system) : system{system} {}
|
explicit nvdevice(Core::System& system) : system{system} {}
|
||||||
virtual ~nvdevice() = default;
|
virtual ~nvdevice() = default;
|
||||||
|
|
||||||
union Ioctl {
|
virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||||
u32_le raw;
|
std::vector<u8>& output) = 0;
|
||||||
BitField<0, 8, u32> cmd;
|
virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
BitField<8, 8, u32> group;
|
const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;
|
||||||
BitField<16, 14, u32> length;
|
virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
BitField<30, 1, u32> is_in;
|
std::vector<u8>& inline_output) = 0;
|
||||||
BitField<31, 1, u32> is_out;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles an ioctl request.
|
|
||||||
* @param command The ioctl command id.
|
|
||||||
* @param input A buffer containing the input data for the ioctl.
|
|
||||||
* @param output A buffer where the output data will be written to.
|
|
||||||
* @returns The result code of the ioctl.
|
|
||||||
*/
|
|
||||||
virtual u32 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) = 0;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
|
@ -18,11 +18,22 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de
|
||||||
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
||||||
nvdisp_disp0 ::~nvdisp_disp0() = default;
|
nvdisp_disp0 ::~nvdisp_disp0() = default;
|
||||||
|
|
||||||
u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
std::vector<u8>& output) {
|
||||||
IoctlVersion version) {
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
return NvResult::NotImplemented;
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvdisp_disp0::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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
|
void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
|
||||||
|
|
|
@ -20,9 +20,11 @@ public:
|
||||||
explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||||
~nvdisp_disp0() override;
|
~nvdisp_disp0() override;
|
||||||
|
|
||||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
IoctlVersion version) override;
|
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||||
|
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) override;
|
||||||
|
|
||||||
/// Performs a screen flip, drawing the buffer pointed to by the handle.
|
/// Performs a screen flip, drawing the buffer pointed to by the handle.
|
||||||
void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
|
void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
|
||||||
|
|
|
@ -17,59 +17,70 @@
|
||||||
|
|
||||||
namespace Service::Nvidia::Devices {
|
namespace Service::Nvidia::Devices {
|
||||||
|
|
||||||
namespace NvErrCodes {
|
|
||||||
constexpr u32 Success{};
|
|
||||||
constexpr u32 OutOfMemory{static_cast<u32>(-12)};
|
|
||||||
constexpr u32 InvalidInput{static_cast<u32>(-22)};
|
|
||||||
} // namespace NvErrCodes
|
|
||||||
|
|
||||||
nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
|
nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
|
||||||
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
||||||
nvhost_as_gpu::~nvhost_as_gpu() = default;
|
nvhost_as_gpu::~nvhost_as_gpu() = default;
|
||||||
|
|
||||||
u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
std::vector<u8>& output) {
|
||||||
IoctlVersion version) {
|
switch (command.group) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
case 'A':
|
||||||
command.raw, input.size(), output.size());
|
switch (command.cmd) {
|
||||||
|
case 0x1:
|
||||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
return BindChannel(input, output);
|
||||||
case IoctlCommand::IocInitalizeExCommand:
|
case 0x2:
|
||||||
return InitalizeEx(input, output);
|
return AllocateSpace(input, output);
|
||||||
case IoctlCommand::IocAllocateSpaceCommand:
|
case 0x3:
|
||||||
return AllocateSpace(input, output);
|
return FreeSpace(input, output);
|
||||||
case IoctlCommand::IocMapBufferExCommand:
|
case 0x5:
|
||||||
return MapBufferEx(input, output);
|
return UnmapBuffer(input, output);
|
||||||
case IoctlCommand::IocBindChannelCommand:
|
case 0x6:
|
||||||
return BindChannel(input, output);
|
return MapBufferEx(input, output);
|
||||||
case IoctlCommand::IocGetVaRegionsCommand:
|
case 0x8:
|
||||||
return GetVARegions(input, output);
|
return GetVARegions(input, output);
|
||||||
case IoctlCommand::IocUnmapBufferCommand:
|
case 0x9:
|
||||||
return UnmapBuffer(input, output);
|
return InitalizeEx(input, output);
|
||||||
case IoctlCommand::IocFreeSpaceCommand:
|
case 0x14:
|
||||||
return FreeSpace(input, output);
|
return Remap(input, output);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) {
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
return Remap(input, output);
|
return NvResult::NotImplemented;
|
||||||
}
|
|
||||||
|
|
||||||
UNIMPLEMENTED_MSG("Unimplemented ioctl command");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) {
|
||||||
|
switch (command.group) {
|
||||||
|
case 'A':
|
||||||
|
switch (command.cmd) {
|
||||||
|
case 0x8:
|
||||||
|
return GetVARegions(input, output, inline_output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlInitalizeEx params{};
|
IoctlInitalizeEx params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
|
||||||
|
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlAllocSpace params{};
|
IoctlAllocSpace params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
|
||||||
|
@ -83,17 +94,17 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
|
||||||
params.offset = system.GPU().MemoryManager().Allocate(size, params.align);
|
params.offset = system.GPU().MemoryManager().Allocate(size, params.align);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result{NvErrCodes::Success};
|
auto result = NvResult::Success;
|
||||||
if (!params.offset) {
|
if (!params.offset) {
|
||||||
LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size);
|
LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size);
|
||||||
result = NvErrCodes::OutOfMemory;
|
result = NvResult::InsufficientMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlFreeSpace params{};
|
IoctlFreeSpace params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
|
||||||
|
@ -104,15 +115,15 @@ u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& outp
|
||||||
static_cast<std::size_t>(params.pages) * params.page_size);
|
static_cast<std::size_t>(params.pages) * params.page_size);
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return NvErrCodes::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
|
const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
|
||||||
|
|
||||||
LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
|
LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
|
||||||
|
|
||||||
auto result{NvErrCodes::Success};
|
auto result = NvResult::Success;
|
||||||
std::vector<IoctlRemapEntry> entries(num_entries);
|
std::vector<IoctlRemapEntry> entries(num_entries);
|
||||||
std::memcpy(entries.data(), input.data(), input.size());
|
std::memcpy(entries.data(), input.data(), input.size());
|
||||||
|
|
||||||
|
@ -123,7 +134,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
|
||||||
const auto object{nvmap_dev->GetObject(entry.nvmap_handle)};
|
const auto object{nvmap_dev->GetObject(entry.nvmap_handle)};
|
||||||
if (!object) {
|
if (!object) {
|
||||||
LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle);
|
LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle);
|
||||||
result = NvErrCodes::InvalidInput;
|
result = NvResult::InvalidState;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +145,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
|
||||||
|
|
||||||
if (!addr) {
|
if (!addr) {
|
||||||
LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!");
|
LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!");
|
||||||
result = NvErrCodes::InvalidInput;
|
result = NvResult::InvalidState;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +154,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlMapBufferEx params{};
|
IoctlMapBufferEx params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
|
||||||
|
@ -157,7 +168,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||||
if (!object) {
|
if (!object) {
|
||||||
LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);
|
LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return NvErrCodes::InvalidInput;
|
return NvResult::InvalidState;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The real nvservices doesn't make a distinction between handles and ids, and
|
// The real nvservices doesn't make a distinction between handles and ids, and
|
||||||
|
@ -184,16 +195,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||||
params.mapping_size, params.offset);
|
params.mapping_size, params.offset);
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return NvErrCodes::InvalidInput;
|
return NvResult::InvalidState;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return NvErrCodes::Success;
|
return NvResult::Success;
|
||||||
} else {
|
} else {
|
||||||
LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset);
|
LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset);
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return NvErrCodes::InvalidInput;
|
return NvResult::InvalidState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,10 +224,10 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||||
params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size);
|
params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result{NvErrCodes::Success};
|
auto result = NvResult::Success;
|
||||||
if (!params.offset) {
|
if (!params.offset) {
|
||||||
LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size);
|
LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size);
|
||||||
result = NvErrCodes::InvalidInput;
|
result = NvResult::InvalidState;
|
||||||
} else {
|
} else {
|
||||||
AddBufferMap(params.offset, size, physical_address, is_alloc);
|
AddBufferMap(params.offset, size, physical_address, is_alloc);
|
||||||
}
|
}
|
||||||
|
@ -225,7 +236,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlUnmapBuffer params{};
|
IoctlUnmapBuffer params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
|
||||||
|
@ -238,20 +249,19 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return NvErrCodes::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlBindChannel params{};
|
IoctlBindChannel params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}", params.fd);
|
||||||
LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
|
|
||||||
|
|
||||||
channel = params.fd;
|
channel = params.fd;
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlGetVaRegions params{};
|
IoctlGetVaRegions params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
|
||||||
|
@ -270,7 +280,31 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o
|
||||||
// TODO(ogniK): This probably can stay stubbed but should add support way way later
|
// TODO(ogniK): This probably can stay stubbed but should add support way way later
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) {
|
||||||
|
IoctlGetVaRegions params{};
|
||||||
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
|
||||||
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
|
||||||
|
params.buf_size);
|
||||||
|
|
||||||
|
params.buf_size = 0x30;
|
||||||
|
params.regions[0].offset = 0x04000000;
|
||||||
|
params.regions[0].page_size = 0x1000;
|
||||||
|
params.regions[0].pages = 0x3fbfff;
|
||||||
|
|
||||||
|
params.regions[1].offset = 0x04000000;
|
||||||
|
params.regions[1].page_size = 0x10000;
|
||||||
|
params.regions[1].pages = 0x1bffff;
|
||||||
|
|
||||||
|
// TODO(ogniK): This probably can stay stubbed but should add support way way later
|
||||||
|
|
||||||
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
|
std::memcpy(inline_output.data(), ¶ms.regions, inline_output.size());
|
||||||
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const {
|
std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const {
|
||||||
|
|
|
@ -30,9 +30,11 @@ public:
|
||||||
explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||||
~nvhost_as_gpu() override;
|
~nvhost_as_gpu() override;
|
||||||
|
|
||||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
IoctlVersion version) override;
|
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||||
|
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class BufferMap final {
|
class BufferMap final {
|
||||||
|
@ -74,32 +76,21 @@ private:
|
||||||
bool is_allocated{};
|
bool is_allocated{};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class IoctlCommand : u32_le {
|
|
||||||
IocInitalizeExCommand = 0x40284109,
|
|
||||||
IocAllocateSpaceCommand = 0xC0184102,
|
|
||||||
IocRemapCommand = 0x00000014,
|
|
||||||
IocMapBufferExCommand = 0xC0284106,
|
|
||||||
IocBindChannelCommand = 0x40044101,
|
|
||||||
IocGetVaRegionsCommand = 0xC0404108,
|
|
||||||
IocUnmapBufferCommand = 0xC0084105,
|
|
||||||
IocFreeSpaceCommand = 0xC0104103,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IoctlInitalizeEx {
|
struct IoctlInitalizeEx {
|
||||||
u32_le big_page_size; // depends on GPU's available_big_page_sizes; 0=default
|
u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default
|
||||||
s32_le as_fd; // ignored; passes 0
|
s32_le as_fd{}; // ignored; passes 0
|
||||||
u32_le flags; // passes 0
|
u32_le flags{}; // passes 0
|
||||||
u32_le reserved; // ignored; passes 0
|
u32_le reserved{}; // ignored; passes 0
|
||||||
u64_le unk0;
|
u64_le unk0{};
|
||||||
u64_le unk1;
|
u64_le unk1{};
|
||||||
u64_le unk2;
|
u64_le unk2{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size");
|
static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size");
|
||||||
|
|
||||||
struct IoctlAllocSpace {
|
struct IoctlAllocSpace {
|
||||||
u32_le pages;
|
u32_le pages{};
|
||||||
u32_le page_size;
|
u32_le page_size{};
|
||||||
AddressSpaceFlags flags;
|
AddressSpaceFlags flags{};
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(1);
|
||||||
union {
|
union {
|
||||||
u64_le offset;
|
u64_le offset;
|
||||||
|
@ -109,70 +100,73 @@ private:
|
||||||
static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
|
static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
|
||||||
|
|
||||||
struct IoctlFreeSpace {
|
struct IoctlFreeSpace {
|
||||||
u64_le offset;
|
u64_le offset{};
|
||||||
u32_le pages;
|
u32_le pages{};
|
||||||
u32_le page_size;
|
u32_le page_size{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");
|
static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");
|
||||||
|
|
||||||
struct IoctlRemapEntry {
|
struct IoctlRemapEntry {
|
||||||
u16_le flags;
|
u16_le flags{};
|
||||||
u16_le kind;
|
u16_le kind{};
|
||||||
u32_le nvmap_handle;
|
u32_le nvmap_handle{};
|
||||||
u32_le map_offset;
|
u32_le map_offset{};
|
||||||
u32_le offset;
|
u32_le offset{};
|
||||||
u32_le pages;
|
u32_le pages{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
|
static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
|
||||||
|
|
||||||
struct IoctlMapBufferEx {
|
struct IoctlMapBufferEx {
|
||||||
AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable
|
AddressSpaceFlags flags{}; // bit0: fixed_offset, bit2: cacheable
|
||||||
u32_le kind; // -1 is default
|
u32_le kind{}; // -1 is default
|
||||||
u32_le nvmap_handle;
|
u32_le nvmap_handle{};
|
||||||
u32_le page_size; // 0 means don't care
|
u32_le page_size{}; // 0 means don't care
|
||||||
s64_le buffer_offset;
|
s64_le buffer_offset{};
|
||||||
u64_le mapping_size;
|
u64_le mapping_size{};
|
||||||
s64_le offset;
|
s64_le offset{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");
|
static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");
|
||||||
|
|
||||||
struct IoctlUnmapBuffer {
|
struct IoctlUnmapBuffer {
|
||||||
s64_le offset;
|
s64_le offset{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size");
|
static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size");
|
||||||
|
|
||||||
struct IoctlBindChannel {
|
struct IoctlBindChannel {
|
||||||
u32_le fd;
|
s32_le fd{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size");
|
static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size");
|
||||||
|
|
||||||
struct IoctlVaRegion {
|
struct IoctlVaRegion {
|
||||||
u64_le offset;
|
u64_le offset{};
|
||||||
u32_le page_size;
|
u32_le page_size{};
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(1);
|
||||||
u64_le pages;
|
u64_le pages{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size");
|
static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size");
|
||||||
|
|
||||||
struct IoctlGetVaRegions {
|
struct IoctlGetVaRegions {
|
||||||
u64_le buf_addr; // (contained output user ptr on linux, ignored)
|
u64_le buf_addr{}; // (contained output user ptr on linux, ignored)
|
||||||
u32_le buf_size; // forced to 2*sizeof(struct va_region)
|
u32_le buf_size{}; // forced to 2*sizeof(struct va_region)
|
||||||
u32_le reserved;
|
u32_le reserved{};
|
||||||
IoctlVaRegion regions[2];
|
IoctlVaRegion regions[2]{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
|
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
|
||||||
"IoctlGetVaRegions is incorrect size");
|
"IoctlGetVaRegions is incorrect size");
|
||||||
|
|
||||||
u32 channel{};
|
s32 channel{};
|
||||||
|
|
||||||
u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 Remap(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
|
|
||||||
|
NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output);
|
||||||
|
|
||||||
std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
|
std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
|
||||||
void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
|
void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
|
||||||
|
|
|
@ -20,41 +20,54 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,
|
||||||
: nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}
|
: nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}
|
||||||
nvhost_ctrl::~nvhost_ctrl() = default;
|
nvhost_ctrl::~nvhost_ctrl() = default;
|
||||||
|
|
||||||
u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
switch (command.group) {
|
||||||
IoctlVersion version) {
|
case 0x0:
|
||||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
switch (command.cmd) {
|
||||||
command.raw, input.size(), output.size());
|
case 0x1b:
|
||||||
|
return NvOsGetConfigU32(input, output);
|
||||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
case 0x1c:
|
||||||
case IoctlCommand::IocGetConfigCommand:
|
return IocCtrlClearEventWait(input, output);
|
||||||
return NvOsGetConfigU32(input, output);
|
case 0x1d:
|
||||||
case IoctlCommand::IocCtrlEventWaitCommand:
|
return IocCtrlEventWait(input, output, false);
|
||||||
return IocCtrlEventWait(input, output, false, ctrl);
|
case 0x1e:
|
||||||
case IoctlCommand::IocCtrlEventWaitAsyncCommand:
|
return IocCtrlEventWait(input, output, true);
|
||||||
return IocCtrlEventWait(input, output, true, ctrl);
|
case 0x1f:
|
||||||
case IoctlCommand::IocCtrlEventRegisterCommand:
|
return IocCtrlEventRegister(input, output);
|
||||||
return IocCtrlEventRegister(input, output);
|
case 0x20:
|
||||||
case IoctlCommand::IocCtrlEventUnregisterCommand:
|
return IocCtrlEventUnregister(input, output);
|
||||||
return IocCtrlEventUnregister(input, output);
|
}
|
||||||
case IoctlCommand::IocCtrlClearEventWaitCommand:
|
break;
|
||||||
return IocCtrlClearEventWait(input, output);
|
|
||||||
default:
|
default:
|
||||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
break;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_ctrl::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_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IocGetConfigParams params{};
|
IocGetConfigParams params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
|
LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
|
||||||
params.param_str.data());
|
params.param_str.data());
|
||||||
return 0x30006; // Returns error on production mode
|
return NvResult::ConfigVarNotFound; // Returns error on production mode
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
|
NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
bool is_async, IoctlCtrl& ctrl) {
|
bool is_async) {
|
||||||
IocCtrlEventWaitParams params{};
|
IocCtrlEventWaitParams params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}",
|
LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}",
|
||||||
|
@ -126,10 +139,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
|
||||||
params.value |= event_id;
|
params.value |= event_id;
|
||||||
event.event.writable->Clear();
|
event.event.writable->Clear();
|
||||||
gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
|
gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
|
||||||
if (!is_async && ctrl.fresh_call) {
|
if (!is_async) {
|
||||||
ctrl.must_delay = true;
|
|
||||||
ctrl.timeout = params.timeout;
|
|
||||||
ctrl.event_id = event_id;
|
|
||||||
return NvResult::Timeout;
|
return NvResult::Timeout;
|
||||||
}
|
}
|
||||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||||
|
@ -139,7 +149,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
|
||||||
return NvResult::BadParameter;
|
return NvResult::BadParameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IocCtrlEventRegisterParams params{};
|
IocCtrlEventRegisterParams params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
const u32 event_id = params.user_event_id & 0x00FF;
|
const u32 event_id = params.user_event_id & 0x00FF;
|
||||||
|
@ -154,7 +164,8 @@ u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<
|
||||||
return NvResult::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
|
||||||
|
std::vector<u8>& output) {
|
||||||
IocCtrlEventUnregisterParams params{};
|
IocCtrlEventUnregisterParams params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
const u32 event_id = params.user_event_id & 0x00FF;
|
const u32 event_id = params.user_event_id & 0x00FF;
|
||||||
|
@ -169,7 +180,7 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto
|
||||||
return NvResult::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IocCtrlEventSignalParams params{};
|
IocCtrlEventSignalParams params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
|
|
||||||
|
|
|
@ -18,132 +18,113 @@ public:
|
||||||
SyncpointManager& syncpoint_manager);
|
SyncpointManager& syncpoint_manager);
|
||||||
~nvhost_ctrl() override;
|
~nvhost_ctrl() override;
|
||||||
|
|
||||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
IoctlVersion version) override;
|
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||||
|
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class IoctlCommand : u32_le {
|
|
||||||
IocSyncptReadCommand = 0xC0080014,
|
|
||||||
IocSyncptIncrCommand = 0x40040015,
|
|
||||||
IocSyncptWaitCommand = 0xC00C0016,
|
|
||||||
IocModuleMutexCommand = 0x40080017,
|
|
||||||
IocModuleRegRDWRCommand = 0xC0180018,
|
|
||||||
IocSyncptWaitexCommand = 0xC0100019,
|
|
||||||
IocSyncptReadMaxCommand = 0xC008001A,
|
|
||||||
IocGetConfigCommand = 0xC183001B,
|
|
||||||
IocCtrlClearEventWaitCommand = 0xC004001C,
|
|
||||||
IocCtrlEventWaitCommand = 0xC010001D,
|
|
||||||
IocCtrlEventWaitAsyncCommand = 0xC010001E,
|
|
||||||
IocCtrlEventRegisterCommand = 0xC004001F,
|
|
||||||
IocCtrlEventUnregisterCommand = 0xC0040020,
|
|
||||||
IocCtrlEventKillCommand = 0x40080021,
|
|
||||||
};
|
|
||||||
struct IocSyncptReadParams {
|
struct IocSyncptReadParams {
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
u32_le value;
|
u32_le value{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size");
|
static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size");
|
||||||
|
|
||||||
struct IocSyncptIncrParams {
|
struct IocSyncptIncrParams {
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size");
|
static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size");
|
||||||
|
|
||||||
struct IocSyncptWaitParams {
|
struct IocSyncptWaitParams {
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
u32_le thresh;
|
u32_le thresh{};
|
||||||
s32_le timeout;
|
s32_le timeout{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size");
|
static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size");
|
||||||
|
|
||||||
struct IocModuleMutexParams {
|
struct IocModuleMutexParams {
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
u32_le lock; // (0 = unlock and 1 = lock)
|
u32_le lock{}; // (0 = unlock and 1 = lock)
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size");
|
static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size");
|
||||||
|
|
||||||
struct IocModuleRegRDWRParams {
|
struct IocModuleRegRDWRParams {
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
u32_le num_offsets;
|
u32_le num_offsets{};
|
||||||
u32_le block_size;
|
u32_le block_size{};
|
||||||
u32_le offsets;
|
u32_le offsets{};
|
||||||
u32_le values;
|
u32_le values{};
|
||||||
u32_le write;
|
u32_le write{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size");
|
static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size");
|
||||||
|
|
||||||
struct IocSyncptWaitexParams {
|
struct IocSyncptWaitexParams {
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
u32_le thresh;
|
u32_le thresh{};
|
||||||
s32_le timeout;
|
s32_le timeout{};
|
||||||
u32_le value;
|
u32_le value{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size");
|
static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size");
|
||||||
|
|
||||||
struct IocSyncptReadMaxParams {
|
struct IocSyncptReadMaxParams {
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
u32_le value;
|
u32_le value{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size");
|
static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size");
|
||||||
|
|
||||||
struct IocGetConfigParams {
|
struct IocGetConfigParams {
|
||||||
std::array<char, 0x41> domain_str;
|
std::array<char, 0x41> domain_str{};
|
||||||
std::array<char, 0x41> param_str;
|
std::array<char, 0x41> param_str{};
|
||||||
std::array<char, 0x101> config_str;
|
std::array<char, 0x101> config_str{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");
|
static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");
|
||||||
|
|
||||||
struct IocCtrlEventSignalParams {
|
struct IocCtrlEventSignalParams {
|
||||||
u32_le event_id;
|
u32_le event_id{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocCtrlEventSignalParams) == 4,
|
static_assert(sizeof(IocCtrlEventSignalParams) == 4,
|
||||||
"IocCtrlEventSignalParams is incorrect size");
|
"IocCtrlEventSignalParams is incorrect size");
|
||||||
|
|
||||||
struct IocCtrlEventWaitParams {
|
struct IocCtrlEventWaitParams {
|
||||||
u32_le syncpt_id;
|
u32_le syncpt_id{};
|
||||||
u32_le threshold;
|
u32_le threshold{};
|
||||||
s32_le timeout;
|
s32_le timeout{};
|
||||||
u32_le value;
|
u32_le value{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size");
|
static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size");
|
||||||
|
|
||||||
struct IocCtrlEventWaitAsyncParams {
|
struct IocCtrlEventWaitAsyncParams {
|
||||||
u32_le syncpt_id;
|
u32_le syncpt_id{};
|
||||||
u32_le threshold;
|
u32_le threshold{};
|
||||||
u32_le timeout;
|
u32_le timeout{};
|
||||||
u32_le value;
|
u32_le value{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16,
|
static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16,
|
||||||
"IocCtrlEventWaitAsyncParams is incorrect size");
|
"IocCtrlEventWaitAsyncParams is incorrect size");
|
||||||
|
|
||||||
struct IocCtrlEventRegisterParams {
|
struct IocCtrlEventRegisterParams {
|
||||||
u32_le user_event_id;
|
u32_le user_event_id{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocCtrlEventRegisterParams) == 4,
|
static_assert(sizeof(IocCtrlEventRegisterParams) == 4,
|
||||||
"IocCtrlEventRegisterParams is incorrect size");
|
"IocCtrlEventRegisterParams is incorrect size");
|
||||||
|
|
||||||
struct IocCtrlEventUnregisterParams {
|
struct IocCtrlEventUnregisterParams {
|
||||||
u32_le user_event_id;
|
u32_le user_event_id{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocCtrlEventUnregisterParams) == 4,
|
static_assert(sizeof(IocCtrlEventUnregisterParams) == 4,
|
||||||
"IocCtrlEventUnregisterParams is incorrect size");
|
"IocCtrlEventUnregisterParams is incorrect size");
|
||||||
|
|
||||||
struct IocCtrlEventKill {
|
struct IocCtrlEventKill {
|
||||||
u64_le user_events;
|
u64_le user_events{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size");
|
static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size");
|
||||||
|
|
||||||
u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async);
|
||||||
u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async,
|
NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
IoctlCtrl& ctrl);
|
NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
|
|
||||||
|
|
||||||
u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
|
|
||||||
|
|
||||||
u32 IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
|
|
||||||
|
|
||||||
EventInterface& events_interface;
|
EventInterface& events_interface;
|
||||||
SyncpointManager& syncpoint_manager;
|
SyncpointManager& syncpoint_manager;
|
||||||
|
|
|
@ -15,39 +15,112 @@ namespace Service::Nvidia::Devices {
|
||||||
nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
|
nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
|
||||||
nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
|
nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
|
||||||
|
|
||||||
u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input,
|
NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||||
const std::vector<u8>& input2, std::vector<u8>& output,
|
std::vector<u8>& output) {
|
||||||
std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) {
|
switch (command.group) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
case 'G':
|
||||||
command.raw, input.size(), output.size());
|
switch (command.cmd) {
|
||||||
|
case 0x1:
|
||||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
return ZCullGetCtxSize(input, output);
|
||||||
case IoctlCommand::IocGetCharacteristicsCommand:
|
case 0x2:
|
||||||
return GetCharacteristics(input, output, output2, version);
|
return ZCullGetInfo(input, output);
|
||||||
case IoctlCommand::IocGetTPCMasksCommand:
|
case 0x3:
|
||||||
return GetTPCMasks(input, output, output2, version);
|
return ZBCSetTable(input, output);
|
||||||
case IoctlCommand::IocGetActiveSlotMaskCommand:
|
case 0x4:
|
||||||
return GetActiveSlotMask(input, output);
|
return ZBCQueryTable(input, output);
|
||||||
case IoctlCommand::IocZcullGetCtxSizeCommand:
|
case 0x5:
|
||||||
return ZCullGetCtxSize(input, output);
|
return GetCharacteristics(input, output);
|
||||||
case IoctlCommand::IocZcullGetInfo:
|
case 0x6:
|
||||||
return ZCullGetInfo(input, output);
|
return GetTPCMasks(input, output);
|
||||||
case IoctlCommand::IocZbcSetTable:
|
case 0x7:
|
||||||
return ZBCSetTable(input, output);
|
return FlushL2(input, output);
|
||||||
case IoctlCommand::IocZbcQueryTable:
|
case 0x14:
|
||||||
return ZBCQueryTable(input, output);
|
return GetActiveSlotMask(input, output);
|
||||||
case IoctlCommand::IocFlushL2:
|
case 0x1c:
|
||||||
return FlushL2(input, output);
|
return GetGpuTime(input, output);
|
||||||
case IoctlCommand::IocGetGpuTime:
|
default:
|
||||||
return GetGpuTime(input, output);
|
break;
|
||||||
default:
|
}
|
||||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
break;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
|
NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
std::vector<u8>& output2, IoctlVersion version) {
|
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input,
|
||||||
|
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||||
|
switch (command.group) {
|
||||||
|
case 'G':
|
||||||
|
switch (command.cmd) {
|
||||||
|
case 0x5:
|
||||||
|
return GetCharacteristics(input, output, inline_output);
|
||||||
|
case 0x6:
|
||||||
|
return GetTPCMasks(input, output, inline_output);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input,
|
||||||
|
std::vector<u8>& output) {
|
||||||
|
LOG_DEBUG(Service_NVDRV, "called");
|
||||||
|
IoctlCharacteristics params{};
|
||||||
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
params.gc.arch = 0x120;
|
||||||
|
params.gc.impl = 0xb;
|
||||||
|
params.gc.rev = 0xa1;
|
||||||
|
params.gc.num_gpc = 0x1;
|
||||||
|
params.gc.l2_cache_size = 0x40000;
|
||||||
|
params.gc.on_board_video_memory_size = 0x0;
|
||||||
|
params.gc.num_tpc_per_gpc = 0x2;
|
||||||
|
params.gc.bus_type = 0x20;
|
||||||
|
params.gc.big_page_size = 0x20000;
|
||||||
|
params.gc.compression_page_size = 0x20000;
|
||||||
|
params.gc.pde_coverage_bit_count = 0x1B;
|
||||||
|
params.gc.available_big_page_sizes = 0x30000;
|
||||||
|
params.gc.gpc_mask = 0x1;
|
||||||
|
params.gc.sm_arch_sm_version = 0x503;
|
||||||
|
params.gc.sm_arch_spa_version = 0x503;
|
||||||
|
params.gc.sm_arch_warp_count = 0x80;
|
||||||
|
params.gc.gpu_va_bit_count = 0x28;
|
||||||
|
params.gc.reserved = 0x0;
|
||||||
|
params.gc.flags = 0x55;
|
||||||
|
params.gc.twod_class = 0x902D;
|
||||||
|
params.gc.threed_class = 0xB197;
|
||||||
|
params.gc.compute_class = 0xB1C0;
|
||||||
|
params.gc.gpfifo_class = 0xB06F;
|
||||||
|
params.gc.inline_to_memory_class = 0xA140;
|
||||||
|
params.gc.dma_copy_class = 0xB0B5;
|
||||||
|
params.gc.max_fbps_count = 0x1;
|
||||||
|
params.gc.fbp_en_mask = 0x0;
|
||||||
|
params.gc.max_ltc_per_fbp = 0x2;
|
||||||
|
params.gc.max_lts_per_ltc = 0x1;
|
||||||
|
params.gc.max_tex_per_tpc = 0x0;
|
||||||
|
params.gc.max_gpc_count = 0x1;
|
||||||
|
params.gc.rop_l2_en_mask_0 = 0x21D70;
|
||||||
|
params.gc.rop_l2_en_mask_1 = 0x0;
|
||||||
|
params.gc.chipname = 0x6230326D67;
|
||||||
|
params.gc.gr_compbit_store_base_hw = 0x0;
|
||||||
|
params.gpu_characteristics_buf_size = 0xA0;
|
||||||
|
params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
|
||||||
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
|
return NvResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called");
|
LOG_DEBUG(Service_NVDRV, "called");
|
||||||
IoctlCharacteristics params{};
|
IoctlCharacteristics params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
@ -89,35 +162,36 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto
|
||||||
params.gpu_characteristics_buf_size = 0xA0;
|
params.gpu_characteristics_buf_size = 0xA0;
|
||||||
params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
|
params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
|
||||||
|
|
||||||
if (version == IoctlVersion::Version3) {
|
std::memcpy(output.data(), input.data(), output.size());
|
||||||
std::memcpy(output.data(), input.data(), output.size());
|
std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size());
|
||||||
std::memcpy(output2.data(), ¶ms.gc, output2.size());
|
return NvResult::Success;
|
||||||
} else {
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
|
NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
std::vector<u8>& output2, IoctlVersion version) {
|
|
||||||
IoctlGpuGetTpcMasksArgs params{};
|
IoctlGpuGetTpcMasksArgs params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
|
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
|
||||||
if (params.mask_buffer_size != 0) {
|
if (params.mask_buffer_size != 0) {
|
||||||
params.tcp_mask = 3;
|
params.tcp_mask = 3;
|
||||||
}
|
}
|
||||||
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
if (version == IoctlVersion::Version3) {
|
return NvResult::Success;
|
||||||
std::memcpy(output.data(), input.data(), output.size());
|
|
||||||
std::memcpy(output2.data(), ¶ms.tcp_mask, output2.size());
|
|
||||||
} else {
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) {
|
||||||
|
IoctlGpuGetTpcMasksArgs params{};
|
||||||
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
|
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
|
||||||
|
if (params.mask_buffer_size != 0) {
|
||||||
|
params.tcp_mask = 3;
|
||||||
|
}
|
||||||
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
|
std::memcpy(inline_output.data(), ¶ms.tcp_mask, inline_output.size());
|
||||||
|
return NvResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called");
|
LOG_DEBUG(Service_NVDRV, "called");
|
||||||
|
|
||||||
IoctlActiveSlotMask params{};
|
IoctlActiveSlotMask params{};
|
||||||
|
@ -127,10 +201,10 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
|
||||||
params.slot = 0x07;
|
params.slot = 0x07;
|
||||||
params.mask = 0x01;
|
params.mask = 0x01;
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called");
|
LOG_DEBUG(Service_NVDRV, "called");
|
||||||
|
|
||||||
IoctlZcullGetCtxSize params{};
|
IoctlZcullGetCtxSize params{};
|
||||||
|
@ -139,10 +213,10 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
|
||||||
}
|
}
|
||||||
params.size = 0x1;
|
params.size = 0x1;
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called");
|
LOG_DEBUG(Service_NVDRV, "called");
|
||||||
|
|
||||||
IoctlNvgpuGpuZcullGetInfoArgs params{};
|
IoctlNvgpuGpuZcullGetInfoArgs params{};
|
||||||
|
@ -162,47 +236,47 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&
|
||||||
params.subregion_height_align_pixels = 0x40;
|
params.subregion_height_align_pixels = 0x40;
|
||||||
params.subregion_count = 0x10;
|
params.subregion_count = 0x10;
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||||
|
|
||||||
IoctlZbcSetTable params{};
|
IoctlZbcSetTable params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
// TODO(ogniK): What does this even actually do?
|
// TODO(ogniK): What does this even actually do?
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||||
|
|
||||||
IoctlZbcQueryTable params{};
|
IoctlZbcQueryTable params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
// TODO : To implement properly
|
// TODO : To implement properly
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||||
|
|
||||||
IoctlFlushL2 params{};
|
IoctlFlushL2 params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
// TODO : To implement properly
|
// TODO : To implement properly
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called");
|
LOG_DEBUG(Service_NVDRV, "called");
|
||||||
|
|
||||||
IoctlGetGpuTime params{};
|
IoctlGetGpuTime params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count());
|
params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count());
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -16,32 +16,13 @@ public:
|
||||||
explicit nvhost_ctrl_gpu(Core::System& system);
|
explicit nvhost_ctrl_gpu(Core::System& system);
|
||||||
~nvhost_ctrl_gpu() override;
|
~nvhost_ctrl_gpu() override;
|
||||||
|
|
||||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
IoctlVersion version) override;
|
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||||
|
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class IoctlCommand : u32_le {
|
|
||||||
IocGetCharacteristicsCommand = 0xC0B04705,
|
|
||||||
IocGetTPCMasksCommand = 0xC0184706,
|
|
||||||
IocGetActiveSlotMaskCommand = 0x80084714,
|
|
||||||
IocZcullGetCtxSizeCommand = 0x80044701,
|
|
||||||
IocZcullGetInfo = 0x80284702,
|
|
||||||
IocZbcSetTable = 0x402C4703,
|
|
||||||
IocZbcQueryTable = 0xC0344704,
|
|
||||||
IocFlushL2 = 0x40084707,
|
|
||||||
IocInvalICache = 0x4008470D,
|
|
||||||
IocSetMmudebugMode = 0x4008470E,
|
|
||||||
IocSetSmDebugMode = 0x4010470F,
|
|
||||||
IocWaitForPause = 0xC0084710,
|
|
||||||
IocGetTcpExceptionEnStatus = 0x80084711,
|
|
||||||
IocNumVsms = 0x80084712,
|
|
||||||
IocVsmsMapping = 0xC0044713,
|
|
||||||
IocGetErrorChannelUserData = 0xC008471B,
|
|
||||||
IocGetGpuTime = 0xC010471C,
|
|
||||||
IocGetCpuTimeCorrelationInfo = 0xC108471D,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IoctlGpuCharacteristics {
|
struct IoctlGpuCharacteristics {
|
||||||
u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200)
|
u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200)
|
||||||
u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B)
|
u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B)
|
||||||
|
@ -159,17 +140,21 @@ private:
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
|
static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
|
||||||
|
|
||||||
u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
|
NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
std::vector<u8>& output2, IoctlVersion version);
|
NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, std::vector<u8>& output2,
|
std::vector<u8>& inline_output);
|
||||||
IoctlVersion version);
|
|
||||||
u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output);
|
std::vector<u8>& inline_output);
|
||||||
u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
|
|
||||||
u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -23,107 +23,132 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
|
||||||
|
|
||||||
nvhost_gpu::~nvhost_gpu() = default;
|
nvhost_gpu::~nvhost_gpu() = default;
|
||||||
|
|
||||||
u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
switch (command.group) {
|
||||||
IoctlVersion version) {
|
case 0x0:
|
||||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
switch (command.cmd) {
|
||||||
command.raw, input.size(), output.size());
|
case 0x3:
|
||||||
|
return GetWaitbase(input, output);
|
||||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
default:
|
||||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
break;
|
||||||
return SetNVMAPfd(input, output);
|
}
|
||||||
case IoctlCommand::IocSetClientDataCommand:
|
break;
|
||||||
return SetClientData(input, output);
|
case 'H':
|
||||||
case IoctlCommand::IocGetClientDataCommand:
|
switch (command.cmd) {
|
||||||
return GetClientData(input, output);
|
case 0x1:
|
||||||
case IoctlCommand::IocZCullBind:
|
return SetNVMAPfd(input, output);
|
||||||
return ZCullBind(input, output);
|
case 0x3:
|
||||||
case IoctlCommand::IocSetErrorNotifierCommand:
|
return ChannelSetTimeout(input, output);
|
||||||
return SetErrorNotifier(input, output);
|
case 0x8:
|
||||||
case IoctlCommand::IocChannelSetPriorityCommand:
|
return SubmitGPFIFOBase(input, output, false);
|
||||||
return SetChannelPriority(input, output);
|
case 0x9:
|
||||||
case IoctlCommand::IocAllocGPFIFOEx2Command:
|
return AllocateObjectContext(input, output);
|
||||||
return AllocGPFIFOEx2(input, output);
|
case 0xb:
|
||||||
case IoctlCommand::IocAllocObjCtxCommand:
|
return ZCullBind(input, output);
|
||||||
return AllocateObjectContext(input, output);
|
case 0xc:
|
||||||
case IoctlCommand::IocChannelGetWaitbaseCommand:
|
return SetErrorNotifier(input, output);
|
||||||
return GetWaitbase(input, output);
|
case 0xd:
|
||||||
case IoctlCommand::IocChannelSetTimeoutCommand:
|
return SetChannelPriority(input, output);
|
||||||
return ChannelSetTimeout(input, output);
|
case 0x1a:
|
||||||
case IoctlCommand::IocChannelSetTimeslice:
|
return AllocGPFIFOEx2(input, output);
|
||||||
return ChannelSetTimeslice(input, output);
|
case 0x1b:
|
||||||
default:
|
return SubmitGPFIFOBase(input, output, true);
|
||||||
|
case 0x1d:
|
||||||
|
return ChannelSetTimeslice(input, output);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
switch (command.cmd) {
|
||||||
|
case 0x14:
|
||||||
|
return SetClientData(input, output);
|
||||||
|
case 0x15:
|
||||||
|
return GetClientData(input, output);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
if (command.group == NVGPU_IOCTL_MAGIC) {
|
return NvResult::NotImplemented;
|
||||||
if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) {
|
|
||||||
return SubmitGPFIFO(input, output);
|
|
||||||
}
|
|
||||||
if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) {
|
|
||||||
return KickoffPB(input, output, input2, version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
|
||||||
return 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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{};
|
IoctlSetNvmapFD params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||||
|
|
||||||
nvmap_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");
|
LOG_DEBUG(Service_NVDRV, "called");
|
||||||
|
|
||||||
IoctlClientData params{};
|
IoctlClientData params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
user_data = params.data;
|
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");
|
LOG_DEBUG(Service_NVDRV, "called");
|
||||||
|
|
||||||
IoctlClientData params{};
|
IoctlClientData params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
params.data = user_data;
|
params.data = user_data;
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
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());
|
std::memcpy(&zcull_params, input.data(), input.size());
|
||||||
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
|
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
|
||||||
zcull_params.mode);
|
zcull_params.mode);
|
||||||
|
|
||||||
std::memcpy(output.data(), &zcull_params, output.size());
|
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{};
|
IoctlSetErrorNotifier params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
|
||||||
params.size, params.mem);
|
params.size, params.mem);
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
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());
|
std::memcpy(&channel_priority, input.data(), input.size());
|
||||||
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
|
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{};
|
IoctlAllocGpfifoEx2 params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
LOG_WARNING(Service_NVDRV,
|
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;
|
params.fence_out = channel_fence;
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
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{};
|
IoctlAllocObjCtx params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
|
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;
|
params.obj_id = 0x0;
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) {
|
static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) {
|
||||||
|
@ -192,8 +217,8 @@ static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence
|
||||||
return result;
|
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) {
|
Tegra::CommandList&& entries) {
|
||||||
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
|
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
|
||||||
params.num_entries, params.flags.raw);
|
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));
|
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)) {
|
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
|
return NvResult::InvalidSize;
|
||||||
}
|
}
|
||||||
IoctlSubmitGpfifo params{};
|
IoctlSubmitGpfifo params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
||||||
|
|
||||||
Tegra::CommandList entries(params.num_entries);
|
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));
|
if (kickoff) {
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
system.Memory().ReadBlock(params.address, entries.command_lists.data(),
|
system.Memory().ReadBlock(params.address, entries.command_lists.data(),
|
||||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
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));
|
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{};
|
IoctlGetWaitbase params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||||
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
||||||
|
|
||||||
params.value = 0; // Seems to be hard coded at 0
|
params.value = 0; // Seems to be hard coded at 0
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
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{};
|
IoctlChannelSetTimeout params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout));
|
std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout));
|
||||||
LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
|
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{};
|
IoctlSetTimeslice params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice));
|
std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice));
|
||||||
LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
|
LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
|
||||||
|
|
||||||
channel_timeslice = params.timeslice;
|
channel_timeslice = params.timeslice;
|
||||||
|
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -20,43 +20,19 @@ class SyncpointManager;
|
||||||
namespace Service::Nvidia::Devices {
|
namespace Service::Nvidia::Devices {
|
||||||
|
|
||||||
class nvmap;
|
class nvmap;
|
||||||
constexpr u32 NVGPU_IOCTL_MAGIC('H');
|
|
||||||
constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8);
|
|
||||||
constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
|
|
||||||
|
|
||||||
class nvhost_gpu final : public nvdevice {
|
class nvhost_gpu final : public nvdevice {
|
||||||
public:
|
public:
|
||||||
explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
|
explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
|
||||||
SyncpointManager& syncpoint_manager);
|
SyncpointManager& syncpoint_manager);
|
||||||
~nvhost_gpu() override;
|
~nvhost_gpu() override;
|
||||||
|
|
||||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
IoctlVersion version) override;
|
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||||
|
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class IoctlCommand : u32_le {
|
|
||||||
IocSetNVMAPfdCommand = 0x40044801,
|
|
||||||
IocAllocGPFIFOCommand = 0x40084805,
|
|
||||||
IocSetClientDataCommand = 0x40084714,
|
|
||||||
IocGetClientDataCommand = 0x80084715,
|
|
||||||
IocZCullBind = 0xc010480b,
|
|
||||||
IocSetErrorNotifierCommand = 0xC018480C,
|
|
||||||
IocChannelSetPriorityCommand = 0x4004480D,
|
|
||||||
IocEnableCommand = 0x0000480E,
|
|
||||||
IocDisableCommand = 0x0000480F,
|
|
||||||
IocPreemptCommand = 0x00004810,
|
|
||||||
IocForceResetCommand = 0x00004811,
|
|
||||||
IocEventIdControlCommand = 0x40084812,
|
|
||||||
IocGetErrorNotificationCommand = 0xC0104817,
|
|
||||||
IocAllocGPFIFOExCommand = 0x40204818,
|
|
||||||
IocAllocGPFIFOEx2Command = 0xC020481A,
|
|
||||||
IocAllocObjCtxCommand = 0xC0104809,
|
|
||||||
IocChannelGetWaitbaseCommand = 0xC0080003,
|
|
||||||
IocChannelSetTimeoutCommand = 0x40044803,
|
|
||||||
IocChannelSetTimeslice = 0xC004481D,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class CtxObjects : u32_le {
|
enum class CtxObjects : u32_le {
|
||||||
Ctx2D = 0x902D,
|
Ctx2D = 0x902D,
|
||||||
Ctx3D = 0xB197,
|
Ctx3D = 0xB197,
|
||||||
|
@ -67,63 +43,63 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IoctlSetNvmapFD {
|
struct IoctlSetNvmapFD {
|
||||||
u32_le nvmap_fd;
|
s32_le nvmap_fd{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
||||||
|
|
||||||
struct IoctlChannelSetTimeout {
|
struct IoctlChannelSetTimeout {
|
||||||
u32_le timeout;
|
u32_le timeout{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size");
|
static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size");
|
||||||
|
|
||||||
struct IoctlAllocGPFIFO {
|
struct IoctlAllocGPFIFO {
|
||||||
u32_le num_entries;
|
u32_le num_entries{};
|
||||||
u32_le flags;
|
u32_le flags{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size");
|
static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size");
|
||||||
|
|
||||||
struct IoctlClientData {
|
struct IoctlClientData {
|
||||||
u64_le data;
|
u64_le data{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size");
|
static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size");
|
||||||
|
|
||||||
struct IoctlZCullBind {
|
struct IoctlZCullBind {
|
||||||
u64_le gpu_va;
|
u64_le gpu_va{};
|
||||||
u32_le mode; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf
|
u32_le mode{}; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(1);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size");
|
static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size");
|
||||||
|
|
||||||
struct IoctlSetErrorNotifier {
|
struct IoctlSetErrorNotifier {
|
||||||
u64_le offset;
|
u64_le offset{};
|
||||||
u64_le size;
|
u64_le size{};
|
||||||
u32_le mem; // nvmap object handle
|
u32_le mem{}; // nvmap object handle
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(1);
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size");
|
static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size");
|
||||||
|
|
||||||
struct IoctlChannelSetPriority {
|
struct IoctlChannelSetPriority {
|
||||||
u32_le priority;
|
u32_le priority{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlChannelSetPriority) == 4,
|
static_assert(sizeof(IoctlChannelSetPriority) == 4,
|
||||||
"IoctlChannelSetPriority is incorrect size");
|
"IoctlChannelSetPriority is incorrect size");
|
||||||
|
|
||||||
struct IoctlSetTimeslice {
|
struct IoctlSetTimeslice {
|
||||||
u32_le timeslice;
|
u32_le timeslice{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size");
|
static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size");
|
||||||
|
|
||||||
struct IoctlEventIdControl {
|
struct IoctlEventIdControl {
|
||||||
u32_le cmd; // 0=disable, 1=enable, 2=clear
|
u32_le cmd{}; // 0=disable, 1=enable, 2=clear
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size");
|
static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size");
|
||||||
|
|
||||||
struct IoctlGetErrorNotification {
|
struct IoctlGetErrorNotification {
|
||||||
u64_le timestamp;
|
u64_le timestamp{};
|
||||||
u32_le info32;
|
u32_le info32{};
|
||||||
u16_le info16;
|
u16_le info16{};
|
||||||
u16_le status; // always 0xFFFF
|
u16_le status{}; // always 0xFFFF
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlGetErrorNotification) == 16,
|
static_assert(sizeof(IoctlGetErrorNotification) == 16,
|
||||||
"IoctlGetErrorNotification is incorrect size");
|
"IoctlGetErrorNotification is incorrect size");
|
||||||
|
@ -131,39 +107,39 @@ private:
|
||||||
static_assert(sizeof(Fence) == 8, "Fence is incorrect size");
|
static_assert(sizeof(Fence) == 8, "Fence is incorrect size");
|
||||||
|
|
||||||
struct IoctlAllocGpfifoEx {
|
struct IoctlAllocGpfifoEx {
|
||||||
u32_le num_entries;
|
u32_le num_entries{};
|
||||||
u32_le flags;
|
u32_le flags{};
|
||||||
u32_le unk0;
|
u32_le unk0{};
|
||||||
u32_le unk1;
|
u32_le unk1{};
|
||||||
u32_le unk2;
|
u32_le unk2{};
|
||||||
u32_le unk3;
|
u32_le unk3{};
|
||||||
u32_le unk4;
|
u32_le unk4{};
|
||||||
u32_le unk5;
|
u32_le unk5{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");
|
static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");
|
||||||
|
|
||||||
struct IoctlAllocGpfifoEx2 {
|
struct IoctlAllocGpfifoEx2 {
|
||||||
u32_le num_entries; // in
|
u32_le num_entries{}; // in
|
||||||
u32_le flags; // in
|
u32_le flags{}; // in
|
||||||
u32_le unk0; // in (1 works)
|
u32_le unk0{}; // in (1 works)
|
||||||
Fence fence_out; // out
|
Fence fence_out{}; // out
|
||||||
u32_le unk1; // in
|
u32_le unk1{}; // in
|
||||||
u32_le unk2; // in
|
u32_le unk2{}; // in
|
||||||
u32_le unk3; // in
|
u32_le unk3{}; // in
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size");
|
static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size");
|
||||||
|
|
||||||
struct IoctlAllocObjCtx {
|
struct IoctlAllocObjCtx {
|
||||||
u32_le class_num; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA,
|
u32_le class_num{}; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA,
|
||||||
// 0xB06F=channel_gpfifo
|
// 0xB06F=channel_gpfifo
|
||||||
u32_le flags;
|
u32_le flags{};
|
||||||
u64_le obj_id; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported
|
u64_le obj_id{}; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size");
|
static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size");
|
||||||
|
|
||||||
struct IoctlSubmitGpfifo {
|
struct IoctlSubmitGpfifo {
|
||||||
u64_le address; // pointer to gpfifo entry structs
|
u64_le address{}; // pointer to gpfifo entry structs
|
||||||
u32_le num_entries; // number of fence objects being submitted
|
u32_le num_entries{}; // number of fence objects being submitted
|
||||||
union {
|
union {
|
||||||
u32_le raw;
|
u32_le raw;
|
||||||
BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list
|
BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list
|
||||||
|
@ -172,7 +148,7 @@ private:
|
||||||
BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt
|
BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt
|
||||||
BitField<8, 1, u32_le> increment; // increment the returned fence
|
BitField<8, 1, u32_le> increment; // increment the returned fence
|
||||||
} flags;
|
} flags;
|
||||||
Fence fence_out; // returned new fence object for others to wait on
|
Fence fence_out{}; // returned new fence object for others to wait on
|
||||||
|
|
||||||
u32 AddIncrementValue() const {
|
u32 AddIncrementValue() const {
|
||||||
return flags.add_increment.Value() << 1;
|
return flags.add_increment.Value() << 1;
|
||||||
|
@ -182,33 +158,34 @@ private:
|
||||||
"IoctlSubmitGpfifo is incorrect size");
|
"IoctlSubmitGpfifo is incorrect size");
|
||||||
|
|
||||||
struct IoctlGetWaitbase {
|
struct IoctlGetWaitbase {
|
||||||
u32 unknown; // seems to be ignored? Nintendo added this
|
u32 unknown{}; // seems to be ignored? Nintendo added this
|
||||||
u32 value;
|
u32 value{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size");
|
static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size");
|
||||||
|
|
||||||
u32_le nvmap_fd{};
|
s32_le nvmap_fd{};
|
||||||
u64_le user_data{};
|
u64_le user_data{};
|
||||||
IoctlZCullBind zcull_params{};
|
IoctlZCullBind zcull_params{};
|
||||||
u32_le channel_priority{};
|
u32_le channel_priority{};
|
||||||
u32_le channel_timeslice{};
|
u32_le channel_timeslice{};
|
||||||
|
|
||||||
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 GetClientData(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 ZCullBind(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
|
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
|
||||||
Tegra::CommandList&& entries);
|
Tegra::CommandList&& entries);
|
||||||
u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output,
|
bool kickoff = false);
|
||||||
const std::vector<u8>& input2, IoctlVersion version);
|
NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline,
|
||||||
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
|
std::vector<u8>& output);
|
||||||
u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
|
||||||
std::shared_ptr<nvmap> nvmap_dev;
|
std::shared_ptr<nvmap> nvmap_dev;
|
||||||
SyncpointManager& syncpoint_manager;
|
SyncpointManager& syncpoint_manager;
|
||||||
|
|
|
@ -15,46 +15,58 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_de
|
||||||
: nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
|
: nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
|
||||||
nvhost_nvdec::~nvhost_nvdec() = default;
|
nvhost_nvdec::~nvhost_nvdec() = default;
|
||||||
|
|
||||||
u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
std::vector<u8>& output) {
|
||||||
IoctlVersion version) {
|
switch (command.group) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
case 0x0:
|
||||||
command.raw, input.size(), output.size());
|
switch (command.cmd) {
|
||||||
|
case 0x1:
|
||||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
return Submit(input, output);
|
||||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
case 0x2:
|
||||||
return SetNVMAPfd(input);
|
return GetSyncpoint(input, output);
|
||||||
case IoctlCommand::IocSubmit:
|
case 0x3:
|
||||||
return Submit(input, output);
|
return GetWaitbase(input, output);
|
||||||
case IoctlCommand::IocGetSyncpoint:
|
case 0x7:
|
||||||
return GetSyncpoint(input, output);
|
return SetSubmitTimeout(input, output);
|
||||||
case IoctlCommand::IocGetWaitbase:
|
case 0x9:
|
||||||
return GetWaitbase(input, output);
|
return MapBuffer(input, output);
|
||||||
case IoctlCommand::IocMapBuffer:
|
case 0xa: {
|
||||||
case IoctlCommand::IocMapBuffer2:
|
if (command.length == 0x1c) {
|
||||||
case IoctlCommand::IocMapBuffer3:
|
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
|
||||||
case IoctlCommand::IocMapBufferEx:
|
Tegra::ChCommandHeaderList cmdlist(1);
|
||||||
return MapBuffer(input, output);
|
cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
|
||||||
case IoctlCommand::IocUnmapBufferEx: {
|
system.GPU().PushCommandBuffer(cmdlist);
|
||||||
// This command is sent when the video stream has ended, flush all video contexts
|
}
|
||||||
// This is usually sent in the folowing order: vic, nvdec, vic.
|
return UnmapBuffer(input, output);
|
||||||
// Inform the GPU to clear any remaining nvdec buffers when this is detected.
|
}
|
||||||
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
|
default:
|
||||||
Tegra::ChCommandHeaderList cmdlist(1);
|
break;
|
||||||
cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
|
}
|
||||||
system.GPU().PushCommandBuffer(cmdlist);
|
break;
|
||||||
[[fallthrough]]; // fallthrough to unmap buffers
|
case 'H':
|
||||||
};
|
switch (command.cmd) {
|
||||||
case IoctlCommand::IocUnmapBuffer:
|
case 0x1:
|
||||||
case IoctlCommand::IocUnmapBuffer2:
|
return SetNVMAPfd(input);
|
||||||
case IoctlCommand::IocUnmapBuffer3:
|
default:
|
||||||
return UnmapBuffer(input, output);
|
break;
|
||||||
case IoctlCommand::IocSetSubmitTimeout:
|
}
|
||||||
return SetSubmitTimeout(input, output);
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw);
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
return 0;
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_nvdec::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;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -14,26 +14,11 @@ public:
|
||||||
explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||||
~nvhost_nvdec() override;
|
~nvhost_nvdec() override;
|
||||||
|
|
||||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
IoctlVersion version) override;
|
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||||
|
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
private:
|
std::vector<u8>& inline_output) override;
|
||||||
enum class IoctlCommand : u32_le {
|
|
||||||
IocSetNVMAPfdCommand = 0x40044801,
|
|
||||||
IocSubmit = 0xC0400001,
|
|
||||||
IocGetSyncpoint = 0xC0080002,
|
|
||||||
IocGetWaitbase = 0xC0080003,
|
|
||||||
IocMapBuffer = 0xC01C0009,
|
|
||||||
IocMapBuffer2 = 0xC16C0009,
|
|
||||||
IocMapBuffer3 = 0xC15C0009,
|
|
||||||
IocMapBufferEx = 0xC0A40009,
|
|
||||||
IocUnmapBuffer = 0xC0A4000A,
|
|
||||||
IocUnmapBuffer2 = 0xC16C000A,
|
|
||||||
IocUnmapBufferEx = 0xC01C000A,
|
|
||||||
IocUnmapBuffer3 = 0xC15C000A,
|
|
||||||
IocSetSubmitTimeout = 0x40040007,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -36,26 +36,20 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
namespace NvErrCodes {
|
|
||||||
constexpr u32 Success{};
|
|
||||||
[[maybe_unused]] constexpr u32 OutOfMemory{static_cast<u32>(-12)};
|
|
||||||
constexpr u32 InvalidInput{static_cast<u32>(-22)};
|
|
||||||
} // namespace NvErrCodes
|
|
||||||
|
|
||||||
nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
|
nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
|
||||||
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
: nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
|
||||||
nvhost_nvdec_common::~nvhost_nvdec_common() = default;
|
nvhost_nvdec_common::~nvhost_nvdec_common() = default;
|
||||||
|
|
||||||
u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
|
NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
|
||||||
IoctlSetNvmapFD params{};
|
IoctlSetNvmapFD params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD));
|
std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD));
|
||||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||||
|
|
||||||
nvmap_fd = params.nvmap_fd;
|
nvmap_fd = params.nvmap_fd;
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlSubmit params{};
|
IoctlSubmit params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit));
|
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit));
|
||||||
LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
|
LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
|
||||||
|
@ -83,12 +77,12 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o
|
||||||
|
|
||||||
for (const auto& cmd_buffer : command_buffers) {
|
for (const auto& cmd_buffer : command_buffers) {
|
||||||
auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
|
auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
|
||||||
ASSERT_OR_EXECUTE(object, return NvErrCodes::InvalidInput;);
|
ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
|
||||||
const auto map = FindBufferMap(object->dma_map_addr);
|
const auto map = FindBufferMap(object->dma_map_addr);
|
||||||
if (!map) {
|
if (!map) {
|
||||||
LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",
|
LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",
|
||||||
object->addr, object->dma_map_addr);
|
object->addr, object->dma_map_addr);
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
|
Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
|
||||||
gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(),
|
gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(),
|
||||||
|
@ -105,10 +99,10 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o
|
||||||
offset = WriteVectors(output, syncpt_increments, offset);
|
offset = WriteVectors(output, syncpt_increments, offset);
|
||||||
offset = WriteVectors(output, wait_checks, offset);
|
offset = WriteVectors(output, wait_checks, offset);
|
||||||
|
|
||||||
return NvErrCodes::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlGetSyncpoint params{};
|
IoctlGetSyncpoint params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint));
|
std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint));
|
||||||
LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
|
LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
|
||||||
|
@ -118,18 +112,18 @@ u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<
|
||||||
params.value = 0;
|
params.value = 0;
|
||||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint));
|
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint));
|
||||||
|
|
||||||
return NvErrCodes::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlGetWaitbase params{};
|
IoctlGetWaitbase params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||||
params.value = 0; // Seems to be hard coded at 0
|
params.value = 0; // Seems to be hard coded at 0
|
||||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase));
|
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase));
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlMapBuffer params{};
|
IoctlMapBuffer params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||||
|
@ -143,7 +137,7 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>
|
||||||
if (!object) {
|
if (!object) {
|
||||||
LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
|
LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return NvErrCodes::InvalidInput;
|
return NvResult::InvalidState;
|
||||||
}
|
}
|
||||||
if (object->dma_map_addr == 0) {
|
if (object->dma_map_addr == 0) {
|
||||||
// NVDEC and VIC memory is in the 32-bit address space
|
// NVDEC and VIC memory is in the 32-bit address space
|
||||||
|
@ -165,10 +159,10 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>
|
||||||
std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
|
std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
|
||||||
cmd_buffer_handles.size() * sizeof(MapBufferEntry));
|
cmd_buffer_handles.size() * sizeof(MapBufferEntry));
|
||||||
|
|
||||||
return NvErrCodes::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlMapBuffer params{};
|
IoctlMapBuffer params{};
|
||||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||||
|
@ -181,7 +175,7 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u
|
||||||
if (!object) {
|
if (!object) {
|
||||||
LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
|
LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
|
||||||
std::memcpy(output.data(), ¶ms, output.size());
|
std::memcpy(output.data(), ¶ms, output.size());
|
||||||
return NvErrCodes::InvalidInput;
|
return NvResult::InvalidState;
|
||||||
}
|
}
|
||||||
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
|
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
|
||||||
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
|
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
|
||||||
|
@ -193,13 +187,14 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u
|
||||||
object->dma_map_addr = 0;
|
object->dma_map_addr = 0;
|
||||||
}
|
}
|
||||||
std::memset(output.data(), 0, output.size());
|
std::memset(output.data(), 0, output.size());
|
||||||
return NvErrCodes::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input,
|
||||||
|
std::vector<u8>& output) {
|
||||||
std::memcpy(&submit_timeout, input.data(), input.size());
|
std::memcpy(&submit_timeout, input.data(), input.size());
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||||
return NvErrCodes::Success;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap(
|
std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap(
|
||||||
|
|
|
@ -18,9 +18,12 @@ public:
|
||||||
explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||||
~nvhost_nvdec_common() override;
|
~nvhost_nvdec_common() override;
|
||||||
|
|
||||||
virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
std::vector<u8>& output) = 0;
|
||||||
IoctlVersion version) = 0;
|
virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;
|
||||||
|
virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class BufferMap final {
|
class BufferMap final {
|
||||||
|
@ -63,102 +66,102 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IoctlSetNvmapFD {
|
struct IoctlSetNvmapFD {
|
||||||
u32_le nvmap_fd;
|
s32_le nvmap_fd{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
||||||
|
|
||||||
struct IoctlSubmitCommandBuffer {
|
struct IoctlSubmitCommandBuffer {
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
u32_le offset;
|
u32_le offset{};
|
||||||
u32_le count;
|
u32_le count{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
|
static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
|
||||||
"IoctlSubmitCommandBuffer is incorrect size");
|
"IoctlSubmitCommandBuffer is incorrect size");
|
||||||
struct IoctlSubmit {
|
struct IoctlSubmit {
|
||||||
u32_le cmd_buffer_count;
|
u32_le cmd_buffer_count{};
|
||||||
u32_le relocation_count;
|
u32_le relocation_count{};
|
||||||
u32_le syncpoint_count;
|
u32_le syncpoint_count{};
|
||||||
u32_le fence_count;
|
u32_le fence_count{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size");
|
static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size");
|
||||||
|
|
||||||
struct CommandBuffer {
|
struct CommandBuffer {
|
||||||
s32 memory_id;
|
s32 memory_id{};
|
||||||
u32 offset;
|
u32 offset{};
|
||||||
s32 word_count;
|
s32 word_count{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size");
|
static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size");
|
||||||
|
|
||||||
struct Reloc {
|
struct Reloc {
|
||||||
s32 cmdbuffer_memory;
|
s32 cmdbuffer_memory{};
|
||||||
s32 cmdbuffer_offset;
|
s32 cmdbuffer_offset{};
|
||||||
s32 target;
|
s32 target{};
|
||||||
s32 target_offset;
|
s32 target_offset{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");
|
static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");
|
||||||
|
|
||||||
struct SyncptIncr {
|
struct SyncptIncr {
|
||||||
u32 id;
|
u32 id{};
|
||||||
u32 increments;
|
u32 increments{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");
|
static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");
|
||||||
|
|
||||||
struct Fence {
|
struct Fence {
|
||||||
u32 id;
|
u32 id{};
|
||||||
u32 value;
|
u32 value{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");
|
static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");
|
||||||
|
|
||||||
struct IoctlGetSyncpoint {
|
struct IoctlGetSyncpoint {
|
||||||
// Input
|
// Input
|
||||||
u32_le param;
|
u32_le param{};
|
||||||
// Output
|
// Output
|
||||||
u32_le value;
|
u32_le value{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size");
|
static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size");
|
||||||
|
|
||||||
struct IoctlGetWaitbase {
|
struct IoctlGetWaitbase {
|
||||||
u32_le unknown; // seems to be ignored? Nintendo added this
|
u32_le unknown{}; // seems to be ignored? Nintendo added this
|
||||||
u32_le value;
|
u32_le value{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
|
static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
|
||||||
|
|
||||||
struct IoctlMapBuffer {
|
struct IoctlMapBuffer {
|
||||||
u32_le num_entries;
|
u32_le num_entries{};
|
||||||
u32_le data_address; // Ignored by the driver.
|
u32_le data_address{}; // Ignored by the driver.
|
||||||
u32_le attach_host_ch_das;
|
u32_le attach_host_ch_das{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
|
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
|
||||||
|
|
||||||
struct IocGetIdParams {
|
struct IocGetIdParams {
|
||||||
// Input
|
// Input
|
||||||
u32_le param;
|
u32_le param{};
|
||||||
// Output
|
// Output
|
||||||
u32_le value;
|
u32_le value{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
|
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
|
||||||
|
|
||||||
// Used for mapping and unmapping command buffers
|
// Used for mapping and unmapping command buffers
|
||||||
struct MapBufferEntry {
|
struct MapBufferEntry {
|
||||||
u32_le map_handle;
|
u32_le map_handle{};
|
||||||
u32_le map_address;
|
u32_le map_address{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
|
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
|
||||||
|
|
||||||
/// Ioctl command implementations
|
/// Ioctl command implementations
|
||||||
u32 SetNVMAPfd(const std::vector<u8>& input);
|
NvResult SetNVMAPfd(const std::vector<u8>& input);
|
||||||
u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
|
|
||||||
std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
|
std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
|
||||||
void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
|
void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
|
||||||
std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
|
std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
|
||||||
|
|
||||||
u32_le nvmap_fd{};
|
s32_le nvmap_fd{};
|
||||||
u32_le submit_timeout{};
|
u32_le submit_timeout{};
|
||||||
std::shared_ptr<nvmap> nvmap_dev;
|
std::shared_ptr<nvmap> nvmap_dev;
|
||||||
|
|
||||||
|
|
|
@ -13,28 +13,43 @@ namespace Service::Nvidia::Devices {
|
||||||
nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
|
nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
|
||||||
nvhost_nvjpg::~nvhost_nvjpg() = default;
|
nvhost_nvjpg::~nvhost_nvjpg() = default;
|
||||||
|
|
||||||
u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input,
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
std::vector<u8>& output) {
|
||||||
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)) {
|
switch (command.group) {
|
||||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
case 'H':
|
||||||
return SetNVMAPfd(input, output);
|
switch (command.cmd) {
|
||||||
|
case 0x1:
|
||||||
|
return SetNVMAPfd(input, output);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
return 0;
|
return NvResult::NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_nvjpg::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_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IoctlSetNvmapFD params{};
|
IoctlSetNvmapFD params{};
|
||||||
std::memcpy(¶ms, input.data(), input.size());
|
std::memcpy(¶ms, input.data(), input.size());
|
||||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||||
|
|
||||||
nvmap_fd = params.nvmap_fd;
|
nvmap_fd = params.nvmap_fd;
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -16,23 +16,21 @@ public:
|
||||||
explicit nvhost_nvjpg(Core::System& system);
|
explicit nvhost_nvjpg(Core::System& system);
|
||||||
~nvhost_nvjpg() override;
|
~nvhost_nvjpg() override;
|
||||||
|
|
||||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
IoctlVersion version) override;
|
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||||
|
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class IoctlCommand : u32_le {
|
|
||||||
IocSetNVMAPfdCommand = 0x40044801,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IoctlSetNvmapFD {
|
struct IoctlSetNvmapFD {
|
||||||
u32_le nvmap_fd;
|
s32_le nvmap_fd{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
||||||
|
|
||||||
u32_le nvmap_fd{};
|
s32_le nvmap_fd{};
|
||||||
|
|
||||||
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -15,36 +15,43 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
|
||||||
|
|
||||||
nvhost_vic::~nvhost_vic() = default;
|
nvhost_vic::~nvhost_vic() = default;
|
||||||
|
|
||||||
u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
switch (command.group) {
|
||||||
IoctlVersion version) {
|
case 0x0:
|
||||||
LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
switch (command.cmd) {
|
||||||
command.raw, input.size(), output.size());
|
case 0x1:
|
||||||
|
return Submit(input, output);
|
||||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
case 0x2:
|
||||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
return GetSyncpoint(input, output);
|
||||||
return SetNVMAPfd(input);
|
case 0x3:
|
||||||
case IoctlCommand::IocSubmit:
|
return GetWaitbase(input, output);
|
||||||
return Submit(input, output);
|
case 0x9:
|
||||||
case IoctlCommand::IocGetSyncpoint:
|
return MapBuffer(input, output);
|
||||||
return GetSyncpoint(input, output);
|
case 0xa:
|
||||||
case IoctlCommand::IocGetWaitbase:
|
return UnmapBuffer(input, output);
|
||||||
return GetWaitbase(input, output);
|
}
|
||||||
case IoctlCommand::IocMapBuffer:
|
case 'H':
|
||||||
case IoctlCommand::IocMapBuffer2:
|
switch (command.cmd) {
|
||||||
case IoctlCommand::IocMapBuffer3:
|
case 0x1:
|
||||||
case IoctlCommand::IocMapBuffer4:
|
return SetNVMAPfd(input);
|
||||||
case IoctlCommand::IocMapBufferEx:
|
}
|
||||||
return MapBuffer(input, output);
|
break;
|
||||||
case IoctlCommand::IocUnmapBuffer:
|
|
||||||
case IoctlCommand::IocUnmapBuffer2:
|
|
||||||
case IoctlCommand::IocUnmapBuffer3:
|
|
||||||
case IoctlCommand::IocUnmapBufferEx:
|
|
||||||
return UnmapBuffer(input, output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw);
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
return 0;
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvhost_vic::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;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -13,25 +13,11 @@ class nvhost_vic final : public nvhost_nvdec_common {
|
||||||
public:
|
public:
|
||||||
explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
|
||||||
~nvhost_vic();
|
~nvhost_vic();
|
||||||
u32 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) override;
|
|
||||||
|
|
||||||
private:
|
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||||
enum class IoctlCommand : u32_le {
|
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
IocSetNVMAPfdCommand = 0x40044801,
|
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||||
IocSubmit = 0xC0400001,
|
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
IocGetSyncpoint = 0xC0080002,
|
std::vector<u8>& inline_output) override;
|
||||||
IocGetWaitbase = 0xC0080003,
|
|
||||||
IocMapBuffer = 0xC01C0009,
|
|
||||||
IocMapBuffer2 = 0xC0340009,
|
|
||||||
IocMapBuffer3 = 0xC0140009,
|
|
||||||
IocMapBuffer4 = 0xC00C0009,
|
|
||||||
IocMapBufferEx = 0xC03C0009,
|
|
||||||
IocUnmapBuffer = 0xC03C000A,
|
|
||||||
IocUnmapBuffer2 = 0xC034000A,
|
|
||||||
IocUnmapBuffer3 = 0xC00C000A,
|
|
||||||
IocUnmapBufferEx = 0xC01C000A,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -11,13 +11,6 @@
|
||||||
|
|
||||||
namespace Service::Nvidia::Devices {
|
namespace Service::Nvidia::Devices {
|
||||||
|
|
||||||
namespace NvErrCodes {
|
|
||||||
enum {
|
|
||||||
OperationNotPermitted = -1,
|
|
||||||
InvalidValue = -22,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
nvmap::nvmap(Core::System& system) : nvdevice(system) {
|
nvmap::nvmap(Core::System& system) : nvdevice(system) {
|
||||||
// Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
|
// Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
|
||||||
// represent this.
|
// represent this.
|
||||||
|
@ -26,6 +19,41 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) {
|
||||||
|
|
||||||
nvmap::~nvmap() = default;
|
nvmap::~nvmap() = default;
|
||||||
|
|
||||||
|
NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
|
switch (command.group) {
|
||||||
|
case 0x1:
|
||||||
|
switch (command.cmd) {
|
||||||
|
case 0x1:
|
||||||
|
return IocCreate(input, output);
|
||||||
|
case 0x3:
|
||||||
|
return IocFromId(input, output);
|
||||||
|
case 0x4:
|
||||||
|
return IocAlloc(input, output);
|
||||||
|
case 0x5:
|
||||||
|
return IocFree(input, output);
|
||||||
|
case 0x9:
|
||||||
|
return IocParam(input, output);
|
||||||
|
case 0xe:
|
||||||
|
return IocGetId(input, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult nvmap::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;
|
||||||
|
}
|
||||||
|
|
||||||
VAddr nvmap::GetObjectAddress(u32 handle) const {
|
VAddr nvmap::GetObjectAddress(u32 handle) const {
|
||||||
auto object = GetObject(handle);
|
auto object = GetObject(handle);
|
||||||
ASSERT(object);
|
ASSERT(object);
|
||||||
|
@ -33,28 +61,6 @@ VAddr nvmap::GetObjectAddress(u32 handle) const {
|
||||||
return object->addr;
|
return object->addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvmap::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) {
|
|
||||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
|
||||||
case IoctlCommand::Create:
|
|
||||||
return IocCreate(input, output);
|
|
||||||
case IoctlCommand::Alloc:
|
|
||||||
return IocAlloc(input, output);
|
|
||||||
case IoctlCommand::GetId:
|
|
||||||
return IocGetId(input, output);
|
|
||||||
case IoctlCommand::FromId:
|
|
||||||
return IocFromId(input, output);
|
|
||||||
case IoctlCommand::Param:
|
|
||||||
return IocParam(input, output);
|
|
||||||
case IoctlCommand::Free:
|
|
||||||
return IocFree(input, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 nvmap::CreateObject(u32 size) {
|
u32 nvmap::CreateObject(u32 size) {
|
||||||
// Create a new nvmap object and obtain a handle to it.
|
// Create a new nvmap object and obtain a handle to it.
|
||||||
auto object = std::make_shared<Object>();
|
auto object = std::make_shared<Object>();
|
||||||
|
@ -70,35 +76,35 @@ u32 nvmap::CreateObject(u32 size) {
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IocCreateParams params;
|
IocCreateParams params;
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
|
LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
|
||||||
|
|
||||||
if (!params.size) {
|
if (!params.size) {
|
||||||
LOG_ERROR(Service_NVDRV, "Size is 0");
|
LOG_ERROR(Service_NVDRV, "Size is 0");
|
||||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
params.handle = CreateObject(params.size);
|
params.handle = CreateObject(params.size);
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IocAllocParams params;
|
IocAllocParams params;
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
|
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
|
||||||
|
|
||||||
if (!params.handle) {
|
if (!params.handle) {
|
||||||
LOG_ERROR(Service_NVDRV, "Handle is 0");
|
LOG_ERROR(Service_NVDRV, "Handle is 0");
|
||||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((params.align - 1) & params.align) {
|
if ((params.align - 1) & params.align) {
|
||||||
LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
|
LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
|
||||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 min_alignment = 0x1000;
|
const u32 min_alignment = 0x1000;
|
||||||
|
@ -109,12 +115,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
auto object = GetObject(params.handle);
|
auto object = GetObject(params.handle);
|
||||||
if (!object) {
|
if (!object) {
|
||||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object->status == Object::Status::Allocated) {
|
if (object->status == Object::Status::Allocated) {
|
||||||
LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
|
LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
|
||||||
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
|
return NvResult::InsufficientMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
object->flags = params.flags;
|
object->flags = params.flags;
|
||||||
|
@ -124,10 +130,10 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
object->status = Object::Status::Allocated;
|
object->status = Object::Status::Allocated;
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IocGetIdParams params;
|
IocGetIdParams params;
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
|
|
||||||
|
@ -135,22 +141,22 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
|
|
||||||
if (!params.handle) {
|
if (!params.handle) {
|
||||||
LOG_ERROR(Service_NVDRV, "Handle is zero");
|
LOG_ERROR(Service_NVDRV, "Handle is zero");
|
||||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto object = GetObject(params.handle);
|
auto object = GetObject(params.handle);
|
||||||
if (!object) {
|
if (!object) {
|
||||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||||
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
params.id = object->id;
|
params.id = object->id;
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
IocFromIdParams params;
|
IocFromIdParams params;
|
||||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||||
|
|
||||||
|
@ -160,13 +166,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
[&](const auto& entry) { return entry.second->id == params.id; });
|
[&](const auto& entry) { return entry.second->id == params.id; });
|
||||||
if (itr == handles.end()) {
|
if (itr == handles.end()) {
|
||||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& object = itr->second;
|
auto& object = itr->second;
|
||||||
if (object->status != Object::Status::Allocated) {
|
if (object->status != Object::Status::Allocated) {
|
||||||
LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
|
LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
|
||||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
itr->second->refcount++;
|
itr->second->refcount++;
|
||||||
|
@ -175,10 +181,10 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
params.handle = itr->first;
|
params.handle = itr->first;
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
|
enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
|
||||||
|
|
||||||
IocParamParams params;
|
IocParamParams params;
|
||||||
|
@ -189,12 +195,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
auto object = GetObject(params.handle);
|
auto object = GetObject(params.handle);
|
||||||
if (!object) {
|
if (!object) {
|
||||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object->status != Object::Status::Allocated) {
|
if (object->status != Object::Status::Allocated) {
|
||||||
LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
|
LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
|
||||||
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (static_cast<ParamTypes>(params.param)) {
|
switch (static_cast<ParamTypes>(params.param)) {
|
||||||
|
@ -216,10 +222,10 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
|
NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
// TODO(Subv): These flags are unconfirmed.
|
// TODO(Subv): These flags are unconfirmed.
|
||||||
enum FreeFlags {
|
enum FreeFlags {
|
||||||
Freed = 0,
|
Freed = 0,
|
||||||
|
@ -234,14 +240,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
auto itr = handles.find(params.handle);
|
auto itr = handles.find(params.handle);
|
||||||
if (itr == handles.end()) {
|
if (itr == handles.end()) {
|
||||||
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
|
||||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
if (!itr->second->refcount) {
|
if (!itr->second->refcount) {
|
||||||
LOG_ERROR(
|
LOG_ERROR(
|
||||||
Service_NVDRV,
|
Service_NVDRV,
|
||||||
"There is no references to this object. The object is already freed. handle={:08X}",
|
"There is no references to this object. The object is already freed. handle={:08X}",
|
||||||
params.handle);
|
params.handle);
|
||||||
return static_cast<u32>(NvErrCodes::InvalidValue);
|
return NvResult::BadValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
itr->second->refcount--;
|
itr->second->refcount--;
|
||||||
|
@ -261,7 +267,7 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||||
handles.erase(params.handle);
|
handles.erase(params.handle);
|
||||||
|
|
||||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||||
return 0;
|
return NvResult::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -19,13 +19,15 @@ public:
|
||||||
explicit nvmap(Core::System& system);
|
explicit nvmap(Core::System& system);
|
||||||
~nvmap() override;
|
~nvmap() override;
|
||||||
|
|
||||||
|
NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||||
|
NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output) override;
|
||||||
|
NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
|
||||||
|
std::vector<u8>& inline_output) override;
|
||||||
|
|
||||||
/// Returns the allocated address of an nvmap object given its handle.
|
/// Returns the allocated address of an nvmap object given its handle.
|
||||||
VAddr GetObjectAddress(u32 handle) const;
|
VAddr GetObjectAddress(u32 handle) const;
|
||||||
|
|
||||||
u32 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) override;
|
|
||||||
|
|
||||||
/// Represents an nvmap object.
|
/// Represents an nvmap object.
|
||||||
struct Object {
|
struct Object {
|
||||||
enum class Status { Created, Allocated };
|
enum class Status { Created, Allocated };
|
||||||
|
@ -58,76 +60,68 @@ private:
|
||||||
/// Mapping of currently allocated handles to the objects they represent.
|
/// Mapping of currently allocated handles to the objects they represent.
|
||||||
std::unordered_map<u32, std::shared_ptr<Object>> handles;
|
std::unordered_map<u32, std::shared_ptr<Object>> handles;
|
||||||
|
|
||||||
enum class IoctlCommand : u32 {
|
|
||||||
Create = 0xC0080101,
|
|
||||||
FromId = 0xC0080103,
|
|
||||||
Alloc = 0xC0200104,
|
|
||||||
Free = 0xC0180105,
|
|
||||||
Param = 0xC00C0109,
|
|
||||||
GetId = 0xC008010E,
|
|
||||||
};
|
|
||||||
struct IocCreateParams {
|
struct IocCreateParams {
|
||||||
// Input
|
// Input
|
||||||
u32_le size;
|
u32_le size{};
|
||||||
// Output
|
// Output
|
||||||
u32_le handle;
|
u32_le handle{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size");
|
static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size");
|
||||||
|
|
||||||
struct IocFromIdParams {
|
struct IocFromIdParams {
|
||||||
// Input
|
// Input
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
// Output
|
// Output
|
||||||
u32_le handle;
|
u32_le handle{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size");
|
static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size");
|
||||||
|
|
||||||
struct IocAllocParams {
|
struct IocAllocParams {
|
||||||
// Input
|
// Input
|
||||||
u32_le handle;
|
u32_le handle{};
|
||||||
u32_le heap_mask;
|
u32_le heap_mask{};
|
||||||
u32_le flags;
|
u32_le flags{};
|
||||||
u32_le align;
|
u32_le align{};
|
||||||
u8 kind;
|
u8 kind{};
|
||||||
INSERT_PADDING_BYTES(7);
|
INSERT_PADDING_BYTES(7);
|
||||||
u64_le addr;
|
u64_le addr{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size");
|
static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size");
|
||||||
|
|
||||||
struct IocFreeParams {
|
struct IocFreeParams {
|
||||||
u32_le handle;
|
u32_le handle{};
|
||||||
INSERT_PADDING_BYTES(4);
|
INSERT_PADDING_BYTES(4);
|
||||||
u64_le address;
|
u64_le address{};
|
||||||
u32_le size;
|
u32_le size{};
|
||||||
u32_le flags;
|
u32_le flags{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size");
|
static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size");
|
||||||
|
|
||||||
struct IocParamParams {
|
struct IocParamParams {
|
||||||
// Input
|
// Input
|
||||||
u32_le handle;
|
u32_le handle{};
|
||||||
u32_le param;
|
u32_le param{};
|
||||||
// Output
|
// Output
|
||||||
u32_le result;
|
u32_le result{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size");
|
static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size");
|
||||||
|
|
||||||
struct IocGetIdParams {
|
struct IocGetIdParams {
|
||||||
// Output
|
// Output
|
||||||
u32_le id;
|
u32_le id{};
|
||||||
// Input
|
// Input
|
||||||
u32_le handle;
|
u32_le handle{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
|
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
|
||||||
|
|
||||||
u32 CreateObject(u32 size);
|
u32 CreateObject(u32 size);
|
||||||
|
|
||||||
u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output);
|
NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Nvidia::Devices
|
} // namespace Service::Nvidia::Devices
|
||||||
|
|
|
@ -23,124 +23,171 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
|
||||||
void NVDRV::Open(Kernel::HLERequestContext& ctx) {
|
void NVDRV::Open(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called");
|
LOG_DEBUG(Service_NVDRV, "called");
|
||||||
|
|
||||||
const auto& buffer = ctx.ReadBuffer();
|
if (!initialized) {
|
||||||
std::string device_name(buffer.begin(), buffer.end());
|
ServiceError(ctx, NvResult::NotInitialized);
|
||||||
|
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& buffer = ctx.ReadBuffer();
|
||||||
|
const std::string device_name(buffer.begin(), buffer.end());
|
||||||
|
DeviceFD fd = nvdrv->Open(device_name);
|
||||||
|
|
||||||
u32 fd = nvdrv->Open(device_name);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u32>(fd);
|
rb.Push<DeviceFD>(fd);
|
||||||
rb.Push<u32>(0);
|
rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) {
|
void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) {
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
u32 fd = rp.Pop<u32>();
|
|
||||||
u32 command = rp.Pop<u32>();
|
|
||||||
|
|
||||||
/// Ioctl 3 has 2 outputs, first in the input params, second is the result
|
|
||||||
std::vector<u8> output(ctx.GetWriteBufferSize(0));
|
|
||||||
std::vector<u8> output2;
|
|
||||||
if (version == IoctlVersion::Version3) {
|
|
||||||
output2.resize((ctx.GetWriteBufferSize(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer.
|
|
||||||
/// KickOfPB uses this
|
|
||||||
auto input = ctx.ReadBuffer(0);
|
|
||||||
|
|
||||||
std::vector<u8> input2;
|
|
||||||
if (version == IoctlVersion::Version2) {
|
|
||||||
input2 = ctx.ReadBuffer(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
IoctlCtrl ctrl{};
|
|
||||||
|
|
||||||
u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version);
|
|
||||||
|
|
||||||
if (ctrl.must_delay) {
|
|
||||||
ctrl.fresh_call = false;
|
|
||||||
ctx.SleepClientThread(
|
|
||||||
"NVServices::DelayedResponse", ctrl.timeout,
|
|
||||||
[=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
|
|
||||||
Kernel::ThreadWakeupReason reason) {
|
|
||||||
IoctlCtrl ctrl2{ctrl};
|
|
||||||
std::vector<u8> tmp_output = output;
|
|
||||||
std::vector<u8> tmp_output2 = output2;
|
|
||||||
const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output,
|
|
||||||
tmp_output2, ctrl2, version);
|
|
||||||
ctx_.WriteBuffer(tmp_output, 0);
|
|
||||||
if (version == IoctlVersion::Version3) {
|
|
||||||
ctx_.WriteBuffer(tmp_output2, 1);
|
|
||||||
}
|
|
||||||
IPC::ResponseBuilder rb{ctx_, 3};
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
|
||||||
rb.Push(ioctl_result);
|
|
||||||
},
|
|
||||||
nvdrv->GetEventWriteable(ctrl.event_id));
|
|
||||||
} else {
|
|
||||||
ctx.WriteBuffer(output);
|
|
||||||
if (version == IoctlVersion::Version3) {
|
|
||||||
ctx.WriteBuffer(output2, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(result);
|
rb.PushEnum(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) {
|
void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called");
|
IPC::RequestParser rp{ctx};
|
||||||
IoctlBase(ctx, IoctlVersion::Version1);
|
const auto fd = rp.Pop<DeviceFD>();
|
||||||
|
const auto command = rp.PopRaw<Ioctl>();
|
||||||
|
LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
ServiceError(ctx, NvResult::NotInitialized);
|
||||||
|
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check device
|
||||||
|
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||||
|
const auto input_buffer = ctx.ReadBuffer(0);
|
||||||
|
|
||||||
|
const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
|
||||||
|
|
||||||
|
if (command.is_out != 0) {
|
||||||
|
ctx.WriteBuffer(output_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushEnum(nv_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
|
void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called");
|
IPC::RequestParser rp{ctx};
|
||||||
IoctlBase(ctx, IoctlVersion::Version2);
|
const auto fd = rp.Pop<DeviceFD>();
|
||||||
|
const auto command = rp.PopRaw<Ioctl>();
|
||||||
|
LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
ServiceError(ctx, NvResult::NotInitialized);
|
||||||
|
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto input_buffer = ctx.ReadBuffer(0);
|
||||||
|
const auto input_inlined_buffer = ctx.ReadBuffer(1);
|
||||||
|
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||||
|
|
||||||
|
const auto nv_result =
|
||||||
|
nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
|
||||||
|
|
||||||
|
if (command.is_out != 0) {
|
||||||
|
ctx.WriteBuffer(output_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushEnum(nv_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
|
void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called");
|
IPC::RequestParser rp{ctx};
|
||||||
IoctlBase(ctx, IoctlVersion::Version3);
|
const auto fd = rp.Pop<DeviceFD>();
|
||||||
|
const auto command = rp.PopRaw<Ioctl>();
|
||||||
|
LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
ServiceError(ctx, NvResult::NotInitialized);
|
||||||
|
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto input_buffer = ctx.ReadBuffer(0);
|
||||||
|
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||||
|
std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1));
|
||||||
|
|
||||||
|
const auto nv_result =
|
||||||
|
nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline);
|
||||||
|
|
||||||
|
if (command.is_out != 0) {
|
||||||
|
ctx.WriteBuffer(output_buffer, 0);
|
||||||
|
ctx.WriteBuffer(output_buffer_inline, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushEnum(nv_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVDRV::Close(Kernel::HLERequestContext& ctx) {
|
void NVDRV::Close(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NVDRV, "called");
|
LOG_DEBUG(Service_NVDRV, "called");
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
ServiceError(ctx, NvResult::NotInitialized);
|
||||||
|
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
u32 fd = rp.Pop<u32>();
|
const auto fd = rp.Pop<DeviceFD>();
|
||||||
|
const auto result = nvdrv->Close(fd);
|
||||||
|
|
||||||
auto result = nvdrv->Close(fd);
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
rb.PushEnum(result);
|
||||||
rb.Push(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
|
void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u32>(0);
|
rb.PushEnum(NvResult::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
|
void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
u32 fd = rp.Pop<u32>();
|
const auto fd = rp.Pop<DeviceFD>();
|
||||||
// TODO(Blinkhawk): Figure the meaning of the flag at bit 16
|
const auto event_id = rp.Pop<u32>() & 0x00FF;
|
||||||
u32 event_id = rp.Pop<u32>() & 0x000000FF;
|
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3, 1};
|
if (!initialized) {
|
||||||
rb.Push(RESULT_SUCCESS);
|
ServiceError(ctx, NvResult::NotInitialized);
|
||||||
|
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nv_result = nvdrv->VerifyFd(fd);
|
||||||
|
|
||||||
|
if (nv_result != NvResult::Success) {
|
||||||
|
LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd);
|
||||||
|
ServiceError(ctx, nv_result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (event_id < MaxNvEvents) {
|
if (event_id < MaxNvEvents) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3, 1};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
auto event = nvdrv->GetEvent(event_id);
|
auto event = nvdrv->GetEvent(event_id);
|
||||||
event->Clear();
|
event->Clear();
|
||||||
rb.PushCopyObjects(event);
|
rb.PushCopyObjects(event);
|
||||||
rb.Push<u32>(NvResult::Success);
|
rb.PushEnum(NvResult::Success);
|
||||||
} else {
|
} else {
|
||||||
rb.Push<u32>(0);
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push<u32>(NvResult::BadParameter);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushEnum(NvResult::BadParameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +198,7 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u32>(0);
|
rb.PushEnum(NvResult::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
|
void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -164,8 +211,9 @@ void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ct
|
||||||
void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
|
void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushEnum(NvResult::Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
|
void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -181,7 +229,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
|
||||||
: ServiceFramework(name), nvdrv(std::move(nvdrv)) {
|
: ServiceFramework(name), nvdrv(std::move(nvdrv)) {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &NVDRV::Open, "Open"},
|
{0, &NVDRV::Open, "Open"},
|
||||||
{1, &NVDRV::Ioctl, "Ioctl"},
|
{1, &NVDRV::Ioctl1, "Ioctl"},
|
||||||
{2, &NVDRV::Close, "Close"},
|
{2, &NVDRV::Close, "Close"},
|
||||||
{3, &NVDRV::Initialize, "Initialize"},
|
{3, &NVDRV::Initialize, "Initialize"},
|
||||||
{4, &NVDRV::QueryEvent, "QueryEvent"},
|
{4, &NVDRV::QueryEvent, "QueryEvent"},
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Open(Kernel::HLERequestContext& ctx);
|
void Open(Kernel::HLERequestContext& ctx);
|
||||||
void Ioctl(Kernel::HLERequestContext& ctx);
|
void Ioctl1(Kernel::HLERequestContext& ctx);
|
||||||
void Ioctl2(Kernel::HLERequestContext& ctx);
|
void Ioctl2(Kernel::HLERequestContext& ctx);
|
||||||
void Ioctl3(Kernel::HLERequestContext& ctx);
|
void Ioctl3(Kernel::HLERequestContext& ctx);
|
||||||
void Close(Kernel::HLERequestContext& ctx);
|
void Close(Kernel::HLERequestContext& ctx);
|
||||||
|
@ -33,11 +33,13 @@ private:
|
||||||
void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);
|
void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);
|
||||||
void GetStatus(Kernel::HLERequestContext& ctx);
|
void GetStatus(Kernel::HLERequestContext& ctx);
|
||||||
void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
|
void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
|
||||||
void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version);
|
|
||||||
|
void ServiceError(Kernel::HLERequestContext& ctx, NvResult result);
|
||||||
|
|
||||||
std::shared_ptr<Module> nvdrv;
|
std::shared_ptr<Module> nvdrv;
|
||||||
|
|
||||||
u64 pid{};
|
u64 pid{};
|
||||||
|
bool initialized{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Nvidia
|
} // namespace Service::Nvidia
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include "common/bit_field.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Service::Nvidia {
|
namespace Service::Nvidia {
|
||||||
|
|
||||||
constexpr u32 MaxSyncPoints = 192;
|
constexpr u32 MaxSyncPoints = 192;
|
||||||
constexpr u32 MaxNvEvents = 64;
|
constexpr u32 MaxNvEvents = 64;
|
||||||
|
using DeviceFD = s32;
|
||||||
|
|
||||||
|
constexpr DeviceFD INVALID_NVDRV_FD = -1;
|
||||||
|
|
||||||
struct Fence {
|
struct Fence {
|
||||||
s32 id;
|
s32 id;
|
||||||
|
@ -20,11 +24,61 @@ struct MultiFence {
|
||||||
std::array<Fence, 4> fences;
|
std::array<Fence, 4> fences;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NvResult : u32 {
|
enum class NvResult : u32 {
|
||||||
Success = 0,
|
Success = 0x0,
|
||||||
BadParameter = 4,
|
NotImplemented = 0x1,
|
||||||
Timeout = 5,
|
NotSupported = 0x2,
|
||||||
ResourceError = 15,
|
NotInitialized = 0x3,
|
||||||
|
BadParameter = 0x4,
|
||||||
|
Timeout = 0x5,
|
||||||
|
InsufficientMemory = 0x6,
|
||||||
|
ReadOnlyAttribute = 0x7,
|
||||||
|
InvalidState = 0x8,
|
||||||
|
InvalidAddress = 0x9,
|
||||||
|
InvalidSize = 0xA,
|
||||||
|
BadValue = 0xB,
|
||||||
|
AlreadyAllocated = 0xD,
|
||||||
|
Busy = 0xE,
|
||||||
|
ResourceError = 0xF,
|
||||||
|
CountMismatch = 0x10,
|
||||||
|
OverFlow = 0x11,
|
||||||
|
InsufficientTransferMemory = 0x1000,
|
||||||
|
InsufficientVideoMemory = 0x10000,
|
||||||
|
BadSurfaceColorScheme = 0x10001,
|
||||||
|
InvalidSurface = 0x10002,
|
||||||
|
SurfaceNotSupported = 0x10003,
|
||||||
|
DispInitFailed = 0x20000,
|
||||||
|
DispAlreadyAttached = 0x20001,
|
||||||
|
DispTooManyDisplays = 0x20002,
|
||||||
|
DispNoDisplaysAttached = 0x20003,
|
||||||
|
DispModeNotSupported = 0x20004,
|
||||||
|
DispNotFound = 0x20005,
|
||||||
|
DispAttachDissallowed = 0x20006,
|
||||||
|
DispTypeNotSupported = 0x20007,
|
||||||
|
DispAuthenticationFailed = 0x20008,
|
||||||
|
DispNotAttached = 0x20009,
|
||||||
|
DispSamePwrState = 0x2000A,
|
||||||
|
DispEdidFailure = 0x2000B,
|
||||||
|
DispDsiReadAckError = 0x2000C,
|
||||||
|
DispDsiReadInvalidResp = 0x2000D,
|
||||||
|
FileWriteFailed = 0x30000,
|
||||||
|
FileReadFailed = 0x30001,
|
||||||
|
EndOfFile = 0x30002,
|
||||||
|
FileOperationFailed = 0x30003,
|
||||||
|
DirOperationFailed = 0x30004,
|
||||||
|
EndOfDirList = 0x30005,
|
||||||
|
ConfigVarNotFound = 0x30006,
|
||||||
|
InvalidConfigVar = 0x30007,
|
||||||
|
LibraryNotFound = 0x30008,
|
||||||
|
SymbolNotFound = 0x30009,
|
||||||
|
MemoryMapFailed = 0x3000A,
|
||||||
|
IoctlFailed = 0x3000F,
|
||||||
|
AccessDenied = 0x30010,
|
||||||
|
DeviceNotFound = 0x30011,
|
||||||
|
KernelDriverNotFound = 0x30012,
|
||||||
|
FileNotFound = 0x30013,
|
||||||
|
PathAlreadyExists = 0x30014,
|
||||||
|
ModuleNotPresent = 0xA000E,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EventState {
|
enum class EventState {
|
||||||
|
@ -34,21 +88,13 @@ enum class EventState {
|
||||||
Busy = 3,
|
Busy = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class IoctlVersion : u32 {
|
union Ioctl {
|
||||||
Version1,
|
u32_le raw;
|
||||||
Version2,
|
BitField<0, 8, u32> cmd;
|
||||||
Version3,
|
BitField<8, 8, u32> group;
|
||||||
};
|
BitField<16, 14, u32> length;
|
||||||
|
BitField<30, 1, u32> is_in;
|
||||||
struct IoctlCtrl {
|
BitField<31, 1, u32> is_out;
|
||||||
// First call done to the servioce for services that call itself again after a call.
|
|
||||||
bool fresh_call{true};
|
|
||||||
// Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep
|
|
||||||
bool must_delay{};
|
|
||||||
// Timeout for the delay
|
|
||||||
s64 timeout{};
|
|
||||||
// NV Event Id
|
|
||||||
s32 event_id{-1};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::Nvidia
|
} // namespace Service::Nvidia
|
||||||
|
|
|
@ -62,36 +62,101 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
|
||||||
|
|
||||||
Module::~Module() = default;
|
Module::~Module() = default;
|
||||||
|
|
||||||
u32 Module::Open(const std::string& device_name) {
|
NvResult Module::VerifyFd(DeviceFD fd) const {
|
||||||
ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}",
|
if (fd < 0) {
|
||||||
device_name);
|
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||||
|
return NvResult::InvalidState;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (open_files.find(fd) == open_files.end()) {
|
||||||
|
LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NvResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceFD Module::Open(const std::string& device_name) {
|
||||||
|
if (devices.find(device_name) == devices.end()) {
|
||||||
|
LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name);
|
||||||
|
return INVALID_NVDRV_FD;
|
||||||
|
}
|
||||||
|
|
||||||
auto device = devices[device_name];
|
auto device = devices[device_name];
|
||||||
const u32 fd = next_fd++;
|
const DeviceFD fd = next_fd++;
|
||||||
|
|
||||||
open_files[fd] = std::move(device);
|
open_files[fd] = std::move(device);
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
std::vector<u8>& output) {
|
||||||
IoctlVersion version) {
|
if (fd < 0) {
|
||||||
auto itr = open_files.find(fd);
|
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||||
ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device");
|
return NvResult::InvalidState;
|
||||||
|
}
|
||||||
|
|
||||||
auto& device = itr->second;
|
auto itr = open_files.find(fd);
|
||||||
return device->ioctl({command}, input, input2, output, output2, ctrl, version);
|
|
||||||
|
if (itr == open_files.end()) {
|
||||||
|
LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
return itr->second->Ioctl1(command, input, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode Module::Close(u32 fd) {
|
NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output) {
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||||
|
return NvResult::InvalidState;
|
||||||
|
}
|
||||||
|
|
||||||
auto itr = open_files.find(fd);
|
auto itr = open_files.find(fd);
|
||||||
ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device");
|
|
||||||
|
if (itr == open_files.end()) {
|
||||||
|
LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
return itr->second->Ioctl2(command, input, inline_input, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||||
|
std::vector<u8>& output, std::vector<u8>& inline_output) {
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||||
|
return NvResult::InvalidState;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto itr = open_files.find(fd);
|
||||||
|
|
||||||
|
if (itr == open_files.end()) {
|
||||||
|
LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
return itr->second->Ioctl3(command, input, output, inline_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
NvResult Module::Close(DeviceFD fd) {
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
|
||||||
|
return NvResult::InvalidState;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto itr = open_files.find(fd);
|
||||||
|
|
||||||
|
if (itr == open_files.end()) {
|
||||||
|
LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
|
||||||
|
return NvResult::NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
open_files.erase(itr);
|
open_files.erase(itr);
|
||||||
|
|
||||||
// TODO(flerovium): return correct result code if operation failed.
|
return NvResult::Success;
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
|
void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
|
||||||
|
|
|
@ -112,14 +112,23 @@ public:
|
||||||
return std::static_pointer_cast<T>(itr->second);
|
return std::static_pointer_cast<T>(itr->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NvResult VerifyFd(DeviceFD fd) const;
|
||||||
|
|
||||||
/// Opens a device node and returns a file descriptor to it.
|
/// Opens a device node and returns a file descriptor to it.
|
||||||
u32 Open(const std::string& device_name);
|
DeviceFD Open(const std::string& device_name);
|
||||||
|
|
||||||
/// Sends an ioctl command to the specified file descriptor.
|
/// Sends an ioctl command to the specified file descriptor.
|
||||||
u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2,
|
NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||||
std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
|
std::vector<u8>& output);
|
||||||
IoctlVersion version);
|
|
||||||
|
NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||||
|
const std::vector<u8>& inline_input, std::vector<u8>& output);
|
||||||
|
|
||||||
|
NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
|
||||||
|
std::vector<u8>& output, std::vector<u8>& inline_output);
|
||||||
|
|
||||||
/// Closes a device file descriptor and returns operation success.
|
/// Closes a device file descriptor and returns operation success.
|
||||||
ResultCode Close(u32 fd);
|
NvResult Close(DeviceFD fd);
|
||||||
|
|
||||||
void SignalSyncpt(const u32 syncpoint_id, const u32 value);
|
void SignalSyncpt(const u32 syncpoint_id, const u32 value);
|
||||||
|
|
||||||
|
@ -132,10 +141,10 @@ private:
|
||||||
SyncpointManager syncpoint_manager;
|
SyncpointManager syncpoint_manager;
|
||||||
|
|
||||||
/// Id to use for the next open file descriptor.
|
/// Id to use for the next open file descriptor.
|
||||||
u32 next_fd = 1;
|
DeviceFD next_fd = 1;
|
||||||
|
|
||||||
/// Mapping of file descriptors to the devices they reference.
|
/// Mapping of file descriptors to the devices they reference.
|
||||||
std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files;
|
std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files;
|
||||||
|
|
||||||
/// Mapping of device node names to their implementation.
|
/// Mapping of device node names to their implementation.
|
||||||
std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
|
std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
|
||||||
|
|
Loading…
Reference in a new issue