Stub host1x channel devices and IOCTLs

host1x channels are generally similar to GPU channels however there is only one channel for each specific class (like a GPU engine) and an address space is shared between them all.

This PR implements the simple IOCTLs with the larger ones that will depend on changes outside of nvdrv being left for future commits. This is enough to partly run oss-nvjpeg.
This commit is contained in:
Billy Laws 2021-10-24 16:16:23 +01:00 committed by PixelyIon
parent 5087d3dc2a
commit 04e5237ec1
5 changed files with 213 additions and 2 deletions

View File

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

View File

@ -0,0 +1,91 @@
// SPDX-License-Identifier: MIT OR MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <soc.h>
#include <services/nvdrv/devices/deserialisation/deserialisation.h>
#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<FileDescriptor> fd) {
state.logger->Debug("fd: {}", fd);
return PosixResult::Success;
}
PosixResult Host1XChannel::Submit(span<SubmitCmdBuf> cmdBufs,
span<SubmitReloc> relocs, span<u32> relocShifts,
span<SubmitSyncpointIncr> syncpointIncrs, span<u32> fenceThresholds) {
state.logger->Debug("numCmdBufs: {}, numRelocs: {}, numSyncpointIncrs: {}, numFenceThresholds: {}",
cmdBufs.size(), relocs.size(), syncpointIncrs.size(), fenceThresholds.size());
return PosixResult::Success;
}
PosixResult Host1XChannel::GetSyncpoint(In<u32> channelSyncpointIdx, Out<u32> syncpointId) {
state.logger->Debug("channelSyncpointIdx: {}", channelSyncpointIdx);
if (channelSyncpointIdx > 0)
throw exception("Multiple channel syncpoints are unimplemented!");
u32 id{core::SyncpointManager::ChannelSyncpoints[static_cast<u32>(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<core::ChannelType> pChannelType, Out<u32> waitBase) {
state.logger->Debug("channelType: {}", static_cast<u32>(pChannelType));
waitBase = 0;
return PosixResult::Success;
}
PosixResult Host1XChannel::SetSubmitTimeout(In<u32> timeout) {
state.logger->Debug("timeout: {}", timeout);
return PosixResult::Success;
}
PosixResult Host1XChannel::MapBuffer(u8 compressed, span<BufferHandle> handles) {
state.logger->Debug("compressed: {}", compressed);
return PosixResult::Success;
}
PosixResult Host1XChannel::UnmapBuffer(u8 compressed, span<BufferHandle> handles) {
state.logger->Debug("compressed: {}", compressed);
return PosixResult::Success;
}
#include <services/nvdrv/devices/deserialisation/macro_def.inc>
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<FileDescriptor>))
IOCTL_CASE_ARGS(INOUT, SIZE(0x8), MAGIC(Host1XChannelMagic), FUNC(0x2),
GetSyncpoint, ARGS(In<u32>, Out<u32>))
IOCTL_CASE_ARGS(INOUT, SIZE(0x8), MAGIC(Host1XChannelMagic), FUNC(0x3),
GetWaitBase, ARGS(In<core::ChannelType>, Out<u32>))
IOCTL_CASE_ARGS(IN, SIZE(0x4), MAGIC(Host1XChannelMagic), FUNC(0x7),
SetSubmitTimeout, ARGS(In<u32>))
}), ({
VARIABLE_IOCTL_CASE_ARGS(INOUT, MAGIC(Host1XChannelMagic), FUNC(0x1),
Submit, ARGS(Save<u32, 0>, Save<u32, 1>, Save<u32, 2>, Save<u32, 3>,
SlotSizeSpan<SubmitCmdBuf, 0>,
SlotSizeSpan<SubmitReloc, 1>, SlotSizeSpan<u32, 1>,
SlotSizeSpan<SubmitSyncpointIncr, 2>, SlotSizeSpan<u32, 3>))
VARIABLE_IOCTL_CASE_ARGS(INOUT, MAGIC(Host1XChannelMagic), FUNC(0x9),
MapBuffer, ARGS(Save<u32, 0>, Pad<u32>, In<u8>, Pad<u8, 3>, SlotSizeSpan<BufferHandle, 0>))
VARIABLE_IOCTL_CASE_ARGS(INOUT, MAGIC(Host1XChannelMagic), FUNC(0xA),
UnmapBuffer, ARGS(Save<u32, 0>, Pad<u32>, In<u8>, Pad<u8, 3>, SlotSizeSpan<BufferHandle, 0>))
}))
#include <services/nvdrv/devices/deserialisation/macro_undef.inc>
}

View File

@ -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 <services/common/fence.h>
#include <services/nvdrv/devices/nvdevice.h>
#include <services/nvdrv/core/syncpoint_manager.h>
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<u32, 3> _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<FileDescriptor> 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<SubmitCmdBuf> cmdBufs,
span<SubmitReloc> relocs, span<u32> relocShifts,
span<SubmitSyncpointIncr> syncpointIncrs, span<u32> 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<u32> channelSyncpointIdx, Out<u32> syncpointId);
/**
* @brief Stubbed in modern nvdrv to return 0
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_GET_WAITBASE
*/
PosixResult GetWaitBase(In<core::ChannelType> pChannelType, Out<u32> waitBase);
/**
* @brief Sets the timeout for channel submits
* @url https://switchbrew.org/wiki/NV_services#NVHOST_IOCTL_CHANNEL_SET_SUBMIT_TIMEOUT
*/
PosixResult SetSubmitTimeout(In<u32> 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<BufferHandle> 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<BufferHandle> handles);
PosixResult Ioctl(IoctlDescriptor cmd, span<u8> buffer) override;
};
}

View File

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

View File

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