summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/archive.cpp426
-rw-r--r--src/core/hle/kernel/archive.h107
-rw-r--r--src/core/hle/kernel/kernel.cpp5
3 files changed, 0 insertions, 538 deletions
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
deleted file mode 100644
index 0e3eb4564..000000000
--- a/src/core/hle/kernel/archive.cpp
+++ /dev/null
@@ -1,426 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <map>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9#include "common/math_util.h"
10
11#include "core/file_sys/archive.h"
12#include "core/file_sys/archive_sdmc.h"
13#include "core/file_sys/directory.h"
14#include "core/hle/kernel/archive.h"
15#include "core/hle/kernel/session.h"
16#include "core/hle/result.h"
17
18////////////////////////////////////////////////////////////////////////////////////////////////////
19// Kernel namespace
20
21namespace Kernel {
22
23// Command to access archive file
24enum class FileCommand : u32 {
25 Dummy1 = 0x000100C6,
26 Control = 0x040100C4,
27 OpenSubFile = 0x08010100,
28 Read = 0x080200C2,
29 Write = 0x08030102,
30 GetSize = 0x08040000,
31 SetSize = 0x08050080,
32 GetAttributes = 0x08060000,
33 SetAttributes = 0x08070040,
34 Close = 0x08080000,
35 Flush = 0x08090000,
36};
37
38// Command to access directory
39enum class DirectoryCommand : u32 {
40 Dummy1 = 0x000100C6,
41 Control = 0x040100C4,
42 Read = 0x08010042,
43 Close = 0x08020000,
44};
45
46class Archive : public Kernel::Session {
47public:
48 std::string GetName() const override { return "Archive: " + name; }
49
50 std::string name; ///< Name of archive (optional)
51 FileSys::Archive* backend; ///< Archive backend interface
52
53 ResultVal<bool> SyncRequest() override {
54 u32* cmd_buff = Kernel::GetCommandBuffer();
55 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
56
57 switch (cmd) {
58 // Read from archive...
59 case FileCommand::Read:
60 {
61 u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
62 u32 length = cmd_buff[3];
63 u32 address = cmd_buff[5];
64
65 // Number of bytes read
66 cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
67 break;
68 }
69 // Write to archive...
70 case FileCommand::Write:
71 {
72 u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
73 u32 length = cmd_buff[3];
74 u32 flush = cmd_buff[4];
75 u32 address = cmd_buff[6];
76
77 // Number of bytes written
78 cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
79 break;
80 }
81 case FileCommand::GetSize:
82 {
83 u64 filesize = (u64) backend->GetSize();
84 cmd_buff[2] = (u32) filesize; // Lower word
85 cmd_buff[3] = (u32) (filesize >> 32); // Upper word
86 break;
87 }
88 case FileCommand::SetSize:
89 {
90 backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32));
91 break;
92 }
93 case FileCommand::Close:
94 {
95 LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
96 CloseArchive(backend->GetIdCode());
97 break;
98 }
99 // Unknown command...
100 default:
101 {
102 LOG_ERROR(Service_FS, "Unknown command=0x%08X", cmd);
103 cmd_buff[0] = UnimplementedFunction(ErrorModule::FS).raw;
104 return MakeResult<bool>(false);
105 }
106 }
107 cmd_buff[1] = 0; // No error
108 return MakeResult<bool>(false);
109 }
110};
111
112class File : public Kernel::Session {
113public:
114 std::string GetName() const override { return "Path: " + path.DebugStr(); }
115
116 FileSys::Path path; ///< Path of the file
117 std::unique_ptr<FileSys::File> backend; ///< File backend interface
118
119 ResultVal<bool> SyncRequest() override {
120 u32* cmd_buff = Kernel::GetCommandBuffer();
121 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
122 switch (cmd) {
123
124 // Read from file...
125 case FileCommand::Read:
126 {
127 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
128 u32 length = cmd_buff[3];
129 u32 address = cmd_buff[5];
130 LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x",
131 GetTypeName().c_str(), GetName().c_str(), offset, length, address);
132 cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
133 break;
134 }
135
136 // Write to file...
137 case FileCommand::Write:
138 {
139 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
140 u32 length = cmd_buff[3];
141 u32 flush = cmd_buff[4];
142 u32 address = cmd_buff[6];
143 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
144 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
145 cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
146 break;
147 }
148
149 case FileCommand::GetSize:
150 {
151 LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str());
152 u64 size = backend->GetSize();
153 cmd_buff[2] = (u32)size;
154 cmd_buff[3] = size >> 32;
155 break;
156 }
157
158 case FileCommand::SetSize:
159 {
160 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
161 LOG_TRACE(Service_FS, "SetSize %s %s size=%llu",
162 GetTypeName().c_str(), GetName().c_str(), size);
163 backend->SetSize(size);
164 break;
165 }
166
167 case FileCommand::Close:
168 {
169 LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
170 Kernel::g_object_pool.Destroy<File>(GetHandle());
171 break;
172 }
173
174 // Unknown command...
175 default:
176 LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
177 ResultCode error = UnimplementedFunction(ErrorModule::FS);
178 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
179 return error;
180 }
181 cmd_buff[1] = 0; // No error
182 return MakeResult<bool>(false);
183 }
184};
185
186class Directory : public Kernel::Session {
187public:
188 std::string GetName() const override { return "Directory: " + path.DebugStr(); }
189
190 FileSys::Path path; ///< Path of the directory
191 std::unique_ptr<FileSys::Directory> backend; ///< File backend interface
192
193 ResultVal<bool> SyncRequest() override {
194 u32* cmd_buff = Kernel::GetCommandBuffer();
195 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
196 switch (cmd) {
197
198 // Read from directory...
199 case DirectoryCommand::Read:
200 {
201 u32 count = cmd_buff[1];
202 u32 address = cmd_buff[3];
203 auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
204 LOG_TRACE(Service_FS, "Read %s %s: count=%d",
205 GetTypeName().c_str(), GetName().c_str(), count);
206
207 // Number of entries actually read
208 cmd_buff[2] = backend->Read(count, entries);
209 break;
210 }
211
212 case DirectoryCommand::Close:
213 {
214 LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
215 Kernel::g_object_pool.Destroy<Directory>(GetHandle());
216 break;
217 }
218
219 // Unknown command...
220 default:
221 LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
222 ResultCode error = UnimplementedFunction(ErrorModule::FS);
223 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
224 return MakeResult<bool>(false);
225 }
226 cmd_buff[1] = 0; // No error
227 return MakeResult<bool>(false);
228 }
229};
230
231////////////////////////////////////////////////////////////////////////////////////////////////////
232
233std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode
234
235ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) {
236 auto itr = g_archive_map.find(id_code);
237 if (itr == g_archive_map.end()) {
238 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
239 ErrorSummary::NotFound, ErrorLevel::Permanent);
240 }
241
242 return MakeResult<Handle>(itr->second);
243}
244
245ResultCode CloseArchive(FileSys::Archive::IdCode id_code) {
246 auto itr = g_archive_map.find(id_code);
247 if (itr == g_archive_map.end()) {
248 LOG_ERROR(Service_FS, "Cannot close archive %d, does not exist!", (int)id_code);
249 return InvalidHandle(ErrorModule::FS);
250 }
251
252 LOG_TRACE(Service_FS, "Closed archive %d", (int) id_code);
253 return RESULT_SUCCESS;
254}
255
256/**
257 * Mounts an archive
258 * @param archive Pointer to the archive to mount
259 */
260ResultCode MountArchive(Archive* archive) {
261 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode();
262 ResultVal<Handle> archive_handle = OpenArchive(id_code);
263 if (archive_handle.Succeeded()) {
264 LOG_ERROR(Service_FS, "Cannot mount two archives with the same ID code! (%d)", (int) id_code);
265 return archive_handle.Code();
266 }
267 g_archive_map[id_code] = archive->GetHandle();
268 LOG_TRACE(Service_FS, "Mounted archive %s", archive->GetName().c_str());
269 return RESULT_SUCCESS;
270}
271
272ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) {
273 Archive* archive = new Archive;
274 Handle handle = Kernel::g_object_pool.Create(archive);
275 archive->name = name;
276 archive->backend = backend;
277
278 ResultCode result = MountArchive(archive);
279 if (result.IsError()) {
280 return result;
281 }
282
283 return RESULT_SUCCESS;
284}
285
286ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
287 // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create
288 // the archive file handles at app loading, and then keep them persistent throughout execution.
289 // Archives file handles are just reused and not actually freed until emulation shut down.
290 // Verify if real hardware works this way, or if new handles are created each time
291 if (path.GetType() == FileSys::Binary)
292 // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend
293 // design. While the functionally of this is OK, our implementation decision to separate
294 // normal files from archive file pointers is very likely wrong.
295 // See https://github.com/citra-emu/citra/issues/205
296 return MakeResult<Handle>(archive_handle);
297
298 File* file = new File;
299 Handle handle = Kernel::g_object_pool.Create(file);
300
301 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
302 if (archive == nullptr) {
303 return InvalidHandle(ErrorModule::FS);
304 }
305 file->path = path;
306 file->backend = archive->backend->OpenFile(path, mode);
307
308 if (!file->backend) {
309 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
310 ErrorSummary::NotFound, ErrorLevel::Permanent);
311 }
312
313 return MakeResult<Handle>(handle);
314}
315
316ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) {
317 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
318 if (archive == nullptr)
319 return InvalidHandle(ErrorModule::FS);
320 if (archive->backend->DeleteFile(path))
321 return RESULT_SUCCESS;
322 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
323 ErrorSummary::Canceled, ErrorLevel::Status);
324}
325
326ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path,
327 Handle dest_archive_handle, const FileSys::Path& dest_path) {
328 Archive* src_archive = Kernel::g_object_pool.GetFast<Archive>(src_archive_handle);
329 Archive* dest_archive = Kernel::g_object_pool.GetFast<Archive>(dest_archive_handle);
330 if (src_archive == nullptr || dest_archive == nullptr)
331 return InvalidHandle(ErrorModule::FS);
332 if (src_archive == dest_archive) {
333 if (src_archive->backend->RenameFile(src_path, dest_path))
334 return RESULT_SUCCESS;
335 } else {
336 // TODO: Implement renaming across archives
337 return UnimplementedFunction(ErrorModule::FS);
338 }
339 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
340 ErrorSummary::NothingHappened, ErrorLevel::Status);
341}
342
343ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
344 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
345 if (archive == nullptr)
346 return InvalidHandle(ErrorModule::FS);
347 if (archive->backend->DeleteDirectory(path))
348 return RESULT_SUCCESS;
349 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
350 ErrorSummary::Canceled, ErrorLevel::Status);
351}
352
353ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
354 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
355 if (archive == nullptr)
356 return InvalidHandle(ErrorModule::FS);
357 if (archive->backend->CreateDirectory(path))
358 return RESULT_SUCCESS;
359 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
360 ErrorSummary::Canceled, ErrorLevel::Status);
361}
362
363ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path,
364 Handle dest_archive_handle, const FileSys::Path& dest_path) {
365 Archive* src_archive = Kernel::g_object_pool.GetFast<Archive>(src_archive_handle);
366 Archive* dest_archive = Kernel::g_object_pool.GetFast<Archive>(dest_archive_handle);
367 if (src_archive == nullptr || dest_archive == nullptr)
368 return InvalidHandle(ErrorModule::FS);
369 if (src_archive == dest_archive) {
370 if (src_archive->backend->RenameDirectory(src_path, dest_path))
371 return RESULT_SUCCESS;
372 } else {
373 // TODO: Implement renaming across archives
374 return UnimplementedFunction(ErrorModule::FS);
375 }
376 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
377 ErrorSummary::NothingHappened, ErrorLevel::Status);
378}
379
380/**
381 * Open a Directory from an Archive
382 * @param archive_handle Handle to an open Archive object
383 * @param path Path to the Directory inside of the Archive
384 * @return Opened Directory object
385 */
386ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
387 Directory* directory = new Directory;
388 Handle handle = Kernel::g_object_pool.Create(directory);
389
390 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
391 if (archive == nullptr) {
392 return InvalidHandle(ErrorModule::FS);
393 }
394 directory->path = path;
395 directory->backend = archive->backend->OpenDirectory(path);
396
397 if (!directory->backend) {
398 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
399 ErrorSummary::NotFound, ErrorLevel::Permanent);
400 }
401
402 return MakeResult<Handle>(handle);
403}
404
405/// Initialize archives
406void ArchiveInit() {
407 g_archive_map.clear();
408
409 // TODO(Link Mauve): Add the other archive types (see here for the known types:
410 // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished
411 // archive type is SDMC, so it is the only one getting exposed.
412
413 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
414 auto archive = new FileSys::Archive_SDMC(sdmc_directory);
415 if (archive->Initialize())
416 CreateArchive(archive, "SDMC");
417 else
418 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
419}
420
421/// Shutdown archives
422void ArchiveShutdown() {
423 g_archive_map.clear();
424}
425
426} // namespace Kernel
diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h
deleted file mode 100644
index b50833a2b..000000000
--- a/src/core/hle/kernel/archive.h
+++ /dev/null
@@ -1,107 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/archive.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/result.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// Kernel namespace
15
16namespace Kernel {
17
18/**
19 * Opens an archive
20 * @param id_code IdCode of the archive to open
21 * @return Handle to the opened archive
22 */
23ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code);
24
25/**
26 * Closes an archive
27 * @param id_code IdCode of the archive to open
28 */
29ResultCode CloseArchive(FileSys::Archive::IdCode id_code);
30
31/**
32 * Creates an Archive
33 * @param backend File system backend interface to the archive
34 * @param name Name of Archive
35 */
36ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name);
37
38/**
39 * Open a File from an Archive
40 * @param archive_handle Handle to an open Archive object
41 * @param path Path to the File inside of the Archive
42 * @param mode Mode under which to open the File
43 * @return Handle to the opened File object
44 */
45ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode);
46
47/**
48 * Delete a File from an Archive
49 * @param archive_handle Handle to an open Archive object
50 * @param path Path to the File inside of the Archive
51 * @return Whether deletion succeeded
52 */
53ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path);
54
55/**
56 * Rename a File between two Archives
57 * @param src_archive_handle Handle to the source Archive object
58 * @param src_path Path to the File inside of the source Archive
59 * @param dest_archive_handle Handle to the destination Archive object
60 * @param dest_path Path to the File inside of the destination Archive
61 * @return Whether rename succeeded
62 */
63ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path,
64 Handle dest_archive_handle, const FileSys::Path& dest_path);
65
66/**
67 * Delete a Directory from an Archive
68 * @param archive_handle Handle to an open Archive object
69 * @param path Path to the Directory inside of the Archive
70 * @return Whether deletion succeeded
71 */
72ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
73
74/**
75 * Create a Directory from an Archive
76 * @param archive_handle Handle to an open Archive object
77 * @param path Path to the Directory inside of the Archive
78 * @return Whether creation of directory succeeded
79 */
80ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
81
82/**
83 * Rename a Directory between two Archives
84 * @param src_archive_handle Handle to the source Archive object
85 * @param src_path Path to the Directory inside of the source Archive
86 * @param dest_archive_handle Handle to the destination Archive object
87 * @param dest_path Path to the Directory inside of the destination Archive
88 * @return Whether rename succeeded
89 */
90ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path,
91 Handle dest_archive_handle, const FileSys::Path& dest_path);
92
93/**
94 * Open a Directory from an Archive
95 * @param archive_handle Handle to an open Archive object
96 * @param path Path to the Directory inside of the Archive
97 * @return Handle to the opened File object
98 */
99ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
100
101/// Initialize archives
102void ArchiveInit();
103
104/// Shutdown archives
105void ArchiveShutdown();
106
107} // namespace FileSys
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b38be0a49..929422b36 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -9,7 +9,6 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/thread.h" 11#include "core/hle/kernel/thread.h"
12#include "core/hle/kernel/archive.h"
13 12
14namespace Kernel { 13namespace Kernel {
15 14
@@ -89,13 +88,11 @@ Object* ObjectPool::CreateByIDType(int type) {
89/// Initialize the kernel 88/// Initialize the kernel
90void Init() { 89void Init() {
91 Kernel::ThreadingInit(); 90 Kernel::ThreadingInit();
92 Kernel::ArchiveInit();
93} 91}
94 92
95/// Shutdown the kernel 93/// Shutdown the kernel
96void Shutdown() { 94void Shutdown() {
97 Kernel::ThreadingShutdown(); 95 Kernel::ThreadingShutdown();
98 Kernel::ArchiveShutdown();
99 96
100 g_object_pool.Clear(); // Free all kernel objects 97 g_object_pool.Clear(); // Free all kernel objects
101} 98}
@@ -106,8 +103,6 @@ void Shutdown() {
106 * @return True on success, otherwise false 103 * @return True on success, otherwise false
107 */ 104 */
108bool LoadExec(u32 entry_point) { 105bool LoadExec(u32 entry_point) {
109 Init();
110
111 Core::g_app_core->SetPC(entry_point); 106 Core::g_app_core->SetPC(entry_point);
112 107
113 // 0x30 is the typical main thread priority I've seen used so far 108 // 0x30 is the typical main thread priority I've seen used so far