summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nvdrv/memory_manager.cpp
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2018-02-08 03:54:35 +0100
committerbunnei <bunneidev@gmail.com>2018-02-08 05:31:26 +0100
commitc711253798b32c4ef73cf38749ea5cf17a352daa (patch)
tree9569ccc93878656bf90c1697b2a2a27efe80867c /src/core/hle/service/nvdrv/memory_manager.cpp
parentnvmap: Refactor to expose nvmap objects. (diff)
downloadyuzu-c711253798b32c4ef73cf38749ea5cf17a352daa.tar
yuzu-c711253798b32c4ef73cf38749ea5cf17a352daa.tar.gz
yuzu-c711253798b32c4ef73cf38749ea5cf17a352daa.tar.bz2
yuzu-c711253798b32c4ef73cf38749ea5cf17a352daa.tar.lz
yuzu-c711253798b32c4ef73cf38749ea5cf17a352daa.tar.xz
yuzu-c711253798b32c4ef73cf38749ea5cf17a352daa.tar.zst
yuzu-c711253798b32c4ef73cf38749ea5cf17a352daa.zip
Diffstat (limited to 'src/core/hle/service/nvdrv/memory_manager.cpp')
-rw-r--r--src/core/hle/service/nvdrv/memory_manager.cpp112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/core/hle/service/nvdrv/memory_manager.cpp b/src/core/hle/service/nvdrv/memory_manager.cpp
new file mode 100644
index 000000000..55a8675d5
--- /dev/null
+++ b/src/core/hle/service/nvdrv/memory_manager.cpp
@@ -0,0 +1,112 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "core/hle/service/nvdrv/memory_manager.h"
+
+namespace Service {
+namespace Nvidia {
+
+PAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
+ boost::optional<PAddr> paddr = FindFreeBlock(size, align);
+ ASSERT(paddr);
+
+ for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
+ PageSlot(*paddr + offset) = static_cast<u64>(PageStatus::Allocated);
+ }
+
+ return *paddr;
+}
+
+PAddr MemoryManager::AllocateSpace(PAddr paddr, u64 size, u64 align) {
+ for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
+ if (IsPageMapped(paddr + offset)) {
+ return AllocateSpace(size, align);
+ }
+ }
+
+ for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
+ PageSlot(paddr + offset) = static_cast<u64>(PageStatus::Allocated);
+ }
+
+ return paddr;
+}
+
+PAddr MemoryManager::MapBufferEx(VAddr vaddr, u64 size) {
+ vaddr &= ~Memory::PAGE_MASK;
+
+ boost::optional<PAddr> paddr = FindFreeBlock(size);
+ ASSERT(paddr);
+
+ for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
+ PageSlot(*paddr + offset) = vaddr + offset;
+ }
+
+ return *paddr;
+}
+
+PAddr MemoryManager::MapBufferEx(VAddr vaddr, PAddr paddr, u64 size) {
+ vaddr &= ~Memory::PAGE_MASK;
+ paddr &= ~Memory::PAGE_MASK;
+
+ for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
+ if (PageSlot(paddr + offset) != static_cast<u64>(PageStatus::Allocated)) {
+ return MapBufferEx(vaddr, size);
+ }
+ }
+
+ for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
+ PageSlot(paddr + offset) = vaddr + offset;
+ }
+
+ return paddr;
+}
+
+boost::optional<PAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
+ PAddr paddr{};
+ u64 free_space{};
+ align = (align + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
+
+ while (paddr + free_space < MAX_ADDRESS) {
+ if (!IsPageMapped(paddr + free_space)) {
+ free_space += Memory::PAGE_SIZE;
+ if (free_space >= size) {
+ return paddr;
+ }
+ } else {
+ paddr += free_space + Memory::PAGE_SIZE;
+ free_space = 0;
+ const u64 remainder{paddr % align};
+ if (!remainder) {
+ paddr = (paddr - remainder) + align;
+ }
+ }
+ }
+
+ return {};
+}
+
+VAddr MemoryManager::PhysicalToVirtualAddress(PAddr paddr) {
+ VAddr base_addr = PageSlot(paddr);
+ ASSERT(base_addr != static_cast<u64>(PageStatus::Unmapped));
+ return base_addr + (paddr & Memory::PAGE_MASK);
+}
+
+bool MemoryManager::IsPageMapped(PAddr paddr) {
+ return PageSlot(paddr) != static_cast<u64>(PageStatus::Unmapped);
+}
+
+VAddr& MemoryManager::PageSlot(PAddr paddr) {
+ auto& block = page_table[(paddr >> (Memory::PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK];
+ if (!block) {
+ block = std::make_unique<PageBlock>();
+ for (unsigned index = 0; index < PAGE_BLOCK_SIZE; index++) {
+ (*block)[index] = static_cast<u64>(PageStatus::Unmapped);
+ }
+ }
+ return (*block)[(paddr >> Memory::PAGE_BITS) & PAGE_BLOCK_MASK];
+}
+
+} // namespace Nvidia
+} // namespace Service