diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/gpu_channel.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/gpu_channel.cpp new file mode 100644 index 00000000..26ea4492 --- /dev/null +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/gpu_channel.cpp @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: MIT OR MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include +#include +#include "gpu_channel.h" + +namespace skyline::service::nvdrv::device::nvhost { + GpuChannel::GpuChannel(const DeviceState &state, Core &core, const SessionContext &ctx) : + NvDevice(state, core, ctx), + smExceptionBreakpointIntReportEvent(std::make_shared(state, false)), + smExceptionBreakpointPauseReportEvent(std::make_shared(state, false)), + errorNotifierEvent(std::make_shared(state, false)) { + channelSyncpoint = core.syncpointManager.AllocateSyncpoint(false); + } + + PosixResult GpuChannel::SetNvmapFd(In id) { + return PosixResult::Success; + } + + PosixResult GpuChannel::SetTimeout(In timeout) { + return PosixResult::Success; + } + + PosixResult GpuChannel::SubmitGpfifo(In userAddress, In numEntries, InOut flags, InOut fence, span gpEntries) { + if (numEntries != gpEntries.size()) + throw exception("GpEntry size mismatch!"); + + if (flags.fenceWait) { + if (flags.incrementWithValue) + return PosixResult::InvalidArgument; + + if (core.syncpointManager.IsFenceSignalled(fence)) + throw exception("Waiting on a fence through SubmitGpfifo is unimplemented"); + } + + state.soc->gm20b.gpfifo.Push(gpEntries); + + fence.id = channelSyncpoint; + + u32 increment{(flags.fenceIncrement ? 2 : 0) + (flags.incrementWithValue ? fence.threshold : 0)}; + fence.threshold = core.syncpointManager.IncrementSyncpointMaxExt(channelSyncpoint, increment); + + if (flags.fenceIncrement) + throw exception("Incrementing a fence through SubmitGpfifo is unimplemented"); + + flags.raw = 0; + + return PosixResult::Success; + } + + PosixResult GpuChannel::AllocObjCtx(In classId, In flags, Out objId) { + return PosixResult::Success; + } + + PosixResult GpuChannel::ZcullBind(In gpuVa, In mode) { + return PosixResult::Success; + } + + PosixResult GpuChannel::SetErrorNotifier(In offset, In size, In mem) { + return PosixResult::Success; + } + + PosixResult GpuChannel::SetPriority(In priority) { + return PosixResult::Success; + } + + PosixResult GpuChannel::AllocGpfifoEx2(In numEntries, In numJobs, In flags, Out fence) { + state.soc->gm20b.gpfifo.Initialize(numEntries); + + fence = core.syncpointManager.GetSyncpointFence(channelSyncpoint); + + return PosixResult::Success; + } + + PosixResult GpuChannel::SetTimeslice(In timeslice) { + return PosixResult::Success; + } + + PosixResult GpuChannel::SetUserData(In userData) { + channelUserData = userData; + return PosixResult::Success; + } + + PosixResult GpuChannel::GetUserData(Out userData) { + userData = channelUserData; + return PosixResult::Success; + } + + std::shared_ptr GpuChannel::QueryEvent(u32 eventId) { + switch (eventId) { + case 1: + return smExceptionBreakpointIntReportEvent; + case 2: + return smExceptionBreakpointPauseReportEvent; + case 3: + return errorNotifierEvent; + default: + return nullptr; + } + } + +#include + static constexpr u32 GpuChannelUserMagic{0x47}; + static constexpr u32 GpuChannelMagic{0x48}; + + VARIABLE_IOCTL_HANDLER_FUNC(GpuChannel, ({ + IOCTL_CASE_ARGS(IN, SIZE(0x4), MAGIC(GpuChannelMagic), FUNC(0x1), + SetNvmapFd, ARGS(In)) + IOCTL_CASE_ARGS(IN, SIZE(0x4), MAGIC(GpuChannelMagic), FUNC(0x3), + SetTimeout, ARGS(In)) + IOCTL_CASE_ARGS(INOUT, SIZE(0x10), MAGIC(GpuChannelMagic), FUNC(0x9), + AllocObjCtx, ARGS(In, In, Out)) + IOCTL_CASE_ARGS(INOUT, SIZE(0x10), MAGIC(GpuChannelMagic), FUNC(0xB), + ZcullBind, ARGS(In, In)) + IOCTL_CASE_ARGS(INOUT, SIZE(0x18), MAGIC(GpuChannelMagic), FUNC(0xC), + SetErrorNotifier, ARGS(In, In, In)) + IOCTL_CASE_ARGS(IN, SIZE(0x4), MAGIC(GpuChannelMagic), FUNC(0xD), + SetPriority, ARGS(In)) + IOCTL_CASE_ARGS(INOUT, SIZE(0x20), MAGIC(GpuChannelMagic), FUNC(0x1A), + AllocGpfifoEx2, ARGS(In, In, In, Out)) + IOCTL_CASE_ARGS(INOUT, SIZE(0x4), MAGIC(GpuChannelMagic), FUNC(0x1D), + SetTimeslice, ARGS(In)) + IOCTL_CASE_ARGS(IN, SIZE(0x8), MAGIC(GpuChannelUserMagic), FUNC(0x14), + SetUserData, ARGS(In)) + IOCTL_CASE_ARGS(OUT, SIZE(0x8), MAGIC(GpuChannelUserMagic), FUNC(0x15), + GetUserData, ARGS(Out)) + }), ({ + VARIABLE_IOCTL_CASE_ARGS(INOUT, MAGIC(GpuChannelMagic), FUNC(0x8), + SubmitGpfifo, ARGS(In, In, InOut, InOut, AutoSizeSpan)) + })) +#include +} diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/gpu_channel.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/gpu_channel.h new file mode 100644 index 00000000..1baf5d26 --- /dev/null +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/gpu_channel.h @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT OR MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include +#include "services/nvdrv/devices/nvdevice.h" + +namespace skyline::service::nvdrv::device::nvhost { + /** + * @brief nvhost::GpuChannel is used to create and submit commands to channels which are effectively GPU processes + * @url https://switchbrew.org/wiki/NV_services#Channels + */ + class GpuChannel : public NvDevice { + private: + u32 channelSyncpoint{}; + u32 channelUserData{}; + std::shared_ptr smExceptionBreakpointIntReportEvent; + std::shared_ptr smExceptionBreakpointPauseReportEvent; + std::shared_ptr errorNotifierEvent; + + public: + /** + * @brief A bitfield of the flags that can be supplied for a specific GPFIFO submission + */ + union SubmitGpfifoFlags { + struct __attribute__((__packed__)) { + bool fenceWait : 1; + bool fenceIncrement : 1; + bool hwFormat : 1; + u8 _pad0_ : 1; + bool suppressWfi : 1; + u8 _pad1_ : 3; + bool incrementWithValue : 1; + }; + u32 raw; + }; + + GpuChannel(const DeviceState &state, Core &core, const SessionContext &ctx); + + /** + * @brief Sets the nvmap handle id to be used for channel submits (does nothing for GPU channels) + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD + */ + PosixResult SetNvmapFd(In id); + + /** + * @brief Sets the timeout for channel submits + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_TIMEOUT + */ + PosixResult SetTimeout(In timeout); + + /** + * @brief Submits GPFIFO entries for this channel + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO + */ + PosixResult SubmitGpfifo(In userAddress, In numEntries, InOut flags, InOut fence, span gpEntries); + + /** + * @brief Allocates a graphic context object + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_OBJ_CTX + */ + PosixResult AllocObjCtx(In classId, In flags, Out objId); + + /** + * @brief Binds a zcull context to the channel + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ZCULL_BIND + */ + PosixResult ZcullBind(In gpuVa, In mode); + + /** + * @brief Initializes the error notifier for this channel + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_ERROR_NOTIFIER + */ + PosixResult SetErrorNotifier(In offset, In size, In mem); + + /** + * @brief Sets the priority of the channel + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_PRIORITY + */ + PosixResult SetPriority(In priority); + + /** + * @brief Allocates a GPFIFO entry + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX2 + */ + PosixResult AllocGpfifoEx2(In numEntries, In numJobs, In flags, Out fence); + + /** + * @brief Sets the timeslice of the channel + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_TIMESLICE) + */ + PosixResult SetTimeslice(In timeslice); + + /** + * @brief Sets the user specific data + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_USER_DATA + */ + PosixResult SetUserData(In userData); + + /** + * @brief Sets the user specific data + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_GET_USER_DATA + */ + PosixResult GetUserData(Out userData); + + std::shared_ptr QueryEvent(u32 eventId) override; + + PosixResult Ioctl(IoctlDescriptor cmd, span buffer) override; + }; +} diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp deleted file mode 100644 index aa759a83..00000000 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.cpp +++ /dev/null @@ -1,144 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) - -#include -#include -#include -#include "nvhost_channel.h" - -namespace skyline::service::nvdrv::device { - NvHostChannel::NvHostChannel(const DeviceState &state) : smExceptionBreakpointIntReportEvent(std::make_shared(state, false)), smExceptionBreakpointPauseReportEvent(std::make_shared(state, false)), errorNotifierEvent(std::make_shared(state, false)), NvDevice(state) { - auto driver{nvdrv::driver.lock()}; - auto &hostSyncpoint{driver->hostSyncpoint}; - - channelFence.id = hostSyncpoint.AllocateSyncpoint(false); - channelFence.UpdateValue(hostSyncpoint); - } - - NvStatus NvHostChannel::SetNvmapFd(IoctlType type, span buffer, span inlineBuffer) { - return NvStatus::Success; - } - - NvStatus NvHostChannel::SetSubmitTimeout(IoctlType type, span buffer, span inlineBuffer) { - return NvStatus::Success; - } - - NvStatus NvHostChannel::SubmitGpfifo(IoctlType type, span buffer, span inlineBuffer) { - struct Data { - soc::gm20b::GpEntry *entries; // In - u32 numEntries; // In - union { - struct __attribute__((__packed__)) { - bool fenceWait : 1; - bool fenceIncrement : 1; - bool hwFormat : 1; - u8 _pad0_ : 1; - bool suppressWfi : 1; - u8 _pad1_ : 3; - bool incrementWithValue : 1; - }; - u32 raw; - } flags; // In - Fence fence; // InOut - } &data = buffer.as(); - - auto driver{nvdrv::driver.lock()}; - auto &hostSyncpoint{driver->hostSyncpoint}; - - if (data.flags.fenceWait) { - if (data.flags.incrementWithValue) - return NvStatus::BadValue; - - if (hostSyncpoint.HasSyncpointExpired(data.fence.id, data.fence.value)) - throw exception("Waiting on a fence through SubmitGpfifo is unimplemented"); - } - - state.soc->gm20b.gpfifo.Push([&]() { - if (type == IoctlType::Ioctl2) - return inlineBuffer.cast(); - else - return span(data.entries, data.numEntries); - }()); - - data.fence.id = channelFence.id; - - u32 increment{(data.flags.fenceIncrement ? 2 : 0) + (data.flags.incrementWithValue ? data.fence.value : 0)}; - data.fence.value = hostSyncpoint.IncrementSyncpointMaxExt(data.fence.id, increment); - - if (data.flags.fenceIncrement) - throw exception("Incrementing a fence through SubmitGpfifo is unimplemented"); - - data.flags.raw = 0; - - return NvStatus::Success; - } - - NvStatus NvHostChannel::AllocObjCtx(IoctlType type, span buffer, span inlineBuffer) { - return NvStatus::Success; - } - - NvStatus NvHostChannel::ZcullBind(IoctlType type, span buffer, span inlineBuffer) { - return NvStatus::Success; - } - - NvStatus NvHostChannel::SetErrorNotifier(IoctlType type, span buffer, span inlineBuffer) { - return NvStatus::Success; - } - - NvStatus NvHostChannel::SetPriority(IoctlType type, span buffer, span inlineBuffer) { - switch (buffer.as()) { - case NvChannelPriority::Low: - timeslice = 1300; - break; - case NvChannelPriority::Medium: - timeslice = 2600; - break; - case NvChannelPriority::High: - timeslice = 5200; - break; - } - - return NvStatus::Success; - } - - NvStatus NvHostChannel::AllocGpfifoEx2(IoctlType type, span buffer, span inlineBuffer) { - struct Data { - u32 numEntries; // In - u32 numJobs; // In - u32 flags; // In - Fence fence; // Out - u32 _res_[3]; // In - } &data = buffer.as(); - - state.soc->gm20b.gpfifo.Initialize(data.numEntries); - - auto driver{nvdrv::driver.lock()}; - channelFence.UpdateValue(driver->hostSyncpoint); - data.fence = channelFence; - - return NvStatus::Success; - } - - NvStatus NvHostChannel::SetTimeslice(IoctlType type, span buffer, span inlineBuffer) { - timeslice = buffer.as(); - return NvStatus::Success; - } - - NvStatus NvHostChannel::SetUserData(IoctlType type, span buffer, span inlineBuffer) { - return NvStatus::Success; - } - - std::shared_ptr NvHostChannel::QueryEvent(u32 eventId) { - switch (eventId) { - case 1: - return smExceptionBreakpointIntReportEvent; - case 2: - return smExceptionBreakpointPauseReportEvent; - case 3: - return errorNotifierEvent; - default: - return nullptr; - } - } - -} diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.h deleted file mode 100644 index 108ee646..00000000 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost_channel.h +++ /dev/null @@ -1,107 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) - -#pragma once - -#include -#include "nvdevice.h" - -namespace skyline::service::nvdrv::device { - /** - * @brief NvHostChannel is used as a common interface for all Channel devices - * @url https://switchbrew.org/wiki/NV_services#Channels - */ - class NvHostChannel : public NvDevice { - private: - enum class NvChannelPriority : u32 { - Low = 0x32, - Medium = 0x64, - High = 0x94, - }; - - Fence channelFence{}; - u32 timeslice{}; - std::shared_ptr smExceptionBreakpointIntReportEvent; - std::shared_ptr smExceptionBreakpointPauseReportEvent; - std::shared_ptr errorNotifierEvent; - - public: - NvHostChannel(const DeviceState &state); - - /** - * @brief Sets the nvmap file descriptor - * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD - */ - NvStatus SetNvmapFd(IoctlType type, span buffer, span inlineBuffer); - - /** - * @brief Sets the timeout for the channel - * @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_SET_SUBMIT_TIMEOUT - */ - NvStatus SetSubmitTimeout(IoctlType type, span buffer, span inlineBuffer); - - /** - * @brief Submits a command to the GPFIFO - * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO - */ - NvStatus SubmitGpfifo(IoctlType type, span buffer, span inlineBuffer); - - /** - * @brief Allocates a graphic context object - * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_OBJ_CTX - */ - NvStatus AllocObjCtx(IoctlType type, span buffer, span inlineBuffer); - - /** - * @brief Initializes the error notifier for this channel - * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ZCULL_BIND - */ - NvStatus ZcullBind(IoctlType type, span buffer, span inlineBuffer); - - /** - * @brief Initializes the error notifier for this channel - * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_ERROR_NOTIFIER - */ - NvStatus SetErrorNotifier(IoctlType type, span buffer, span inlineBuffer); - - /** - * @brief Sets the priority of the channel - * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_PRIORITY - */ - NvStatus SetPriority(IoctlType type, span buffer, span inlineBuffer); - - /** - * @brief Allocates a GPFIFO entry - * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX2 - */ - NvStatus AllocGpfifoEx2(IoctlType type, span buffer, span inlineBuffer); - - /** - * @brief Sets the timeslice of the channel - * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_TIMESLICE) - */ - NvStatus SetTimeslice(IoctlType type, span buffer, span inlineBuffer); - - /** - * @brief Sets the user specific data - * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_USER_DATA - */ - NvStatus SetUserData(IoctlType type, span buffer, span inlineBuffer); - - std::shared_ptr QueryEvent(u32 eventId) override; - - NVDEVICE_DECL( - NVFUNC(0x4801, NvHostChannel, SetNvmapFd), - NVFUNC(0x4803, NvHostChannel, SetSubmitTimeout), - NVFUNC(0x4808, NvHostChannel, SubmitGpfifo), - NVFUNC(0x4809, NvHostChannel, AllocObjCtx), - NVFUNC(0x480B, NvHostChannel, ZcullBind), - NVFUNC(0x480C, NvHostChannel, SetErrorNotifier), - NVFUNC(0x480D, NvHostChannel, SetPriority), - NVFUNC(0x481A, NvHostChannel, AllocGpfifoEx2), - NVFUNC(0x481B, NvHostChannel, SubmitGpfifo), // Our SubmitGpfifo implementation also handles SubmitGpfifoEx - NVFUNC(0x481D, NvHostChannel, SetTimeslice), - NVFUNC(0x4714, NvHostChannel, SetUserData) - ) - }; -}