// 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 { class GpuChannel; /** * @brief nvhost::AsGpu (/dev/nvhost-as-gpu) is used to access a GPU virtual address space * @url https://switchbrew.org/wiki/NV_services#.2Fdev.2Fnvhost-as-gpu */ class AsGpu : public NvDevice { private: struct Mapping { u8 *ptr; u64 offset; u64 size; bool fixed; bool bigPage; // Only valid if fixed == false bool sparseAlloc; Mapping(u8 *ptr, u64 offset, u64 size, bool fixed, bool bigPage, bool sparseAlloc) : ptr(ptr), offset(offset), size(size), fixed(fixed), bigPage(bigPage), sparseAlloc(sparseAlloc) {} }; struct Allocation { u64 size; std::list> mappings; u32 pageSize; bool sparse; }; std::map> mappingMap; //!< This maps the base addresses of mapped buffers to their total sizes and mapping type, this is needed as what was originally a single buffer may have been split into multiple GPU side buffers with the remap flag. std::map allocationMap; //!< Holds allocations created by AllocSpace from which fixed buffers can be mapped into std::mutex mutex; //!< Locks all AS operations struct VM { static constexpr u32 PageSize{soc::gm20b::GmmuSmallPageSize}; static constexpr u32 PageSizeBits{soc::gm20b::GmmuSmallPageSizeBits}; static constexpr u32 SupportedBigPageSizes{0x30000}; static constexpr u32 DefaultBigPageSize{soc::gm20b::GmmuMinBigPageSize}; u32 bigPageSize{DefaultBigPageSize}; u32 bigPageSizeBits{soc::gm20b::GmmuMinBigPageSizeBits}; static constexpr u32 VaStartShift{10}; static constexpr u64 DefaultVaSplit{1ULL << 34}; static constexpr u64 DefaultVaRange{1ULL << 37}; u64 vaRangeStart{DefaultBigPageSize << VaStartShift}; u64 vaRangeSplit{DefaultVaSplit}; u64 vaRangeEnd{DefaultVaRange}; using Allocator = FlatAllocator; std::unique_ptr bigPageAllocator; std::shared_ptr smallPageAllocator; //! Shared as this is also used by nvhost::GpuChannel bool initialised{}; } vm; std::shared_ptr asCtx; //!< The guest GPU AS context that is associated with each particular instance friend GpuChannel; void FreeMappingLocked(u64 offset); public: struct MappingFlags { bool fixed : 1; bool sparse : 1; u8 _pad0_ : 6; bool remap : 1; u32 _pad1_ : 23; }; static_assert(sizeof(MappingFlags) == sizeof(u32)); struct VaRegion { u64 offset; u32 pageSize; u32 _pad0_; u64 pages; }; static_assert(sizeof(VaRegion) == 0x18); struct RemapEntry { u16 flags; u16 kind; core::NvMap::Handle::Id handle; u32 handleOffsetBigPages; u32 asOffsetBigPages; u32 bigPages; }; static_assert(sizeof(RemapEntry) == 0x14); AsGpu(const DeviceState &state, Driver &driver, Core &core, const SessionContext &ctx); /** * @brief Binds this address space to a channel * @url https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_BIND_CHANNEL */ PosixResult BindChannel(In channelFd); /** * @brief Reserves a region in this address space * @url https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_FREE_SPACE */ PosixResult AllocSpace(In pages, In pageSize, In flags, InOut offset); /** * @brief Frees an allocated region in this address space * @url https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_FREE_SPACE */ PosixResult FreeSpace(In offset, In pages, In pageSize); /** * @brief Unmaps a region in this address space * @url https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_UNMAP_BUFFER */ PosixResult UnmapBuffer(In offset); /** * @brief Maps a region into this address space with extra parameters * @url https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_MAP_BUFFER_EX */ PosixResult MapBufferEx(In flags, In kind, In handle, In bufferOffset, In mappingSize, InOut offset); /** * @brief Returns info about the address space and its page sizes * @url https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_GET_VA_REGIONS */ PosixResult GetVaRegions(In bufAddr, InOut bufSize, Out> vaRegions); /** * @brief Ioctl3 variant of GetVaRegions */ PosixResult GetVaRegions3(span inlineBuffer, In bufAddr, InOut bufSize, Out> vaRegions); /** * @brief Allocates this address space with the given parameters * @url https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_ALLOC_AS_EX */ PosixResult AllocAsEx(In flags, In asFd, In bigPageSize, In vaRangeStart, In vaRangeEnd, In vaRangeSplit); /** * @brief Remaps a region of the GPU address space * @url https://switchbrew.org/wiki/NV_services#NVGPU_AS_IOCTL_REMAP */ PosixResult Remap(span entries); PosixResult Ioctl(IoctlDescriptor cmd, span buffer) override; PosixResult Ioctl3(IoctlDescriptor cmd, span buffer, span inlineBuffer) override; }; }