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)},
{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<kernel::ipc::IpcBuffer> 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<kernel::ipc::IpcBuffer> 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<u8>(reinterpret_cast<u8 *>(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<u8>(reinterpret_cast<u8 *>(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<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) {
return {};
}

View File

@ -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)

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;
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);

View File

@ -17,9 +17,9 @@ namespace skyline::service::nvdrv::device {
NvStatus NvHostAsGpu::AllocSpace(IoctlType type, std::span<u8> buffer, std::span<u8> 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