From bb2c31264d9f5bb4717c38f5c829fe37c152f968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=97=B1=20PixelyIon?= Date: Sun, 20 Sep 2020 11:19:09 +0530 Subject: [PATCH] Implement IOCTL2 & IOCTL3 --- .../skyline/services/nvdrv/INvDrvServices.cpp | 72 +++++++++++++------ .../skyline/services/nvdrv/INvDrvServices.h | 16 ++++- .../services/nvdrv/devices/nvdevice.cpp | 14 +++- .../services/nvdrv/devices/nvhost_as_gpu.cpp | 6 +- 4 files changed, 80 insertions(+), 28 deletions(-) diff --git a/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp b/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp index 34c5e3dd..2018320f 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.cpp @@ -13,7 +13,7 @@ namespace skyline::service::nvdrv { {0x2, SFUNC(INvDrvServices::Close)}, {0x3, SFUNC(INvDrvServices::Initialize)}, {0x4, SFUNC(INvDrvServices::QueryEvent)}, - {0x8, SFUNC(INvDrvServices::SetAruidByPID)}, + {0x8, SFUNC(INvDrvServices::SetAruid)}, {0xD, SFUNC(INvDrvServices::SetGraphicsFirmwareMemoryMarginEnabled)} }) { if (nvdrv::driver.expired()) @@ -39,26 +39,22 @@ namespace skyline::service::nvdrv { // Strip the permissions from the command leaving only the ID cmd &= 0xFFFF; - try { - std::optional buffer{std::nullopt}; - if (request.inputBuf.empty() || request.outputBuf.empty()) { - 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) { + std::optional buffer{std::nullopt}; + if (request.inputBuf.empty() || request.outputBuf.empty()) { + if (!request.inputBuf.empty()) buffer = request.inputBuf.at(0); - } else { - throw exception("IOCTL Input Buffer != Output Buffer"); - } - - 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); + 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 { + throw exception("IOCTL Input Buffer (0x{:X}) != Output Buffer (0x{:X})", request.inputBuf[0].address, request.outputBuf[0].address); } + + response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl, std::span(reinterpret_cast(buffer->address), buffer->size), {})); + return {}; } Result INvDrvServices::Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { @@ -97,11 +93,47 @@ namespace skyline::service::nvdrv { return {}; } - Result INvDrvServices::SetAruidByPID(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + Result INvDrvServices::SetAruid(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { response.Push(device::NvStatus::Success); return {}; } + Result INvDrvServices::Ioctl2(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + auto fd = request.Pop(); + auto cmd = request.Pop(); + + auto device = driver->GetDevice(fd); + + // Strip the permissions from the command leaving only the ID + cmd &= 0xFFFF; + + if (request.inputBuf.size() < 2 || request.outputBuf.empty()) + throw exception("Inadequate amount of buffers for IOCTL2: I - {}, O - {}", request.inputBuf.size(), request.outputBuf.size()); + else if (request.inputBuf[0].address != request.outputBuf[0].address) + throw exception("IOCTL2 Input Buffer (0x{:X}) != Output Buffer (0x{:X}) [Input Buffer #2: 0x{:X}]", request.inputBuf[0].address, request.outputBuf[0].address, request.inputBuf[1].address); + + response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl2, std::span(reinterpret_cast(request.inputBuf[0].address), request.inputBuf[0].size), std::span(reinterpret_cast(request.inputBuf[1].address), request.inputBuf[1].size))); + return {}; + } + + Result INvDrvServices::Ioctl3(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + auto fd = request.Pop(); + auto cmd = request.Pop(); + + auto device = driver->GetDevice(fd); + + // Strip the permissions from the command leaving only the ID + cmd &= 0xFFFF; + + if (request.inputBuf.empty() || request.outputBuf.size() < 2) + throw exception("Inadequate amount of buffers for IOCTL3: I - {}, O - {}", request.inputBuf.size(), request.outputBuf.size()); + else if (request.inputBuf[0].address != request.outputBuf[0].address) + throw exception("IOCTL3 Input Buffer (0x{:X}) != Output Buffer (0x{:X}) [Output Buffer #2: 0x{:X}]", request.inputBuf[0].address, request.outputBuf[0].address, request.outputBuf[1].address); + + response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl3, std::span(reinterpret_cast(request.inputBuf[0].address), request.inputBuf[0].size), std::span(reinterpret_cast(request.outputBuf[1].address), request.outputBuf[1].size))); + return {}; + } + Result INvDrvServices::SetGraphicsFirmwareMemoryMarginEnabled(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { return {}; } diff --git a/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.h b/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.h index b7a4ac6e..572c3c24 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.h +++ b/app/src/main/cpp/skyline/services/nvdrv/INvDrvServices.h @@ -25,7 +25,7 @@ namespace skyline::service::nvdrv { Result Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); /** - * @brief Close the specified FD (https://switchbrew.org/wiki/NV_services#Close) + * @brief Perform an IOCTL on the specified FD (https://switchbrew.org/wiki/NV_services#Ioctl) */ Result Ioctl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); @@ -45,9 +45,19 @@ namespace skyline::service::nvdrv { Result QueryEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); /** - * @brief This sets the AppletResourceUserId which matches the PID (https://switchbrew.org/wiki/NV_services#SetAruidByPID) + * @brief This sets the AppletResourceUserId which matches the PID (https://switchbrew.org/wiki/NV_services#SetAruid) */ - Result SetAruidByPID(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + Result SetAruid(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Perform an IOCTL on the specified FD with an extra input buffer (https://switchbrew.org/wiki/NV_services#Ioctl2) + */ + Result Ioctl2(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Perform an IOCTL on the specified FD with an extra output buffer (https://switchbrew.org/wiki/NV_services#Ioctl3) + */ + Result Ioctl3(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); /** * @brief This enables the graphics firmware memory margin (https://switchbrew.org/wiki/NV_services#SetGraphicsFirmwareMemoryMarginEnabled) 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 1e034a9f..038acc8f 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvdevice.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvdevice.cpp @@ -21,14 +21,24 @@ namespace skyline::service::nvdrv::device { std::pair, std::span)>, std::string_view> function; try { function = GetIoctlFunction(cmd); - state.logger->Debug("IOCTL @ {}: {}", GetName(), function.second); + std::string_view typeString{[type] { + switch (type) { + case IoctlType::Ioctl: + return "IOCTL"; + case IoctlType::Ioctl2: + return "IOCTL2"; + case IoctlType::Ioctl3: + return "IOCTL3"; + } + }()}; + state.logger->Debug("{} @ {}: {}", typeString, GetName(), function.second); } catch (std::out_of_range &) { state.logger->Warn("Cannot find IOCTL for device '{}': 0x{:X}", GetName(), cmd); return NvStatus::NotImplemented; } try { return function.first(type, buffer, inlineBuffer); - } catch (std::exception &e) { + } catch (const std::exception &e) { throw exception("{} (Device: {})", e.what(), GetName()); } exit(0); 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 c5d1484d..c0aae8c3 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 @@ -17,9 +17,9 @@ namespace skyline::service::nvdrv::device { NvStatus NvHostAsGpu::AllocSpace(IoctlType type, std::span buffer, std::span inlineBuffer) { struct Data { - u32 pages; // In - u32 pageSize; // In - u32 flags; // In + u32 pages; // In + u32 pageSize; // In + u32 flags; // In u32 _pad_; union { u64 offset; // InOut