summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Subv2018-01-07 21:25:57 -0500
committerGravatar bunnei2018-01-10 23:28:05 -0500
commit94a5e97eb3e331f5c02e3ff2c0d4a9d62f072ba7 (patch)
tree3067e1a6e631253b880851e739a47926d75fe15a /src
parentIPC: Corrected some definitions for the buffer C descriptor flags. (diff)
downloadyuzu-94a5e97eb3e331f5c02e3ff2c0d4a9d62f072ba7.tar.gz
yuzu-94a5e97eb3e331f5c02e3ff2c0d4a9d62f072ba7.tar.xz
yuzu-94a5e97eb3e331f5c02e3ff2c0d4a9d62f072ba7.zip
NV: Implemented the nvdrv:a service and the /dev/nvmap device.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp16
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h25
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_a.cpp283
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_a.h30
4 files changed, 354 insertions, 0 deletions
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
new file mode 100644
index 000000000..a2d55eaee
--- /dev/null
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -0,0 +1,16 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/nvdrv/nvdrv.h"
6#include "core/hle/service/nvdrv/nvdrv_a.h"
7
8namespace Service {
9namespace NVDRV {
10
11void InstallInterfaces(SM::ServiceManager& service_manager) {
12 std::make_shared<NVDRV_A>()->InstallAsService(service_manager);
13}
14
15} // namespace nvdrv
16} // namespace Service
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
new file mode 100644
index 000000000..a8f305d33
--- /dev/null
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -0,0 +1,25 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include "common/common_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service {
12namespace NVDRV {
13
14class nvdevice {
15public:
16 virtual ~nvdevice() = default;
17
18 virtual u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) = 0;
19};
20
21/// Registers all NVDRV services with the specified service manager.
22void InstallInterfaces(SM::ServiceManager& service_manager);
23
24} // namespace NVDRV
25} // namespace Service
diff --git a/src/core/hle/service/nvdrv/nvdrv_a.cpp b/src/core/hle/service/nvdrv/nvdrv_a.cpp
new file mode 100644
index 000000000..af6b7f7aa
--- /dev/null
+++ b/src/core/hle/service/nvdrv/nvdrv_a.cpp
@@ -0,0 +1,283 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/service/nvdrv/nvdrv.h"
8#include "core/hle/service/nvdrv/nvdrv_a.h"
9
10namespace Service {
11namespace NVDRV {
12
13class nvhost_as_gpu : public nvdevice {
14public:
15 u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override {
16 ASSERT(false, "Unimplemented");
17 return 0;
18 }
19};
20
21class nvmap : public nvdevice {
22public:
23 u32 ioctl(u32 command, const std::vector<u8>& input, std::vector<u8>& output) override {
24 switch (command) {
25 case IocCreateCommand:
26 return IocCreate(input, output);
27 case IocAllocCommand:
28 return IocAlloc(input, output);
29 case IocGetIdCommand:
30 return IocGetId(input, output);
31 case IocFromIdCommand:
32 return IocFromId(input, output);
33 case IocParamCommand:
34 return IocParam(input, output);
35 }
36
37 ASSERT(false, "Unimplemented");
38 }
39
40private:
41 // Represents an nvmap object.
42 struct Object {
43 enum class Status { Created, Allocated };
44 u32 id;
45 u32 size;
46 u32 flags;
47 u32 align;
48 u8 kind;
49 u64 addr;
50 Status status;
51 };
52
53 u32 next_handle = 1;
54 u32 next_id = 1;
55 std::unordered_map<u32, std::shared_ptr<Object>> handles;
56
57 enum IoctlCommands {
58 IocCreateCommand = 0xC0080101,
59 IocFromIdCommand = 0xC0080103,
60 IocAllocCommand = 0xC0200104,
61 IocParamCommand = 0xC00C0109,
62 IocGetIdCommand = 0xC008010E
63 };
64
65 struct IocCreateParams {
66 // Input
67 u32_le size;
68 // Output
69 u32_le handle;
70 };
71
72 struct IocAllocParams {
73 // Input
74 u32_le handle;
75 u32_le heap_mask;
76 u32_le flags;
77 u32_le align;
78 u8 kind;
79 INSERT_PADDING_BYTES(7);
80 u64_le addr;
81 };
82
83 struct IocGetIdParams {
84 // Output
85 u32_le id;
86 // Input
87 u32_le handle;
88 };
89
90 struct IocFromIdParams {
91 // Input
92 u32_le id;
93 // Output
94 u32_le handle;
95 };
96
97 struct IocParamParams {
98 // Input
99 u32_le handle;
100 u32_le type;
101 // Output
102 u32_le value;
103 };
104
105 u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
106 IocCreateParams params;
107 std::memcpy(&params, input.data(), sizeof(params));
108
109 // Create a new nvmap object and obtain a handle to it.
110 auto object = std::make_shared<Object>();
111 object->id = next_id++;
112 object->size = params.size;
113 object->status = Object::Status::Created;
114
115 u32 handle = next_handle++;
116 handles[handle] = std::move(object);
117
118 LOG_WARNING(Service, "(STUBBED) size 0x%08X", params.size);
119
120 params.handle = handle;
121
122 std::memcpy(output.data(), &params, sizeof(params));
123 return 0;
124 }
125
126 u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
127 IocAllocParams params;
128 std::memcpy(&params, input.data(), sizeof(params));
129
130 auto itr = handles.find(params.handle);
131 ASSERT(itr != handles.end());
132
133 auto object = itr->second;
134 object->flags = params.flags;
135 object->align = params.align;
136 object->kind = params.kind;
137 object->addr = params.addr;
138 object->status = Object::Status::Allocated;
139
140 LOG_WARNING(Service, "(STUBBED) Allocated address 0x%llx", params.addr);
141
142 std::memcpy(output.data(), &params, sizeof(params));
143 return 0;
144 }
145
146 u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
147 IocGetIdParams params;
148 std::memcpy(&params, input.data(), sizeof(params));
149
150 LOG_WARNING(Service, "called");
151
152 auto itr = handles.find(params.handle);
153 ASSERT(itr != handles.end());
154
155 params.id = itr->second->id;
156
157 std::memcpy(output.data(), &params, sizeof(params));
158 return 0;
159 }
160
161 u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
162 IocFromIdParams params;
163 std::memcpy(&params, input.data(), sizeof(params));
164
165 LOG_WARNING(Service, "(STUBBED) called");
166
167 auto itr = std::find_if(handles.begin(), handles.end(),
168 [&](const auto& entry) { return entry.second->id == params.id; });
169 ASSERT(itr != handles.end());
170
171 // Make a new handle for the object
172 u32 handle = next_handle++;
173 handles[handle] = itr->second;
174
175 params.handle = handle;
176
177 std::memcpy(output.data(), &params, sizeof(params));
178 return 0;
179 }
180
181 u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
182 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
183
184 IocParamParams params;
185 std::memcpy(&params, input.data(), sizeof(params));
186
187 LOG_WARNING(Service, "(STUBBED) called type=%u", params.type);
188
189 auto itr = handles.find(params.handle);
190 ASSERT(itr != handles.end());
191
192 auto object = itr->second;
193 ASSERT(object->status == Object::Status::Allocated);
194
195 switch (static_cast<ParamTypes>(params.type)) {
196 case ParamTypes::Size:
197 params.value = object->size;
198 break;
199 case ParamTypes::Alignment:
200 params.value = object->align;
201 break;
202 case ParamTypes::Heap:
203 // TODO(Subv): Seems to be a hardcoded value?
204 params.value = 0x40000000;
205 break;
206 case ParamTypes::Kind:
207 params.value = object->kind;
208 break;
209 default:
210 ASSERT(false, "Unimplemented");
211 }
212
213 std::memcpy(output.data(), &params, sizeof(params));
214 return 0;
215 }
216};
217
218void NVDRV_A::Open(Kernel::HLERequestContext& ctx) {
219 LOG_WARNING(Service, "(STUBBED) called");
220
221 auto buffer = ctx.BufferDescriptorA()[0];
222
223 std::string device_name = Memory::ReadCString(buffer.Address(), buffer.Size());
224
225 auto device = devices[device_name];
226 u32 fd = next_fd++;
227
228 open_files[fd] = device;
229
230 IPC::RequestBuilder rb{ctx, 4};
231 rb.Push(RESULT_SUCCESS);
232 rb.Push<u32>(fd);
233 rb.Push<u32>(0);
234}
235
236void NVDRV_A::Ioctl(Kernel::HLERequestContext& ctx) {
237 LOG_WARNING(Service, "(STUBBED) called");
238
239 IPC::RequestParser rp{ctx};
240 u32 fd = rp.Pop<u32>();
241 u32 command = rp.Pop<u32>();
242
243 auto input_buffer = ctx.BufferDescriptorA()[0];
244 auto output_buffer = ctx.BufferDescriptorB()[0];
245
246 std::vector<u8> input(input_buffer.Size());
247 std::vector<u8> output(output_buffer.Size());
248
249 Memory::ReadBlock(input_buffer.Address(), input.data(), input_buffer.Size());
250 auto itr = open_files.find(fd);
251 ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device");
252
253 auto device = itr->second;
254 u32 nv_result = device->ioctl(command, input, output);
255
256 Memory::WriteBlock(output_buffer.Address(), output.data(), output_buffer.Size());
257
258 IPC::RequestBuilder rb{ctx, 3};
259 rb.Push(RESULT_SUCCESS);
260 rb.Push(nv_result);
261}
262
263void NVDRV_A::Initialize(Kernel::HLERequestContext& ctx) {
264 LOG_WARNING(Service, "(STUBBED) called");
265 IPC::RequestBuilder rb{ctx, 3};
266 rb.Push(RESULT_SUCCESS);
267 rb.Push<u32>(0);
268}
269
270NVDRV_A::NVDRV_A() : ServiceFramework("nvdrv:a") {
271 static const FunctionInfo functions[] = {
272 {0, &NVDRV_A::Open, "Open"},
273 {1, &NVDRV_A::Ioctl, "Ioctl"},
274 {3, &NVDRV_A::Initialize, "Initialize"},
275 };
276 RegisterHandlers(functions);
277
278 devices["/dev/nvhost-as-gpu"] = std::make_shared<nvhost_as_gpu>();
279 devices["/dev/nvmap"] = std::make_shared<nvmap>();
280}
281
282} // namespace NVDRV
283} // namespace Service
diff --git a/src/core/hle/service/nvdrv/nvdrv_a.h b/src/core/hle/service/nvdrv/nvdrv_a.h
new file mode 100644
index 000000000..09522a486
--- /dev/null
+++ b/src/core/hle/service/nvdrv/nvdrv_a.h
@@ -0,0 +1,30 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8#include <memory>
9
10namespace Service {
11namespace NVDRV {
12
13class NVDRV_A final : public ServiceFramework<NVDRV_A> {
14public:
15 NVDRV_A();
16 ~NVDRV_A() = default;
17
18private:
19 void Open(Kernel::HLERequestContext& ctx);
20 void Ioctl(Kernel::HLERequestContext& ctx);
21 void Initialize(Kernel::HLERequestContext& ctx);
22
23 u32 next_fd = 1;
24
25 std::unordered_map<u32, std::shared_ptr<nvdevice>> open_files;
26 std::unordered_map<std::string, std::shared_ptr<nvdevice>> devices;
27};
28
29} // namespace NVDRV
30} // namespace Service