2020-04-19 23:04:05 +02:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
2020-03-27 20:36:02 +01:00
|
|
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
#include <kernel/types/KProcess.h>
|
|
|
|
#include "devices/nvhost_ctrl.h"
|
|
|
|
#include "devices/nvhost_ctrl_gpu.h"
|
|
|
|
#include "devices/nvhost_channel.h"
|
|
|
|
#include "devices/nvhost_as_gpu.h"
|
2020-03-26 15:33:19 +01:00
|
|
|
#include "INvDrvServices.h"
|
2020-03-24 21:17:31 +01:00
|
|
|
|
|
|
|
namespace skyline::service::nvdrv {
|
|
|
|
u32 INvDrvServices::OpenDevice(const std::string &path) {
|
|
|
|
state.logger->Debug("Opening NVDRV device ({}): {}", fdIndex, path);
|
|
|
|
auto type = device::nvDeviceMap.at(path);
|
|
|
|
for (const auto &device : fdMap) {
|
|
|
|
if (device.second->deviceType == type) {
|
|
|
|
device.second->refCount++;
|
|
|
|
fdMap[fdIndex] = device.second;
|
|
|
|
return fdIndex++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<device::NvDevice> object;
|
|
|
|
switch (type) {
|
2020-04-22 19:02:27 +02:00
|
|
|
case device::NvDeviceType::nvhost_ctrl:
|
2020-03-24 21:17:31 +01:00
|
|
|
object = std::make_shared<device::NvHostCtrl>(state);
|
|
|
|
break;
|
2020-04-22 19:02:27 +02:00
|
|
|
|
|
|
|
case device::NvDeviceType::nvhost_gpu:
|
|
|
|
case device::NvDeviceType::nvhost_vic:
|
|
|
|
case device::NvDeviceType::nvhost_nvdec:
|
2020-03-24 21:17:31 +01:00
|
|
|
object = std::make_shared<device::NvHostChannel>(state, type);
|
|
|
|
break;
|
2020-04-22 19:02:27 +02:00
|
|
|
|
|
|
|
case device::NvDeviceType::nvhost_ctrl_gpu:
|
2020-03-24 21:17:31 +01:00
|
|
|
object = std::make_shared<device::NvHostCtrlGpu>(state);
|
|
|
|
break;
|
2020-04-22 19:02:27 +02:00
|
|
|
|
|
|
|
case device::NvDeviceType::nvmap:
|
2020-03-24 21:17:31 +01:00
|
|
|
object = std::make_shared<device::NvMap>(state);
|
|
|
|
break;
|
2020-04-22 19:02:27 +02:00
|
|
|
|
|
|
|
case device::NvDeviceType::nvhost_as_gpu:
|
2020-03-24 21:17:31 +01:00
|
|
|
object = std::make_shared<device::NvHostAsGpu>(state);
|
|
|
|
break;
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
default:
|
|
|
|
throw exception("Cannot find NVDRV device");
|
|
|
|
}
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
deviceMap[type] = object;
|
|
|
|
fdMap[fdIndex] = object;
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
return fdIndex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
INvDrvServices::INvDrvServices(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager, Service::nvdrv_INvDrvServices, "INvDrvServices", {
|
|
|
|
{0x0, SFUNC(INvDrvServices::Open)},
|
|
|
|
{0x1, SFUNC(INvDrvServices::Ioctl)},
|
|
|
|
{0x2, SFUNC(INvDrvServices::Close)},
|
|
|
|
{0x3, SFUNC(INvDrvServices::Initialize)},
|
|
|
|
{0x4, SFUNC(INvDrvServices::QueryEvent)},
|
|
|
|
{0x8, SFUNC(INvDrvServices::SetAruidByPID)}
|
|
|
|
}) {}
|
|
|
|
|
|
|
|
void INvDrvServices::Open(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
|
|
|
auto buffer = request.inputBuf.at(0);
|
|
|
|
auto path = state.process->GetString(buffer.address, buffer.size);
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
response.Push<u32>(OpenDevice(path));
|
|
|
|
response.Push<u32>(constant::status::Success);
|
|
|
|
}
|
|
|
|
|
|
|
|
void INvDrvServices::Ioctl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
|
|
|
auto fd = request.Pop<u32>();
|
|
|
|
auto cmd = request.Pop<u32>();
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
state.logger->Debug("IOCTL on device: 0x{:X}, cmd: 0x{:X}", fd, cmd);
|
|
|
|
try {
|
|
|
|
if (request.inputBuf.empty() || request.outputBuf.empty()) {
|
|
|
|
if (request.inputBuf.empty()) {
|
|
|
|
device::IoctlData data(request.outputBuf.at(0));
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
fdMap.at(fd)->HandleIoctl(cmd, data);
|
|
|
|
response.Push<u32>(data.status);
|
|
|
|
} else {
|
|
|
|
device::IoctlData data(request.inputBuf.at(0));
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
fdMap.at(fd)->HandleIoctl(cmd, data);
|
|
|
|
response.Push<u32>(data.status);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
device::IoctlData data(request.inputBuf.at(0), request.outputBuf.at(0));
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
fdMap.at(fd)->HandleIoctl(cmd, data);
|
|
|
|
response.Push<u32>(data.status);
|
|
|
|
}
|
|
|
|
} catch (const std::out_of_range &) {
|
|
|
|
throw exception("IOCTL was requested on an invalid file descriptor");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void INvDrvServices::Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
2020-04-22 19:02:27 +02:00
|
|
|
auto fd = request.Pop<u32>();
|
2020-03-24 21:17:31 +01:00
|
|
|
state.logger->Debug("Closing NVDRV device ({})", fd);
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
try {
|
|
|
|
auto device = fdMap.at(fd);
|
|
|
|
if (!--device->refCount)
|
|
|
|
deviceMap.erase(device->deviceType);
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
fdMap.erase(fd);
|
|
|
|
} catch (const std::out_of_range &) {
|
|
|
|
state.logger->Warn("Trying to close non-existent FD");
|
|
|
|
}
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
response.Push<u32>(constant::status::Success);
|
|
|
|
}
|
|
|
|
|
|
|
|
void INvDrvServices::Initialize(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
|
|
|
response.Push<u32>(constant::status::Success);
|
|
|
|
}
|
|
|
|
|
|
|
|
void INvDrvServices::QueryEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
|
|
|
auto fd = request.Pop<u32>();
|
|
|
|
auto eventId = request.Pop<u32>();
|
|
|
|
auto event = std::make_shared<type::KEvent>(state);
|
|
|
|
auto handle = state.process->InsertItem<type::KEvent>(event);
|
2020-04-22 19:02:27 +02:00
|
|
|
|
2020-03-24 21:17:31 +01:00
|
|
|
state.logger->Debug("QueryEvent: FD: {}, Event ID: {}, Handle: {}", fd, eventId, handle);
|
|
|
|
response.copyHandles.push_back(handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
void INvDrvServices::SetAruidByPID(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
|
|
|
response.Push<u32>(constant::status::Success);
|
|
|
|
}
|
|
|
|
}
|