Merge pull request #11873 from liamwhite/buffer-control
nvdrv: add ioctl command serialization wrapper
This commit is contained in:
commit
e7f4110791
|
@ -0,0 +1,159 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include "common/concepts.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
|
||||
struct IoctlOneArgTraits {
|
||||
template <typename T, typename R, typename A, typename... B>
|
||||
static A GetFirstArgImpl(R (T::*)(A, B...));
|
||||
};
|
||||
|
||||
struct IoctlTwoArgTraits {
|
||||
template <typename T, typename R, typename A, typename B, typename... C>
|
||||
static A GetFirstArgImpl(R (T::*)(A, B, C...));
|
||||
|
||||
template <typename T, typename R, typename A, typename B, typename... C>
|
||||
static B GetSecondArgImpl(R (T::*)(A, B, C...));
|
||||
};
|
||||
|
||||
struct Null {};
|
||||
|
||||
// clang-format off
|
||||
|
||||
template <typename FixedArg, typename VarArg, typename InlInVarArg, typename InlOutVarArg, typename F>
|
||||
NvResult WrapGeneric(F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, std::span<u8> inline_output) {
|
||||
constexpr bool HasFixedArg = !std::is_same_v<FixedArg, Null>;
|
||||
constexpr bool HasVarArg = !std::is_same_v<VarArg, Null>;
|
||||
constexpr bool HasInlInVarArg = !std::is_same_v<InlInVarArg, Null>;
|
||||
constexpr bool HasInlOutVarArg = !std::is_same_v<InlOutVarArg, Null>;
|
||||
|
||||
// Declare the fixed-size input value.
|
||||
FixedArg fixed{};
|
||||
size_t var_offset = 0;
|
||||
|
||||
if constexpr (HasFixedArg) {
|
||||
// Read the fixed-size input value.
|
||||
var_offset = std::min(sizeof(FixedArg), input.size());
|
||||
if (var_offset > 0) {
|
||||
std::memcpy(&fixed, input.data(), var_offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the variable-sized inputs.
|
||||
const size_t num_var_args = HasVarArg ? ((input.size() - var_offset) / sizeof(VarArg)) : 0;
|
||||
std::vector<VarArg> var_args(num_var_args);
|
||||
if constexpr (HasVarArg) {
|
||||
if (num_var_args > 0) {
|
||||
std::memcpy(var_args.data(), input.data() + var_offset, num_var_args * sizeof(VarArg));
|
||||
}
|
||||
}
|
||||
|
||||
const size_t num_inl_in_var_args = HasInlInVarArg ? (inline_input.size() / sizeof(InlInVarArg)) : 0;
|
||||
std::vector<InlInVarArg> inl_in_var_args(num_inl_in_var_args);
|
||||
if constexpr (HasInlInVarArg) {
|
||||
if (num_inl_in_var_args > 0) {
|
||||
std::memcpy(inl_in_var_args.data(), inline_input.data(), num_inl_in_var_args * sizeof(InlInVarArg));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct inline output data.
|
||||
const size_t num_inl_out_var_args = HasInlOutVarArg ? (inline_output.size() / sizeof(InlOutVarArg)) : 0;
|
||||
std::vector<InlOutVarArg> inl_out_var_args(num_inl_out_var_args);
|
||||
|
||||
// Perform the call.
|
||||
NvResult result = callable(fixed, var_args, inl_in_var_args, inl_out_var_args);
|
||||
|
||||
// Copy outputs.
|
||||
if constexpr (HasFixedArg) {
|
||||
if (output.size() > 0) {
|
||||
std::memcpy(output.data(), &fixed, std::min(output.size(), sizeof(FixedArg)));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (HasVarArg) {
|
||||
if (num_var_args > 0 && output.size() > var_offset) {
|
||||
const size_t max_var_size = output.size() - var_offset;
|
||||
std::memcpy(output.data() + var_offset, var_args.data(), std::min(max_var_size, num_var_args * sizeof(VarArg)));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy inline outputs.
|
||||
if constexpr (HasInlOutVarArg) {
|
||||
if (num_inl_out_var_args > 0) {
|
||||
std::memcpy(inline_output.data(), inl_out_var_args.data(), num_inl_out_var_args * sizeof(InlOutVarArg));
|
||||
}
|
||||
}
|
||||
|
||||
// We're done.
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Self, typename F, typename... Rest>
|
||||
NvResult WrapFixed(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
|
||||
using FixedArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>;
|
||||
|
||||
const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
|
||||
return (self->*callable)(fixed, std::forward<Rest>(rest)...);
|
||||
};
|
||||
|
||||
return WrapGeneric<FixedArg, Null, Null, Null>(std::move(Callable), input, {}, output, {});
|
||||
}
|
||||
|
||||
template <typename Self, typename F, typename... Rest>
|
||||
NvResult WrapFixedInlOut(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output, Rest&&... rest) {
|
||||
using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
|
||||
using InlOutVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
|
||||
|
||||
const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
|
||||
return (self->*callable)(fixed, inl_out, std::forward<Rest>(rest)...);
|
||||
};
|
||||
|
||||
return WrapGeneric<FixedArg, Null, Null, InlOutVarArg>(std::move(Callable), input, {}, output, inline_output);
|
||||
}
|
||||
|
||||
template <typename Self, typename F, typename... Rest>
|
||||
NvResult WrapVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
|
||||
using VarArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>::value_type;
|
||||
|
||||
const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
|
||||
return (self->*callable)(var, std::forward<Rest>(rest)...);
|
||||
};
|
||||
|
||||
return WrapGeneric<Null, VarArg, Null, Null>(std::move(Callable), input, {}, output, {});
|
||||
}
|
||||
|
||||
template <typename Self, typename F, typename... Rest>
|
||||
NvResult WrapFixedVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) {
|
||||
using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
|
||||
using VarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
|
||||
|
||||
const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
|
||||
return (self->*callable)(fixed, var, std::forward<Rest>(rest)...);
|
||||
};
|
||||
|
||||
return WrapGeneric<FixedArg, VarArg, Null, Null>(std::move(Callable), input, {}, output, {});
|
||||
}
|
||||
|
||||
template <typename Self, typename F, typename... Rest>
|
||||
NvResult WrapFixedInlIn(Self* self, F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, Rest&&... rest) {
|
||||
using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>;
|
||||
using InlInVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type;
|
||||
|
||||
const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult {
|
||||
return (self->*callable)(fixed, inl_in, std::forward<Rest>(rest)...);
|
||||
};
|
||||
|
||||
return WrapGeneric<FixedArg, Null, InlInVarArg, Null>(std::move(Callable), input, inline_input, output, {});
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
|
@ -11,6 +11,7 @@
|
|||
#include "core/core.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
|
@ -33,21 +34,21 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> i
|
|||
case 'A':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return BindChannel(input, output);
|
||||
return WrapFixed(this, &nvhost_as_gpu::BindChannel, input, output);
|
||||
case 0x2:
|
||||
return AllocateSpace(input, output);
|
||||
return WrapFixed(this, &nvhost_as_gpu::AllocateSpace, input, output);
|
||||
case 0x3:
|
||||
return FreeSpace(input, output);
|
||||
return WrapFixed(this, &nvhost_as_gpu::FreeSpace, input, output);
|
||||
case 0x5:
|
||||
return UnmapBuffer(input, output);
|
||||
return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output);
|
||||
case 0x6:
|
||||
return MapBufferEx(input, output);
|
||||
return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output);
|
||||
case 0x8:
|
||||
return GetVARegions(input, output);
|
||||
return WrapFixed(this, &nvhost_as_gpu::GetVARegions1, input, output);
|
||||
case 0x9:
|
||||
return AllocAsEx(input, output);
|
||||
return WrapFixed(this, &nvhost_as_gpu::AllocAsEx, input, output);
|
||||
case 0x14:
|
||||
return Remap(input, output);
|
||||
return WrapVariable(this, &nvhost_as_gpu::Remap, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -72,7 +73,8 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
|
|||
case 'A':
|
||||
switch (command.cmd) {
|
||||
case 0x8:
|
||||
return GetVARegions(input, output, inline_output);
|
||||
return WrapFixedInlOut(this, &nvhost_as_gpu::GetVARegions3, input, output,
|
||||
inline_output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -87,10 +89,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
|
|||
void nvhost_as_gpu::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_as_gpu::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocAsEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size);
|
||||
|
||||
std::scoped_lock lock(mutex);
|
||||
|
@ -141,10 +140,7 @@ NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> outpu
|
|||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocSpace params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
NvResult nvhost_as_gpu::AllocateSpace(IoctlAllocSpace& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages,
|
||||
params.page_size, params.flags);
|
||||
|
||||
|
@ -194,7 +190,6 @@ NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> o
|
|||
.big_pages = params.page_size != VM::YUZU_PAGESIZE,
|
||||
};
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
|
@ -222,10 +217,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
|
|||
mapping_map.erase(offset);
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlFreeSpace params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset,
|
||||
params.pages, params.page_size);
|
||||
|
||||
|
@ -264,18 +256,11 @@ NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> outpu
|
|||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) {
|
||||
const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
|
||||
|
||||
std::scoped_lock lock(mutex);
|
||||
entries.resize_destructive(num_entries);
|
||||
std::memcpy(entries.data(), input.data(), input.size());
|
||||
NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", entries.size());
|
||||
|
||||
if (!vm.initialised) {
|
||||
return NvResult::BadValue;
|
||||
|
@ -317,14 +302,10 @@ NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) {
|
|||
}
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), entries.data(), output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlMapBufferEx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) {
|
||||
LOG_DEBUG(Service_NVDRV,
|
||||
"called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}"
|
||||
", offset={}",
|
||||
|
@ -421,14 +402,10 @@ NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> out
|
|||
mapping_map[params.offset] = mapping;
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlUnmapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
|
||||
|
||||
std::scoped_lock lock(mutex);
|
||||
|
@ -464,9 +441,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> out
|
|||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlBindChannel params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
NvResult nvhost_as_gpu::BindChannel(IoctlBindChannel& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
|
||||
|
||||
auto gpu_channel_device = module.GetDevice<nvhost_gpu>(params.fd);
|
||||
|
@ -493,10 +468,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) {
|
|||
};
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetVaRegions params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
NvResult nvhost_as_gpu::GetVARegions1(IoctlGetVaRegions& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
|
||||
params.buf_size);
|
||||
|
||||
|
@ -508,15 +480,10 @@ NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> ou
|
|||
|
||||
GetVARegionsImpl(params);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) {
|
||||
IoctlGetVaRegions params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
|
||||
NvResult nvhost_as_gpu::GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
|
||||
params.buf_size);
|
||||
|
||||
|
@ -528,9 +495,10 @@ NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> ou
|
|||
|
||||
GetVARegionsImpl(params);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
std::memcpy(inline_output.data(), ¶ms.regions[0], sizeof(VaRegion));
|
||||
std::memcpy(inline_output.data() + sizeof(VaRegion), ¶ms.regions[1], sizeof(VaRegion));
|
||||
const size_t num_regions = std::min(params.regions.size(), regions.size());
|
||||
for (size_t i = 0; i < num_regions; i++) {
|
||||
regions[i] = params.regions[i];
|
||||
}
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
|
|
@ -139,18 +139,17 @@ private:
|
|||
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2,
|
||||
"IoctlGetVaRegions is incorrect size");
|
||||
|
||||
NvResult AllocAsEx(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult AllocateSpace(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult Remap(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult MapBufferEx(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult FreeSpace(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult BindChannel(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult AllocAsEx(IoctlAllocAsEx& params);
|
||||
NvResult AllocateSpace(IoctlAllocSpace& params);
|
||||
NvResult Remap(std::span<IoctlRemapEntry> params);
|
||||
NvResult MapBufferEx(IoctlMapBufferEx& params);
|
||||
NvResult UnmapBuffer(IoctlUnmapBuffer& params);
|
||||
NvResult FreeSpace(IoctlFreeSpace& params);
|
||||
NvResult BindChannel(IoctlBindChannel& params);
|
||||
|
||||
void GetVARegionsImpl(IoctlGetVaRegions& params);
|
||||
NvResult GetVARegions(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetVARegions(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output);
|
||||
NvResult GetVARegions1(IoctlGetVaRegions& params);
|
||||
NvResult GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions);
|
||||
|
||||
void FreeMappingLocked(u64 offset);
|
||||
|
||||
|
@ -213,7 +212,6 @@ private:
|
|||
bool initialised{};
|
||||
} vm;
|
||||
std::shared_ptr<Tegra::MemoryManager> gmmu;
|
||||
Common::ScratchBuffer<IoctlRemapEntry> entries;
|
||||
|
||||
// s32 channel{};
|
||||
// u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE};
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/host1x/host1x.h"
|
||||
|
@ -40,19 +41,19 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inp
|
|||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
case 0x1b:
|
||||
return NvOsGetConfigU32(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl::NvOsGetConfigU32, input, output);
|
||||
case 0x1c:
|
||||
return IocCtrlClearEventWait(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlClearEventWait, input, output);
|
||||
case 0x1d:
|
||||
return IocCtrlEventWait(input, output, true);
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlEventWait, input, output, true);
|
||||
case 0x1e:
|
||||
return IocCtrlEventWait(input, output, false);
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlEventWait, input, output, false);
|
||||
case 0x1f:
|
||||
return IocCtrlEventRegister(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlEventRegister, input, output);
|
||||
case 0x20:
|
||||
return IocCtrlEventUnregister(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlEventUnregister, input, output);
|
||||
case 0x21:
|
||||
return IocCtrlEventUnregisterBatch(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl::IocCtrlEventUnregisterBatch, input, output);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -79,25 +80,19 @@ void nvhost_ctrl::OnOpen(DeviceFD fd) {}
|
|||
|
||||
void nvhost_ctrl::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output) {
|
||||
IocGetConfigParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
NvResult nvhost_ctrl::NvOsGetConfigU32(IocGetConfigParams& params) {
|
||||
LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
|
||||
params.param_str.data());
|
||||
return NvResult::ConfigVarNotFound; // Returns error on production mode
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::span<u8> output,
|
||||
bool is_allocation) {
|
||||
IocCtrlEventWaitParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
NvResult nvhost_ctrl::IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_allocation) {
|
||||
LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_allocation={}",
|
||||
params.fence.id, params.fence.value, params.timeout, is_allocation);
|
||||
|
||||
bool must_unmark_fail = !is_allocation;
|
||||
const u32 event_id = params.value.raw;
|
||||
SCOPE_EXIT({
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
if (must_unmark_fail) {
|
||||
events[event_id].fails = 0;
|
||||
}
|
||||
|
@ -231,9 +226,7 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) {
|
|||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventRegisterParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
NvResult nvhost_ctrl::IocCtrlEventRegister(IocCtrlEventRegisterParams& params) {
|
||||
const u32 event_id = params.user_event_id;
|
||||
LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
|
||||
if (event_id >= MaxNvEvents) {
|
||||
|
@ -252,9 +245,7 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::span<
|
|||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventUnregisterParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregister(IocCtrlEventUnregisterParams& params) {
|
||||
const u32 event_id = params.user_event_id & 0x00FF;
|
||||
LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
|
||||
|
||||
|
@ -262,9 +253,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::spa
|
|||
return FreeEvent(event_id);
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventUnregisterBatchParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchParams& params) {
|
||||
u64 event_mask = params.user_events;
|
||||
LOG_DEBUG(Service_NVDRV, " called, event_mask: {:X}", event_mask);
|
||||
|
||||
|
@ -280,10 +269,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std
|
|||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCtrlEventClearParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlClearEventWait(IocCtrlEventClearParams& params) {
|
||||
u32 event_id = params.event_id.slot;
|
||||
LOG_DEBUG(Service_NVDRV, "called, event_id: {:X}", event_id);
|
||||
|
||||
|
|
|
@ -186,12 +186,12 @@ private:
|
|||
static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8,
|
||||
"IocCtrlEventKill is incorrect size");
|
||||
|
||||
NvResult NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlEventWait(std::span<const u8> input, std::span<u8> output, bool is_allocation);
|
||||
NvResult IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult NvOsGetConfigU32(IocGetConfigParams& params);
|
||||
NvResult IocCtrlEventRegister(IocCtrlEventRegisterParams& params);
|
||||
NvResult IocCtrlEventUnregister(IocCtrlEventUnregisterParams& params);
|
||||
NvResult IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchParams& params);
|
||||
NvResult IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_allocation);
|
||||
NvResult IocCtrlClearEventWait(IocCtrlEventClearParams& params);
|
||||
|
||||
NvResult FreeEvent(u32 slot);
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
|
||||
|
@ -27,23 +28,23 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8>
|
|||
case 'G':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return ZCullGetCtxSize(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::ZCullGetCtxSize, input, output);
|
||||
case 0x2:
|
||||
return ZCullGetInfo(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::ZCullGetInfo, input, output);
|
||||
case 0x3:
|
||||
return ZBCSetTable(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::ZBCSetTable, input, output);
|
||||
case 0x4:
|
||||
return ZBCQueryTable(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::ZBCQueryTable, input, output);
|
||||
case 0x5:
|
||||
return GetCharacteristics(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::GetCharacteristics1, input, output);
|
||||
case 0x6:
|
||||
return GetTPCMasks(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::GetTPCMasks1, input, output);
|
||||
case 0x7:
|
||||
return FlushL2(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::FlushL2, input, output);
|
||||
case 0x14:
|
||||
return GetActiveSlotMask(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::GetActiveSlotMask, input, output);
|
||||
case 0x1c:
|
||||
return GetGpuTime(input, output);
|
||||
return WrapFixed(this, &nvhost_ctrl_gpu::GetGpuTime, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -65,9 +66,11 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
|
|||
case 'G':
|
||||
switch (command.cmd) {
|
||||
case 0x5:
|
||||
return GetCharacteristics(input, output, inline_output);
|
||||
return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetCharacteristics3, input, output,
|
||||
inline_output);
|
||||
case 0x6:
|
||||
return GetTPCMasks(input, output, inline_output);
|
||||
return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetTPCMasks3, input, output,
|
||||
inline_output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -82,10 +85,8 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
|
|||
void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) {
|
||||
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;
|
||||
|
@ -123,15 +124,13 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::spa
|
|||
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(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) {
|
||||
NvResult nvhost_ctrl_gpu::GetCharacteristics3(
|
||||
IoctlCharacteristics& params, std::span<IoctlGpuCharacteristics> gpu_characteristics) {
|
||||
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;
|
||||
|
@ -169,70 +168,47 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::spa
|
|||
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());
|
||||
std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size());
|
||||
if (!gpu_characteristics.empty()) {
|
||||
gpu_characteristics.front() = params.gc;
|
||||
}
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGpuGetTpcMasksArgs params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params) {
|
||||
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());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output) {
|
||||
IoctlGpuGetTpcMasksArgs params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
NvResult nvhost_ctrl_gpu::GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask) {
|
||||
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());
|
||||
if (!tpc_mask.empty()) {
|
||||
tpc_mask.front() = params.tcp_mask;
|
||||
}
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvhost_ctrl_gpu::GetActiveSlotMask(IoctlActiveSlotMask& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlActiveSlotMask params{};
|
||||
if (input.size() > 0) {
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
}
|
||||
params.slot = 0x07;
|
||||
params.mask = 0x01;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(IoctlZcullGetCtxSize& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlZcullGetCtxSize params{};
|
||||
if (input.size() > 0) {
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
}
|
||||
params.size = 0x1;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvhost_ctrl_gpu::ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlNvgpuGpuZcullGetInfoArgs params{};
|
||||
|
||||
if (input.size() > 0) {
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
}
|
||||
|
||||
params.width_align_pixels = 0x20;
|
||||
params.height_align_pixels = 0x20;
|
||||
params.pixel_squares_by_aliquots = 0x400;
|
||||
|
@ -243,53 +219,28 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::span<u8>
|
|||
params.subregion_width_align_pixels = 0x20;
|
||||
params.subregion_height_align_pixels = 0x40;
|
||||
params.subregion_count = 0x10;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvhost_ctrl_gpu::ZBCSetTable(IoctlZbcSetTable& params) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlZbcSetTable params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO(ogniK): What does this even actually do?
|
||||
|
||||
// Prevent null pointer being passed as arg 1
|
||||
if (output.empty()) {
|
||||
LOG_WARNING(Service_NVDRV, "Avoiding passing null pointer to memcpy");
|
||||
} else {
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
}
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvhost_ctrl_gpu::ZBCQueryTable(IoctlZbcQueryTable& params) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlZbcQueryTable params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO : To implement properly
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvhost_ctrl_gpu::FlushL2(IoctlFlushL2& params) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IoctlFlushL2 params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
// TODO : To implement properly
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvhost_ctrl_gpu::GetGpuTime(IoctlGetGpuTime& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlGetGpuTime params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count());
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -151,21 +151,20 @@ private:
|
|||
};
|
||||
static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
|
||||
|
||||
NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output);
|
||||
NvResult GetCharacteristics1(IoctlCharacteristics& params);
|
||||
NvResult GetCharacteristics3(IoctlCharacteristics& params,
|
||||
std::span<IoctlGpuCharacteristics> gpu_characteristics);
|
||||
|
||||
NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output,
|
||||
std::span<u8> inline_output);
|
||||
NvResult GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params);
|
||||
NvResult GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask);
|
||||
|
||||
NvResult GetActiveSlotMask(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZCullGetInfo(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZBCSetTable(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZBCQueryTable(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult FlushL2(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetGpuTime(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetActiveSlotMask(IoctlActiveSlotMask& params);
|
||||
NvResult ZCullGetCtxSize(IoctlZcullGetCtxSize& params);
|
||||
NvResult ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params);
|
||||
NvResult ZBCSetTable(IoctlZbcSetTable& params);
|
||||
NvResult ZBCQueryTable(IoctlZbcQueryTable& params);
|
||||
NvResult FlushL2(IoctlFlushL2& params);
|
||||
NvResult GetGpuTime(IoctlGetGpuTime& params);
|
||||
|
||||
EventInterface& events_interface;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
#include "core/memory.h"
|
||||
|
@ -52,7 +53,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||
case 0x0:
|
||||
switch (command.cmd) {
|
||||
case 0x3:
|
||||
return GetWaitbase(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::GetWaitbase, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -60,25 +61,25 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return SetNVMAPfd(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::SetNVMAPfd, input, output);
|
||||
case 0x3:
|
||||
return ChannelSetTimeout(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output);
|
||||
case 0x8:
|
||||
return SubmitGPFIFOBase(input, output, false);
|
||||
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, false);
|
||||
case 0x9:
|
||||
return AllocateObjectContext(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output);
|
||||
case 0xb:
|
||||
return ZCullBind(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::ZCullBind, input, output);
|
||||
case 0xc:
|
||||
return SetErrorNotifier(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::SetErrorNotifier, input, output);
|
||||
case 0xd:
|
||||
return SetChannelPriority(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::SetChannelPriority, input, output);
|
||||
case 0x1a:
|
||||
return AllocGPFIFOEx2(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output);
|
||||
case 0x1b:
|
||||
return SubmitGPFIFOBase(input, output, true);
|
||||
return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, true);
|
||||
case 0x1d:
|
||||
return ChannelSetTimeslice(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -86,9 +87,9 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||
case 'G':
|
||||
switch (command.cmd) {
|
||||
case 0x14:
|
||||
return SetClientData(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::SetClientData, input, output);
|
||||
case 0x15:
|
||||
return GetClientData(input, output);
|
||||
return WrapFixed(this, &nvhost_gpu::GetClientData, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -104,7 +105,8 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1b:
|
||||
return SubmitGPFIFOBase(input, inline_input, output);
|
||||
return WrapFixedInlIn(this, &nvhost_gpu::SubmitGPFIFOBase2, input, inline_input,
|
||||
output);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -121,63 +123,45 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||
void nvhost_gpu::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_gpu::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvhost_gpu::SetClientData(IoctlClientData& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlClientData params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
user_data = params.data;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvhost_gpu::GetClientData(IoctlClientData& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
IoctlClientData params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
params.data = user_data;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::span<u8> output) {
|
||||
std::memcpy(&zcull_params, input.data(), input.size());
|
||||
NvResult nvhost_gpu::ZCullBind(IoctlZCullBind& params) {
|
||||
zcull_params = params;
|
||||
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
|
||||
zcull_params.mode);
|
||||
|
||||
std::memcpy(output.data(), &zcull_params, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetErrorNotifier params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
|
||||
params.size, params.mem);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::span<u8> output) {
|
||||
std::memcpy(&channel_priority, input.data(), input.size());
|
||||
NvResult nvhost_gpu::SetChannelPriority(IoctlChannelSetPriority& params) {
|
||||
channel_priority = params.priority;
|
||||
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocGpfifoEx2 params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
NvResult nvhost_gpu::AllocGPFIFOEx2(IoctlAllocGpfifoEx2& params) {
|
||||
LOG_WARNING(Service_NVDRV,
|
||||
"(STUBBED) called, num_entries={:X}, flags={:X}, unk0={:X}, "
|
||||
"unk1={:X}, unk2={:X}, unk3={:X}",
|
||||
|
@ -193,18 +177,14 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> out
|
|||
|
||||
params.fence_out = syncpoint_manager.GetSyncpointFence(channel_syncpoint);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlAllocObjCtx params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
|
||||
params.flags);
|
||||
|
||||
params.obj_id = 0x0;
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
|
@ -248,8 +228,7 @@ static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementW
|
|||
return result;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output,
|
||||
Tegra::CommandList&& entries) {
|
||||
NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries) {
|
||||
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
|
||||
params.num_entries, params.flags.raw);
|
||||
|
||||
|
@ -290,65 +269,55 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> o
|
|||
|
||||
flags.raw = 0;
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output,
|
||||
bool kickoff) {
|
||||
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
||||
std::span<Tegra::CommandListHeader> commands, bool kickoff) {
|
||||
if (params.num_entries > commands.size()) {
|
||||
UNIMPLEMENTED();
|
||||
return NvResult::InvalidSize;
|
||||
}
|
||||
IoctlSubmitGpfifo params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo));
|
||||
Tegra::CommandList entries(params.num_entries);
|
||||
|
||||
Tegra::CommandList entries(params.num_entries);
|
||||
if (kickoff) {
|
||||
system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(),
|
||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||
} else {
|
||||
std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)],
|
||||
std::memcpy(entries.command_lists.data(), commands.data(),
|
||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||
}
|
||||
|
||||
return SubmitGPFIFOImpl(params, output, std::move(entries));
|
||||
return SubmitGPFIFOImpl(params, std::move(entries));
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
|
||||
std::span<u8> output) {
|
||||
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
|
||||
NvResult nvhost_gpu::SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
|
||||
std::span<const Tegra::CommandListHeader> commands) {
|
||||
if (params.num_entries > commands.size()) {
|
||||
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));
|
||||
std::memcpy(entries.command_lists.data(), commands.data(),
|
||||
params.num_entries * sizeof(Tegra::CommandListHeader));
|
||||
return SubmitGPFIFOImpl(params, std::move(entries));
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetWaitbase params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
NvResult nvhost_gpu::GetWaitbase(IoctlGetWaitbase& params) {
|
||||
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
|
||||
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlChannelSetTimeout params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout));
|
||||
NvResult nvhost_gpu::ChannelSetTimeout(IoctlChannelSetTimeout& params) {
|
||||
LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetTimeslice params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice));
|
||||
NvResult nvhost_gpu::ChannelSetTimeslice(IoctlSetTimeslice& params) {
|
||||
LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
|
||||
|
||||
channel_timeslice = params.timeslice;
|
||||
|
|
|
@ -186,23 +186,24 @@ private:
|
|||
u32_le channel_priority{};
|
||||
u32_le channel_timeslice{};
|
||||
|
||||
NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetClientData(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetClientData(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ZCullBind(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetErrorNotifier(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetChannelPriority(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult AllocateObjectContext(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output,
|
||||
Tegra::CommandList&& entries);
|
||||
NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output,
|
||||
bool kickoff = false);
|
||||
NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
|
||||
std::span<u8> output);
|
||||
NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ChannelSetTimeout(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetNVMAPfd(IoctlSetNvmapFD& params);
|
||||
NvResult SetClientData(IoctlClientData& params);
|
||||
NvResult GetClientData(IoctlClientData& params);
|
||||
NvResult ZCullBind(IoctlZCullBind& params);
|
||||
NvResult SetErrorNotifier(IoctlSetErrorNotifier& params);
|
||||
NvResult SetChannelPriority(IoctlChannelSetPriority& params);
|
||||
NvResult AllocGPFIFOEx2(IoctlAllocGpfifoEx2& params);
|
||||
NvResult AllocateObjectContext(IoctlAllocObjCtx& params);
|
||||
|
||||
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries);
|
||||
NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
||||
std::span<Tegra::CommandListHeader> commands, bool kickoff = false);
|
||||
NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
|
||||
std::span<const Tegra::CommandListHeader> commands);
|
||||
|
||||
NvResult GetWaitbase(IoctlGetWaitbase& params);
|
||||
NvResult ChannelSetTimeout(IoctlChannelSetTimeout& params);
|
||||
NvResult ChannelSetTimeslice(IoctlSetTimeslice& params);
|
||||
|
||||
EventInterface& events_interface;
|
||||
NvCore::Container& core;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
|
||||
|
@ -25,18 +26,18 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
|
|||
if (!host1x_file.fd_to_id.contains(fd)) {
|
||||
host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++;
|
||||
}
|
||||
return Submit(fd, input, output);
|
||||
return WrapFixedVariable(this, &nvhost_nvdec::Submit, input, output, fd);
|
||||
}
|
||||
case 0x2:
|
||||
return GetSyncpoint(input, output);
|
||||
return WrapFixed(this, &nvhost_nvdec::GetSyncpoint, input, output);
|
||||
case 0x3:
|
||||
return GetWaitbase(input, output);
|
||||
return WrapFixed(this, &nvhost_nvdec::GetWaitbase, input, output);
|
||||
case 0x7:
|
||||
return SetSubmitTimeout(input, output);
|
||||
return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output);
|
||||
case 0x9:
|
||||
return MapBuffer(input, output);
|
||||
return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output);
|
||||
case 0xa:
|
||||
return UnmapBuffer(input, output);
|
||||
return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -44,7 +45,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
|
|||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return SetNVMAPfd(input);
|
||||
return WrapFixed(this, &nvhost_nvdec::SetNVMAPfd, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ std::size_t SliceVectors(std::span<const u8> input, std::vector<T>& dst, std::si
|
|||
return 0;
|
||||
}
|
||||
const size_t bytes_copied = count * sizeof(T);
|
||||
if (input.size() < offset + bytes_copied) {
|
||||
return 0;
|
||||
}
|
||||
std::memcpy(dst.data(), input.data() + offset, bytes_copied);
|
||||
return bytes_copied;
|
||||
}
|
||||
|
@ -41,6 +44,9 @@ std::size_t WriteVectors(std::span<u8> dst, const std::vector<T>& src, std::size
|
|||
return 0;
|
||||
}
|
||||
const size_t bytes_copied = src.size() * sizeof(T);
|
||||
if (dst.size() < offset + bytes_copied) {
|
||||
return 0;
|
||||
}
|
||||
std::memcpy(dst.data() + offset, src.data(), bytes_copied);
|
||||
return bytes_copied;
|
||||
}
|
||||
|
@ -63,18 +69,14 @@ nvhost_nvdec_common::~nvhost_nvdec_common() {
|
|||
core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint);
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::SetNVMAPfd(std::span<const u8> input) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD));
|
||||
NvResult nvhost_nvdec_common::SetNVMAPfd(IoctlSetNvmapFD& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSubmit params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit));
|
||||
NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, DeviceFD fd) {
|
||||
LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
|
||||
|
||||
// Instantiate param buffers
|
||||
|
@ -85,12 +87,12 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std
|
|||
std::vector<u32> fence_thresholds(params.fence_count);
|
||||
|
||||
// Slice input into their respective buffers
|
||||
std::size_t offset = sizeof(IoctlSubmit);
|
||||
offset += SliceVectors(input, command_buffers, params.cmd_buffer_count, offset);
|
||||
offset += SliceVectors(input, relocs, params.relocation_count, offset);
|
||||
offset += SliceVectors(input, reloc_shifts, params.relocation_count, offset);
|
||||
offset += SliceVectors(input, syncpt_increments, params.syncpoint_count, offset);
|
||||
offset += SliceVectors(input, fence_thresholds, params.fence_count, offset);
|
||||
std::size_t offset = 0;
|
||||
offset += SliceVectors(data, command_buffers, params.cmd_buffer_count, offset);
|
||||
offset += SliceVectors(data, relocs, params.relocation_count, offset);
|
||||
offset += SliceVectors(data, reloc_shifts, params.relocation_count, offset);
|
||||
offset += SliceVectors(data, syncpt_increments, params.syncpoint_count, offset);
|
||||
offset += SliceVectors(data, fence_thresholds, params.fence_count, offset);
|
||||
|
||||
auto& gpu = system.GPU();
|
||||
if (gpu.UseNvdec()) {
|
||||
|
@ -108,72 +110,51 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std
|
|||
cmdlist.size() * sizeof(u32));
|
||||
gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist);
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit));
|
||||
// Some games expect command_buffers to be written back
|
||||
offset = sizeof(IoctlSubmit);
|
||||
offset += WriteVectors(output, command_buffers, offset);
|
||||
offset += WriteVectors(output, relocs, offset);
|
||||
offset += WriteVectors(output, reloc_shifts, offset);
|
||||
offset += WriteVectors(output, syncpt_increments, offset);
|
||||
offset += WriteVectors(output, fence_thresholds, offset);
|
||||
offset = 0;
|
||||
offset += WriteVectors(data, command_buffers, offset);
|
||||
offset += WriteVectors(data, relocs, offset);
|
||||
offset += WriteVectors(data, reloc_shifts, offset);
|
||||
offset += WriteVectors(data, syncpt_increments, offset);
|
||||
offset += WriteVectors(data, fence_thresholds, offset);
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetSyncpoint params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint));
|
||||
NvResult nvhost_nvdec_common::GetSyncpoint(IoctlGetSyncpoint& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
|
||||
|
||||
// const u32 id{NvCore::SyncpointManager::channel_syncpoints[static_cast<u32>(channel_type)]};
|
||||
params.value = channel_syncpoint;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint));
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlGetWaitbase params{};
|
||||
NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) {
|
||||
LOG_CRITICAL(Service_NVDRV, "called WAITBASE");
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase));
|
||||
params.value = 0; // Seems to be hard coded at 0
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||
|
||||
SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
|
||||
|
||||
for (auto& cmd_buffer : cmd_buffer_handles) {
|
||||
cmd_buffer.map_address = nvmap.PinHandle(cmd_buffer.map_handle);
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBuffer));
|
||||
std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
|
||||
cmd_buffer_handles.size() * sizeof(MapBufferEntry));
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlMapBuffer params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer));
|
||||
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
|
||||
|
||||
SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
|
||||
for (auto& cmd_buffer : cmd_buffer_handles) {
|
||||
nvmap.UnpinHandle(cmd_buffer.map_handle);
|
||||
NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries) {
|
||||
const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));
|
||||
for (size_t i = 0; i < num_entries; i++) {
|
||||
entries[i].map_address = nvmap.PinHandle(entries[i].map_handle);
|
||||
}
|
||||
|
||||
std::memset(output.data(), 0, output.size());
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::span<u8> output) {
|
||||
std::memcpy(&submit_timeout, input.data(), input.size());
|
||||
NvResult nvhost_nvdec_common::UnmapBuffer(IoctlMapBuffer& params,
|
||||
std::span<MapBufferEntry> entries) {
|
||||
const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size()));
|
||||
for (size_t i = 0; i < num_entries; i++) {
|
||||
nvmap.UnpinHandle(entries[i].map_handle);
|
||||
entries[i] = {};
|
||||
}
|
||||
|
||||
params = {};
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_nvdec_common::SetSubmitTimeout(u32 timeout) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
|
|
@ -107,13 +107,13 @@ protected:
|
|||
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
|
||||
|
||||
/// Ioctl command implementations
|
||||
NvResult SetNVMAPfd(std::span<const u8> input);
|
||||
NvResult Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetSyncpoint(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult MapBuffer(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetSubmitTimeout(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetNVMAPfd(IoctlSetNvmapFD&);
|
||||
NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd);
|
||||
NvResult GetSyncpoint(IoctlGetSyncpoint& params);
|
||||
NvResult GetWaitbase(IoctlGetWaitbase& params);
|
||||
NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries);
|
||||
NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries);
|
||||
NvResult SetSubmitTimeout(u32 timeout);
|
||||
|
||||
Kernel::KEvent* QueryEvent(u32 event_id) override;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
|
@ -18,7 +19,7 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
|
|||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return SetNVMAPfd(input, output);
|
||||
return WrapFixed(this, &nvhost_nvjpg::SetNVMAPfd, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -46,9 +47,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in
|
|||
void nvhost_nvjpg::OnOpen(DeviceFD fd) {}
|
||||
void nvhost_nvjpg::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
|
|
|
@ -33,7 +33,7 @@ private:
|
|||
|
||||
s32_le nvmap_fd{};
|
||||
|
||||
NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult SetNVMAPfd(IoctlSetNvmapFD& params);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
|
||||
|
@ -25,16 +26,16 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||
if (!host1x_file.fd_to_id.contains(fd)) {
|
||||
host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++;
|
||||
}
|
||||
return Submit(fd, input, output);
|
||||
return WrapFixedVariable(this, &nvhost_vic::Submit, input, output, fd);
|
||||
}
|
||||
case 0x2:
|
||||
return GetSyncpoint(input, output);
|
||||
return WrapFixed(this, &nvhost_vic::GetSyncpoint, input, output);
|
||||
case 0x3:
|
||||
return GetWaitbase(input, output);
|
||||
return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output);
|
||||
case 0x9:
|
||||
return MapBuffer(input, output);
|
||||
return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output);
|
||||
case 0xa:
|
||||
return UnmapBuffer(input, output);
|
||||
return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -42,7 +43,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
|
|||
case 'H':
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return SetNVMAPfd(input);
|
||||
return WrapFixed(this, &nvhost_vic::SetNVMAPfd, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/service/nvdrv/core/container.h"
|
||||
#include "core/hle/service/nvdrv/core/nvmap.h"
|
||||
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvmap.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
|
@ -31,17 +32,17 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
|
|||
case 0x1:
|
||||
switch (command.cmd) {
|
||||
case 0x1:
|
||||
return IocCreate(input, output);
|
||||
return WrapFixed(this, &nvmap::IocCreate, input, output);
|
||||
case 0x3:
|
||||
return IocFromId(input, output);
|
||||
return WrapFixed(this, &nvmap::IocFromId, input, output);
|
||||
case 0x4:
|
||||
return IocAlloc(input, output);
|
||||
return WrapFixed(this, &nvmap::IocAlloc, input, output);
|
||||
case 0x5:
|
||||
return IocFree(input, output);
|
||||
return WrapFixed(this, &nvmap::IocFree, input, output);
|
||||
case 0x9:
|
||||
return IocParam(input, output);
|
||||
return WrapFixed(this, &nvmap::IocParam, input, output);
|
||||
case 0xe:
|
||||
return IocGetId(input, output);
|
||||
return WrapFixed(this, &nvmap::IocGetId, input, output);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -69,9 +70,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, st
|
|||
void nvmap::OnOpen(DeviceFD fd) {}
|
||||
void nvmap::OnClose(DeviceFD fd) {}
|
||||
|
||||
NvResult nvmap::IocCreate(std::span<const u8> input, std::span<u8> output) {
|
||||
IocCreateParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
NvResult nvmap::IocCreate(IocCreateParams& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size);
|
||||
|
||||
std::shared_ptr<NvCore::NvMap::Handle> handle_description{};
|
||||
|
@ -85,13 +84,10 @@ NvResult nvmap::IocCreate(std::span<const u8> input, std::span<u8> output) {
|
|||
params.handle = handle_description->id;
|
||||
LOG_DEBUG(Service_NVDRV, "handle: {}, size: 0x{:X}", handle_description->id, params.size);
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) {
|
||||
IocAllocParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
NvResult nvmap::IocAlloc(IocAllocParams& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address);
|
||||
|
||||
if (!params.handle) {
|
||||
|
@ -133,14 +129,10 @@ NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) {
|
|||
handle_description->size,
|
||||
Kernel::KMemoryPermission::None, true, false)
|
||||
.IsSuccess());
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return result;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocGetId(std::span<const u8> input, std::span<u8> output) {
|
||||
IocGetIdParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
NvResult nvmap::IocGetId(IocGetIdParams& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
// See the comment in FromId for extra info on this function
|
||||
|
@ -157,14 +149,10 @@ NvResult nvmap::IocGetId(std::span<const u8> input, std::span<u8> output) {
|
|||
}
|
||||
|
||||
params.id = handle_description->id;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocFromId(std::span<const u8> input, std::span<u8> output) {
|
||||
IocFromIdParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
NvResult nvmap::IocFromId(IocFromIdParams& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, id:{}", params.id);
|
||||
|
||||
// Handles and IDs are always the same value in nvmap however IDs can be used globally given the
|
||||
|
@ -188,16 +176,12 @@ NvResult nvmap::IocFromId(std::span<const u8> input, std::span<u8> output) {
|
|||
return result;
|
||||
}
|
||||
params.handle = handle_description->id;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocParam(std::span<const u8> input, std::span<u8> output) {
|
||||
NvResult nvmap::IocParam(IocParamParams& params) {
|
||||
enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
|
||||
|
||||
IocParamParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
LOG_DEBUG(Service_NVDRV, "called type={}", params.param);
|
||||
|
||||
if (!params.handle) {
|
||||
|
@ -237,14 +221,10 @@ NvResult nvmap::IocParam(std::span<const u8> input, std::span<u8> output) {
|
|||
return NvResult::BadValue;
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) {
|
||||
IocFreeParams params;
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
NvResult nvmap::IocFree(IocFreeParams& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
if (!params.handle) {
|
||||
|
@ -267,7 +247,6 @@ NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) {
|
|||
// This is possible when there's internal dups or other duplicates.
|
||||
}
|
||||
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -99,12 +99,12 @@ public:
|
|||
};
|
||||
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
|
||||
|
||||
NvResult IocCreate(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocAlloc(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocGetId(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocFromId(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocParam(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocFree(std::span<const u8> input, std::span<u8> output);
|
||||
NvResult IocCreate(IocCreateParams& params);
|
||||
NvResult IocAlloc(IocAllocParams& params);
|
||||
NvResult IocGetId(IocGetIdParams& params);
|
||||
NvResult IocFromId(IocFromIdParams& params);
|
||||
NvResult IocParam(IocParamParams& params);
|
||||
NvResult IocFree(IocFreeParams& params);
|
||||
|
||||
private:
|
||||
/// Id to use for the next handle that is created.
|
||||
|
|
|
@ -71,24 +71,17 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address,
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::span<u8> SerializeIoc(T& params) {
|
||||
return std::span(reinterpret_cast<u8*>(std::addressof(params)), sizeof(T));
|
||||
}
|
||||
|
||||
Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) {
|
||||
// Create a handle.
|
||||
Nvidia::Devices::nvmap::IocCreateParams create_in_params{
|
||||
Nvidia::Devices::nvmap::IocCreateParams create_params{
|
||||
.size = size,
|
||||
.handle = 0,
|
||||
};
|
||||
Nvidia::Devices::nvmap::IocCreateParams create_out_params{};
|
||||
R_UNLESS(nvmap.IocCreate(SerializeIoc(create_in_params), SerializeIoc(create_out_params)) ==
|
||||
Nvidia::NvResult::Success,
|
||||
R_UNLESS(nvmap.IocCreate(create_params) == Nvidia::NvResult::Success,
|
||||
VI::ResultOperationFailed);
|
||||
|
||||
// Assign the output handle.
|
||||
*out_nv_map_handle = create_out_params.handle;
|
||||
*out_nv_map_handle = create_params.handle;
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
|
@ -96,13 +89,10 @@ Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap,
|
|||
|
||||
Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) {
|
||||
// Free the handle.
|
||||
Nvidia::Devices::nvmap::IocFreeParams free_in_params{
|
||||
Nvidia::Devices::nvmap::IocFreeParams free_params{
|
||||
.handle = handle,
|
||||
};
|
||||
Nvidia::Devices::nvmap::IocFreeParams free_out_params{};
|
||||
R_UNLESS(nvmap.IocFree(SerializeIoc(free_in_params), SerializeIoc(free_out_params)) ==
|
||||
Nvidia::NvResult::Success,
|
||||
VI::ResultOperationFailed);
|
||||
R_UNLESS(nvmap.IocFree(free_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed);
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
|
@ -111,7 +101,7 @@ Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) {
|
|||
Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer,
|
||||
u32 size) {
|
||||
// Assign the allocated memory to the handle.
|
||||
Nvidia::Devices::nvmap::IocAllocParams alloc_in_params{
|
||||
Nvidia::Devices::nvmap::IocAllocParams alloc_params{
|
||||
.handle = handle,
|
||||
.heap_mask = 0,
|
||||
.flags = {},
|
||||
|
@ -119,10 +109,7 @@ Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::Proce
|
|||
.kind = 0,
|
||||
.address = GetInteger(buffer),
|
||||
};
|
||||
Nvidia::Devices::nvmap::IocAllocParams alloc_out_params{};
|
||||
R_UNLESS(nvmap.IocAlloc(SerializeIoc(alloc_in_params), SerializeIoc(alloc_out_params)) ==
|
||||
Nvidia::NvResult::Success,
|
||||
VI::ResultOperationFailed);
|
||||
R_UNLESS(nvmap.IocAlloc(alloc_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed);
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
|
|
Reference in New Issue