diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index fd5ae191..43d02e79 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -229,6 +229,7 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/nvdrv/devices/nvhost/ctrl.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost/ctrl_gpu.cpp ${source_DIR}/skyline/services/nvdrv/devices/nvhost/gpu_channel.cpp + ${source_DIR}/skyline/services/nvdrv/devices/nvhost/host1x_channel.cpp ${source_DIR}/skyline/services/hosbinder/parcel.cpp ${source_DIR}/skyline/services/hosbinder/IHOSBinderDriver.cpp ${source_DIR}/skyline/services/hosbinder/GraphicBufferProducer.cpp diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/host1x_channel.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/host1x_channel.cpp new file mode 100644 index 00000000..ad6fdd01 --- /dev/null +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/host1x_channel.cpp @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: MIT OR MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include +#include +#include "host1x_channel.h" + +namespace skyline::service::nvdrv::device::nvhost { + Host1XChannel::Host1XChannel(const DeviceState &state, + Driver &driver, + Core &core, + const SessionContext &ctx, + core::ChannelType channelType) + : NvDevice(state, driver, core, ctx), + channelType(channelType) {} + + PosixResult Host1XChannel::SetNvmapFd(In fd) { + state.logger->Debug("fd: {}", fd); + return PosixResult::Success; + } + + PosixResult Host1XChannel::Submit(span cmdBufs, + span relocs, span relocShifts, + span syncpointIncrs, span fenceThresholds) { + state.logger->Debug("numCmdBufs: {}, numRelocs: {}, numSyncpointIncrs: {}, numFenceThresholds: {}", + cmdBufs.size(), relocs.size(), syncpointIncrs.size(), fenceThresholds.size()); + + return PosixResult::Success; + } + + PosixResult Host1XChannel::GetSyncpoint(In channelSyncpointIdx, Out syncpointId) { + state.logger->Debug("channelSyncpointIdx: {}", channelSyncpointIdx); + + if (channelSyncpointIdx > 0) + throw exception("Multiple channel syncpoints are unimplemented!"); + + u32 id{core::SyncpointManager::ChannelSyncpoints[static_cast(channelType)]}; + if (!id) + throw exception("Requested syncpoint for a channel with none specified!"); + + state.logger->Debug("syncpointId: {}", id); + syncpointId = id; + return PosixResult::Success; + } + + PosixResult Host1XChannel::GetWaitBase(In pChannelType, Out waitBase) { + state.logger->Debug("channelType: {}", static_cast(pChannelType)); + waitBase = 0; + return PosixResult::Success; + } + + PosixResult Host1XChannel::SetSubmitTimeout(In timeout) { + state.logger->Debug("timeout: {}", timeout); + return PosixResult::Success; + } + + PosixResult Host1XChannel::MapBuffer(u8 compressed, span handles) { + state.logger->Debug("compressed: {}", compressed); + return PosixResult::Success; + } + + PosixResult Host1XChannel::UnmapBuffer(u8 compressed, span handles) { + state.logger->Debug("compressed: {}", compressed); + return PosixResult::Success; + } +#include + static constexpr u32 Host1XChannelMagic{0x00}; + static constexpr u32 GpuChannelMagic{0x48}; //!< Used for SetNvmapFd which is needed in both GPU and host1x channels + + VARIABLE_IOCTL_HANDLER_FUNC(Host1XChannel, ({ + IOCTL_CASE_ARGS(IN, SIZE(0x4), MAGIC(GpuChannelMagic), FUNC(0x1), + SetNvmapFd, ARGS(In)) + IOCTL_CASE_ARGS(INOUT, SIZE(0x8), MAGIC(Host1XChannelMagic), FUNC(0x2), + GetSyncpoint, ARGS(In, Out)) + IOCTL_CASE_ARGS(INOUT, SIZE(0x8), MAGIC(Host1XChannelMagic), FUNC(0x3), + GetWaitBase, ARGS(In, Out)) + IOCTL_CASE_ARGS(IN, SIZE(0x4), MAGIC(Host1XChannelMagic), FUNC(0x7), + SetSubmitTimeout, ARGS(In)) + }), ({ + VARIABLE_IOCTL_CASE_ARGS(INOUT, MAGIC(Host1XChannelMagic), FUNC(0x1), + Submit, ARGS(Save, Save, Save, Save, + SlotSizeSpan, + SlotSizeSpan, SlotSizeSpan, + SlotSizeSpan, SlotSizeSpan)) + VARIABLE_IOCTL_CASE_ARGS(INOUT, MAGIC(Host1XChannelMagic), FUNC(0x9), + MapBuffer, ARGS(Save, Pad, In, Pad, SlotSizeSpan)) + VARIABLE_IOCTL_CASE_ARGS(INOUT, MAGIC(Host1XChannelMagic), FUNC(0xA), + UnmapBuffer, ARGS(Save, Pad, In, Pad, SlotSizeSpan)) + })) +#include +} diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/host1x_channel.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/host1x_channel.h new file mode 100644 index 00000000..e48287bd --- /dev/null +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/host1x_channel.h @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT OR MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include +#include + +namespace skyline::service::nvdrv::device::nvhost { + /** + * @brief nvhost::Host1XChannel is used by applications to interface with host1x channels, such as VIC and NVDEC + * @url https://switchbrew.org/wiki/NV_services#Channels + */ + class Host1XChannel : public NvDevice { + private: + core::ChannelType channelType; //!< The specific host1x channel that this instance refers to + std::mutex channelMutex; //!< Synchronises submit operations + + public: + /** + * @brief Describes how a gather for a submit should be generated from a given handle + */ + struct SubmitCmdBuf { + core::NvMap::Handle::Id mem; + u32 offset; //!< Offset from the handle of where the gather should start + u32 words; //!< Size for the gather in 4 byte words + }; + + /** + * @brief Describes a single memory relocation that can be applied to a pinned handle before command submission + * @note These are used like: patchMem[patchOffset] = pinMem.iova + pinOffset + */ + struct SubmitReloc { + core::NvMap::Handle::Id patchMem; + u32 patchOffset; + core::NvMap::Handle::Id pinMem; + u32 pinOffset; + }; + + /** + * @brief Describes how the command buffers supplied with the submit will affect a given syncpoint + */ + struct SubmitSyncpointIncr { + u32 syncpointId; + u32 numIncrs; + std::array _res_; + }; + + /** + * @brief A buffer descriptor used for MapBuffer and UnmapBuffer + */ + struct BufferHandle { + core::NvMap::Handle::Id handle; //!< Handle to be (un)pinned + u32 address; //!< The output IOVA that the handle was pinned too + }; + + Host1XChannel(const DeviceState &state, + Driver &driver, + Core &core, + const SessionContext &ctx, + core::ChannelType channelType); + + /** + * @brief Sets the nvmap client to be used for channel submits + * @url https://switchbrew.org/wiki/NV_services#NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD + */ + PosixResult SetNvmapFd(In id); + + /** + * @brief Submits the specified command buffer data to the channel and returns fences that can be waited on + * @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_SUBMIT + */ + PosixResult Submit(span cmdBufs, + span relocs, span relocShifts, + span syncpointIncrs, span fenceThresholds); + + /** + * @brief Returns the syncpoint ID that is located at the given index in this channel's syncpoint array + * @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_GET_SYNCPOINT + */ + PosixResult GetSyncpoint(In channelSyncpointIdx, Out syncpointId); + + /** + * @brief Stubbed in modern nvdrv to return 0 + * @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_GET_WAITBASE + */ + PosixResult GetWaitBase(In pChannelType, Out waitBase); + + /** + * @brief Sets the timeout for channel submits + * @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_SET_SUBMIT_TIMEOUT + */ + PosixResult SetSubmitTimeout(In timeout); + + /** + * @brief Pins a set of nvmap handles into the channel address space for use in submitted command buffers + * @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_MAP_CMD_BUFFER + */ + PosixResult MapBuffer(u8 compressed, span handles); + + /** + * @brief Unpins a set of nvmap handles into the channel address space + * @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_UNMAP_CMD_BUFFER + */ + PosixResult UnmapBuffer(u8 compressed, span handles); + + PosixResult Ioctl(IoctlDescriptor cmd, span buffer) override; + }; +} diff --git a/app/src/main/cpp/skyline/services/nvdrv/driver.cpp b/app/src/main/cpp/skyline/services/nvdrv/driver.cpp index 340ac62d..15e48fdf 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/driver.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/driver.cpp @@ -7,7 +7,7 @@ #include "devices/nvhost/ctrl_gpu.h" #include "devices/nvhost/gpu_channel.h" #include "devices/nvhost/as_gpu.h" - +#include "devices/nvhost/host1x_channel.h" namespace skyline::service::nvdrv { Driver::Driver(const DeviceState &state) : state(state), core(state) {} @@ -44,6 +44,15 @@ namespace skyline::service::nvdrv { ) } + if (ctx.perms.AccessJpeg) + DEVICE_SWITCH(DEVICE_CASE("/dev/nvhost-nvjpg", nvhost::Host1XChannel, core::ChannelType::NvJpg)) + + if (ctx.perms.AccessVic) + DEVICE_SWITCH(DEVICE_CASE("/dev/nvhost-vic", nvhost::Host1XChannel, core::ChannelType::Vic)) + + if (ctx.perms.AccessVideoDecoder) + DEVICE_SWITCH(DEVICE_CASE("/dev/nvhost-nvdec", nvhost::Host1XChannel, core::ChannelType::NvDec)) + #undef DEVICE_CASE #undef DEVICE_SWITCH diff --git a/app/src/main/cpp/skyline/soc/host1x.h b/app/src/main/cpp/skyline/soc/host1x.h index ac3a04a8..37c1f3f6 100644 --- a/app/src/main/cpp/skyline/soc/host1x.h +++ b/app/src/main/cpp/skyline/soc/host1x.h @@ -8,7 +8,7 @@ namespace skyline::soc::host1x { /** * @brief An abstraction for the graphics host, this handles DMA on behalf of the CPU when communicating to it's clients alongside handling syncpts - * @note This is different from the GM20B Host, it serves a similar function and has an interface for accessing Host1X syncpts + * @note This is different from the GM20B Host, it serves a similar function and has an interface for accessing host1x syncpts */ class Host1X { public: