summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-02-07 22:10:42 -0800
committerGravatar GitHub2018-02-07 22:10:42 -0800
commitdb11c9a0b927a8f1d09f4cdf6bbe524485cb61b4 (patch)
treea9a7ab29e0c2e89bf2ec9874df074eb9db792dcc /src
parentMerge pull request #168 from mailwl/new-stubs (diff)
parentnvhost_as_gpu: Implement AllocateSpace and MapBufferEx. (diff)
downloadyuzu-db11c9a0b927a8f1d09f4cdf6bbe524485cb61b4.tar.gz
yuzu-db11c9a0b927a8f1d09f4cdf6bbe524485cb61b4.tar.xz
yuzu-db11c9a0b927a8f1d09f4cdf6bbe524485cb61b4.zip
Merge pull request #169 from bunnei/gpu-mem
nvdrv: Implement AllocateSpace and MapBufferEx
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp38
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp27
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h14
-rw-r--r--src/core/hle/service/nvdrv/memory_manager.cpp112
-rw-r--r--src/core/hle/service/nvdrv/memory_manager.h48
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp2
8 files changed, 225 insertions, 30 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 02c178441..eab08207d 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -137,6 +137,8 @@ add_library(core STATIC
137 hle/service/nvdrv/devices/nvmap.h 137 hle/service/nvdrv/devices/nvmap.h
138 hle/service/nvdrv/interface.cpp 138 hle/service/nvdrv/interface.cpp
139 hle/service/nvdrv/interface.h 139 hle/service/nvdrv/interface.h
140 hle/service/nvdrv/memory_manager.cpp
141 hle/service/nvdrv/memory_manager.h
140 hle/service/nvdrv/nvdrv.cpp 142 hle/service/nvdrv/nvdrv.cpp
141 hle/service/nvdrv/nvdrv.h 143 hle/service/nvdrv/nvdrv.h
142 hle/service/nvdrv/nvmemp.cpp 144 hle/service/nvdrv/nvmemp.cpp
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 11ab25545..cf3601f02 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -5,6 +5,7 @@
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" 7#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
8#include "core/hle/service/nvdrv/devices/nvmap.h"
8 9
9namespace Service { 10namespace Service {
10namespace Nvidia { 11namespace Nvidia {
@@ -40,9 +41,16 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou
40u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { 41u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
41 IoctlAllocSpace params{}; 42 IoctlAllocSpace params{};
42 std::memcpy(&params, input.data(), input.size()); 43 std::memcpy(&params, input.data(), input.size());
43 LOG_WARNING(Service_NVDRV, "(STUBBED) called, pages=%x, page_size=%x, flags=%x", params.pages, 44 LOG_DEBUG(Service_NVDRV, "called, pages=%x, page_size=%x, flags=%x", params.pages,
44 params.page_size, params.flags); 45 params.page_size, params.flags);
45 params.offset = 0xdeadbeef; // TODO(ogniK): Actually allocate space and give a real offset 46
47 const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)};
48 if (params.flags & 1) {
49 params.offset = memory_manager->AllocateSpace(params.offset, size, 1);
50 } else {
51 params.offset = memory_manager->AllocateSpace(size, params.align);
52 }
53
46 std::memcpy(output.data(), &params, output.size()); 54 std::memcpy(output.data(), &params, output.size());
47 return 0; 55 return 0;
48} 56}
@@ -51,12 +59,24 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
51 IoctlMapBufferEx params{}; 59 IoctlMapBufferEx params{};
52 std::memcpy(&params, input.data(), input.size()); 60 std::memcpy(&params, input.data(), input.size());
53 61
54 LOG_WARNING(Service_NVDRV, 62 LOG_DEBUG(Service_NVDRV,
55 "(STUBBED) called, flags=%x, nvmap_handle=%x, buffer_offset=%lx, mapping_size=%lx, " 63 "called, flags=%x, nvmap_handle=%x, buffer_offset=%lx, mapping_size=%lx, offset=%lx",
56 "offset=%lx", 64 params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size,
57 params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size, 65 params.offset);
58 params.offset); 66
59 params.offset = 0x0; // TODO(ogniK): Actually map and give a real offset 67 if (!params.nvmap_handle) {
68 return 0;
69 }
70
71 auto object = nvmap_dev->GetObject(params.nvmap_handle);
72 ASSERT(object);
73
74 if (params.flags & 1) {
75 params.offset = memory_manager->MapBufferEx(object->addr, params.offset, object->size);
76 } else {
77 params.offset = memory_manager->MapBufferEx(object->addr, object->size);
78 }
79
60 std::memcpy(output.data(), &params, output.size()); 80 std::memcpy(output.data(), &params, output.size());
61 return 0; 81 return 0;
62} 82}
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 06c256d5d..9d37b971a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -4,18 +4,25 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <utility>
7#include <vector> 9#include <vector>
8#include "common/common_types.h" 10#include "common/common_types.h"
9#include "common/swap.h" 11#include "common/swap.h"
10#include "core/hle/service/nvdrv/devices/nvdevice.h" 12#include "core/hle/service/nvdrv/devices/nvdevice.h"
13#include "core/hle/service/nvdrv/memory_manager.h"
11 14
12namespace Service { 15namespace Service {
13namespace Nvidia { 16namespace Nvidia {
14namespace Devices { 17namespace Devices {
15 18
19class nvmap;
20
16class nvhost_as_gpu final : public nvdevice { 21class nvhost_as_gpu final : public nvdevice {
17public: 22public:
18 nvhost_as_gpu() = default; 23 nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvdevice(), nvmap_dev(std::move(nvmap_dev)) {
24 memory_manager = std::make_shared<MemoryManager>();
25 }
19 ~nvhost_as_gpu() override = default; 26 ~nvhost_as_gpu() override = default;
20 27
21 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 28 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
@@ -92,6 +99,9 @@ private:
92 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output); 99 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
93 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); 100 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
94 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); 101 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
102
103 std::shared_ptr<nvmap> nvmap_dev;
104 std::shared_ptr<MemoryManager> memory_manager;
95}; 105};
96 106
97} // namespace Devices 107} // namespace Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index cb3692689..02b33374a 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -13,10 +13,8 @@ namespace Nvidia {
13namespace Devices { 13namespace Devices {
14 14
15VAddr nvmap::GetObjectAddress(u32 handle) const { 15VAddr nvmap::GetObjectAddress(u32 handle) const {
16 auto itr = handles.find(handle); 16 auto object = GetObject(handle);
17 ASSERT(itr != handles.end()); 17 ASSERT(object);
18
19 auto object = itr->second;
20 ASSERT(object->status == Object::Status::Allocated); 18 ASSERT(object->status == Object::Status::Allocated);
21 return object->addr; 19 return object->addr;
22} 20}
@@ -52,7 +50,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
52 u32 handle = next_handle++; 50 u32 handle = next_handle++;
53 handles[handle] = std::move(object); 51 handles[handle] = std::move(object);
54 52
55 LOG_WARNING(Service_NVDRV, "(STUBBED) size 0x%08X", params.size); 53 LOG_DEBUG(Service_NVDRV, "size=0x%08X", params.size);
56 54
57 params.handle = handle; 55 params.handle = handle;
58 56
@@ -64,17 +62,16 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
64 IocAllocParams params; 62 IocAllocParams params;
65 std::memcpy(&params, input.data(), sizeof(params)); 63 std::memcpy(&params, input.data(), sizeof(params));
66 64
67 auto itr = handles.find(params.handle); 65 auto object = GetObject(params.handle);
68 ASSERT(itr != handles.end()); 66 ASSERT(object);
69 67
70 auto object = itr->second;
71 object->flags = params.flags; 68 object->flags = params.flags;
72 object->align = params.align; 69 object->align = params.align;
73 object->kind = params.kind; 70 object->kind = params.kind;
74 object->addr = params.addr; 71 object->addr = params.addr;
75 object->status = Object::Status::Allocated; 72 object->status = Object::Status::Allocated;
76 73
77 LOG_WARNING(Service_NVDRV, "(STUBBED) Allocated address 0x%llx", params.addr); 74 LOG_DEBUG(Service_NVDRV, "called, addr=0x%llx", params.addr);
78 75
79 std::memcpy(output.data(), &params, sizeof(params)); 76 std::memcpy(output.data(), &params, sizeof(params));
80 return 0; 77 return 0;
@@ -86,10 +83,10 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
86 83
87 LOG_WARNING(Service_NVDRV, "called"); 84 LOG_WARNING(Service_NVDRV, "called");
88 85
89 auto itr = handles.find(params.handle); 86 auto object = GetObject(params.handle);
90 ASSERT(itr != handles.end()); 87 ASSERT(object);
91 88
92 params.id = itr->second->id; 89 params.id = object->id;
93 90
94 std::memcpy(output.data(), &params, sizeof(params)); 91 std::memcpy(output.data(), &params, sizeof(params));
95 return 0; 92 return 0;
@@ -123,10 +120,8 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
123 120
124 LOG_WARNING(Service_NVDRV, "(STUBBED) called type=%u", params.type); 121 LOG_WARNING(Service_NVDRV, "(STUBBED) called type=%u", params.type);
125 122
126 auto itr = handles.find(params.handle); 123 auto object = GetObject(params.handle);
127 ASSERT(itr != handles.end()); 124 ASSERT(object);
128
129 auto object = itr->second;
130 ASSERT(object->status == Object::Status::Allocated); 125 ASSERT(object->status == Object::Status::Allocated);
131 126
132 switch (static_cast<ParamTypes>(params.type)) { 127 switch (static_cast<ParamTypes>(params.type)) {
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 1591ac8ff..4681e438b 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -26,8 +26,7 @@ public:
26 26
27 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override; 27 u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
28 28
29private: 29 /// Represents an nvmap object.
30 // Represents an nvmap object.
31 struct Object { 30 struct Object {
32 enum class Status { Created, Allocated }; 31 enum class Status { Created, Allocated };
33 u32 id; 32 u32 id;
@@ -39,10 +38,19 @@ private:
39 Status status; 38 Status status;
40 }; 39 };
41 40
41 std::shared_ptr<Object> GetObject(u32 handle) const {
42 auto itr = handles.find(handle);
43 if (itr != handles.end()) {
44 return itr->second;
45 }
46 return {};
47 }
48
49private:
42 /// Id to use for the next handle that is created. 50 /// Id to use for the next handle that is created.
43 u32 next_handle = 1; 51 u32 next_handle = 1;
44 52
45 // Id to use for the next object that is created. 53 /// Id to use for the next object that is created.
46 u32 next_id = 1; 54 u32 next_id = 1;
47 55
48 /// Mapping of currently allocated handles to the objects they represent. 56 /// Mapping of currently allocated handles to the objects they represent.
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 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/hle/service/nvdrv/memory_manager.h"
7
8namespace Service {
9namespace Nvidia {
10
11PAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
12 boost::optional<PAddr> paddr = FindFreeBlock(size, align);
13 ASSERT(paddr);
14
15 for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
16 PageSlot(*paddr + offset) = static_cast<u64>(PageStatus::Allocated);
17 }
18
19 return *paddr;
20}
21
22PAddr MemoryManager::AllocateSpace(PAddr paddr, u64 size, u64 align) {
23 for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
24 if (IsPageMapped(paddr + offset)) {
25 return AllocateSpace(size, align);
26 }
27 }
28
29 for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
30 PageSlot(paddr + offset) = static_cast<u64>(PageStatus::Allocated);
31 }
32
33 return paddr;
34}
35
36PAddr MemoryManager::MapBufferEx(VAddr vaddr, u64 size) {
37 vaddr &= ~Memory::PAGE_MASK;
38
39 boost::optional<PAddr> paddr = FindFreeBlock(size);
40 ASSERT(paddr);
41
42 for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
43 PageSlot(*paddr + offset) = vaddr + offset;
44 }
45
46 return *paddr;
47}
48
49PAddr MemoryManager::MapBufferEx(VAddr vaddr, PAddr paddr, u64 size) {
50 vaddr &= ~Memory::PAGE_MASK;
51 paddr &= ~Memory::PAGE_MASK;
52
53 for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
54 if (PageSlot(paddr + offset) != static_cast<u64>(PageStatus::Allocated)) {
55 return MapBufferEx(vaddr, size);
56 }
57 }
58
59 for (u64 offset = 0; offset < size; offset += Memory::PAGE_SIZE) {
60 PageSlot(paddr + offset) = vaddr + offset;
61 }
62
63 return paddr;
64}
65
66boost::optional<PAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
67 PAddr paddr{};
68 u64 free_space{};
69 align = (align + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
70
71 while (paddr + free_space < MAX_ADDRESS) {
72 if (!IsPageMapped(paddr + free_space)) {
73 free_space += Memory::PAGE_SIZE;
74 if (free_space >= size) {
75 return paddr;
76 }
77 } else {
78 paddr += free_space + Memory::PAGE_SIZE;
79 free_space = 0;
80 const u64 remainder{paddr % align};
81 if (!remainder) {
82 paddr = (paddr - remainder) + align;
83 }
84 }
85 }
86
87 return {};
88}
89
90VAddr MemoryManager::PhysicalToVirtualAddress(PAddr paddr) {
91 VAddr base_addr = PageSlot(paddr);
92 ASSERT(base_addr != static_cast<u64>(PageStatus::Unmapped));
93 return base_addr + (paddr & Memory::PAGE_MASK);
94}
95
96bool MemoryManager::IsPageMapped(PAddr paddr) {
97 return PageSlot(paddr) != static_cast<u64>(PageStatus::Unmapped);
98}
99
100VAddr& MemoryManager::PageSlot(PAddr paddr) {
101 auto& block = page_table[(paddr >> (Memory::PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK];
102 if (!block) {
103 block = std::make_unique<PageBlock>();
104 for (unsigned index = 0; index < PAGE_BLOCK_SIZE; index++) {
105 (*block)[index] = static_cast<u64>(PageStatus::Unmapped);
106 }
107 }
108 return (*block)[(paddr >> Memory::PAGE_BITS) & PAGE_BLOCK_MASK];
109}
110
111} // namespace Nvidia
112} // namespace Service
diff --git a/src/core/hle/service/nvdrv/memory_manager.h b/src/core/hle/service/nvdrv/memory_manager.h
new file mode 100644
index 000000000..4ba1a3952
--- /dev/null
+++ b/src/core/hle/service/nvdrv/memory_manager.h
@@ -0,0 +1,48 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <memory>
9#include "common/common_types.h"
10#include "core/memory.h"
11
12namespace Service {
13namespace Nvidia {
14
15class MemoryManager final {
16public:
17 MemoryManager() = default;
18
19 PAddr AllocateSpace(u64 size, u64 align);
20 PAddr AllocateSpace(PAddr paddr, u64 size, u64 align);
21 PAddr MapBufferEx(VAddr vaddr, u64 size);
22 PAddr MapBufferEx(VAddr vaddr, PAddr paddr, u64 size);
23 VAddr PhysicalToVirtualAddress(PAddr paddr);
24
25private:
26 boost::optional<PAddr> FindFreeBlock(u64 size, u64 align = 1);
27 bool IsPageMapped(PAddr paddr);
28 VAddr& PageSlot(PAddr paddr);
29
30 enum class PageStatus : u64 {
31 Unmapped = 0xFFFFFFFFFFFFFFFFULL,
32 Allocated = 0xFFFFFFFFFFFFFFFEULL,
33 };
34
35 static constexpr u64 MAX_ADDRESS{0x10000000000ULL};
36 static constexpr u64 PAGE_TABLE_BITS{14};
37 static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS};
38 static constexpr u64 PAGE_TABLE_MASK{PAGE_TABLE_SIZE - 1};
39 static constexpr u64 PAGE_BLOCK_BITS{14};
40 static constexpr u64 PAGE_BLOCK_SIZE{1 << PAGE_BLOCK_BITS};
41 static constexpr u64 PAGE_BLOCK_MASK{PAGE_BLOCK_SIZE - 1};
42
43 using PageBlock = std::array<VAddr, PAGE_BLOCK_SIZE>;
44 std::array<std::unique_ptr<PageBlock>, PAGE_TABLE_SIZE> page_table{};
45};
46
47} // namespace Nvidia
48} // namespace Service
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 1cf8f3175..a98634422 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -31,7 +31,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
31 31
32Module::Module() { 32Module::Module() {
33 auto nvmap_dev = std::make_shared<Devices::nvmap>(); 33 auto nvmap_dev = std::make_shared<Devices::nvmap>();
34 devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(); 34 devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(nvmap_dev);
35 devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(); 35 devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>();
36 devices["/dev/nvmap"] = nvmap_dev; 36 devices["/dev/nvmap"] = nvmap_dev;
37 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev); 37 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);