From 8db2cf29f2d5de91b7c24f4be4a04e042ed4aa04 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sat, 18 Sep 2021 13:16:41 +0100 Subject: [PATCH] Implement AsGpu::FreeSpace and clean up locking and debug prints --- .../services/nvdrv/devices/nvhost/as_gpu.cpp | 80 +++++++++++++++++-- .../services/nvdrv/devices/nvhost/as_gpu.h | 6 +- .../services/nvdrv/devices/nvhost/ctrl.cpp | 11 ++- .../nvdrv/devices/nvhost/gpu_channel.cpp | 16 ++++ .../skyline/services/nvdrv/devices/nvmap.cpp | 14 +++- 5 files changed, 116 insertions(+), 11 deletions(-) diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/as_gpu.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/as_gpu.cpp index 1c487ef5..5b4d85a9 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/as_gpu.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/as_gpu.cpp @@ -22,7 +22,13 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult AsGpu::AllocSpace(In pages, In pageSize, In flags, InOut offset) { - state.logger->Debug("pages: 0x{:X}, pageSize: 0x{:X}, flags: ( fixed: {}, sparse: {} ), offset: 0x{:X}", pages, pageSize, flags.fixed, flags.sparse, offset); + state.logger->Debug("pages: 0x{:X}, pageSize: 0x{:X}, flags: ( fixed: {}, sparse: {} ), offset: 0x{:X}", + pages, pageSize, flags.fixed, flags.sparse, offset); + + std::scoped_lock lock(mutex); + + if (!vm.initialised) + return PosixResult::InvalidArgument; if (pageSize != VM::PageSize && pageSize != vm.bigPageSize) return PosixResult::InvalidArgument; @@ -44,7 +50,7 @@ namespace skyline::service::nvdrv::device::nvhost { else offset = static_cast(allocator->Allocate(pages)) << pageSizeBits; - u64 size{static_cast(pages) * static_cast(pageSize)}; + u64 size{static_cast(pages) * pageSize}; if (flags.sparse) state.soc->gm20b.gmmu.Map(offset, GMMU::SparsePlaceholderAddress(), size, true); @@ -58,14 +64,67 @@ namespace skyline::service::nvdrv::device::nvhost { return PosixResult::Success; } + void AsGpu::FreeMappingLocked(u64 offset) { + auto mapping{mappingMap.at(offset)}; + + if (!mapping->fixed) { + auto &allocator{mapping->bigPage ? vm.bigPageAllocator : vm.smallPageAllocator}; + u32 pageSizeBits{mapping->bigPage ? vm.bigPageSizeBits : VM::PageSizeBits}; + + allocator->Free(mapping->offset >> pageSizeBits, mapping->size >> pageSizeBits); + } + + // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state + // Only FreeSpace can unmap them fully + if (mapping->sparseAlloc) + state.soc->gm20b.gmmu.Map(offset, GMMU::SparsePlaceholderAddress(), mapping->size, true); + else + state.soc->gm20b.gmmu.Unmap(offset, mapping->size); + + mappingMap.erase(offset); + } + PosixResult AsGpu::FreeSpace(In offset, In pages, In pageSize) { - // TODO: implement after UNMAP + state.logger->Debug("offset: 0x{:X}, pages: 0x{:X}, pageSize: 0x{:X}", offset, pages, pageSize); + + std::scoped_lock lock(mutex); + + if (!vm.initialised) + return PosixResult::InvalidArgument; + + try { + auto allocation{allocationMap[offset]}; + + if (allocation.pageSize != pageSize || allocation.size != (static_cast(pages) * pageSize)) + return PosixResult::InvalidArgument; + + for (const auto &mapping : allocation.mappings) + FreeMapping(mapping->offset); + + // Unset sparse flag if required + if (allocation.sparse) + state.soc->gm20b.gmmu.Unmap(offset, allocation.size); + + auto &allocator{pageSize == VM::PageSize ? vm.smallPageAllocator : vm.bigPageAllocator}; + u32 pageSizeBits{pageSize == VM::PageSize ? VM::PageSizeBits : vm.bigPageSizeBits}; + + allocator->Free(offset >> pageSizeBits, allocation.size >> pageSizeBits); + allocationMap.erase(offset); + } catch (const std::out_of_range &e) { + return PosixResult::InvalidArgument; + } + return PosixResult::Success; } PosixResult AsGpu::UnmapBuffer(In offset) { state.logger->Debug("offset: 0x{:X}", offset); + std::scoped_lock lock(mutex); + + if (!vm.initialised) + return PosixResult::InvalidArgument; + try { auto mapping{mappingMap.at(offset)}; @@ -92,11 +151,13 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult AsGpu::MapBufferEx(In flags, In kind, In handle, In bufferOffset, In mappingSize, InOut offset) { + state.logger->Debug("flags: ( fixed: {}, remap: {} ), kind: {}, handle: {}, bufferOffset: 0x{:X}, mappingSize: 0x{:X}, offset: 0x{:X}", flags.fixed, flags.remap, kind, handle, bufferOffset, mappingSize, offset); + + std::scoped_lock lock(mutex); + if (!vm.initialised) return PosixResult::InvalidArgument; - state.logger->Debug("flags: ( fixed: {}, remap: {} ), kind: {}, handle: {}, bufferOffset: 0x{:X}, mappingSize: 0x{:X}, offset: 0x{:X}", flags.fixed, flags.remap, kind, handle, bufferOffset, mappingSize, offset); - // Remaps a subregion of an existing mapping to a different PA if (flags.remap) { try { @@ -164,6 +225,8 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult AsGpu::GetVaRegions(In bufAddr, InOut bufSize, Out> vaRegions) { + std::scoped_lock lock(mutex); + if (!vm.initialised) return PosixResult::InvalidArgument; @@ -188,6 +251,8 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult AsGpu::AllocAsEx(In flags, In asFd, In bigPageSize, In vaRangeStart, In vaRangeEnd, In vaRangeSplit) { + std::scoped_lock lock(mutex); + if (vm.initialised) throw exception("Cannot initialise an address space twice!"); @@ -232,6 +297,11 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult AsGpu::Remap(span entries) { + std::scoped_lock lock(mutex); + + if (!vm.initialised) + return PosixResult::InvalidArgument; + for (const auto &entry : entries) { u64 virtAddr{static_cast(entry.asOffsetBigPages) << vm.bigPageSizeBits}; u64 size{static_cast(entry.bigPages) << vm.bigPageSizeBits}; diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/as_gpu.h b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/as_gpu.h index edce48bf..00529fe7 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/as_gpu.h +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/as_gpu.h @@ -38,9 +38,8 @@ namespace skyline::service::nvdrv::device::nvhost { }; 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; - + 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{0x1000}; @@ -66,6 +65,7 @@ namespace skyline::service::nvdrv::device::nvhost { bool initialised{}; } vm; + void FreeMappingLocked(u64 offset); public: struct MappingFlags { diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/ctrl.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/ctrl.cpp index 45a1ca33..bb1798da 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/ctrl.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/ctrl.cpp @@ -70,6 +70,9 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult Ctrl::SyncpointWaitEventImpl(In fence, In timeout, InOut value, bool allocate) { + state.logger->Debug("fence: ( id: {}, threshold: {} ), timeout: {}, value: {}, allocate: {}", + fence.id, fence.threshold, timeout, value.val, allocate); + if (fence.id >= soc::host1x::SyncpointCount) return PosixResult::InvalidArgument; @@ -147,6 +150,8 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult Ctrl::SyncpointClearEventWait(In value) { + state.logger->Debug("slot: {}", value.slot); + u16 slot{value.slot}; if (slot >= SyncpointEventCount) return PosixResult::InvalidArgument; @@ -178,7 +183,7 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult Ctrl::SyncpointAllocateEvent(In slot) { - state.logger->Debug("Registering syncpoint event: {}", slot); + state.logger->Debug("slot: {}", slot); if (slot >= SyncpointEventCount) return PosixResult::InvalidArgument; @@ -196,11 +201,15 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult Ctrl::SyncpointFreeEvent(In slot) { + state.logger->Debug("slot: {}", slot); + std::lock_guard lock(syncpointEventMutex); return SyncpointFreeEventLocked(slot); } PosixResult Ctrl::SyncpointFreeEventBatch(In bitmask) { + state.logger->Debug("bitmask: 0x{:X}", bitmask); + auto err{PosixResult::Success}; // Avoid repeated locks/unlocks by just locking now 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 index af2b3549..29b652fe 100644 --- 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 @@ -15,14 +15,23 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult GpuChannel::SetNvmapFd(In id) { + state.logger->Debug("id: {}", id); return PosixResult::Success; } PosixResult GpuChannel::SetTimeout(In timeout) { + state.logger->Debug("timeout: {}", timeout); return PosixResult::Success; } PosixResult GpuChannel::SubmitGpfifo(In userAddress, In numEntries, InOut flags, InOut fence, span gpEntries) { + state.logger->Debug("userAddress: 0x{:X}, numEntries: {}," + "flags ( fenceWait: {}, fenceIncrement: {}, hwFormat: {}, suppressWfi: {}, incrementWithValue: {})," + "fence ( id: {}, threshold: {} )", + userAddress, numEntries, + +flags.fenceWait, +flags.fenceIncrement, +flags.hwFormat, +flags.suppressWfi, +flags.incrementWithValue, + fence.id, fence.threshold); + if (numEntries > gpEntries.size()) throw exception("GpEntry size mismatch!"); @@ -54,22 +63,27 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult GpuChannel::AllocObjCtx(In classId, In flags, Out objId) { + state.logger->Debug("classId: 0x{:X}, flags: 0x{:X}", classId, flags); return PosixResult::Success; } PosixResult GpuChannel::ZcullBind(In gpuVa, In mode) { + state.logger->Debug("gpuVa: 0x{:X}, mode: {}", gpuVa, mode); return PosixResult::Success; } PosixResult GpuChannel::SetErrorNotifier(In offset, In size, In mem) { + state.logger->Debug("offset: 0x{:X}, size: 0x{:X}, mem: 0x{:X}", offset, size, mem); return PosixResult::Success; } PosixResult GpuChannel::SetPriority(In priority) { + state.logger->Debug("priority: {}", priority); return PosixResult::Success; } PosixResult GpuChannel::AllocGpfifoEx2(In numEntries, In numJobs, In flags, Out fence) { + state.logger->Debug("numEntries: {}, numJobs: {}, flags: 0x{:X}", numEntries, numJobs, flags); state.soc->gm20b.gpfifo.Initialize(numEntries); fence = core.syncpointManager.GetSyncpointFence(channelSyncpoint); @@ -78,10 +92,12 @@ namespace skyline::service::nvdrv::device::nvhost { } PosixResult GpuChannel::SetTimeslice(In timeslice) { + state.logger->Debug("timeslice: {}", timeslice); return PosixResult::Success; } PosixResult GpuChannel::SetUserData(In userData) { + state.logger->Debug("userData: 0x{:X}", userData); channelUserData = userData; return PosixResult::Success; } diff --git a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp index 586e3e6c..dc80888d 100644 --- a/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp +++ b/app/src/main/cpp/skyline/services/nvdrv/devices/nvmap.cpp @@ -20,6 +20,8 @@ namespace skyline::service::nvdrv::device { } PosixResult NvMap::FromId(In id, Out handle) { + state.logger->Debug("id: {}", id); + // Handles and IDs are always the same value in nvmap however IDs can be used globally given the right permissions. // Since we don't plan on ever supporting multiprocess we can skip implementing handle refs and so this function // just does simple validation and passes through the handle id. @@ -34,6 +36,8 @@ namespace skyline::service::nvdrv::device { } PosixResult NvMap::Alloc(In handle, In heapMask, In flags, InOut align, In kind, In address) { + state.logger->Debug("handle: {}, flags: ( mapUncached: {}, keepUncachedAfterFree: {} ), align: 0x{:X}, kind: {}, address: 0x{:X}", handle, flags.mapUncached, flags.keepUncachedAfterFree, align, kind, address); + if (!handle) [[unlikely]] return PosixResult::InvalidArgument; @@ -48,12 +52,12 @@ namespace skyline::service::nvdrv::device { if (!h) [[unlikely]] return PosixResult::InvalidArgument; - state.logger->Debug("handle: {}, flags: ( mapUncached: {}, keepUncachedAfterFree: {} ), align: 0x{:X}, kind: {}, address: 0x{:X}", handle, flags.mapUncached, flags.keepUncachedAfterFree, align, kind, address); - return h->Alloc(flags, align, kind, address); } PosixResult NvMap::Free(In handle, Out address, Out size, Out flags) { + state.logger->Debug("handle: {}", handle); + if (!handle) [[unlikely]] return PosixResult::Success; @@ -61,12 +65,16 @@ namespace skyline::service::nvdrv::device { address = freeInfo->address; size = static_cast(freeInfo->size); flags = NvMapCore::Handle::Flags{ .mapUncached = freeInfo->wasUncached }; + } else { + state.logger->Debug("Handle not freed"); } return PosixResult::Success; } PosixResult NvMap::Param(In handle, In param, Out result) { + state.logger->Debug("handle: {}, param: {}", handle, param); + if (!handle) return PosixResult::InvalidArgument; @@ -103,6 +111,8 @@ namespace skyline::service::nvdrv::device { } PosixResult NvMap::GetId(Out id, In handle) { + state.logger->Debug("handle: {}", handle); + // See the comment in FromId for extra info on this function if (!handle) [[unlikely]] return PosixResult::InvalidArgument;