From a5fece80206c0b597192c9470d665288ee633f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=97=B1=20PixelyIon?= Date: Sat, 19 Sep 2020 20:15:17 +0530 Subject: [PATCH] NVDRV IOCTL Refactor Buffer -> Span + All buffers as arguments + Return -> NvStatus + Print Service Names + Function Names --- app/proguard-rules.pro | 3 + app/src/main/cpp/skyline/common.h | 18 ++- .../skyline/services/nvdrv/INvDrvServices.cpp | 35 ++-- .../services/nvdrv/devices/nvdevice.cpp | 28 ++-- .../skyline/services/nvdrv/devices/nvdevice.h | 67 +++----- .../services/nvdrv/devices/nvhost_as_gpu.cpp | 142 ++++++++-------- .../services/nvdrv/devices/nvhost_as_gpu.h | 18 +-- .../services/nvdrv/devices/nvhost_channel.cpp | 86 +++++----- .../services/nvdrv/devices/nvhost_channel.h | 18 +-- .../services/nvdrv/devices/nvhost_ctrl.cpp | 108 ++++++------- .../services/nvdrv/devices/nvhost_ctrl.h | 12 +- .../nvdrv/devices/nvhost_ctrl_gpu.cpp | 152 +++++++----------- .../services/nvdrv/devices/nvhost_ctrl_gpu.h | 10 +- .../skyline/services/nvdrv/devices/nvmap.cpp | 127 ++++++++------- .../skyline/services/nvdrv/devices/nvmap.h | 12 +- 15 files changed, 407 insertions(+), 429 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 477bb5b3..ad28b745 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,3 +1,6 @@ # Skyline Proguard Rules # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html + +# Retain all classes within Skyline for traces + JNI access + Serializable classes +-keep class emu.skyline.* diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h index e313a8a8..92524a1f 100644 --- a/app/src/main/cpp/skyline/common.h +++ b/app/src/main/cpp/skyline/common.h @@ -187,7 +187,7 @@ namespace skyline { } template - constexpr std::array HexStringToArray(const std::string_view &hexString) { + constexpr std::array HexStringToArray(std::string_view hexString) { if (hexString.size() != Size * 2) throw exception("Invalid size"); std::array result; @@ -198,9 +198,23 @@ namespace skyline { return result; } - constexpr std::size_t Hash(const std::string_view& view) { + constexpr std::size_t Hash(std::string_view view) { return frz::elsa{}(frz::string(view.data(), view.size()), 0); } + + template + constexpr Out& As(const std::span &span) { + if (span.size_bytes() < sizeof(Out)) + throw exception("Span size less than Out type size"); + return *reinterpret_cast(span.data()); + } + + template + constexpr std::span AsSpan(const std::span &span) { + if (span.size_bytes() < sizeof(Out)) + throw exception("Span size less than Out type size"); + return std::span(reinterpret_cast(span.data()), span.size_bytes() / sizeof(Out)); + } } /** diff --git a/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp b/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp index 42fae047..34c5e3dd 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp @@ -33,7 +33,6 @@ namespace skyline::service::nvdrv { Result INvDrvServices::Ioctl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { auto fd = request.Pop(); auto cmd = request.Pop(); - state.logger->Debug("IOCTL on device: 0x{:X}, cmd: 0x{:X}", fd, cmd); auto device = driver->GetDevice(fd); @@ -41,29 +40,25 @@ namespace skyline::service::nvdrv { cmd &= 0xFFFF; try { + std::optional buffer{std::nullopt}; if (request.inputBuf.empty() || request.outputBuf.empty()) { - if (request.inputBuf.empty()) { - device::IoctlData data(request.outputBuf.at(0)); - - device->HandleIoctl(cmd, data); - response.Push(data.status); - } else { - device::IoctlData data(request.inputBuf.at(0)); - - device->HandleIoctl(cmd, data); - response.Push(data.status); - } + if (!request.inputBuf.empty()) + buffer = request.inputBuf.at(0); + else if (!request.outputBuf.empty()) + buffer = request.outputBuf.at(0); + else + throw exception("No IOCTL Buffers"); + } else if (request.inputBuf.at(0).address == request.outputBuf.at(0).address) { + buffer = request.inputBuf.at(0); } else { - device::IoctlData data(request.inputBuf.at(0), request.outputBuf.at(0)); - - device->HandleIoctl(cmd, data); - response.Push(data.status); + throw exception("IOCTL Input Buffer != Output Buffer"); } - } catch (const std::out_of_range &) { - throw exception("IOCTL was requested on an invalid file descriptor"); - } - return {}; + response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl, std::span(reinterpret_cast(buffer->address), buffer->size), {})); + return {}; + } catch (const std::out_of_range &) { + throw exception("IOCTL was requested on an invalid file descriptor: 0x{:X}", fd); + } } Result INvDrvServices::Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvdevice.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvdevice.cpp index 12874204..1e034a9f 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvdevice.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvdevice.cpp @@ -4,29 +4,33 @@ #include "nvdevice.h" namespace skyline::service::nvdrv::device { - std::string NvDevice::GetName() { - int status{}; - size_t length{}; - auto mangledName{typeid(*this).name()}; + const std::string &NvDevice::GetName() { + if (name.empty()) { + auto mangledName = typeid(*this).name(); - std::unique_ptr demangled{ abi::__cxa_demangle(mangledName, nullptr, &length, &status), std::free}; + int status{}; + size_t length{}; + std::unique_ptr demangled{abi::__cxa_demangle(mangledName, nullptr, &length, &status), std::free}; - return (status == 0) ? std::string(demangled.get() + std::char_traits::length("skyline::service::nvdrv::device")) : mangledName; + name = (status == 0) ? std::string(demangled.get() + std::char_traits::length("skyline::service::nvdrv::device::")) : mangledName; + } + return name; } - void NvDevice::HandleIoctl(u32 cmd, IoctlData &input) { - std::function function; + NvStatus NvDevice::HandleIoctl(u32 cmd, IoctlType type, std::span buffer, std::span inlineBuffer) { + std::pair, std::span)>, std::string_view> function; try { - function = GetServiceFunction(cmd); + function = GetIoctlFunction(cmd); + state.logger->Debug("IOCTL @ {}: {}", GetName(), function.second); } catch (std::out_of_range &) { state.logger->Warn("Cannot find IOCTL for device '{}': 0x{:X}", GetName(), cmd); - input.status = NvStatus::NotImplemented; - return; + return NvStatus::NotImplemented; } try { - function(input); + return function.first(type, buffer, inlineBuffer); } catch (std::exception &e) { throw exception("{} (Device: {})", e.what(), GetName()); } + exit(0); } } diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvdevice.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvdevice.h index fb698aa6..82ad4690 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvdevice.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvdevice.h @@ -8,12 +8,13 @@ #include #include -#define NVFUNC(id, Class, Function) std::pair>(id, &Class::Function) +#define NVFUNC(id, Class, Function) std::pair, std::span)>, std::string_view>>{id, {&Class::Function, #Function}} #define NVDEVICE_DECL_AUTO(name, value) decltype(value) name = value -#define NVDEVICE_DECL(...) \ -NVDEVICE_DECL_AUTO(functions, frz::make_unordered_map({__VA_ARGS__})); \ -std::function GetServiceFunction(u32 index) { \ - return std::bind(functions.at(index), this, std::placeholders::_1); \ +#define NVDEVICE_DECL(...) \ +NVDEVICE_DECL_AUTO(functions, frz::make_unordered_map({__VA_ARGS__})); \ +std::pair, std::span)>, std::string_view> GetIoctlFunction(u32 id) { \ + auto& function = functions.at(id); \ + return std::make_pair(std::bind(function.first, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), function.second); \ } namespace skyline::service::nvdrv::device { @@ -49,53 +50,21 @@ namespace skyline::service::nvdrv::device { }; /** - * @brief This holds all the input and output data for an IOCTL function + * @brief The IOCTL call variants, they have different buffer configurations */ - struct IoctlData { - std::vector input; //!< A vector of all input IOCTL buffers - std::vector output; //!< A vector of all output IOCTL buffers - NvStatus status{NvStatus::Success}; //!< The error code that is returned to the application - - /** - * @brief This constructor takes 1 input buffer and 1 output buffer, it's used for Ioctl - * @param input An input buffer - * @param output An output buffer - */ - IoctlData(kernel::ipc::InputBuffer input, kernel::ipc::OutputBuffer output) : input({input}), output({output}) {} - - /** - * @brief This constructor takes 1 input buffer, it's used for Ioctl sometimes - * @param output An output buffer - */ - IoctlData(kernel::ipc::InputBuffer input) : input({input}) {} - - /** - * @brief This constructor takes 1 output buffer, it's used for Ioctl sometimes - * @param output An output buffer - */ - IoctlData(kernel::ipc::OutputBuffer output) : output({output}) {} - - /** - * @brief This constructor takes 2 input buffers and 1 output buffer, it's used for Ioctl1 - * @param input1 The first input buffer - * @param input2 The second input buffer - * @param output An output buffer - */ - IoctlData(kernel::ipc::InputBuffer input1, kernel::ipc::InputBuffer input2, kernel::ipc::OutputBuffer output) : input({input1, input2}), output({output}) {} - - /** - * @brief This constructor takes 1 input buffer and 2 output buffers, it's used for Ioctl2 - * @param input An input buffer - * @param output1 The first output buffer - * @param output2 The second output buffer - */ - IoctlData(kernel::ipc::InputBuffer input, kernel::ipc::OutputBuffer output1, kernel::ipc::OutputBuffer output2) : input({input}), output({output1, output2}) {} + enum class IoctlType : u8 { + Ioctl, //!< 1 input/output buffer + Ioctl2, //!< 1 input/output buffer + 1 input buffer + Ioctl3, //!< 1 input/output buffer + 1 output buffer }; /** * @brief NvDevice is the base class that all /dev/nv* devices inherit from */ class NvDevice { + private: + std::string name; //!< The name of the device + protected: const DeviceState &state; //!< The state of the device @@ -104,19 +73,19 @@ namespace skyline::service::nvdrv::device { virtual ~NvDevice() = default; - virtual std::function GetServiceFunction(u32 index) = 0; + virtual std::pair, std::span)>, std::string_view> GetIoctlFunction(u32 id) = 0; /** * @return The name of the class + * @note The lifetime of the returned string is tied to that of the class */ - std::string GetName(); + const std::string& GetName(); /** * @brief This handles IOCTL calls for devices * @param cmd The IOCTL command that was called - * @param input The input to the IOCTL call */ - void HandleIoctl(u32 cmd, IoctlData &input); + NvStatus HandleIoctl(u32 cmd, IoctlType type, std::span buffer, std::span inlineBuffer); inline virtual std::shared_ptr QueryEvent(u32 eventId) { return nullptr; diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp index fdcb961d..c5d1484d 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.cpp @@ -11,20 +11,21 @@ namespace skyline::service::nvdrv::device { NvHostAsGpu::NvHostAsGpu(const DeviceState &state) : NvDevice(state) {} - void NvHostAsGpu::BindChannel(IoctlData &buffer) { - struct Data { - u32 fd; - } &channelInfo = state.process->GetReference(buffer.input.at(0).address); + NvStatus NvHostAsGpu::BindChannel(IoctlType type, std::span buffer, std::span inlineBuffer) { + return NvStatus::Success; } - void NvHostAsGpu::AllocSpace(IoctlData &buffer) { + NvStatus NvHostAsGpu::AllocSpace(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { - u32 pages; - u32 pageSize; - u32 flags; + u32 pages; // In + u32 pageSize; // In + u32 flags; // In u32 _pad_; - u64 offset; - } region = state.process->GetObject(buffer.input.at(0).address); + union { + u64 offset; // InOut + u64 align; // In + }; + } region = util::As(buffer); u64 size = static_cast(region.pages) * static_cast(region.pageSize); @@ -35,57 +36,62 @@ namespace skyline::service::nvdrv::device { if (region.offset == 0) { state.logger->Warn("Failed to allocate GPU address space region!"); - buffer.status = NvStatus::BadParameter; + return NvStatus::BadParameter; } - state.process->WriteMemory(region, buffer.output.at(0).address); + return NvStatus::Success; } - void NvHostAsGpu::UnmapBuffer(IoctlData &buffer) { - auto offset = state.process->GetObject(buffer.input.at(0).address); + NvStatus NvHostAsGpu::UnmapBuffer(IoctlType type, std::span buffer, std::span inlineBuffer) { + u64 offset{util::As(buffer)}; if (!state.gpu->memoryManager.Unmap(offset)) state.logger->Warn("Failed to unmap chunk at 0x{:X}", offset); + + return NvStatus::Success; } - void NvHostAsGpu::Modify(IoctlData &buffer) { + NvStatus NvHostAsGpu::Modify(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { - u32 flags; - u32 kind; - u32 nvmapHandle; - u32 pageSize; - u64 bufferOffset; - u64 mappingSize; - u64 offset; - } region = state.process->GetObject(buffer.input.at(0).address); + u32 flags; // In + u32 kind; // In + u32 nvmapHandle; // In + u32 pageSize; // InOut + u64 bufferOffset; // In + u64 mappingSize; // In + u64 offset; // InOut + } &data = util::As(buffer); - if (!region.nvmapHandle) - return; + try { + auto driver = nvdrv::driver.lock(); + auto nvmap = driver->nvMap.lock(); + auto mapping = nvmap->handleTable.at(data.nvmapHandle); - auto driver = nvdrv::driver.lock(); - auto nvmap = driver->nvMap.lock(); - auto mapping = nvmap->handleTable.at(region.nvmapHandle); + u64 mapPhysicalAddress = data.bufferOffset + mapping->address; + u64 mapSize = data.mappingSize ? data.mappingSize : mapping->size; - u64 mapPhysicalAddress = region.bufferOffset + mapping->address; - u64 mapSize = region.mappingSize ? region.mappingSize : mapping->size; + if (data.flags & 1) + data.offset = state.gpu->memoryManager.MapFixed(data.offset, mapPhysicalAddress, mapSize); + else + data.offset = state.gpu->memoryManager.MapAllocate(mapPhysicalAddress, mapSize); - if (region.flags & 1) - region.offset = state.gpu->memoryManager.MapFixed(region.offset, mapPhysicalAddress, mapSize); - else - region.offset = state.gpu->memoryManager.MapAllocate(mapPhysicalAddress, mapSize); + if (data.offset == 0) { + state.logger->Warn("Failed to map GPU address space region!"); + return NvStatus::BadParameter; + } - if (region.offset == 0) { - state.logger->Warn("Failed to map GPU address space region!"); - buffer.status = NvStatus::BadParameter; + return NvStatus::Success; + } catch (const std::out_of_range &) { + state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.nvmapHandle); + return NvStatus::BadParameter; } - - state.process->WriteMemory(region, buffer.output.at(0).address); } - void NvHostAsGpu::GetVaRegions(IoctlData &buffer) { + NvStatus NvHostAsGpu::GetVaRegions(IoctlType type, std::span buffer, std::span inlineBuffer) { + /* struct Data { u64 _pad0_; - u32 bufferSize; + u32 bufferSize; // InOut u32 _pad1_; struct { @@ -93,38 +99,40 @@ namespace skyline::service::nvdrv::device { u32 page_size; u32 pad; u64 pages; - } regions[2]; - } ®ionInfo = state.process->GetReference(buffer.input.at(0).address); - state.process->WriteMemory(regionInfo, buffer.output.at(0).address); + } regions[2]; // Out + } ®ionInfo = util::As(buffer); + */ + return NvStatus::Success; } - void NvHostAsGpu::InitializeEx(IoctlData &buffer) { + NvStatus NvHostAsGpu::AllocAsEx(IoctlType type, std::span buffer, std::span inlineBuffer) { + /* struct Data { - u32 bigPageSize; - i32 asFd; - u32 flags; - u32 reserved; - u64 vaRangeStart; - u64 vaRangeEnd; - u64 vaRangeSplit; - } addressSpace = state.process->GetObject(buffer.input.at(0).address); + u32 bigPageSize; // In + i32 asFd; // In + u32 flags; // In + u32 reserved; // In + u64 vaRangeStart; // In + u64 vaRangeEnd; // In + u64 vaRangeSplit; // In + } addressSpace = util::As(buffer); + */ + return NvStatus::Success; } - void NvHostAsGpu::Remap(IoctlData &buffer) { + NvStatus NvHostAsGpu::Remap(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Entry { - u16 flags; - u16 kind; - u32 nvmapHandle; - u32 mapOffset; - u32 gpuOffset; - u32 pages; + u16 flags; // In + u16 kind; // In + u32 nvmapHandle; // In + u32 mapOffset; // In + u32 gpuOffset; // In + u32 pages; // In }; constexpr u32 MinAlignmentShift{0x10}; // This shift is applied to all addresses passed to Remap - size_t entryCount{buffer.input.at(0).size / sizeof(Entry)}; - std::span entries(state.process->GetPointer(buffer.input.at(0).address), entryCount); - + auto entries{util::AsSpan(buffer)}; for (auto entry : entries) { try { auto driver = nvdrv::driver.lock(); @@ -136,10 +144,12 @@ namespace skyline::service::nvdrv::device { u64 mapSize = static_cast(entry.pages) << MinAlignmentShift; state.gpu->memoryManager.MapFixed(mapAddress, mapPhysicalAddress, mapSize); - } catch (const std::exception &e) { - buffer.status = NvStatus::BadValue; - return; + } catch (const std::out_of_range &) { + state.logger->Warn("Invalid NvMap handle: 0x{:X}", entry.nvmapHandle); + return NvStatus::BadParameter; } } + + return NvStatus::Success; } } diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.h index b9dfe140..7b4eabfa 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_as_gpu.h @@ -16,37 +16,37 @@ namespace skyline::service::nvdrv::device { /** * @brief This binds a channel to the address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_BIND_CHANNEL) */ - void BindChannel(IoctlData &buffer); + NvStatus BindChannel(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This reserves a region in the GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_ALLOC_SPACE) */ - void AllocSpace(IoctlData &buffer); + NvStatus AllocSpace(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This unmaps a region in the GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_UNMAP_BUFFER) */ - void UnmapBuffer(IoctlData &buffer); + NvStatus UnmapBuffer(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This maps a region in the GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_MODIFY) */ - void Modify(IoctlData &buffer); + NvStatus Modify(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This returns the application's GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_GET_VA_REGIONS) */ - void GetVaRegions(IoctlData &buffer); + NvStatus GetVaRegions(IoctlType type, std::span buffer, std::span inlineBuffer); /** - * @brief This initializes the application's GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_INITIALIZE_EX) + * @brief This initializes the application's GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_ALLOC_AS_EX) */ - void InitializeEx(IoctlData &buffer); + NvStatus AllocAsEx(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief Remaps a region of the GPU address space (https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_REMAP) */ - void Remap(IoctlData &buffer); + NvStatus Remap(IoctlType type, std::span buffer, std::span inlineBuffer); NVDEVICE_DECL( NVFUNC(0x4101, NvHostAsGpu, BindChannel), @@ -54,7 +54,7 @@ namespace skyline::service::nvdrv::device { NVFUNC(0x4105, NvHostAsGpu, UnmapBuffer), NVFUNC(0x4106, NvHostAsGpu, Modify), NVFUNC(0x4108, NvHostAsGpu, GetVaRegions), - NVFUNC(0x4109, NvHostAsGpu, InitializeEx), + NVFUNC(0x4109, NvHostAsGpu, AllocAsEx), NVFUNC(0x4114, NvHostAsGpu, Remap) ) }; diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp index ff298628..e2715755 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp @@ -16,14 +16,18 @@ namespace skyline::service::nvdrv::device { channelFence.UpdateValue(hostSyncpoint); } - void NvHostChannel::SetNvmapFd(IoctlData &buffer) {} + NvStatus NvHostChannel::SetNvmapFd(IoctlType type, std::span buffer, std::span inlineBuffer) { + return NvStatus::Success; + } - void NvHostChannel::SetSubmitTimeout(IoctlData &buffer) {} + NvStatus NvHostChannel::SetSubmitTimeout(IoctlType type, std::span buffer, std::span inlineBuffer) { + return NvStatus::Success; + } - void NvHostChannel::SubmitGpfifo(IoctlData &buffer) { + NvStatus NvHostChannel::SubmitGpfifo(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { - u64 address; - u32 numEntries; + u64 address; // In + u32 numEntries; // In union { struct __attribute__((__packed__)) { bool fenceWait : 1; @@ -35,46 +39,50 @@ namespace skyline::service::nvdrv::device { bool incrementWithValue : 1; }; u32 raw; - } flags; - Fence fence; - } &args = state.process->GetReference(buffer.output.at(0).address); + } flags; // In + Fence fence; // InOut + } &data = util::As(buffer); auto driver = nvdrv::driver.lock(); auto &hostSyncpoint = driver->hostSyncpoint; - if (args.flags.fenceWait) { - if (args.flags.incrementWithValue) { - buffer.status = NvStatus::BadValue; - return; - } + if (data.flags.fenceWait) { + if (data.flags.incrementWithValue) + return NvStatus::BadValue; - if (hostSyncpoint.HasSyncpointExpired(args.fence.id, args.fence.value)) + if (hostSyncpoint.HasSyncpointExpired(data.fence.id, data.fence.value)) throw exception("Waiting on a fence through SubmitGpfifo is unimplemented"); } - state.gpu->gpfifo.Push(std::span(state.process->GetPointer(args.address), args.numEntries)); + state.gpu->gpfifo.Push(std::span(state.process->GetPointer(data.address), data.numEntries)); - args.fence.id = channelFence.id; + data.fence.id = channelFence.id; - u32 increment = (args.flags.fenceIncrement ? 2 : 0) + (args.flags.incrementWithValue ? args.fence.value : 0); - args.fence.value = hostSyncpoint.IncrementSyncpointMaxExt(args.fence.id, increment); + u32 increment = (data.flags.fenceIncrement ? 2 : 0) + (data.flags.incrementWithValue ? data.fence.value : 0); + data.fence.value = hostSyncpoint.IncrementSyncpointMaxExt(data.fence.id, increment); - if (args.flags.fenceIncrement) + if (data.flags.fenceIncrement) throw exception("Incrementing a fence through SubmitGpfifo is unimplemented"); - args.flags.raw = 0; + data.flags.raw = 0; + + return NvStatus::Success; } - void NvHostChannel::AllocObjCtx(IoctlData &buffer) {} + NvStatus NvHostChannel::AllocObjCtx(IoctlType type, std::span buffer, std::span inlineBuffer) { + return NvStatus::Success; + } - void NvHostChannel::ZcullBind(IoctlData &buffer) {} + NvStatus NvHostChannel::ZcullBind(IoctlType type, std::span buffer, std::span inlineBuffer) { + return NvStatus::Success; + } - void NvHostChannel::SetErrorNotifier(IoctlData &buffer) {} + NvStatus NvHostChannel::SetErrorNotifier(IoctlType type, std::span buffer, std::span inlineBuffer) { + return NvStatus::Success; + } - void NvHostChannel::SetPriority(IoctlData &buffer) { - auto priority = state.process->GetObject(buffer.input.at(0).address); - - switch (priority) { + NvStatus NvHostChannel::SetPriority(IoctlType type, std::span buffer, std::span inlineBuffer) { + switch (util::As(buffer)) { case NvChannelPriority::Low: timeslice = 1300; break; @@ -85,23 +93,29 @@ namespace skyline::service::nvdrv::device { timeslice = 5200; break; } + + return NvStatus::Success; } - void NvHostChannel::AllocGpfifoEx2(IoctlData &buffer) { + NvStatus NvHostChannel::AllocGpfifoEx2(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { - u32 numEntries; - u32 numJobs; - u32 flags; - Fence fence; - u32 reserved[3]; - } &args = state.process->GetReference(buffer.input.at(0).address); + u32 numEntries; // In + u32 numJobs; // In + u32 flags; // In + Fence fence; // Out + u32 reserved[3]; // In + } &data = util::As(buffer); auto driver = nvdrv::driver.lock(); channelFence.UpdateValue(driver->hostSyncpoint); - args.fence = channelFence; + data.fence = channelFence; + + return NvStatus::Success; } - void NvHostChannel::SetUserData(IoctlData &buffer) {} + NvStatus NvHostChannel::SetUserData(IoctlType type, std::span buffer, std::span inlineBuffer) { + return NvStatus::Success; + } std::shared_ptr NvHostChannel::QueryEvent(u32 eventId) { switch (eventId) { diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.h index da58fcbb..236ebd85 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.h @@ -30,47 +30,47 @@ namespace skyline::service::nvdrv::device { /** * @brief This sets the nvmap file descriptor (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD) */ - void SetNvmapFd(IoctlData &buffer); + NvStatus SetNvmapFd(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This sets the timeout for the channel (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_SET_SUBMIT_TIMEOUT) */ - void SetSubmitTimeout(IoctlData &buffer); + NvStatus SetSubmitTimeout(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This submits a command to the GPFIFO (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) */ - void SubmitGpfifo(IoctlData &buffer); + NvStatus SubmitGpfifo(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This allocates a graphic context object (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_OBJ_CTX) */ - void AllocObjCtx(IoctlData &buffer); + NvStatus AllocObjCtx(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This initializes the error notifier for this channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ZCULL_BIND) */ - void ZcullBind(IoctlData &buffer); + NvStatus ZcullBind(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This initializes the error notifier for this channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_ERROR_NOTIFIER) */ - void SetErrorNotifier(IoctlData &buffer); + NvStatus SetErrorNotifier(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This sets the priority of the channel (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_PRIORITY) */ - void SetPriority(IoctlData &buffer); + NvStatus SetPriority(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This allocates a GPFIFO entry (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX2) */ - void AllocGpfifoEx2(IoctlData &buffer); + NvStatus AllocGpfifoEx2(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This sets the user specific data (https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_USER_DATA) */ - void SetUserData(IoctlData &buffer); + NvStatus SetUserData(IoctlType type, std::span buffer, std::span inlineBuffer); std::shared_ptr QueryEvent(u32 eventId); diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl.cpp index dee771e1..46bb21ef 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl.cpp @@ -72,91 +72,79 @@ namespace skyline::service::nvdrv::device { throw exception("Failed to find a free nvhost event!"); } - void NvHostCtrl::EventWaitImpl(IoctlData &buffer, bool async) { + NvStatus NvHostCtrl::EventWaitImpl(std::span buffer, bool async) { struct Data { - Fence fence; - u32 timeout; - EventValue value; - } &args = state.process->GetReference(buffer.output.at(0).address); + Fence fence; // In + u32 timeout; // In + EventValue value; // InOut + } &data = util::As(buffer); - if (args.fence.id >= constant::MaxHwSyncpointCount) { - buffer.status = NvStatus::BadValue; - return; - } + if (data.fence.id >= constant::MaxHwSyncpointCount) + return NvStatus::BadValue; - if (args.timeout == 0) { - buffer.status = NvStatus::Timeout; - return; - } + if (data.timeout == 0) + return NvStatus::Timeout; auto driver = nvdrv::driver.lock(); auto &hostSyncpoint = driver->hostSyncpoint; // Check if the syncpoint has already expired using the last known values - if (hostSyncpoint.HasSyncpointExpired(args.fence.id, args.fence.value)) { - args.value.val = hostSyncpoint.ReadSyncpointMinValue(args.fence.id); - return; + if (hostSyncpoint.HasSyncpointExpired(data.fence.id, data.fence.value)) { + data.value.val = hostSyncpoint.ReadSyncpointMinValue(data.fence.id); + return NvStatus::Success; } // Sync the syncpoint with the GPU then check again - auto minVal = hostSyncpoint.UpdateMin(args.fence.id); - if (hostSyncpoint.HasSyncpointExpired(args.fence.id, args.fence.value)) { - args.value.val = minVal; - return; + auto minVal = hostSyncpoint.UpdateMin(data.fence.id); + if (hostSyncpoint.HasSyncpointExpired(data.fence.id, data.fence.value)) { + data.value.val = minVal; + return NvStatus::Success; } u32 userEventId{}; - if (async) { - if (args.value.val >= constant::NvHostEventCount || !events.at(args.value.val)) { - buffer.status = NvStatus::BadValue; - return; - } + if (data.value.val >= constant::NvHostEventCount || !events.at(data.value.val)) + return NvStatus::BadValue; - userEventId = args.value.val; + userEventId = data.value.val; } else { - args.fence.value = 0; + data.fence.value = 0; - userEventId = FindFreeEvent(args.fence.id); + userEventId = FindFreeEvent(data.fence.id); } - auto event = &*events.at(userEventId); + auto& event = *events.at(userEventId); + if (event.state == NvHostEvent::State::Cancelled || event.state == NvHostEvent::State::Available || event.state == NvHostEvent::State::Signaled) { + state.logger->Debug("Now waiting on nvhost event: {} with fence: {}", userEventId, data.fence.id); + event.Wait(state.gpu, data.fence); - if (event->state == NvHostEvent::State::Cancelled || event->state == NvHostEvent::State::Available || event->state == NvHostEvent::State::Signaled) { - state.logger->Debug("Now waiting on nvhost event: {} with fence: {}", userEventId, args.fence.id); - event->Wait(state.gpu, args.fence); - - args.value.val = 0; + data.value.val = 0; if (async) { - args.value.syncpointIdAsync = args.fence.id; + data.value.syncpointIdAsync = data.fence.id; } else { - args.value.syncpointIdNonAsync = args.fence.id; - args.value.nonAsync = true; + data.value.syncpointIdNonAsync = data.fence.id; + data.value.nonAsync = true; } - args.value.val |= userEventId; + data.value.val |= userEventId; - buffer.status = NvStatus::Timeout; - return; + return NvStatus::Timeout; } else { - buffer.status = NvStatus::BadValue; - return; + return NvStatus::BadValue; } } - void NvHostCtrl::GetConfig(IoctlData &buffer) { - buffer.status = NvStatus::BadValue; + NvStatus NvHostCtrl::GetConfig(IoctlType type, std::span buffer, std::span inlineBuffer) { + return NvStatus::BadValue; } - void NvHostCtrl::EventSignal(IoctlData &buffer) { - auto userEventId = static_cast(state.process->GetObject(buffer.input.at(0).address)); + NvStatus NvHostCtrl::EventSignal(IoctlType type, std::span buffer, std::span inlineBuffer) { + auto userEventId{util::As(buffer)}; state.logger->Debug("Signalling nvhost event: {}", userEventId); - if (userEventId >= constant::NvHostEventCount || !events.at(userEventId)) { - buffer.status = NvStatus::BadValue; - return; - } + if (userEventId >= constant::NvHostEventCount || !events.at(userEventId)) + return NvStatus::BadValue; auto &event = *events.at(userEventId); @@ -171,30 +159,32 @@ namespace skyline::service::nvdrv::device { auto driver = nvdrv::driver.lock(); auto &hostSyncpoint = driver->hostSyncpoint; hostSyncpoint.UpdateMin(event.fence.id); + + return NvStatus::Success; } - void NvHostCtrl::EventWait(IoctlData &buffer) { - EventWaitImpl(buffer, false); + NvStatus NvHostCtrl::EventWait(IoctlType type, std::span buffer, std::span inlineBuffer) { + return EventWaitImpl(buffer, false); } - void NvHostCtrl::EventWaitAsync(IoctlData &buffer) { - EventWaitImpl(buffer, true); + NvStatus NvHostCtrl::EventWaitAsync(IoctlType type, std::span buffer, std::span inlineBuffer) { + return EventWaitImpl(buffer, true); } - void NvHostCtrl::EventRegister(IoctlData &buffer) { - auto userEventId = state.process->GetObject(buffer.input.at(0).address); + NvStatus NvHostCtrl::EventRegister(IoctlType type, std::span buffer, std::span inlineBuffer) { + auto userEventId{util::As(buffer)}; state.logger->Debug("Registering nvhost event: {}", userEventId); auto &event = events.at(userEventId); - if (event) throw exception("Recreating events is unimplemented"); - event = NvHostEvent(state); + + return NvStatus::Success; } std::shared_ptr NvHostCtrl::QueryEvent(u32 eventId) { - auto eventValue = EventValue{.val = eventId}; + EventValue eventValue{.val = eventId}; const auto &event = events.at(eventValue.nonAsync ? eventValue.eventSlotNonAsync : eventValue.eventSlotAsync); if (event && event->fence.id == (eventValue.nonAsync ? eventValue.syncpointIdNonAsync : eventValue.syncpointIdAsync)) diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl.h index c96fdcad..7fa2653c 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl.h @@ -87,7 +87,7 @@ namespace skyline { */ u32 FindFreeEvent(u32 syncpointId); - void EventWaitImpl(IoctlData &buffer, bool async); + NvStatus EventWaitImpl(std::span buffer, bool async); public: NvHostCtrl(const DeviceState &state); @@ -95,27 +95,27 @@ namespace skyline { /** * @brief This gets the value of an nvdrv setting, it returns an error code on production switches (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_GET_CONFIG) */ - void GetConfig(IoctlData &buffer); + NvStatus GetConfig(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This signals an NvHost event (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_SIGNAL) */ - void EventSignal(IoctlData &buffer); + NvStatus EventSignal(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This synchronously waits on an NvHost event (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_WAIT) */ - void EventWait(IoctlData &buffer); + NvStatus EventWait(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This asynchronously waits on an NvHost event (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_WAIT_ASYNC) */ - void EventWaitAsync(IoctlData &buffer); + NvStatus EventWaitAsync(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This registers an NvHost event (https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CTRL_EVENT_REGISTER) */ - void EventRegister(IoctlData &buffer); + NvStatus EventRegister(IoctlType type, std::span buffer, std::span inlineBuffer); std::shared_ptr QueryEvent(u32 eventId); diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.cpp index ba211e31..fc35007b 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -7,13 +7,13 @@ namespace skyline::service::nvdrv::device { NvHostCtrlGpu::NvHostCtrlGpu(const DeviceState &state) : errorNotifierEvent(std::make_shared(state)), unknownEvent(std::make_shared(state)), NvDevice(state) {} - void NvHostCtrlGpu::ZCullGetCtxSize(IoctlData &buffer) { - u32 size = 0x1; - state.process->WriteMemory(size, buffer.output[0].address); + NvStatus NvHostCtrlGpu::ZCullGetCtxSize(IoctlType type, std::span buffer, std::span inlineBuffer) { + util::As(buffer) = 0x1; + return NvStatus::Success; } - void NvHostCtrlGpu::ZCullGetInfo(IoctlData &buffer) { - struct { + NvStatus NvHostCtrlGpu::ZCullGetInfo(IoctlType type, std::span buffer, std::span inlineBuffer) { + struct ZCullInfo { u32 widthAlignPixels{0x20}; u32 heightAlignPixels{0x20}; u32 pixelSquaresByAliquots{0x400}; @@ -26,119 +26,84 @@ namespace skyline::service::nvdrv::device { u32 subregionCount{0x10}; } zCullInfo; - state.process->WriteMemory(zCullInfo, buffer.output[0].address); + util::As(buffer) = zCullInfo; + return NvStatus::Success; } - void NvHostCtrlGpu::GetCharacteristics(IoctlData &buffer) { + NvStatus NvHostCtrlGpu::GetCharacteristics(IoctlType type, std::span buffer, std::span inlineBuffer) { struct GpuCharacteristics { - u32 arch; // 0x120 (NVGPU_GPU_ARCH_GM200) - u32 impl; // 0xB (NVGPU_GPU_IMPL_GM20B) or 0xE (NVGPU_GPU_IMPL_GM20B_B) - u32 rev; // 0xA1 (Revision A1) - u32 numGpc; // 0x1 - u64 l2CacheSize; // 0x40000 - u64 onBoardVideoMemorySize; // 0x0 (not used) - u32 numTpcPerGpc; // 0x2 - u32 busType; // 0x20 (NVGPU_GPU_BUS_TYPE_AXI) - u32 bigPageSize; // 0x20000 - u32 compressionPageSize; // 0x20000 - u32 pdeCoverageBitCount; // 0x1B - u32 availableBigPageSizes; // 0x30000 - u32 gpcMask; // 0x1 - u32 smArchSmVersion; // 0x503 (Maxwell Generation 5.0.3) - u32 smArchSpaVersion; // 0x503 (Maxwell Generation 5.0.3) - u32 smArchWarpCount; // 0x80 - u32 gpuVaBitCount; // 0x28 - u32 reserved; // NULL - u64 flags; // 0x55 (HAS_SYNCPOINTS | SUPPORT_SPARSE_ALLOCS | SUPPORT_CYCLE_STATS | SUPPORT_CYCLE_STATS_SNAPSHOT) - u32 twodClass; // 0x902D (FERMI_TWOD_A) - u32 threedClass; // 0xB197 (MAXWELL_B) - u32 computeClass; // 0xB1C0 (MAXWELL_COMPUTE_B) - u32 gpfifoClass; // 0xB06F (MAXWELL_CHANNEL_GPFIFO_A) - u32 inlineToMemoryClass; // 0xA140 (KEPLER_INLINE_TO_MEMORY_B) - u32 dmaCopyClass; // 0xB0B5 (MAXWELL_DMA_COPY_A) - u32 maxFbpsCount; // 0x1 - u32 fbpEnMask; // 0x0 (disabled) - u32 maxLtcPerFbp; // 0x2 - u32 maxLtsPerLtc; // 0x1 - u32 maxTexPerTpc; // 0x0 (not supported) - u32 maxGpcCount; // 0x1 - u32 ropL2EnMask0; // 0x21D70 (fuse_status_opt_rop_l2_fbp_r) - u32 ropL2EnMask1; // 0x0 - u64 chipName; // 0x6230326D67 ("gm20b") - u64 grCompbitStoreBaseHw; // 0x0 (not supported) + u32 arch{0x120}; // NVGPU_GPU_ARCH_GM200 + u32 impl{0xB}; // 0xB (NVGPU_GPU_IMPL_GM20B) or 0xE (NVGPU_GPU_IMPL_GM20B_B) + u32 rev{0xA1}; + u32 numGpc{0x1}; + u64 l2CacheSize{0x40000}; + u64 onBoardVideoMemorySize{}; // UMA + u32 numTpcPerGpc{0x2}; + u32 busType{0x20}; // NVGPU_GPU_BUS_TYPE_AXI + u32 bigPageSize{0x20000}; + u32 compressionPageSize{0x20000}; + u32 pdeCoverageBitCount{0x1B}; + u32 availableBigPageSizes{0x30000}; + u32 gpcMask{0x1}; + u32 smArchSmVersion{0x503}; // Maxwell Generation 5.0.3 + u32 smArchSpaVersion{0x503}; // Maxwell Generation 5.0.3 + u32 smArchWarpCount{0x80}; + u32 gpuVaBitCount{0x28}; + u32 reserved{}; + u64 flags{0x55}; // HAS_SYNCPOINTS | SUPPORT_SPARSE_ALLOCS | SUPPORT_CYCLE_STATS | SUPPORT_CYCLE_STATS_SNAPSHOT + u32 twodClass{0x902D}; // FERMI_TWOD_A + u32 threedClass{0xB197}; // MAXWELL_B + u32 computeClass{0xB1C0}; // MAXWELL_COMPUTE_B + u32 gpfifoClass{0xB06F}; // MAXWELL_CHANNEL_GPFIFO_A + u32 inlineToMemoryClass{0xA140}; // KEPLER_INLINE_TO_MEMORY_B + u32 dmaCopyClass{0xA140}; // MAXWELL_DMA_COPY_A + u32 maxFbpsCount{0x1}; // 0x1 + u32 fbpEnMask{}; // Disabled + u32 maxLtcPerFbp{0x2}; + u32 maxLtsPerLtc{0x1}; + u32 maxTexPerTpc{}; // Not Supported + u32 maxGpcCount{0x1}; + u32 ropL2EnMask0{0x21D70}; // fuse_status_opt_rop_l2_fbp_r + u32 ropL2EnMask1{}; + u64 chipName{util::MakeMagic("gm20b")}; + u64 grCompbitStoreBaseHw{}; // Not Supported }; struct Data { u64 gpuCharacteristicsBufSize; // InOut u64 gpuCharacteristicsBufAddr; // In GpuCharacteristics gpuCharacteristics; // Out - } data = state.process->GetObject(buffer.input[0].address); + } &data = util::As(buffer); - data.gpuCharacteristics = { - .arch = 0x120, - .impl = 0xB, - .rev = 0xA1, - .numGpc = 0x1, - .l2CacheSize = 0x40000, - .onBoardVideoMemorySize = 0x0, - .numTpcPerGpc = 0x2, - .busType = 0x20, - .bigPageSize = 0x20000, - .compressionPageSize = 0x20000, - .pdeCoverageBitCount = 0x1B, - .availableBigPageSizes = 0x30000, - .gpcMask = 0x1, - .smArchSmVersion = 0x503, - .smArchSpaVersion = 0x503, - .smArchWarpCount = 0x80, - .gpuVaBitCount = 0x2, - .flags = 0x55, - .twodClass = 0x902D, - .threedClass = 0xB197, - .computeClass = 0xB1C0, - .gpfifoClass = 0xB06F, - .inlineToMemoryClass = 0xA140, - .dmaCopyClass = 0xB0B5, - .maxFbpsCount = 0x1, - .fbpEnMask = 0x0, - .maxLtcPerFbp = 0x2, - .maxLtsPerLtc = 0x1, - .maxTexPerTpc = 0x0, - .maxGpcCount = 0x1, - .ropL2EnMask0 = 0x21D70, - .ropL2EnMask1 = 0x0, - .chipName = 0x6230326D67, - .grCompbitStoreBaseHw = 0x0 - }; + if (data.gpuCharacteristicsBufSize < sizeof(GpuCharacteristics)) + return NvStatus::InvalidSize; - data.gpuCharacteristicsBufSize = 0xA0; + data.gpuCharacteristics = GpuCharacteristics{}; + data.gpuCharacteristicsBufSize = sizeof(GpuCharacteristics); - state.process->WriteMemory(data, buffer.output[0].address); + return NvStatus::Success; } - void NvHostCtrlGpu::GetTpcMasks(IoctlData &buffer) { + NvStatus NvHostCtrlGpu::GetTpcMasks(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { u32 maskBufSize; // In u32 reserved[3]; // In u64 maskBuf; // Out - } data = state.process->GetObject(buffer.input[0].address); + } &data = util::As(buffer); if (data.maskBufSize) data.maskBuf = 0x3; - state.process->WriteMemory(data, buffer.output[0].address); + return NvStatus::Success; } - void NvHostCtrlGpu::GetActiveSlotMask(IoctlData &buffer) { + NvStatus NvHostCtrlGpu::GetActiveSlotMask(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { - u32 slot; // Out - u32 mask; // Out - } data = { - .slot = 0x07, - .mask = 0x01 - }; - - state.process->WriteMemory(data, buffer.output[0].address); + u32 slot{0x07}; // Out + u32 mask{0x01}; // Out + } data; + util::As(buffer) = data; + return NvStatus::Success; } std::shared_ptr NvHostCtrlGpu::QueryEvent(u32 eventId) { @@ -151,5 +116,4 @@ namespace skyline::service::nvdrv::device { return nullptr; } } - } diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.h index eb3bc6f5..5ea34863 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_ctrl_gpu.h @@ -20,27 +20,27 @@ namespace skyline::service::nvdrv::device { /** * @brief This returns a u32 GPU ZCULL Context Size (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZCULL_GET_CTX_SIZE) */ - void ZCullGetCtxSize(IoctlData &buffer); + NvStatus ZCullGetCtxSize(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This returns a the GPU ZCULL Information (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZCULL_GET_INFO) */ - void ZCullGetInfo(IoctlData &buffer); + NvStatus ZCullGetInfo(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This returns a struct with certain GPU characteristics (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_GET_CHARACTERISTICS) */ - void GetCharacteristics(IoctlData &buffer); + NvStatus GetCharacteristics(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This returns the TPC mask value for each GPC (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_GET_TPC_MASKS) */ - void GetTpcMasks(IoctlData &buffer); + NvStatus GetTpcMasks(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This returns the mask value for a ZBC slot (https://switchbrew.org/wiki/NV_services#NVGPU_GPU_IOCTL_ZBC_GET_ACTIVE_SLOT_MASK) */ - void GetActiveSlotMask(IoctlData &buffer); + NvStatus GetActiveSlotMask(IoctlType type, std::span buffer, std::span inlineBuffer); std::shared_ptr QueryEvent(u32 eventId); diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp index bcde19ee..bad99df3 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp @@ -9,138 +9,153 @@ namespace skyline::service::nvdrv::device { NvMap::NvMap(const DeviceState &state) : NvDevice(state) {} - void NvMap::Create(IoctlData &buffer) { + NvStatus NvMap::Create(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { u32 size; // In u32 handle; // Out - } data = state.process->GetObject(buffer.input[0].address); + } &data = util::As(buffer); handleTable[handleIndex] = std::make_shared(idIndex++, data.size); data.handle = handleIndex++; - state.process->WriteMemory(data, buffer.output[0].address); - state.logger->Debug("Create: Input: Size: 0x{:X}, Output: Handle: 0x{:X}, Status: {}", data.size, data.handle, buffer.status); + state.logger->Debug("Size: 0x{:X} -> Handle: 0x{:X}", data.size, data.handle); + return NvStatus::Success; } - void NvMap::FromId(IoctlData &buffer) { + NvStatus NvMap::FromId(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { u32 id; // In u32 handle; // Out - } data = state.process->GetObject(buffer.input[0].address); + } &data = util::As(buffer); - bool found{}; for (const auto &object : handleTable) { if (object.second->id == data.id) { data.handle = object.first; - found = true; - break; + state.logger->Debug("ID: 0x{:X} -> Handle: 0x{:X}", data.id, data.handle); + return NvStatus::Success; } } - if (found) - state.process->WriteMemory(data, buffer.output[0].address); - else - buffer.status = NvStatus::BadValue; - - state.logger->Debug("FromId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status); + state.logger->Warn("Handle not found for ID: 0x{:X}", data.id); + return NvStatus::BadValue; } - void NvMap::Alloc(IoctlData &buffer) { + NvStatus NvMap::Alloc(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { u32 handle; // In u32 heapMask; // In u32 flags; // In u32 align; // In - u8 kind; // In + u8 kind; // In u8 _pad0_[7]; u64 address; // InOut - } data = state.process->GetObject(buffer.input[0].address); + } &data = util::As(buffer); - auto &object = handleTable.at(data.handle); - object->heapMask = data.heapMask; - object->flags = data.flags; - object->align = data.align; - object->kind = data.kind; - object->address = data.address; - object->status = NvMapObject::Status::Allocated; + try { + auto &object = handleTable.at(data.handle); + object->heapMask = data.heapMask; + object->flags = data.flags; + object->align = data.align; + object->kind = data.kind; + object->address = data.address; + object->status = NvMapObject::Status::Allocated; - state.logger->Debug("Alloc: Input: Handle: 0x{:X}, HeapMask: 0x{:X}, Flags: {}, Align: 0x{:X}, Kind: {}, Address: 0x{:X}, Output: Status: {}", data.handle, data.heapMask, data.flags, data.align, data.kind, data.address, buffer.status); + state.logger->Debug("Handle: 0x{:X}, HeapMask: 0x{:X}, Flags: {}, Align: 0x{:X}, Kind: {}, Address: 0x{:X}", data.handle, data.heapMask, data.flags, data.align, data.kind, data.address); + return NvStatus::Success; + } catch (const std::out_of_range &) { + state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.handle); + return NvStatus::BadParameter; + } } - void NvMap::Free(IoctlData &buffer) { + NvStatus NvMap::Free(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { u32 handle; // In u32 _pad0_; u64 address; // Out u32 size; // Out u32 flags; // Out - } data = state.process->GetObject(buffer.input[0].address); + } &data = util::As(buffer); - const auto &object = handleTable.at(data.handle); - if (object.use_count() > 1) { - data.address = static_cast(object->address); - data.flags = 0x0; - } else { - data.address = 0x0; - data.flags = 0x1; // Not free yet + try { + const auto &object = handleTable.at(data.handle); + if (object.use_count() > 1) { + data.address = static_cast(object->address); + data.flags = 0x0; + } else { + data.address = 0x0; + data.flags = 0x1; // Not free yet + } + + data.size = object->size; + handleTable.erase(data.handle); + + state.logger->Debug("Handle: 0x{:X} -> Address: 0x{:X}, Size: 0x{:X}, Flags: 0x{:X}", data.handle, data.address, data.size, data.flags); + return NvStatus::Success; + } catch (const std::out_of_range &) { + state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.handle); + return NvStatus::BadParameter; } - - data.size = object->size; - handleTable.erase(data.handle); - - state.process->WriteMemory(data, buffer.output[0].address); } - void NvMap::Param(IoctlData &buffer) { + NvStatus NvMap::Param(IoctlType type, std::span buffer, std::span inlineBuffer) { enum class Parameter : u32 { Size = 1, Alignment = 2, Base = 3, HeapMask = 4, Kind = 5, Compr = 6 }; // https://android.googlesource.com/kernel/tegra/+/refs/heads/android-tegra-flounder-3.10-marshmallow/include/linux/nvmap.h#102 struct Data { u32 handle; // In Parameter parameter; // In u32 result; // Out - } data = state.process->GetObject(buffer.input[0].address); + } &data = util::As(buffer); try { auto &object = handleTable.at(data.handle); - switch (data.parameter) { case Parameter::Size: data.result = object->size; break; + case Parameter::Alignment: data.result = object->align; break; + case Parameter::HeapMask: data.result = object->heapMask; break; + case Parameter::Kind: data.result = object->kind; break; + case Parameter::Compr: data.result = 0; break; + default: - buffer.status = NvStatus::NotImplemented; - return; + state.logger->Warn("Parameter not implemented: 0x{:X}", data.parameter); + return NvStatus::NotImplemented; } - state.process->WriteMemory(data, buffer.output[0].address); - state.logger->Debug("Param: Input: Handle: 0x{:X}, Parameter: {}, Output: Result: 0x{:X}, Status: {}", data.handle, data.parameter, data.result, buffer.status); - } catch (std::exception &e) { - buffer.status = NvStatus::BadParameter; - return; + state.logger->Debug("Handle: 0x{:X}, Parameter: {} -> Result: 0x{:X}", data.handle, data.parameter, data.result); + return NvStatus::Success; + } catch (const std::out_of_range &) { + state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.handle); + return NvStatus::BadParameter; } } - void NvMap::GetId(IoctlData &buffer) { + NvStatus NvMap::GetId(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { u32 id; // Out u32 handle; // In - } data = state.process->GetObject(buffer.input[0].address); + } &data = util::As(buffer); - data.id = handleTable.at(data.handle)->id; - - state.process->WriteMemory(data, buffer.output[0].address); - state.logger->Debug("GetId: Input: Handle: 0x{:X}, Output: ID: 0x{:X}, Status: {}", data.handle, data.id, buffer.status); + try { + data.id = handleTable.at(data.handle)->id; + state.logger->Debug("Handle: 0x{:X} -> ID: 0x{:X}", data.handle, data.id); + return NvStatus::Success; + } catch (const std::out_of_range &) { + state.logger->Warn("Invalid NvMap handle: 0x{:X}", data.handle); + return NvStatus::BadParameter; + } } } diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h index a465e3e5..0448a3c4 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.h @@ -44,32 +44,32 @@ namespace skyline::service::nvdrv::device { /** * @brief This creates an NvMapObject and returns an handle to it (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_CREATE) */ - void Create(IoctlData &buffer); + NvStatus Create(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This returns the handle of an NvMapObject from it's ID (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_FROM_ID) */ - void FromId(IoctlData &buffer); + NvStatus FromId(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This allocates memory for an NvMapObject (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_ALLOC) */ - void Alloc(IoctlData &buffer); + NvStatus Alloc(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This frees previously allocated memory (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_FREE) */ - void Free(IoctlData &buffer); + NvStatus Free(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This returns a particular parameter from an NvMapObject (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_PARAM) */ - void Param(IoctlData &buffer); + NvStatus Param(IoctlType type, std::span buffer, std::span inlineBuffer); /** * @brief This returns the ID of an NvMapObject from it's handle (https://switchbrew.org/wiki/NV_services#NVMAP_IOC_GET_ID) */ - void GetId(IoctlData &buffer); + NvStatus GetId(IoctlType type, std::span buffer, std::span inlineBuffer); NVDEVICE_DECL( NVFUNC(0x0101, NvMap, Create),