Implement IOCTL2 & IOCTL3

This commit is contained in:
◱ PixelyIon 2020-09-20 11:19:09 +05:30 committed by ◱ PixelyIon
parent a5fece8020
commit bb2c31264d
4 changed files with 80 additions and 28 deletions

View File

@ -13,7 +13,7 @@ namespace skyline::service::nvdrv {
{0x2, SFUNC(INvDrvServices::Close)}, {0x2, SFUNC(INvDrvServices::Close)},
{0x3, SFUNC(INvDrvServices::Initialize)}, {0x3, SFUNC(INvDrvServices::Initialize)},
{0x4, SFUNC(INvDrvServices::QueryEvent)}, {0x4, SFUNC(INvDrvServices::QueryEvent)},
{0x8, SFUNC(INvDrvServices::SetAruidByPID)}, {0x8, SFUNC(INvDrvServices::SetAruid)},
{0xD, SFUNC(INvDrvServices::SetGraphicsFirmwareMemoryMarginEnabled)} {0xD, SFUNC(INvDrvServices::SetGraphicsFirmwareMemoryMarginEnabled)}
}) { }) {
if (nvdrv::driver.expired()) if (nvdrv::driver.expired())
@ -39,7 +39,6 @@ namespace skyline::service::nvdrv {
// Strip the permissions from the command leaving only the ID // Strip the permissions from the command leaving only the ID
cmd &= 0xFFFF; cmd &= 0xFFFF;
try {
std::optional<kernel::ipc::IpcBuffer> buffer{std::nullopt}; std::optional<kernel::ipc::IpcBuffer> buffer{std::nullopt};
if (request.inputBuf.empty() || request.outputBuf.empty()) { if (request.inputBuf.empty() || request.outputBuf.empty()) {
if (!request.inputBuf.empty()) if (!request.inputBuf.empty())
@ -51,14 +50,11 @@ namespace skyline::service::nvdrv {
} else if (request.inputBuf.at(0).address == request.outputBuf.at(0).address) { } else if (request.inputBuf.at(0).address == request.outputBuf.at(0).address) {
buffer = request.inputBuf.at(0); buffer = request.inputBuf.at(0);
} else { } else {
throw exception("IOCTL Input Buffer != Output Buffer"); 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<u8>(reinterpret_cast<u8 *>(buffer->address), buffer->size), {})); response.Push(device->HandleIoctl(cmd, device::IoctlType::Ioctl, std::span<u8>(reinterpret_cast<u8 *>(buffer->address), buffer->size), {}));
return {}; 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) { Result INvDrvServices::Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
@ -97,11 +93,47 @@ namespace skyline::service::nvdrv {
return {}; 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); response.Push(device::NvStatus::Success);
return {}; return {};
} }
Result INvDrvServices::Ioctl2(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto fd = request.Pop<u32>();
auto cmd = request.Pop<u32>();
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<u8>(reinterpret_cast<u8 *>(request.inputBuf[0].address), request.inputBuf[0].size), std::span<u8>(reinterpret_cast<u8 *>(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<u32>();
auto cmd = request.Pop<u32>();
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<u8>(reinterpret_cast<u8 *>(request.inputBuf[0].address), request.inputBuf[0].size), std::span<u8>(reinterpret_cast<u8 *>(request.outputBuf[1].address), request.outputBuf[1].size)));
return {};
}
Result INvDrvServices::SetGraphicsFirmwareMemoryMarginEnabled(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { Result INvDrvServices::SetGraphicsFirmwareMemoryMarginEnabled(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
return {}; return {};
} }

View File

@ -25,7 +25,7 @@ namespace skyline::service::nvdrv {
Result Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); 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); 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); 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) * @brief This enables the graphics firmware memory margin (https://switchbrew.org/wiki/NV_services#SetGraphicsFirmwareMemoryMarginEnabled)

View File

@ -21,14 +21,24 @@ namespace skyline::service::nvdrv::device {
std::pair<std::function<NvStatus(IoctlType, std::span<u8>, std::span<u8>)>, std::string_view> function; std::pair<std::function<NvStatus(IoctlType, std::span<u8>, std::span<u8>)>, std::string_view> function;
try { try {
function = GetIoctlFunction(cmd); 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 &) { } catch (std::out_of_range &) {
state.logger->Warn("Cannot find IOCTL for device '{}': 0x{:X}", GetName(), cmd); state.logger->Warn("Cannot find IOCTL for device '{}': 0x{:X}", GetName(), cmd);
return NvStatus::NotImplemented; return NvStatus::NotImplemented;
} }
try { try {
return function.first(type, buffer, inlineBuffer); return function.first(type, buffer, inlineBuffer);
} catch (std::exception &e) { } catch (const std::exception &e) {
throw exception("{} (Device: {})", e.what(), GetName()); throw exception("{} (Device: {})", e.what(), GetName());
} }
exit(0); exit(0);