mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2025-06-15 16:17:57 -05:00
core: Make nvservices more standardized
This commit is contained in:
@ -23,124 +23,171 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
|
||||
void NVDRV::Open(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
const auto& buffer = ctx.ReadBuffer();
|
||||
std::string device_name(buffer.begin(), buffer.end());
|
||||
if (!initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& buffer = ctx.ReadBuffer();
|
||||
const std::string device_name(buffer.begin(), buffer.end());
|
||||
DeviceFD fd = nvdrv->Open(device_name);
|
||||
|
||||
u32 fd = nvdrv->Open(device_name);
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(fd);
|
||||
rb.Push<u32>(0);
|
||||
rb.Push<DeviceFD>(fd);
|
||||
rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
|
||||
}
|
||||
|
||||
void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 fd = rp.Pop<u32>();
|
||||
u32 command = rp.Pop<u32>();
|
||||
|
||||
/// Ioctl 3 has 2 outputs, first in the input params, second is the result
|
||||
std::vector<u8> output(ctx.GetWriteBufferSize(0));
|
||||
std::vector<u8> output2;
|
||||
if (version == IoctlVersion::Version3) {
|
||||
output2.resize((ctx.GetWriteBufferSize(1)));
|
||||
}
|
||||
|
||||
/// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer.
|
||||
/// KickOfPB uses this
|
||||
auto input = ctx.ReadBuffer(0);
|
||||
|
||||
std::vector<u8> input2;
|
||||
if (version == IoctlVersion::Version2) {
|
||||
input2 = ctx.ReadBuffer(1);
|
||||
}
|
||||
|
||||
IoctlCtrl ctrl{};
|
||||
|
||||
u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version);
|
||||
|
||||
if (ctrl.must_delay) {
|
||||
ctrl.fresh_call = false;
|
||||
ctx.SleepClientThread(
|
||||
"NVServices::DelayedResponse", ctrl.timeout,
|
||||
[=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
|
||||
Kernel::ThreadWakeupReason reason) {
|
||||
IoctlCtrl ctrl2{ctrl};
|
||||
std::vector<u8> tmp_output = output;
|
||||
std::vector<u8> tmp_output2 = output2;
|
||||
const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output,
|
||||
tmp_output2, ctrl2, version);
|
||||
ctx_.WriteBuffer(tmp_output, 0);
|
||||
if (version == IoctlVersion::Version3) {
|
||||
ctx_.WriteBuffer(tmp_output2, 1);
|
||||
}
|
||||
IPC::ResponseBuilder rb{ctx_, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(ioctl_result);
|
||||
},
|
||||
nvdrv->GetEventWriteable(ctrl.event_id));
|
||||
} else {
|
||||
ctx.WriteBuffer(output);
|
||||
if (version == IoctlVersion::Version3) {
|
||||
ctx.WriteBuffer(output2, 1);
|
||||
}
|
||||
}
|
||||
void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(result);
|
||||
rb.PushEnum(result);
|
||||
}
|
||||
|
||||
void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlBase(ctx, IoctlVersion::Version1);
|
||||
void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto command = rp.PopRaw<Ioctl>();
|
||||
LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
|
||||
|
||||
if (!initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check device
|
||||
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||
const auto input_buffer = ctx.ReadBuffer(0);
|
||||
|
||||
const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
|
||||
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(nv_result);
|
||||
}
|
||||
|
||||
void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlBase(ctx, IoctlVersion::Version2);
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto command = rp.PopRaw<Ioctl>();
|
||||
LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
|
||||
|
||||
if (!initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto input_buffer = ctx.ReadBuffer(0);
|
||||
const auto input_inlined_buffer = ctx.ReadBuffer(1);
|
||||
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||
|
||||
const auto nv_result =
|
||||
nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
|
||||
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(nv_result);
|
||||
}
|
||||
|
||||
void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
IoctlBase(ctx, IoctlVersion::Version3);
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto command = rp.PopRaw<Ioctl>();
|
||||
LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
|
||||
|
||||
if (!initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto input_buffer = ctx.ReadBuffer(0);
|
||||
std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
|
||||
std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1));
|
||||
|
||||
const auto nv_result =
|
||||
nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline);
|
||||
|
||||
if (command.is_out != 0) {
|
||||
ctx.WriteBuffer(output_buffer, 0);
|
||||
ctx.WriteBuffer(output_buffer_inline, 1);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(nv_result);
|
||||
}
|
||||
|
||||
void NVDRV::Close(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_NVDRV, "called");
|
||||
|
||||
if (!initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 fd = rp.Pop<u32>();
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto result = nvdrv->Close(fd);
|
||||
|
||||
auto result = nvdrv->Close(fd);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(result);
|
||||
}
|
||||
|
||||
void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
initialized = true;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0);
|
||||
rb.PushEnum(NvResult::Success);
|
||||
}
|
||||
|
||||
void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u32 fd = rp.Pop<u32>();
|
||||
// TODO(Blinkhawk): Figure the meaning of the flag at bit 16
|
||||
u32 event_id = rp.Pop<u32>() & 0x000000FF;
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto event_id = rp.Pop<u32>() & 0x00FF;
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
if (!initialized) {
|
||||
ServiceError(ctx, NvResult::NotInitialized);
|
||||
LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto nv_result = nvdrv->VerifyFd(fd);
|
||||
|
||||
if (nv_result != NvResult::Success) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd);
|
||||
ServiceError(ctx, nv_result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event_id < MaxNvEvents) {
|
||||
IPC::ResponseBuilder rb{ctx, 3, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
auto event = nvdrv->GetEvent(event_id);
|
||||
event->Clear();
|
||||
rb.PushCopyObjects(event);
|
||||
rb.Push<u32>(NvResult::Success);
|
||||
rb.PushEnum(NvResult::Success);
|
||||
} else {
|
||||
rb.Push<u32>(0);
|
||||
rb.Push<u32>(NvResult::BadParameter);
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(NvResult::BadParameter);
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +198,7 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(0);
|
||||
rb.PushEnum(NvResult::Success);
|
||||
}
|
||||
|
||||
void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
|
||||
@ -164,8 +211,9 @@ void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ct
|
||||
void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum(NvResult::Success);
|
||||
}
|
||||
|
||||
void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
|
||||
@ -181,7 +229,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
|
||||
: ServiceFramework(name), nvdrv(std::move(nvdrv)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &NVDRV::Open, "Open"},
|
||||
{1, &NVDRV::Ioctl, "Ioctl"},
|
||||
{1, &NVDRV::Ioctl1, "Ioctl"},
|
||||
{2, &NVDRV::Close, "Close"},
|
||||
{3, &NVDRV::Initialize, "Initialize"},
|
||||
{4, &NVDRV::QueryEvent, "QueryEvent"},
|
||||
|
Reference in New Issue
Block a user