diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 6e1ff70f68..df0339ba85 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -10,6 +10,7 @@ #include "common/alignment.h" #include "common/assert.h" +#include "common/common_types.h" #include "common/logging.h" #include "core/core.h" #include "core/hle/service/nvdrv/core/container.h" @@ -130,12 +131,12 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { const auto start_pages{static_cast(vm.va_range_start >> VM::PAGE_SIZE_BITS)}; const auto end_pages{static_cast(vm.va_range_split >> VM::PAGE_SIZE_BITS)}; - vm.small_page_allocator = std::make_shared(start_pages, end_pages); + vm.small_page_allocator.emplace(start_pages, end_pages); const auto start_big_pages{static_cast(vm.va_range_split >> vm.big_page_size_bits)}; const auto end_big_pages{ static_cast((vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits)}; - vm.big_page_allocator = std::make_unique(start_big_pages, end_big_pages); + vm.big_page_allocator.emplace(start_big_pages, end_big_pages); gmmu = std::make_shared(system, max_big_page_bits, vm.va_range_split, vm.big_page_size_bits, VM::PAGE_SIZE_BITS); @@ -188,8 +189,8 @@ NvResult nvhost_as_gpu::AllocateSpace(IoctlAllocSpace& params) { } allocation_map[params.offset] = { - .size = size, .mappings{}, + .size = size, .page_size = params.page_size, .sparse = (params.flags & MappingFlags::Sparse) != MappingFlags::None, .big_pages = params.page_size != VM::YUZU_PAGESIZE, @@ -199,71 +200,52 @@ NvResult nvhost_as_gpu::AllocateSpace(IoctlAllocSpace& params) { } void nvhost_as_gpu::FreeMappingLocked(u64 offset) { - auto mapping{mapping_map.at(offset)}; - - if (!mapping->fixed) { - auto& allocator{mapping->big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; - u32 page_size_bits{mapping->big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; - u32 page_size{mapping->big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; - u64 aligned_size{Common::AlignUp(mapping->size, page_size)}; - - allocator.Free(static_cast(mapping->offset >> page_size_bits), - static_cast(aligned_size >> page_size_bits)); + auto const it = mapping_map.find(offset); + auto const mapping = it->second; + if (!mapping.fixed) { + auto& allocator{mapping.big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; + u32 page_size_bits{mapping.big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; + u32 page_size{mapping.big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; + u64 aligned_size{Common::AlignUp(mapping.size, page_size)}; + allocator.Free(u32(mapping.offset >> page_size_bits), u32(aligned_size >> page_size_bits)); } - - nvmap.UnpinHandle(mapping->handle); - + nvmap.UnpinHandle(mapping.handle); // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state // Only FreeSpace can unmap them fully - if (mapping->sparse_alloc) { - gmmu->MapSparse(offset, mapping->size, mapping->big_page); + if (mapping.sparse_alloc) { + gmmu->MapSparse(offset, mapping.size, mapping.big_page); } else { - gmmu->Unmap(offset, mapping->size); + gmmu->Unmap(offset, mapping.size); } - - mapping_map.erase(offset); + mapping_map.erase(it); } NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) { - LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset, - params.pages, params.page_size); - + LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset, params.pages, params.page_size); std::scoped_lock lock(mutex); - if (!vm.initialised) { return NvResult::BadValue; } - - try { - auto allocation{allocation_map[params.offset]}; - - if (allocation.page_size != params.page_size || - allocation.size != (static_cast(params.pages) * params.page_size)) { + if (auto const it = allocation_map.find(params.offset); it != allocation_map.end()) { + auto const allocation = it->second; + if (allocation.page_size != params.page_size || allocation.size != (u64(params.pages) * params.page_size)) return NvResult::BadValue; - } - for (const auto& mapping : allocation.mappings) { - FreeMappingLocked(mapping->offset); - } + for (const auto mapping_offset : allocation.mappings) + FreeMappingLocked(mapping_offset); // Unset sparse flag if required - if (allocation.sparse) { + if (allocation.sparse) gmmu->Unmap(params.offset, allocation.size); - } - auto& allocator{params.page_size == VM::YUZU_PAGESIZE ? *vm.small_page_allocator - : *vm.big_page_allocator}; - u32 page_size_bits{params.page_size == VM::YUZU_PAGESIZE ? VM::PAGE_SIZE_BITS - : vm.big_page_size_bits}; + auto& allocator{params.page_size == VM::YUZU_PAGESIZE ? *vm.small_page_allocator : *vm.big_page_allocator}; + u32 page_size_bits{params.page_size == VM::YUZU_PAGESIZE ? VM::PAGE_SIZE_BITS : vm.big_page_size_bits}; - allocator.Free(static_cast(params.offset >> page_size_bits), - static_cast(allocation.size >> page_size_bits)); + allocator.Free(u32(params.offset >> page_size_bits), u32(allocation.size >> page_size_bits)); allocation_map.erase(params.offset); - } catch (const std::out_of_range&) { - return NvResult::BadValue; + return NvResult::Success; } - - return NvResult::Success; + return NvResult::BadValue; } NvResult nvhost_as_gpu::Remap(std::span entries) { @@ -327,26 +309,18 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { // Remaps a subregion of an existing mapping to a different PA if ((params.flags & MappingFlags::Remap) != MappingFlags::None) { - try { - auto mapping{mapping_map.at(params.offset)}; - - if (mapping->size < params.mapping_size) { - LOG_WARNING(Service_NVDRV, - "Cannot remap a partially mapped GPU address space region: {:#X}", - params.offset); + if (auto const it = mapping_map.find(params.offset); it != mapping_map.end()) { + auto const mapping = it->second; + if (mapping.size < params.mapping_size) { + LOG_WARNING(Service_NVDRV, "Cannot remap a partially mapped GPU address space region: {:#X}", params.offset); return NvResult::BadValue; } - - u64 gpu_address{static_cast(params.offset + params.buffer_offset)}; - VAddr device_address{mapping->ptr + params.buffer_offset}; - - gmmu->Map(gpu_address, device_address, params.mapping_size, - static_cast(params.kind), mapping->big_page); - + u64 gpu_address = u64(params.offset + params.buffer_offset); + VAddr device_address{mapping.ptr + params.buffer_offset}; + gmmu->Map(gpu_address, device_address, params.mapping_size, Tegra::PTEKind(params.kind), mapping.big_page); return NvResult::Success; - } catch (const std::out_of_range&) { - LOG_WARNING(Service_NVDRV, "Cannot remap an unmapped GPU address space region: {:#X}", - params.offset); + } else { + LOG_WARNING(Service_NVDRV, "Cannot remap an unmapped GPU address space region: {:#X}", params.offset); return NvResult::BadValue; } } @@ -356,8 +330,7 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { return NvResult::BadValue; } - DAddr device_address{ - static_cast(nvmap.PinHandle(params.handle, false) + params.buffer_offset)}; + DAddr device_address = DAddr(nvmap.PinHandle(params.handle, false) + params.buffer_offset); u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; bool big_page{[&]() { @@ -381,32 +354,22 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { } const bool use_big_pages = alloc->second.big_pages && big_page; - gmmu->Map(params.offset, device_address, size, static_cast(params.kind), - use_big_pages); + gmmu->Map(params.offset, device_address, size, static_cast(params.kind), use_big_pages); - auto mapping{std::make_shared(params.handle, device_address, params.offset, size, - true, use_big_pages, alloc->second.sparse)}; - alloc->second.mappings.push_back(mapping); - mapping_map[params.offset] = mapping; + alloc->second.mappings.push_back(params.offset); + mapping_map.insert_or_assign(params.offset, Mapping(params.handle, device_address, params.offset, size, true, use_big_pages, alloc->second.sparse)); } else { auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; u32 page_size_bits{big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; - params.offset = static_cast(allocator.Allocate( - static_cast(Common::AlignUp(size, page_size) >> page_size_bits))) - << page_size_bits; + params.offset = u64(allocator.Allocate(u32(Common::AlignUp(size, page_size) >> page_size_bits))) << page_size_bits; if (!params.offset) { ASSERT_MSG(false, "Failed to allocate free space in the GPU AS!"); return NvResult::InsufficientMemory; } - - gmmu->Map(params.offset, device_address, Common::AlignUp(size, page_size), - static_cast(params.kind), big_page); - - auto mapping{std::make_shared(params.handle, device_address, params.offset, size, - false, big_page, false)}; - mapping_map[params.offset] = mapping; + gmmu->Map(params.offset, device_address, Common::AlignUp(size, page_size), Tegra::PTEKind(params.kind), big_page); + mapping_map.insert_or_assign(params.offset, Mapping(params.handle, device_address, params.offset, size, false, big_page, false)); } map_buffer_offsets.insert(params.offset); @@ -415,37 +378,32 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { } NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { - if (map_buffer_offsets.find(params.offset) != map_buffer_offsets.end()) { + std::scoped_lock lock(mutex); + if (auto const offset_it = map_buffer_offsets.find(params.offset); offset_it != map_buffer_offsets.end()) { LOG_DEBUG(Service_NVDRV, "called, offset={:#X}", params.offset); - - std::scoped_lock lock(mutex); - if (!vm.initialised) { return NvResult::BadValue; } - auto mapping{mapping_map.at(params.offset)}; - - if (!mapping->fixed) { - auto& allocator{mapping->big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; - u32 page_size_bits{mapping->big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; - - allocator.Free(static_cast(mapping->offset >> page_size_bits), - static_cast(mapping->size >> page_size_bits)); + auto const it = mapping_map.find(params.offset); + auto const mapping = it->second; + if (!mapping.fixed) { + auto& allocator{mapping.big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; + u32 page_size_bits{mapping.big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; + allocator.Free(u32(mapping.offset >> page_size_bits), u32(mapping.size >> page_size_bits)); } // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state // Only FreeSpace can unmap them fully - if (mapping->sparse_alloc) { - gmmu->MapSparse(params.offset, mapping->size, mapping->big_page); + if (mapping.sparse_alloc) { + gmmu->MapSparse(params.offset, mapping.size, mapping.big_page); } else { - gmmu->Unmap(params.offset, mapping->size); + gmmu->Unmap(params.offset, mapping.size); } - nvmap.UnpinHandle(mapping->handle); - - mapping_map.erase(params.offset); - map_buffer_offsets.erase(params.offset); + nvmap.UnpinHandle(mapping.handle); + mapping_map.erase(it); + map_buffer_offsets.erase(offset_it); } return NvResult::Success; } @@ -478,8 +436,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) { } NvResult nvhost_as_gpu::GetVARegions1(IoctlGetVaRegions& params) { - LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr, - params.buf_size); + LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr, params.buf_size); std::scoped_lock lock(mutex); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 7d50fd4c33..862bdd60bf 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -165,35 +165,36 @@ private: NvCore::NvMap& nvmap; struct Mapping { - NvCore::NvMap::Handle::Id handle; DAddr ptr; u64 offset; u64 size; - bool fixed; - bool big_page; // Only valid if fixed == false - bool sparse_alloc; + NvCore::NvMap::Handle::Id handle; + bool fixed : 1; + bool big_page : 1; // Only valid if fixed == false + bool sparse_alloc : 1; - Mapping(NvCore::NvMap::Handle::Id handle_, DAddr ptr_, u64 offset_, u64 size_, bool fixed_, - bool big_page_, bool sparse_alloc_) - : handle(handle_), ptr(ptr_), offset(offset_), size(size_), fixed(fixed_), - big_page(big_page_), sparse_alloc(sparse_alloc_) {} + Mapping(NvCore::NvMap::Handle::Id handle_, DAddr ptr_, u64 offset_, u64 size_, bool fixed_, bool big_page_, bool sparse_alloc_) + : ptr(ptr_), offset(offset_), size(size_), handle(handle_) + , fixed(fixed_), big_page(big_page_), sparse_alloc(sparse_alloc_) + {} }; struct Allocation { + std::vector mappings; u64 size; - std::list> mappings; u32 page_size; bool sparse; bool big_pages; }; - std::map> - mapping_map; //!< 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 allocation_map; //!< Holds allocations created by AllocSpace from - //!< which fixed buffers can be mapped into - std::mutex mutex; //!< Locks all AS operations + //!< 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 mapping_map; + //!< Holds allocations created by AllocSpace from + //!< which fixed buffers can be mapped into + std::map allocation_map; + std::mutex mutex; //!< Locks all AS operations struct VM { static constexpr u32 YUZU_PAGESIZE{0x1000}; @@ -213,9 +214,8 @@ private: using Allocator = Common::FlatAllocator; - std::unique_ptr big_page_allocator; - std::shared_ptr - small_page_allocator; //! Shared as this is also used by nvhost::GpuChannel + std::optional big_page_allocator; + std::optional small_page_allocator; //! Shared as this is also used by nvhost::GpuChannel bool initialised{}; } vm;