summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/citra.cpp14
-rw-r--r--src/citra/emu_window/emu_window_sdl2.cpp4
-rw-r--r--src/citra_qt/debugger/graphics_vertex_shader.cpp12
-rw-r--r--src/citra_qt/main.cpp7
-rw-r--r--src/citra_qt/main.h2
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/common/vector_math.h5
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/arm/skyeye_common/armstate.cpp7
-rw-r--r--src/core/file_sys/archive_backend.h29
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp48
-rw-r--r--src/core/file_sys/archive_extsavedata.h13
-rw-r--r--src/core/file_sys/archive_romfs.cpp8
-rw-r--r--src/core/file_sys/archive_romfs.h3
-rw-r--r--src/core/file_sys/archive_savedata.cpp36
-rw-r--r--src/core/file_sys/archive_savedata.h4
-rw-r--r--src/core/file_sys/archive_savedatacheck.cpp8
-rw-r--r--src/core/file_sys/archive_savedatacheck.h3
-rw-r--r--src/core/file_sys/archive_sdmc.cpp7
-rw-r--r--src/core/file_sys/archive_sdmc.h3
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp8
-rw-r--r--src/core/file_sys/archive_systemsavedata.h3
-rw-r--r--src/core/file_sys/disk_archive.cpp80
-rw-r--r--src/core/file_sys/disk_archive.h12
-rw-r--r--src/core/file_sys/file_backend.h13
-rw-r--r--src/core/file_sys/ivfc_archive.cpp21
-rw-r--r--src/core/file_sys/ivfc_archive.h12
-rw-r--r--src/core/gdbstub/gdbstub.h2
-rw-r--r--src/core/hle/kernel/session.h12
-rw-r--r--src/core/hle/result.h6
-rw-r--r--src/core/hle/service/cfg/cfg.cpp5
-rw-r--r--src/core/hle/service/fs/archive.cpp90
-rw-r--r--src/core/hle/service/fs/archive.h17
-rw-r--r--src/core/hle/service/fs/fs_user.cpp139
-rw-r--r--src/core/hle/service/ndm/ndm.cpp47
-rw-r--r--src/core/hle/service/ndm/ndm.h52
-rw-r--r--src/core/hle/service/ndm/ndm_u.cpp (renamed from src/core/hle/service/ndm_u.cpp)23
-rw-r--r--src/core/hle/service/ndm/ndm_u.h (renamed from src/core/hle/service/ndm_u.h)15
-rw-r--r--src/core/hle/service/ptm/ptm.cpp2
-rw-r--r--src/core/hle/service/service.cpp5
-rw-r--r--src/core/hle/service/soc_u.cpp13
-rw-r--r--src/core/hw/gpu.h8
-rw-r--r--src/core/hw/lcd.h8
-rw-r--r--src/core/loader/loader.h2
-rw-r--r--src/video_core/command_processor.cpp23
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp24
-rw-r--r--src/video_core/pica.h20
-rw-r--r--src/video_core/shader/shader.cpp34
-rw-r--r--src/video_core/shader/shader_interpreter.cpp17
-rw-r--r--src/video_core/shader/shader_jit_x64.cpp68
-rw-r--r--src/video_core/shader/shader_jit_x64.h5
52 files changed, 716 insertions, 291 deletions
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index 415b98a05..40e40f192 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -19,6 +19,8 @@
19#include "common/logging/log.h" 19#include "common/logging/log.h"
20#include "common/logging/backend.h" 20#include "common/logging/backend.h"
21#include "common/logging/filter.h" 21#include "common/logging/filter.h"
22#include "common/make_unique.h"
23#include "common/scope_exit.h"
22 24
23#include "core/settings.h" 25#include "core/settings.h"
24#include "core/system.h" 26#include "core/system.h"
@@ -64,6 +66,7 @@ int main(int argc, char **argv) {
64 Log::SetFilter(&log_filter); 66 Log::SetFilter(&log_filter);
65 67
66 MicroProfileOnThreadCreate("EmuThread"); 68 MicroProfileOnThreadCreate("EmuThread");
69 SCOPE_EXIT({ MicroProfileShutdown(); });
67 70
68 if (boot_filename.empty()) { 71 if (boot_filename.empty()) {
69 LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); 72 LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
@@ -76,12 +79,13 @@ int main(int argc, char **argv) {
76 GDBStub::ToggleServer(Settings::values.use_gdbstub); 79 GDBStub::ToggleServer(Settings::values.use_gdbstub);
77 GDBStub::SetServerPort(static_cast<u32>(Settings::values.gdbstub_port)); 80 GDBStub::SetServerPort(static_cast<u32>(Settings::values.gdbstub_port));
78 81
79 EmuWindow_SDL2* emu_window = new EmuWindow_SDL2; 82 std::unique_ptr<EmuWindow_SDL2> emu_window = Common::make_unique<EmuWindow_SDL2>();
80 83
81 VideoCore::g_hw_renderer_enabled = Settings::values.use_hw_renderer; 84 VideoCore::g_hw_renderer_enabled = Settings::values.use_hw_renderer;
82 VideoCore::g_shader_jit_enabled = Settings::values.use_shader_jit; 85 VideoCore::g_shader_jit_enabled = Settings::values.use_shader_jit;
83 86
84 System::Init(emu_window); 87 System::Init(emu_window.get());
88 SCOPE_EXIT({ System::Shutdown(); });
85 89
86 Loader::ResultStatus load_result = Loader::LoadFile(boot_filename); 90 Loader::ResultStatus load_result = Loader::LoadFile(boot_filename);
87 if (Loader::ResultStatus::Success != load_result) { 91 if (Loader::ResultStatus::Success != load_result) {
@@ -93,11 +97,5 @@ int main(int argc, char **argv) {
93 Core::RunLoop(); 97 Core::RunLoop();
94 } 98 }
95 99
96 System::Shutdown();
97
98 delete emu_window;
99
100 MicroProfileShutdown();
101
102 return 0; 100 return 0;
103} 101}
diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp
index 1fed82e78..924189f4c 100644
--- a/src/citra/emu_window/emu_window_sdl2.cpp
+++ b/src/citra/emu_window/emu_window_sdl2.cpp
@@ -73,6 +73,10 @@ EmuWindow_SDL2::EmuWindow_SDL2() {
73 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 73 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
74 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 74 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
75 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 75 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
76 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
77 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
78 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
79 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
76 80
77 std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); 81 std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
78 render_window = SDL_CreateWindow(window_title.c_str(), 82 render_window = SDL_CreateWindow(window_title.c_str(),
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp
index 4b676f1b1..d648d4640 100644
--- a/src/citra_qt/debugger/graphics_vertex_shader.cpp
+++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp
@@ -179,9 +179,17 @@ QVariant GraphicsVertexShaderModel::data(const QModelIndex& index, int role) con
179 AlignToColumn(kOutputColumnWidth); 179 AlignToColumn(kOutputColumnWidth);
180 print_input(output, src1, swizzle.negate_src1, SelectorToString(swizzle.src1_selector)); 180 print_input(output, src1, swizzle.negate_src1, SelectorToString(swizzle.src1_selector));
181 AlignToColumn(kInputOperandColumnWidth); 181 AlignToColumn(kInputOperandColumnWidth);
182 print_input(output, src2, swizzle.negate_src2, SelectorToString(swizzle.src2_selector)); 182 if (src_is_inverted) {
183 print_input(output, src2, swizzle.negate_src2, SelectorToString(swizzle.src2_selector));
184 } else {
185 print_input(output, src2, swizzle.negate_src2, SelectorToString(swizzle.src2_selector), true, instr.mad.AddressRegisterName());
186 }
183 AlignToColumn(kInputOperandColumnWidth); 187 AlignToColumn(kInputOperandColumnWidth);
184 print_input(output, src3, swizzle.negate_src3, SelectorToString(swizzle.src3_selector)); 188 if (src_is_inverted) {
189 print_input(output, src3, swizzle.negate_src3, SelectorToString(swizzle.src3_selector), true, instr.mad.AddressRegisterName());
190 } else {
191 print_input(output, src3, swizzle.negate_src3, SelectorToString(swizzle.src3_selector));
192 }
185 AlignToColumn(kInputOperandColumnWidth); 193 AlignToColumn(kInputOperandColumnWidth);
186 break; 194 break;
187 } 195 }
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 57adbc136..32cceaf7e 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -310,6 +310,7 @@ bool GMainWindow::LoadROM(const std::string& filename) {
310 310
311void GMainWindow::BootGame(const std::string& filename) { 311void GMainWindow::BootGame(const std::string& filename) {
312 LOG_INFO(Frontend, "Citra starting..."); 312 LOG_INFO(Frontend, "Citra starting...");
313 StoreRecentFile(filename); // Put the filename on top of the list
313 314
314 if (!InitializeSystem()) 315 if (!InitializeSystem())
315 return; 316 return;
@@ -374,11 +375,11 @@ void GMainWindow::ShutdownGame() {
374 emulation_running = false; 375 emulation_running = false;
375} 376}
376 377
377void GMainWindow::StoreRecentFile(const QString& filename) 378void GMainWindow::StoreRecentFile(const std::string& filename)
378{ 379{
379 QSettings settings; 380 QSettings settings;
380 QStringList recent_files = settings.value("recentFiles").toStringList(); 381 QStringList recent_files = settings.value("recentFiles").toStringList();
381 recent_files.prepend(filename); 382 recent_files.prepend(QString::fromStdString(filename));
382 recent_files.removeDuplicates(); 383 recent_files.removeDuplicates();
383 while (recent_files.size() > max_recent_files_item) { 384 while (recent_files.size() > max_recent_files_item) {
384 recent_files.removeLast(); 385 recent_files.removeLast();
@@ -426,7 +427,6 @@ void GMainWindow::OnMenuLoadFile() {
426 QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), rom_path, tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.cci *.cxi)")); 427 QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), rom_path, tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.cci *.cxi)"));
427 if (!filename.isEmpty()) { 428 if (!filename.isEmpty()) {
428 settings.setValue("romsPath", QFileInfo(filename).path()); 429 settings.setValue("romsPath", QFileInfo(filename).path());
429 StoreRecentFile(filename);
430 430
431 BootGame(filename.toLocal8Bit().data()); 431 BootGame(filename.toLocal8Bit().data());
432 } 432 }
@@ -462,7 +462,6 @@ void GMainWindow::OnMenuRecentFile() {
462 QFileInfo file_info(filename); 462 QFileInfo file_info(filename);
463 if (file_info.exists()) { 463 if (file_info.exists()) {
464 BootGame(filename.toLocal8Bit().data()); 464 BootGame(filename.toLocal8Bit().data());
465 StoreRecentFile(filename); // Put the filename on top of the list
466 } else { 465 } else {
467 // Display an error message and remove the file from the list. 466 // Display an error message and remove the file from the list.
468 QMessageBox::information(this, tr("File not found"), tr("File \"%1\" not found").arg(filename)); 467 QMessageBox::information(this, tr("File not found"), tr("File \"%1\" not found").arg(filename));
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index 945aea0cd..6e4e56689 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -75,7 +75,7 @@ private:
75 * 75 *
76 * @param filename the filename to store 76 * @param filename the filename to store
77 */ 77 */
78 void StoreRecentFile(const QString& filename); 78 void StoreRecentFile(const std::string& filename);
79 79
80 /** 80 /**
81 * Updates the recent files menu. 81 * Updates the recent files menu.
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 54291429a..4c86151ab 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -42,6 +42,7 @@ namespace Log {
42 SUB(Service, AM) \ 42 SUB(Service, AM) \
43 SUB(Service, PTM) \ 43 SUB(Service, PTM) \
44 SUB(Service, LDR) \ 44 SUB(Service, LDR) \
45 SUB(Service, NDM) \
45 SUB(Service, NIM) \ 46 SUB(Service, NIM) \
46 SUB(Service, NWM) \ 47 SUB(Service, NWM) \
47 SUB(Service, CAM) \ 48 SUB(Service, CAM) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 4b01805ae..e4c39c308 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -57,6 +57,7 @@ enum class Class : ClassType {
57 Service_AM, ///< The AM (Application manager) service 57 Service_AM, ///< The AM (Application manager) service
58 Service_PTM, ///< The PTM (Power status & misc.) service 58 Service_PTM, ///< The PTM (Power status & misc.) service
59 Service_LDR, ///< The LDR (3ds dll loader) service 59 Service_LDR, ///< The LDR (3ds dll loader) service
60 Service_NDM, ///< The NDM (Network daemon manager) service
60 Service_NIM, ///< The NIM (Network interface manager) service 61 Service_NIM, ///< The NIM (Network interface manager) service
61 Service_NWM, ///< The NWM (Network wlan manager) service 62 Service_NWM, ///< The NWM (Network wlan manager) service
62 Service_CAM, ///< The CAM (Camera) service 63 Service_CAM, ///< The CAM (Camera) service
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 02688e35e..cfb9481b6 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -447,7 +447,10 @@ public:
447 447
448 void SetZero() 448 void SetZero()
449 { 449 {
450 x=0; y=0; z=0; 450 x = 0;
451 y = 0;
452 z = 0;
453 w = 0;
451 } 454 }
452 455
453 // Common alias: RGBA (colors) 456 // Common alias: RGBA (colors)
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 35b61dada..3473e2f5b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -87,7 +87,8 @@ set(SRCS
87 hle/service/ir/ir_user.cpp 87 hle/service/ir/ir_user.cpp
88 hle/service/ldr_ro.cpp 88 hle/service/ldr_ro.cpp
89 hle/service/mic_u.cpp 89 hle/service/mic_u.cpp
90 hle/service/ndm_u.cpp 90 hle/service/ndm/ndm.cpp
91 hle/service/ndm/ndm_u.cpp
91 hle/service/news/news.cpp 92 hle/service/news/news.cpp
92 hle/service/news/news_s.cpp 93 hle/service/news/news_s.cpp
93 hle/service/news/news_u.cpp 94 hle/service/news/news_u.cpp
@@ -218,7 +219,8 @@ set(HEADERS
218 hle/service/ir/ir_user.h 219 hle/service/ir/ir_user.h
219 hle/service/ldr_ro.h 220 hle/service/ldr_ro.h
220 hle/service/mic_u.h 221 hle/service/mic_u.h
221 hle/service/ndm_u.h 222 hle/service/ndm/ndm.h
223 hle/service/ndm/ndm_u.h
222 hle/service/news/news.h 224 hle/service/news/news.h
223 hle/service/news/news_s.h 225 hle/service/news/news_s.h
224 hle/service/news/news_u.h 226 hle/service/news/news_u.h
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp
index 2d814345a..5550c112e 100644
--- a/src/core/arm/skyeye_common/armstate.cpp
+++ b/src/core/arm/skyeye_common/armstate.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include "common/swap.h" 6#include "common/swap.h"
6#include "common/logging/log.h" 7#include "common/logging/log.h"
7#include "core/memory.h" 8#include "core/memory.h"
@@ -48,8 +49,7 @@ void ARMul_State::ChangePrivilegeMode(u32 new_mode)
48 Spsr[UNDEFBANK] = Spsr_copy; 49 Spsr[UNDEFBANK] = Spsr_copy;
49 break; 50 break;
50 case FIQ32MODE: 51 case FIQ32MODE:
51 Reg_firq[0] = Reg[13]; 52 std::copy(Reg.begin() + 8, Reg.end() - 1, Reg_firq.begin());
52 Reg_firq[1] = Reg[14];
53 Spsr[FIQBANK] = Spsr_copy; 53 Spsr[FIQBANK] = Spsr_copy;
54 break; 54 break;
55 } 55 }
@@ -85,8 +85,7 @@ void ARMul_State::ChangePrivilegeMode(u32 new_mode)
85 Bank = UNDEFBANK; 85 Bank = UNDEFBANK;
86 break; 86 break;
87 case FIQ32MODE: 87 case FIQ32MODE:
88 Reg[13] = Reg_firq[0]; 88 std::copy(Reg_firq.begin(), Reg_firq.end(), Reg.begin() + 8);
89 Reg[14] = Reg_firq[1];
90 Spsr_copy = Spsr[FIQBANK]; 89 Spsr_copy = Spsr[FIQBANK];
91 Bank = FIQBANK; 90 Bank = FIQBANK;
92 break; 91 break;
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 601e95d8c..5d91e47f3 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -11,6 +11,7 @@
11 11
12#include "common/bit_field.h" 12#include "common/bit_field.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/swap.h"
14 15
15#include "core/hle/result.h" 16#include "core/hle/result.h"
16 17
@@ -62,6 +63,14 @@ private:
62 std::u16string u16str; 63 std::u16string u16str;
63}; 64};
64 65
66struct ArchiveFormatInfo {
67 u32_le total_size; ///< The pre-defined size of the archive, as specified in the Create or Format call
68 u32_le number_directories; ///< The pre-defined number of directories in the archive, as specified in the Create or Format call
69 u32_le number_files; ///< The pre-defined number of files in the archive, as specified in the Create or Format call
70 u8 duplicate_data; ///< Whether the archive should duplicate the data, as specified in the Create or Format call
71};
72static_assert(std::is_pod<ArchiveFormatInfo>::value, "ArchiveFormatInfo is not POD");
73
65class ArchiveBackend : NonCopyable { 74class ArchiveBackend : NonCopyable {
66public: 75public:
67 virtual ~ArchiveBackend() { 76 virtual ~ArchiveBackend() {
@@ -76,16 +85,16 @@ public:
76 * Open a file specified by its path, using the specified mode 85 * Open a file specified by its path, using the specified mode
77 * @param path Path relative to the archive 86 * @param path Path relative to the archive
78 * @param mode Mode to open the file with 87 * @param mode Mode to open the file with
79 * @return Opened file, or nullptr 88 * @return Opened file, or error code
80 */ 89 */
81 virtual std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const = 0; 90 virtual ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode mode) const = 0;
82 91
83 /** 92 /**
84 * Delete a file specified by its path 93 * Delete a file specified by its path
85 * @param path Path relative to the archive 94 * @param path Path relative to the archive
86 * @return Whether the file could be deleted 95 * @return Result of the operation
87 */ 96 */
88 virtual bool DeleteFile(const Path& path) const = 0; 97 virtual ResultCode DeleteFile(const Path& path) const = 0;
89 98
90 /** 99 /**
91 * Rename a File specified by its path 100 * Rename a File specified by its path
@@ -108,7 +117,7 @@ public:
108 * @param size The size of the new file, filled with zeroes 117 * @param size The size of the new file, filled with zeroes
109 * @return File creation result code 118 * @return File creation result code
110 */ 119 */
111 virtual ResultCode CreateFile(const Path& path, u32 size) const = 0; 120 virtual ResultCode CreateFile(const Path& path, u64 size) const = 0;
112 121
113 /** 122 /**
114 * Create a directory specified by its path 123 * Create a directory specified by its path
@@ -159,9 +168,17 @@ public:
159 /** 168 /**
160 * Deletes the archive contents and then re-creates the base folder 169 * Deletes the archive contents and then re-creates the base folder
161 * @param path Path to the archive 170 * @param path Path to the archive
171 * @param format_info Format information for the new archive
162 * @return ResultCode of the operation, 0 on success 172 * @return ResultCode of the operation, 0 on success
163 */ 173 */
164 virtual ResultCode Format(const Path& path) = 0; 174 virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) = 0;
175
176 /**
177 * Retrieves the format info about the archive with the specified path
178 * @param path Path to the archive
179 * @return Format information about the archive or error code
180 */
181 virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const = 0;
165}; 182};
166 183
167} // namespace FileSys 184} // namespace FileSys
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index 92dad8e6f..961264fe5 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -58,7 +58,7 @@ Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) {
58} 58}
59 59
60ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, bool shared) 60ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, bool shared)
61 : mount_point(GetExtDataContainerPath(mount_location, shared)) { 61 : shared(shared), mount_point(GetExtDataContainerPath(mount_location, shared)) {
62 LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str()); 62 LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str());
63} 63}
64 64
@@ -74,21 +74,59 @@ bool ArchiveFactory_ExtSaveData::Initialize() {
74ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) { 74ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) {
75 std::string fullpath = GetExtSaveDataPath(mount_point, path) + "user/"; 75 std::string fullpath = GetExtSaveDataPath(mount_point, path) + "user/";
76 if (!FileUtil::Exists(fullpath)) { 76 if (!FileUtil::Exists(fullpath)) {
77 // TODO(Subv): Check error code, this one is probably wrong 77 // TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData.
78 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, 78 // ExtSaveData seems to return FS_NotFound (120) when the archive doesn't exist.
79 ErrorSummary::InvalidState, ErrorLevel::Status); 79 if (!shared) {
80 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS,
81 ErrorSummary::InvalidState, ErrorLevel::Status);
82 } else {
83 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
84 ErrorSummary::InvalidState, ErrorLevel::Status);
85 }
80 } 86 }
81 auto archive = Common::make_unique<DiskArchive>(fullpath); 87 auto archive = Common::make_unique<DiskArchive>(fullpath);
82 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 88 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
83} 89}
84 90
85ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path) { 91ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
86 // These folders are always created with the ExtSaveData 92 // These folders are always created with the ExtSaveData
87 std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/"; 93 std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/";
88 std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/"; 94 std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/";
89 FileUtil::CreateFullPath(user_path); 95 FileUtil::CreateFullPath(user_path);
90 FileUtil::CreateFullPath(boss_path); 96 FileUtil::CreateFullPath(boss_path);
97
98 // Write the format metadata
99 std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata";
100 FileUtil::IOFile file(metadata_path, "wb");
101
102 if (!file.IsOpen()) {
103 // TODO(Subv): Find the correct error code
104 return ResultCode(-1);
105 }
106
107 file.WriteBytes(&format_info, sizeof(format_info));
91 return RESULT_SUCCESS; 108 return RESULT_SUCCESS;
92} 109}
93 110
111ResultVal<ArchiveFormatInfo> ArchiveFactory_ExtSaveData::GetFormatInfo(const Path& path) const {
112 std::string metadata_path = GetExtSaveDataPath(mount_point, path) + "metadata";
113 FileUtil::IOFile file(metadata_path, "rb");
114
115 if (!file.IsOpen()) {
116 LOG_ERROR(Service_FS, "Could not open metadata information for archive");
117 // TODO(Subv): Verify error code
118 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status);
119 }
120
121 ArchiveFormatInfo info = {};
122 file.ReadBytes(&info, sizeof(info));
123 return MakeResult<ArchiveFormatInfo>(info);
124}
125
126void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data, size_t icon_size) {
127 std::string game_path = FileSys::GetExtSaveDataPath(GetMountPoint(), path);
128 FileUtil::IOFile icon_file(game_path + "icon", "wb");
129 icon_file.WriteBytes(icon_data, icon_size);
130}
131
94} // namespace FileSys 132} // namespace FileSys
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index ec8d770fc..e9a72850d 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -31,11 +31,22 @@ public:
31 std::string GetName() const override { return "ExtSaveData"; } 31 std::string GetName() const override { return "ExtSaveData"; }
32 32
33 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 33 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
34 ResultCode Format(const Path& path) override; 34 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
35 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
35 36
36 const std::string& GetMountPoint() const { return mount_point; } 37 const std::string& GetMountPoint() const { return mount_point; }
37 38
39 /**
40 * Writes the SMDH icon of the ExtSaveData to file
41 * @param path Path of this ExtSaveData
42 * @param icon_data Binary data of the icon
43 * @param icon_size Size of the icon data
44 */
45 void WriteIcon(const Path& path, const u8* icon_data, size_t icon_size);
46
38private: 47private:
48 bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData archive
49
39 /** 50 /**
40 * This holds the full directory path for this archive, it is only set after a successful call 51 * This holds the full directory path for this archive, it is only set after a successful call
41 * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>. 52 * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>.
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index 696b51a94..a9a29ebde 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -29,11 +29,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path
29 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 29 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
30} 30}
31 31
32ResultCode ArchiveFactory_RomFS::Format(const Path& path) { 32ResultCode ArchiveFactory_RomFS::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
33 LOG_ERROR(Service_FS, "Attempted to format a RomFS archive."); 33 LOG_ERROR(Service_FS, "Attempted to format a RomFS archive.");
34 // TODO: Verify error code 34 // TODO: Verify error code
35 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, 35 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,
36 ErrorSummary::NotSupported, ErrorLevel::Permanent); 36 ErrorSummary::NotSupported, ErrorLevel::Permanent);
37} 37}
38 38
39ResultVal<ArchiveFormatInfo> ArchiveFactory_RomFS::GetFormatInfo(const Path& path) const {
40 // TODO(Subv): Implement
41 LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
42 return ResultCode(-1);
43}
44
39} // namespace FileSys 45} // namespace FileSys
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index 2bedfa9c6..c5a329122 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -26,7 +26,8 @@ public:
26 26
27 std::string GetName() const override { return "RomFS"; } 27 std::string GetName() const override { return "RomFS"; }
28 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 28 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
29 ResultCode Format(const Path& path) override; 29 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
30 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
30 31
31private: 32private:
32 std::shared_ptr<FileUtil::IOFile> romfs_file; 33 std::shared_ptr<FileUtil::IOFile> romfs_file;
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index 12876899f..fe020d21c 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -26,11 +26,17 @@ static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) {
26} 26}
27 27
28static std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) { 28static std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) {
29 u32 high = program_id >> 32; 29 u32 high = (u32)(program_id >> 32);
30 u32 low = program_id & 0xFFFFFFFF; 30 u32 low = (u32)(program_id & 0xFFFFFFFF);
31 return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, low); 31 return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, low);
32} 32}
33 33
34static std::string GetSaveDataMetadataPath(const std::string& mount_location, u64 program_id) {
35 u32 high = (u32)(program_id >> 32);
36 u32 low = (u32)(program_id & 0xFFFFFFFF);
37 return Common::StringFromFormat("%s%08x/%08x/data/00000001.metadata", mount_location.c_str(), high, low);
38}
39
34ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory) 40ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directory)
35 : mount_point(GetSaveDataContainerPath(sdmc_directory)) { 41 : mount_point(GetSaveDataContainerPath(sdmc_directory)) {
36 LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str()); 42 LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str());
@@ -51,11 +57,35 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const P
51 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 57 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
52} 58}
53 59
54ResultCode ArchiveFactory_SaveData::Format(const Path& path) { 60ResultCode ArchiveFactory_SaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
55 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id); 61 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
56 FileUtil::DeleteDirRecursively(concrete_mount_point); 62 FileUtil::DeleteDirRecursively(concrete_mount_point);
57 FileUtil::CreateFullPath(concrete_mount_point); 63 FileUtil::CreateFullPath(concrete_mount_point);
64
65 // Write the format metadata
66 std::string metadata_path = GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id);
67 FileUtil::IOFile file(metadata_path, "wb");
68
69 if (file.IsOpen()) {
70 file.WriteBytes(&format_info, sizeof(format_info));
71 return RESULT_SUCCESS;
72 }
58 return RESULT_SUCCESS; 73 return RESULT_SUCCESS;
59} 74}
60 75
76ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveData::GetFormatInfo(const Path& path) const {
77 std::string metadata_path = GetSaveDataMetadataPath(mount_point, Kernel::g_current_process->codeset->program_id);
78 FileUtil::IOFile file(metadata_path, "rb");
79
80 if (!file.IsOpen()) {
81 LOG_ERROR(Service_FS, "Could not open metadata information for archive");
82 // TODO(Subv): Verify error code
83 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, ErrorSummary::InvalidState, ErrorLevel::Status);
84 }
85
86 ArchiveFormatInfo info = {};
87 file.ReadBytes(&info, sizeof(info));
88 return MakeResult<ArchiveFormatInfo>(info);
89}
90
61} // namespace FileSys 91} // namespace FileSys
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
index 1f65297dd..7a5a24089 100644
--- a/src/core/file_sys/archive_savedata.h
+++ b/src/core/file_sys/archive_savedata.h
@@ -23,7 +23,9 @@ public:
23 std::string GetName() const override { return "SaveData"; } 23 std::string GetName() const override { return "SaveData"; }
24 24
25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
26 ResultCode Format(const Path& path) override; 26 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
27
28 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
27 29
28private: 30private:
29 std::string mount_point; 31 std::string mount_point;
diff --git a/src/core/file_sys/archive_savedatacheck.cpp b/src/core/file_sys/archive_savedatacheck.cpp
index ea1dfe2c7..3db11c500 100644
--- a/src/core/file_sys/archive_savedatacheck.cpp
+++ b/src/core/file_sys/archive_savedatacheck.cpp
@@ -48,11 +48,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(co
48 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 48 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
49} 49}
50 50
51ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path) { 51ResultCode ArchiveFactory_SaveDataCheck::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
52 LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive."); 52 LOG_ERROR(Service_FS, "Attempted to format a SaveDataCheck archive.");
53 // TODO: Verify error code 53 // TODO: Verify error code
54 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, 54 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS,
55 ErrorSummary::NotSupported, ErrorLevel::Permanent); 55 ErrorSummary::NotSupported, ErrorLevel::Permanent);
56} 56}
57 57
58ResultVal<ArchiveFormatInfo> ArchiveFactory_SaveDataCheck::GetFormatInfo(const Path& path) const {
59 // TODO(Subv): Implement
60 LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
61 return ResultCode(-1);
62}
63
58} // namespace FileSys 64} // namespace FileSys
diff --git a/src/core/file_sys/archive_savedatacheck.h b/src/core/file_sys/archive_savedatacheck.h
index b14aefe8b..ea2624d64 100644
--- a/src/core/file_sys/archive_savedatacheck.h
+++ b/src/core/file_sys/archive_savedatacheck.h
@@ -23,7 +23,8 @@ public:
23 std::string GetName() const override { return "SaveDataCheck"; } 23 std::string GetName() const override { return "SaveDataCheck"; }
24 24
25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
26 ResultCode Format(const Path& path) override; 26 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
27 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
27 28
28private: 29private:
29 std::string mount_point; 30 std::string mount_point;
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 5c825f429..657221cbf 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -40,9 +40,14 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SDMC::Open(const Path&
40 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 40 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
41} 41}
42 42
43ResultCode ArchiveFactory_SDMC::Format(const Path& path) { 43ResultCode ArchiveFactory_SDMC::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
44 // This is kind of an undesirable operation, so let's just ignore it. :) 44 // This is kind of an undesirable operation, so let's just ignore it. :)
45 return RESULT_SUCCESS; 45 return RESULT_SUCCESS;
46} 46}
47 47
48ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path) const {
49 // TODO(Subv): Implement
50 LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
51 return ResultCode(-1);
52}
48} // namespace FileSys 53} // namespace FileSys
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 10b273bdb..35c0f3725 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -29,7 +29,8 @@ public:
29 std::string GetName() const override { return "SDMC"; } 29 std::string GetName() const override { return "SDMC"; }
30 30
31 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 31 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
32 ResultCode Format(const Path& path) override; 32 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
33 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
33 34
34private: 35private:
35 std::string sdmc_directory; 36 std::string sdmc_directory;
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
index 896f89529..e1780de2f 100644
--- a/src/core/file_sys/archive_systemsavedata.cpp
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -63,11 +63,17 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SystemSaveData::Open(c
63 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 63 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
64} 64}
65 65
66ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path) { 66ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) {
67 std::string fullpath = GetSystemSaveDataPath(base_path, path); 67 std::string fullpath = GetSystemSaveDataPath(base_path, path);
68 FileUtil::DeleteDirRecursively(fullpath); 68 FileUtil::DeleteDirRecursively(fullpath);
69 FileUtil::CreateFullPath(fullpath); 69 FileUtil::CreateFullPath(fullpath);
70 return RESULT_SUCCESS; 70 return RESULT_SUCCESS;
71} 71}
72 72
73ResultVal<ArchiveFormatInfo> ArchiveFactory_SystemSaveData::GetFormatInfo(const Path& path) const {
74 // TODO(Subv): Implement
75 LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str());
76 return ResultCode(-1);
77}
78
73} // namespace FileSys 79} // namespace FileSys
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
index afc689848..2bc13d4ee 100644
--- a/src/core/file_sys/archive_systemsavedata.h
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -23,7 +23,8 @@ public:
23 ArchiveFactory_SystemSaveData(const std::string& mount_point); 23 ArchiveFactory_SystemSaveData(const std::string& mount_point);
24 24
25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 25 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
26 ResultCode Format(const Path& path) override; 26 ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
27 ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override;
27 28
28 std::string GetName() const override { return "SystemSaveData"; } 29 std::string GetName() const override { return "SystemSaveData"; }
29 30
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
index a51416774..8e4ea01c5 100644
--- a/src/core/file_sys/disk_archive.cpp
+++ b/src/core/file_sys/disk_archive.cpp
@@ -17,16 +17,28 @@
17 17
18namespace FileSys { 18namespace FileSys {
19 19
20std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const { 20ResultVal<std::unique_ptr<FileBackend>> DiskArchive::OpenFile(const Path& path, const Mode mode) const {
21 LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); 21 LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
22 auto file = Common::make_unique<DiskFile>(*this, path, mode); 22 auto file = Common::make_unique<DiskFile>(*this, path, mode);
23 if (!file->Open()) 23 ResultCode result = file->Open();
24 return nullptr; 24 if (result.IsError())
25 return std::move(file); 25 return result;
26 return MakeResult<std::unique_ptr<FileBackend>>(std::move(file));
26} 27}
27 28
28bool DiskArchive::DeleteFile(const Path& path) const { 29ResultCode DiskArchive::DeleteFile(const Path& path) const {
29 return FileUtil::Delete(mount_point + path.AsString()); 30 std::string file_path = mount_point + path.AsString();
31
32 if (FileUtil::IsDirectory(file_path))
33 return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
34
35 if (!FileUtil::Exists(file_path))
36 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status);
37
38 if (FileUtil::Delete(file_path))
39 return RESULT_SUCCESS;
40
41 return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
30} 42}
31 43
32bool DiskArchive::RenameFile(const Path& src_path, const Path& dest_path) const { 44bool DiskArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
@@ -37,11 +49,14 @@ bool DiskArchive::DeleteDirectory(const Path& path) const {
37 return FileUtil::DeleteDir(mount_point + path.AsString()); 49 return FileUtil::DeleteDir(mount_point + path.AsString());
38} 50}
39 51
40ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u32 size) const { 52ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u64 size) const {
41 std::string full_path = mount_point + path.AsString(); 53 std::string full_path = mount_point + path.AsString();
42 54
55 if (FileUtil::IsDirectory(full_path))
56 return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
57
43 if (FileUtil::Exists(full_path)) 58 if (FileUtil::Exists(full_path))
44 return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::FS, ErrorSummary::NothingHappened, ErrorLevel::Info); 59 return ResultCode(ErrorDescription::FS_AlreadyExists, ErrorModule::FS, ErrorSummary::NothingHappened, ErrorLevel::Status);
45 60
46 if (size == 0) { 61 if (size == 0) {
47 FileUtil::CreateEmptyFile(full_path); 62 FileUtil::CreateEmptyFile(full_path);
@@ -89,38 +104,57 @@ DiskFile::DiskFile(const DiskArchive& archive, const Path& path, const Mode mode
89 this->mode.hex = mode.hex; 104 this->mode.hex = mode.hex;
90} 105}
91 106
92bool DiskFile::Open() { 107ResultCode DiskFile::Open() {
93 if (!mode.create_flag && !FileUtil::Exists(path)) { 108 if (FileUtil::IsDirectory(path))
94 LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", path.c_str()); 109 return ResultCode(ErrorDescription::FS_NotAFile, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
95 return false; 110
111 // Specifying only the Create flag is invalid
112 if (mode.create_flag && !mode.read_flag && !mode.write_flag) {
113 return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
114 }
115
116 if (!FileUtil::Exists(path)) {
117 if (!mode.create_flag) {
118 LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", path.c_str());
119 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status);
120 } else {
121 // Create the file
122 FileUtil::CreateEmptyFile(path);
123 }
96 } 124 }
97 125
98 std::string mode_string; 126 std::string mode_string = "";
99 if (mode.create_flag) 127 if (mode.write_flag)
100 mode_string = "w+"; 128 mode_string += "r+"; // Files opened with Write access can be read from
101 else if (mode.write_flag)
102 mode_string = "r+"; // Files opened with Write access can be read from
103 else if (mode.read_flag) 129 else if (mode.read_flag)
104 mode_string = "r"; 130 mode_string += "r";
105 131
106 // Open the file in binary mode, to avoid problems with CR/LF on Windows systems 132 // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
107 mode_string += "b"; 133 mode_string += "b";
108 134
109 file = Common::make_unique<FileUtil::IOFile>(path, mode_string.c_str()); 135 file = Common::make_unique<FileUtil::IOFile>(path, mode_string.c_str());
110 return file->IsOpen(); 136 if (file->IsOpen())
137 return RESULT_SUCCESS;
138 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Status);
111} 139}
112 140
113size_t DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const { 141ResultVal<size_t> DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const {
142 if (!mode.read_flag && !mode.write_flag)
143 return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
144
114 file->Seek(offset, SEEK_SET); 145 file->Seek(offset, SEEK_SET);
115 return file->ReadBytes(buffer, length); 146 return MakeResult<size_t>(file->ReadBytes(buffer, length));
116} 147}
117 148
118size_t DiskFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const { 149ResultVal<size_t> DiskFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
150 if (!mode.write_flag)
151 return ResultCode(ErrorDescription::FS_InvalidOpenFlags, ErrorModule::FS, ErrorSummary::Canceled, ErrorLevel::Status);
152
119 file->Seek(offset, SEEK_SET); 153 file->Seek(offset, SEEK_SET);
120 size_t written = file->WriteBytes(buffer, length); 154 size_t written = file->WriteBytes(buffer, length);
121 if (flush) 155 if (flush)
122 file->Flush(); 156 file->Flush();
123 return written; 157 return MakeResult<size_t>(written);
124} 158}
125 159
126u64 DiskFile::GetSize() const { 160u64 DiskFile::GetSize() const {
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
index ef9a98057..b4cc2f702 100644
--- a/src/core/file_sys/disk_archive.h
+++ b/src/core/file_sys/disk_archive.h
@@ -33,11 +33,11 @@ public:
33 33
34 virtual std::string GetName() const override { return "DiskArchive: " + mount_point; } 34 virtual std::string GetName() const override { return "DiskArchive: " + mount_point; }
35 35
36 std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; 36 ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode mode) const override;
37 bool DeleteFile(const Path& path) const override; 37 ResultCode DeleteFile(const Path& path) const override;
38 bool RenameFile(const Path& src_path, const Path& dest_path) const override; 38 bool RenameFile(const Path& src_path, const Path& dest_path) const override;
39 bool DeleteDirectory(const Path& path) const override; 39 bool DeleteDirectory(const Path& path) const override;
40 ResultCode CreateFile(const Path& path, u32 size) const override; 40 ResultCode CreateFile(const Path& path, u64 size) const override;
41 bool CreateDirectory(const Path& path) const override; 41 bool CreateDirectory(const Path& path) const override;
42 bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; 42 bool RenameDirectory(const Path& src_path, const Path& dest_path) const override;
43 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; 43 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
@@ -54,9 +54,9 @@ class DiskFile : public FileBackend {
54public: 54public:
55 DiskFile(const DiskArchive& archive, const Path& path, const Mode mode); 55 DiskFile(const DiskArchive& archive, const Path& path, const Mode mode);
56 56
57 bool Open() override; 57 ResultCode Open() override;
58 size_t Read(u64 offset, size_t length, u8* buffer) const override; 58 ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override;
59 size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; 59 ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
60 u64 GetSize() const override; 60 u64 GetSize() const override;
61 bool SetSize(u64 size) const override; 61 bool SetSize(u64 size) const override;
62 bool Close() const override; 62 bool Close() const override;
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index df7165df3..9137bbbad 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -7,6 +7,7 @@
7#include <cstddef> 7#include <cstddef>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/result.h"
10 11
11//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
12// FileSys namespace 13// FileSys namespace
@@ -20,18 +21,18 @@ public:
20 21
21 /** 22 /**
22 * Open the file 23 * Open the file
23 * @return true if the file opened correctly 24 * @return Result of the file operation
24 */ 25 */
25 virtual bool Open() = 0; 26 virtual ResultCode Open() = 0;
26 27
27 /** 28 /**
28 * Read data from the file 29 * Read data from the file
29 * @param offset Offset in bytes to start reading data from 30 * @param offset Offset in bytes to start reading data from
30 * @param length Length in bytes of data to read from file 31 * @param length Length in bytes of data to read from file
31 * @param buffer Buffer to read data into 32 * @param buffer Buffer to read data into
32 * @return Number of bytes read 33 * @return Number of bytes read, or error code
33 */ 34 */
34 virtual size_t Read(u64 offset, size_t length, u8* buffer) const = 0; 35 virtual ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const = 0;
35 36
36 /** 37 /**
37 * Write data to the file 38 * Write data to the file
@@ -39,9 +40,9 @@ public:
39 * @param length Length in bytes of data to write to file 40 * @param length Length in bytes of data to write to file
40 * @param flush The flush parameters (0 == do not flush) 41 * @param flush The flush parameters (0 == do not flush)
41 * @param buffer Buffer to read data from 42 * @param buffer Buffer to read data from
42 * @return Number of bytes written 43 * @return Number of bytes written, or error code
43 */ 44 */
44 virtual size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const = 0; 45 virtual ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const = 0;
45 46
46 /** 47 /**
47 * Get the size of the file in bytes 48 * Get the size of the file in bytes
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp
index 2efc31a8c..a8e9a72ef 100644
--- a/src/core/file_sys/ivfc_archive.cpp
+++ b/src/core/file_sys/ivfc_archive.cpp
@@ -20,13 +20,15 @@ std::string IVFCArchive::GetName() const {
20 return "IVFC"; 20 return "IVFC";
21} 21}
22 22
23std::unique_ptr<FileBackend> IVFCArchive::OpenFile(const Path& path, const Mode mode) const { 23ResultVal<std::unique_ptr<FileBackend>> IVFCArchive::OpenFile(const Path& path, const Mode mode) const {
24 return Common::make_unique<IVFCFile>(romfs_file, data_offset, data_size); 24 return MakeResult<std::unique_ptr<FileBackend>>(Common::make_unique<IVFCFile>(romfs_file, data_offset, data_size));
25} 25}
26 26
27bool IVFCArchive::DeleteFile(const Path& path) const { 27ResultCode IVFCArchive::DeleteFile(const Path& path) const {
28 LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive (%s).", GetName().c_str()); 28 LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive (%s).", GetName().c_str());
29 return false; 29 // TODO(Subv): Verify error code
30 return ResultCode(ErrorDescription::NoData, ErrorModule::FS,
31 ErrorSummary::Canceled, ErrorLevel::Status);
30} 32}
31 33
32bool IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const { 34bool IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
@@ -39,7 +41,7 @@ bool IVFCArchive::DeleteDirectory(const Path& path) const {
39 return false; 41 return false;
40} 42}
41 43
42ResultCode IVFCArchive::CreateFile(const Path& path, u32 size) const { 44ResultCode IVFCArchive::CreateFile(const Path& path, u64 size) const {
43 LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive (%s).", GetName().c_str()); 45 LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive (%s).", GetName().c_str());
44 // TODO: Verify error code 46 // TODO: Verify error code
45 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, ErrorLevel::Permanent); 47 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, ErrorLevel::Permanent);
@@ -66,17 +68,18 @@ u64 IVFCArchive::GetFreeBytes() const {
66 68
67//////////////////////////////////////////////////////////////////////////////////////////////////// 69////////////////////////////////////////////////////////////////////////////////////////////////////
68 70
69size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const { 71ResultVal<size_t> IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const {
70 LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); 72 LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length);
71 romfs_file->Seek(data_offset + offset, SEEK_SET); 73 romfs_file->Seek(data_offset + offset, SEEK_SET);
72 size_t read_length = (size_t)std::min((u64)length, data_size - offset); 74 size_t read_length = (size_t)std::min((u64)length, data_size - offset);
73 75
74 return romfs_file->ReadBytes(buffer, read_length); 76 return MakeResult<size_t>(romfs_file->ReadBytes(buffer, read_length));
75} 77}
76 78
77size_t IVFCFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const { 79ResultVal<size_t> IVFCFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
78 LOG_ERROR(Service_FS, "Attempted to write to IVFC file"); 80 LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
79 return 0; 81 // TODO(Subv): Find error code
82 return MakeResult<size_t>(0);
80} 83}
81 84
82u64 IVFCFile::GetSize() const { 85u64 IVFCFile::GetSize() const {
diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h
index f3fd82de4..19d32dcca 100644
--- a/src/core/file_sys/ivfc_archive.h
+++ b/src/core/file_sys/ivfc_archive.h
@@ -34,11 +34,11 @@ public:
34 34
35 std::string GetName() const override; 35 std::string GetName() const override;
36 36
37 std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override; 37 ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode mode) const override;
38 bool DeleteFile(const Path& path) const override; 38 ResultCode DeleteFile(const Path& path) const override;
39 bool RenameFile(const Path& src_path, const Path& dest_path) const override; 39 bool RenameFile(const Path& src_path, const Path& dest_path) const override;
40 bool DeleteDirectory(const Path& path) const override; 40 bool DeleteDirectory(const Path& path) const override;
41 ResultCode CreateFile(const Path& path, u32 size) const override; 41 ResultCode CreateFile(const Path& path, u64 size) const override;
42 bool CreateDirectory(const Path& path) const override; 42 bool CreateDirectory(const Path& path) const override;
43 bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; 43 bool RenameDirectory(const Path& src_path, const Path& dest_path) const override;
44 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; 44 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
@@ -55,9 +55,9 @@ public:
55 IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size) 55 IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
56 : romfs_file(file), data_offset(offset), data_size(size) {} 56 : romfs_file(file), data_offset(offset), data_size(size) {}
57 57
58 bool Open() override { return true; } 58 ResultCode Open() override { return RESULT_SUCCESS; }
59 size_t Read(u64 offset, size_t length, u8* buffer) const override; 59 ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override;
60 size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; 60 ResultVal<size_t> Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
61 u64 GetSize() const override; 61 u64 GetSize() const override;
62 bool SetSize(u64 size) const override; 62 bool SetSize(u64 size) const override;
63 bool Close() const override { return false; } 63 bool Close() const override { return false; }
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h
index aff705a32..4f21da23b 100644
--- a/src/core/gdbstub/gdbstub.h
+++ b/src/core/gdbstub/gdbstub.h
@@ -7,6 +7,8 @@
7#pragma once 7#pragma once
8#include <atomic> 8#include <atomic>
9 9
10#include "common/common_types.h"
11
10namespace GDBStub { 12namespace GDBStub {
11 13
12/// Breakpoint Method 14/// Breakpoint Method
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index adaffcafe..6ddaf970e 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -16,23 +16,23 @@
16 16
17namespace IPC { 17namespace IPC {
18 18
19inline u32 MakeHeader(u16 command_id, unsigned int regular_params, unsigned int translate_params) { 19constexpr u32 MakeHeader(u16 command_id, unsigned int regular_params, unsigned int translate_params) {
20 return ((u32)command_id << 16) | (((u32)regular_params & 0x3F) << 6) | (((u32)translate_params & 0x3F) << 0); 20 return ((u32)command_id << 16) | (((u32)regular_params & 0x3F) << 6) | (((u32)translate_params & 0x3F) << 0);
21} 21}
22 22
23inline u32 MoveHandleDesc(unsigned int num_handles = 1) { 23constexpr u32 MoveHandleDesc(unsigned int num_handles = 1) {
24 return 0x0 | ((num_handles - 1) << 26); 24 return 0x0 | ((num_handles - 1) << 26);
25} 25}
26 26
27inline u32 CopyHandleDesc(unsigned int num_handles = 1) { 27constexpr u32 CopyHandleDesc(unsigned int num_handles = 1) {
28 return 0x10 | ((num_handles - 1) << 26); 28 return 0x10 | ((num_handles - 1) << 26);
29} 29}
30 30
31inline u32 CallingPidDesc() { 31constexpr u32 CallingPidDesc() {
32 return 0x20; 32 return 0x20;
33} 33}
34 34
35inline u32 StaticBufferDesc(u32 size, unsigned int buffer_id) { 35constexpr u32 StaticBufferDesc(u32 size, unsigned int buffer_id) {
36 return 0x2 | (size << 14) | ((buffer_id & 0xF) << 10); 36 return 0x2 | (size << 14) | ((buffer_id & 0xF) << 10);
37} 37}
38 38
@@ -42,7 +42,7 @@ enum MappedBufferPermissions {
42 RW = R | W, 42 RW = R | W,
43}; 43};
44 44
45inline u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) { 45constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) {
46 return 0x8 | (size << 4) | (u32)perms; 46 return 0x8 | (size << 4) | (u32)perms;
47} 47}
48 48
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 69613fbbb..0cb76ba1c 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -19,8 +19,12 @@
19enum class ErrorDescription : u32 { 19enum class ErrorDescription : u32 {
20 Success = 0, 20 Success = 0,
21 WrongAddress = 53, 21 WrongAddress = 53,
22 FS_NotFound = 100, 22 FS_NotFound = 120,
23 FS_AlreadyExists = 190,
24 FS_InvalidOpenFlags = 230,
25 FS_NotAFile = 250,
23 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive 26 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
27 FS_InvalidPath = 702,
24 InvalidSection = 1000, 28 InvalidSection = 1000,
25 TooLarge = 1001, 29 TooLarge = 1001,
26 NotAuthorized = 1002, 30 NotAuthorized = 1002,
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 4c82a58e4..525432957 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -310,7 +310,8 @@ ResultCode UpdateConfigNANDSavegame() {
310 310
311ResultCode FormatConfig() { 311ResultCode FormatConfig() {
312 ResultCode res = DeleteConfigNANDSaveFile(); 312 ResultCode res = DeleteConfigNANDSaveFile();
313 if (!res.IsSuccess()) 313 // The delete command fails if the file doesn't exist, so we have to check that too
314 if (!res.IsSuccess() && res.description != ErrorDescription::FS_NotFound)
314 return res; 315 return res;
315 // Delete the old data 316 // Delete the old data
316 cfg_config_file_buffer.fill(0); 317 cfg_config_file_buffer.fill(0);
@@ -407,7 +408,7 @@ void Init() {
407 // If the archive didn't exist, create the files inside 408 // If the archive didn't exist, create the files inside
408 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { 409 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
409 // Format the archive to create the directories 410 // Format the archive to create the directories
410 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); 411 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, FileSys::ArchiveFormatInfo(), archive_path);
411 412
412 // Open it again to get a valid archive now that the folder exists 413 // Open it again to get a valid archive now that the folder exists
413 archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); 414 archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path);
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index d64b3656a..590697e76 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -103,7 +103,18 @@ ResultVal<bool> File::SyncRequest() {
103 u32 address = cmd_buff[5]; 103 u32 address = cmd_buff[5];
104 LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x", 104 LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x",
105 GetTypeName().c_str(), GetName().c_str(), offset, length, address); 105 GetTypeName().c_str(), GetName().c_str(), offset, length, address);
106 cmd_buff[2] = static_cast<u32>(backend->Read(offset, length, Memory::GetPointer(address))); 106
107 if (offset + length > backend->GetSize()) {
108 LOG_ERROR(Service_FS, "Reading from out of bounds offset=0x%llX length=0x%08X file_size=0x%llX",
109 offset, length, backend->GetSize());
110 }
111
112 ResultVal<size_t> read = backend->Read(offset, length, Memory::GetPointer(address));
113 if (read.Failed()) {
114 cmd_buff[1] = read.Code().raw;
115 return read.Code();
116 }
117 cmd_buff[2] = static_cast<u32>(*read);
107 break; 118 break;
108 } 119 }
109 120
@@ -116,7 +127,13 @@ ResultVal<bool> File::SyncRequest() {
116 u32 address = cmd_buff[6]; 127 u32 address = cmd_buff[6];
117 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", 128 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
118 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); 129 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
119 cmd_buff[2] = static_cast<u32>(backend->Write(offset, length, flush != 0, Memory::GetPointer(address))); 130
131 ResultVal<size_t> written = backend->Write(offset, length, flush != 0, Memory::GetPointer(address));
132 if (written.Failed()) {
133 cmd_buff[1] = written.Code().raw;
134 return written.Code();
135 }
136 cmd_buff[2] = static_cast<u32>(*written);
120 break; 137 break;
121 } 138 }
122 139
@@ -294,13 +311,11 @@ ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_han
294 if (archive == nullptr) 311 if (archive == nullptr)
295 return ERR_INVALID_HANDLE; 312 return ERR_INVALID_HANDLE;
296 313
297 std::unique_ptr<FileSys::FileBackend> backend = archive->OpenFile(path, mode); 314 auto backend = archive->OpenFile(path, mode);
298 if (backend == nullptr) { 315 if (backend.Failed())
299 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, 316 return backend.Code();
300 ErrorSummary::NotFound, ErrorLevel::Status);
301 }
302 317
303 auto file = Kernel::SharedPtr<File>(new File(std::move(backend), path)); 318 auto file = Kernel::SharedPtr<File>(new File(backend.MoveFrom(), path));
304 return MakeResult<Kernel::SharedPtr<File>>(std::move(file)); 319 return MakeResult<Kernel::SharedPtr<File>>(std::move(file));
305} 320}
306 321
@@ -309,10 +324,7 @@ ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Pa
309 if (archive == nullptr) 324 if (archive == nullptr)
310 return ERR_INVALID_HANDLE; 325 return ERR_INVALID_HANDLE;
311 326
312 if (archive->DeleteFile(path)) 327 return archive->DeleteFile(path);
313 return RESULT_SUCCESS;
314 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
315 ErrorSummary::Canceled, ErrorLevel::Status);
316} 328}
317 329
318ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, 330ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
@@ -347,7 +359,7 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
347 ErrorSummary::Canceled, ErrorLevel::Status); 359 ErrorSummary::Canceled, ErrorLevel::Status);
348} 360}
349 361
350ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size) { 362ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u64 file_size) {
351 ArchiveBackend* archive = GetArchive(archive_handle); 363 ArchiveBackend* archive = GetArchive(archive_handle);
352 if (archive == nullptr) 364 if (archive == nullptr)
353 return ERR_INVALID_HANDLE; 365 return ERR_INVALID_HANDLE;
@@ -395,7 +407,7 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a
395 407
396 std::unique_ptr<FileSys::DirectoryBackend> backend = archive->OpenDirectory(path); 408 std::unique_ptr<FileSys::DirectoryBackend> backend = archive->OpenDirectory(path);
397 if (backend == nullptr) { 409 if (backend == nullptr) {
398 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, 410 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS,
399 ErrorSummary::NotFound, ErrorLevel::Permanent); 411 ErrorSummary::NotFound, ErrorLevel::Permanent);
400 } 412 }
401 413
@@ -410,49 +422,45 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) {
410 return MakeResult<u64>(archive->GetFreeBytes()); 422 return MakeResult<u64>(archive->GetFreeBytes());
411} 423}
412 424
413ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { 425ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path) {
414 auto archive_itr = id_code_map.find(id_code); 426 auto archive_itr = id_code_map.find(id_code);
415 if (archive_itr == id_code_map.end()) { 427 if (archive_itr == id_code_map.end()) {
416 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error 428 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
417 } 429 }
418 430
419 return archive_itr->second->Format(path); 431 return archive_itr->second->Format(path, format_info);
432}
433
434ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path) {
435 auto archive = id_code_map.find(id_code);
436 if (archive == id_code_map.end()) {
437 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
438 }
439
440 return archive->second->GetFormatInfo(archive_path);
420} 441}
421 442
422ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size) { 443ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info) {
423 // Construct the binary path to the archive first 444 // Construct the binary path to the archive first
424 FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); 445 FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
425 446
426 std::string media_type_directory; 447 auto archive = id_code_map.find(media_type == MediaType::NAND ? ArchiveIdCode::SharedExtSaveData : ArchiveIdCode::ExtSaveData);
427 if (media_type == MediaType::NAND) { 448
428 media_type_directory = FileUtil::GetUserPath(D_NAND_IDX); 449 if (archive == id_code_map.end()) {
429 } else if (media_type == MediaType::SDMC) { 450 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
430 media_type_directory = FileUtil::GetUserPath(D_SDMC_IDX);
431 } else {
432 LOG_ERROR(Service_FS, "Unsupported media type %u", media_type);
433 return ResultCode(-1); // TODO(Subv): Find the right error code
434 } 451 }
435 452
436 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); 453 auto ext_savedata = static_cast<FileSys::ArchiveFactory_ExtSaveData*>(archive->second.get());
437 std::string game_path = FileSys::GetExtSaveDataPath(base_path, path); 454
438 // These two folders are always created with the ExtSaveData 455 ResultCode result = ext_savedata->Format(path, format_info);
439 std::string user_path = game_path + "user/"; 456 if (result.IsError())
440 std::string boss_path = game_path + "boss/"; 457 return result;
441 if (!FileUtil::CreateFullPath(user_path))
442 return ResultCode(-1); // TODO(Subv): Find the right error code
443 if (!FileUtil::CreateFullPath(boss_path))
444 return ResultCode(-1); // TODO(Subv): Find the right error code
445 458
446 u8* smdh_icon = Memory::GetPointer(icon_buffer); 459 u8* smdh_icon = Memory::GetPointer(icon_buffer);
447 if (!smdh_icon) 460 if (!smdh_icon)
448 return ResultCode(-1); // TODO(Subv): Find the right error code 461 return ResultCode(-1); // TODO(Subv): Find the right error code
449 462
450 // Create the icon 463 ext_savedata->WriteIcon(path, smdh_icon, icon_size);
451 FileUtil::IOFile icon_file(game_path + "icon", "wb+");
452 if (!icon_file.IsGood())
453 return ResultCode(-1); // TODO(Subv): Find the right error code
454
455 icon_file.WriteBytes(smdh_icon, icon_size);
456 return RESULT_SUCCESS; 464 return RESULT_SUCCESS;
457} 465}
458 466
@@ -473,7 +481,7 @@ ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) {
473 // Delete all directories (/user, /boss) and the icon file. 481 // Delete all directories (/user, /boss) and the icon file.
474 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); 482 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
475 std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); 483 std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path);
476 if (!FileUtil::DeleteDirRecursively(extsavedata_path)) 484 if (FileUtil::Exists(extsavedata_path) && !FileUtil::DeleteDirRecursively(extsavedata_path))
477 return ResultCode(-1); // TODO(Subv): Find the right error code 485 return ResultCode(-1); // TODO(Subv): Find the right error code
478 return RESULT_SUCCESS; 486 return RESULT_SUCCESS;
479} 487}
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 952deb4d4..006606740 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -136,7 +136,7 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
136 * @param file_size The size of the new file, filled with zeroes 136 * @param file_size The size of the new file, filled with zeroes
137 * @return File creation result code 137 * @return File creation result code
138 */ 138 */
139ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u32 file_size); 139ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u64 file_size);
140 140
141/** 141/**
142 * Create a Directory from an Archive 142 * Create a Directory from an Archive
@@ -177,10 +177,20 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle);
177 * Erases the contents of the physical folder that contains the archive 177 * Erases the contents of the physical folder that contains the archive
178 * identified by the specified id code and path 178 * identified by the specified id code and path
179 * @param id_code The id of the archive to format 179 * @param id_code The id of the archive to format
180 * @param format_info Format information about the new archive
180 * @param path The path to the archive, if relevant. 181 * @param path The path to the archive, if relevant.
181 * @return ResultCode 0 on success or the corresponding code on error 182 * @return ResultCode 0 on success or the corresponding code on error
182 */ 183 */
183ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = FileSys::Path()); 184ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path = FileSys::Path());
185
186/**
187 * Retrieves the format info about the archive of the specified type and path.
188 * The format info is supplied by the client code when creating archives.
189 * @param id_code The id of the archive
190 * @param archive_path The path of the archive, if relevant
191 * @return The format info of the archive, or the corresponding error code if failed.
192 */
193ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path);
184 194
185/** 195/**
186 * Creates a blank SharedExtSaveData archive for the specified extdata ID 196 * Creates a blank SharedExtSaveData archive for the specified extdata ID
@@ -189,9 +199,10 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = File
189 * @param low The low word of the extdata id to create 199 * @param low The low word of the extdata id to create
190 * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData 200 * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData
191 * @param icon_size Size of the SMDH icon 201 * @param icon_size Size of the SMDH icon
202 * @param format_info Format information about the new archive
192 * @return ResultCode 0 on success or the corresponding code on error 203 * @return ResultCode 0 on success or the corresponding code on error
193 */ 204 */
194ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size); 205ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info);
195 206
196/** 207/**
197 * Deletes the SharedExtSaveData archive for the specified extdata ID 208 * Deletes the SharedExtSaveData archive for the specified extdata ID
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 632620a56..3ec7ceb30 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -234,7 +234,7 @@ static void DeleteDirectory(Service::Interface* self) {
234 * 3 : Archive handle upper word 234 * 3 : Archive handle upper word
235 * 4 : File path string type 235 * 4 : File path string type
236 * 5 : File path string size 236 * 5 : File path string size
237 * 7 : File size (filled with zeroes) 237 * 7-8 : File size
238 * 10: File path string data 238 * 10: File path string data
239 * Outputs: 239 * Outputs:
240 * 1 : Result of function, 0 on success, otherwise error code 240 * 1 : Result of function, 0 on success, otherwise error code
@@ -245,12 +245,12 @@ static void CreateFile(Service::Interface* self) {
245 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); 245 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
246 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); 246 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
247 u32 filename_size = cmd_buff[5]; 247 u32 filename_size = cmd_buff[5];
248 u32 file_size = cmd_buff[7]; 248 u64 file_size = ((u64)cmd_buff[8] << 32) | cmd_buff[7];
249 u32 filename_ptr = cmd_buff[10]; 249 u32 filename_ptr = cmd_buff[10];
250 250
251 FileSys::Path file_path(filename_type, filename_size, filename_ptr); 251 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
252 252
253 LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", filename_type, filename_size, file_path.DebugStr().c_str()); 253 LOG_DEBUG(Service_FS, "type=%d size=%llu data=%s", filename_type, filename_size, file_path.DebugStr().c_str());
254 254
255 cmd_buff[1] = CreateFileInArchive(archive_handle, file_path, file_size).raw; 255 cmd_buff[1] = CreateFileInArchive(archive_handle, file_path, file_size).raw;
256} 256}
@@ -443,17 +443,22 @@ static void IsSdmcWriteable(Service::Interface* self) {
443 * Inputs: 443 * Inputs:
444 * 0 : 0x084C0242 444 * 0 : 0x084C0242
445 * 1 : Archive ID 445 * 1 : Archive ID
446 * 2 : Archive low path type 446 * 2 : Archive path type
447 * 3 : Archive low path size 447 * 3 : Archive path size
448 * 10 : (LowPathSize << 14) | 2 448 * 4 : Size in Blocks (1 block = 512 bytes)
449 * 5 : Number of directories
450 * 6 : Number of files
451 * 7 : Directory bucket count
452 * 8 : File bucket count
453 * 9 : Duplicate data
454 * 10 : (PathSize << 14) | 2
449 * 11 : Archive low path 455 * 11 : Archive low path
450 * Outputs: 456 * Outputs:
451 * 1 : Result of function, 0 on success, otherwise error code 457 * 1 : Result of function, 0 on success, otherwise error code
452 */ 458 */
453static void FormatSaveData(Service::Interface* self) { 459static void FormatSaveData(Service::Interface* self) {
454 // TODO(Subv): Find out what the other inputs and outputs of this function are
455 u32* cmd_buff = Kernel::GetCommandBuffer(); 460 u32* cmd_buff = Kernel::GetCommandBuffer();
456 LOG_DEBUG(Service_FS, "(STUBBED)"); 461 LOG_WARNING(Service_FS, "(STUBBED)");
457 462
458 auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]); 463 auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
459 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); 464 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
@@ -464,9 +469,9 @@ static void FormatSaveData(Service::Interface* self) {
464 LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); 469 LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());
465 470
466 if (archive_id != FS::ArchiveIdCode::SaveData) { 471 if (archive_id != FS::ArchiveIdCode::SaveData) {
467 // TODO(Subv): What should happen if somebody attempts to format a different archive? 472 LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", archive_id);
468 LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", cmd_buff[1]); 473 cmd_buff[1] = ResultCode(ErrorDescription::FS_InvalidPath, ErrorModule::FS,
469 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; 474 ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw;
470 return; 475 return;
471 } 476 }
472 477
@@ -477,23 +482,40 @@ static void FormatSaveData(Service::Interface* self) {
477 return; 482 return;
478 } 483 }
479 484
480 cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; 485 FileSys::ArchiveFormatInfo format_info;
486 format_info.duplicate_data = cmd_buff[9] & 0xFF;
487 format_info.number_directories = cmd_buff[5];
488 format_info.number_files = cmd_buff[6];
489 format_info.total_size = cmd_buff[4] * 512;
490
491 cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData, format_info).raw;
481} 492}
482 493
483/** 494/**
484 * FS_User::FormatThisUserSaveData service function 495 * FS_User::FormatThisUserSaveData service function
485 * Inputs: 496 * Inputs:
486 * 0: 0x080F0180 497 * 0: 0x080F0180
498 * 1 : Size in Blocks (1 block = 512 bytes)
499 * 2 : Number of directories
500 * 3 : Number of files
501 * 4 : Directory bucket count
502 * 5 : File bucket count
503 * 6 : Duplicate data
487 * Outputs: 504 * Outputs:
488 * 1 : Result of function, 0 on success, otherwise error code 505 * 1 : Result of function, 0 on success, otherwise error code
489 */ 506 */
490static void FormatThisUserSaveData(Service::Interface* self) { 507static void FormatThisUserSaveData(Service::Interface* self) {
491 u32* cmd_buff = Kernel::GetCommandBuffer(); 508 u32* cmd_buff = Kernel::GetCommandBuffer();
492 LOG_DEBUG(Service_FS, "(STUBBED)");
493 509
494 // TODO(Subv): Find out what the inputs and outputs of this function are 510 FileSys::ArchiveFormatInfo format_info;
511 format_info.duplicate_data = cmd_buff[6] & 0xFF;
512 format_info.number_directories = cmd_buff[2];
513 format_info.number_files = cmd_buff[3];
514 format_info.total_size = cmd_buff[1] * 512;
515
516 cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData, format_info).raw;
495 517
496 cmd_buff[1] = FormatArchive(ArchiveIdCode::SaveData).raw; 518 LOG_TRACE(Service_FS, "called");
497} 519}
498 520
499/** 521/**
@@ -531,10 +553,9 @@ static void GetFreeBytes(Service::Interface* self) {
531 * 2 : Low word of the saveid to create 553 * 2 : Low word of the saveid to create
532 * 3 : High word of the saveid to create 554 * 3 : High word of the saveid to create
533 * 4 : Unknown 555 * 4 : Unknown
534 * 5 : Unknown 556 * 5 : Number of directories
535 * 6 : Unknown 557 * 6 : Number of files
536 * 7 : Unknown 558 * 7-8 : Size limit
537 * 8 : Unknown
538 * 9 : Size of the SMDH icon 559 * 9 : Size of the SMDH icon
539 * 10: (SMDH Size << 4) | 0x0000000A 560 * 10: (SMDH Size << 4) | 0x0000000A
540 * 11: Pointer to the SMDH icon for the new ExtSaveData 561 * 11: Pointer to the SMDH icon for the new ExtSaveData
@@ -556,7 +577,12 @@ static void CreateExtSaveData(Service::Interface* self) {
556 cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size, 577 cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size,
557 cmd_buff[10], icon_buffer); 578 cmd_buff[10], icon_buffer);
558 579
559 cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size).raw; 580 FileSys::ArchiveFormatInfo format_info;
581 format_info.number_directories = cmd_buff[5];
582 format_info.number_files = cmd_buff[6];
583 format_info.duplicate_data = false;
584 format_info.total_size = 0;
585 cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size, format_info).raw;
560} 586}
561 587
562/** 588/**
@@ -707,6 +733,75 @@ static void GetPriority(Service::Interface* self) {
707 LOG_DEBUG(Service_FS, "called priority=0x%X", priority); 733 LOG_DEBUG(Service_FS, "called priority=0x%X", priority);
708} 734}
709 735
736/**
737 * FS_User::GetArchiveResource service function.
738 * Inputs:
739 * 0 : 0x08490040
740 * 1 : Media type
741 * Outputs:
742 * 1 : Result of function, 0 on success, otherwise error code
743 * 2 : Sector byte-size
744 * 3 : Cluster byte-size
745 * 4 : Partition capacity in clusters
746 * 5 : Available free space in clusters
747 */
748static void GetArchiveResource(Service::Interface* self) {
749 u32* cmd_buff = Kernel::GetCommandBuffer();
750
751 LOG_WARNING(Service_FS, "(STUBBED) called Media type=0x%08X", cmd_buff[1]);
752
753 cmd_buff[1] = RESULT_SUCCESS.raw;
754 cmd_buff[2] = 512;
755 cmd_buff[3] = 16384;
756 cmd_buff[4] = 0x80000; // 8GiB capacity
757 cmd_buff[5] = 0x80000; // 8GiB free
758}
759
760/**
761 * FS_User::GetFormatInfo service function.
762 * Inputs:
763 * 0 : 0x084500C2
764 * 1 : Archive ID
765 * 2 : Archive path type
766 * 3 : Archive path size
767 * 4 : (PathSize << 14) | 2
768 * 5 : Archive low path
769 * Outputs:
770 * 0 : 0x08450140
771 * 1 : Result of function, 0 on success, otherwise error code
772 * 2 : Total size
773 * 3 : Number of directories
774 * 4 : Number of files
775 * 5 : Duplicate data
776 */
777static void GetFormatInfo(Service::Interface* self) {
778 u32* cmd_buff = Kernel::GetCommandBuffer();
779
780 auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
781 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
782 u32 archivename_size = cmd_buff[3];
783 u32 archivename_ptr = cmd_buff[5];
784 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
785
786 LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());
787
788 cmd_buff[0] = IPC::MakeHeader(0x0845, 5, 0);
789
790 auto format_info = GetArchiveFormatInfo(archive_id, archive_path);
791
792 if (format_info.Failed()) {
793 LOG_ERROR(Service_FS, "Failed to retrieve the format info");
794 cmd_buff[1] = format_info.Code().raw;
795 return;
796 }
797
798 cmd_buff[1] = RESULT_SUCCESS.raw;
799 cmd_buff[2] = format_info->total_size;
800 cmd_buff[3] = format_info->number_directories;
801 cmd_buff[4] = format_info->number_files;
802 cmd_buff[5] = format_info->duplicate_data;
803}
804
710const Interface::FunctionInfo FunctionTable[] = { 805const Interface::FunctionInfo FunctionTable[] = {
711 {0x000100C6, nullptr, "Dummy1"}, 806 {0x000100C6, nullptr, "Dummy1"},
712 {0x040100C4, nullptr, "Control"}, 807 {0x040100C4, nullptr, "Control"},
@@ -778,11 +873,11 @@ const Interface::FunctionInfo FunctionTable[] = {
778 {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"}, 873 {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
779 {0x08430000, nullptr, "InitializeCtrFileSystem"}, 874 {0x08430000, nullptr, "InitializeCtrFileSystem"},
780 {0x08440000, nullptr, "CreateSeed"}, 875 {0x08440000, nullptr, "CreateSeed"},
781 {0x084500C2, nullptr, "GetFormatInfo"}, 876 {0x084500C2, GetFormatInfo, "GetFormatInfo"},
782 {0x08460102, nullptr, "GetLegacyRomHeader2"}, 877 {0x08460102, nullptr, "GetLegacyRomHeader2"},
783 {0x08470180, nullptr, "FormatCtrCardUserSaveData"}, 878 {0x08470180, nullptr, "FormatCtrCardUserSaveData"},
784 {0x08480042, nullptr, "GetSdmcCtrRootPath"}, 879 {0x08480042, nullptr, "GetSdmcCtrRootPath"},
785 {0x08490040, nullptr, "GetArchiveResource"}, 880 {0x08490040, GetArchiveResource, "GetArchiveResource"},
786 {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, 881 {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
787 {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, 882 {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
788 {0x084C0242, FormatSaveData, "FormatSaveData"}, 883 {0x084C0242, FormatSaveData, "FormatSaveData"},
diff --git a/src/core/hle/service/ndm/ndm.cpp b/src/core/hle/service/ndm/ndm.cpp
new file mode 100644
index 000000000..47076a7b8
--- /dev/null
+++ b/src/core/hle/service/ndm/ndm.cpp
@@ -0,0 +1,47 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6#include "common/logging/log.h"
7#include "core/hle/service/service.h"
8#include "core/hle/service/ndm/ndm.h"
9#include "core/hle/service/ndm/ndm_u.h"
10
11namespace Service {
12namespace NDM {
13
14void SuspendDaemons(Service::Interface* self) {
15 u32* cmd_buff = Kernel::GetCommandBuffer();
16
17 LOG_WARNING(Service_NDM, "(STUBBED) bit_mask=0x%08X ", cmd_buff[1]);
18
19 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
20}
21
22void ResumeDaemons(Service::Interface* self) {
23 u32* cmd_buff = Kernel::GetCommandBuffer();
24
25 LOG_WARNING(Service_NDM, "(STUBBED) bit_mask=0x%08X ", cmd_buff[1]);
26
27 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
28}
29
30void OverrideDefaultDaemons(Service::Interface* self) {
31 u32* cmd_buff = Kernel::GetCommandBuffer();
32
33 LOG_WARNING(Service_NDM, "(STUBBED) bit_mask=0x%08X ", cmd_buff[1]);
34
35 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
36}
37
38void Init() {
39 AddService(new NDM_U_Interface);
40}
41
42void Shutdown() {
43
44}
45
46}// namespace NDM
47}// namespace Service
diff --git a/src/core/hle/service/ndm/ndm.h b/src/core/hle/service/ndm/ndm.h
new file mode 100644
index 000000000..734730f8c
--- /dev/null
+++ b/src/core/hle/service/ndm/ndm.h
@@ -0,0 +1,52 @@
1// Copyright 2016 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 "common/common_types.h"
8
9namespace Service {
10
11class Interface;
12
13namespace NDM {
14
15/**
16 * SuspendDaemons
17 * Inputs:
18 * 0 : Command header (0x00020082)
19 * 1 : Daemon bit mask
20 * Outputs:
21 * 1 : Result, 0 on success, otherwise error code
22 */
23void SuspendDaemons(Service::Interface* self);
24
25/**
26 * ResumeDaemons
27 * Inputs:
28 * 0 : Command header (0x00020082)
29 * 1 : Daemon bit mask
30 * Outputs:
31 * 1 : Result, 0 on success, otherwise error code
32 */
33void ResumeDaemons(Service::Interface* self);
34
35/**
36 * OverrideDefaultDaemons
37 * Inputs:
38 * 0 : Command header (0x00020082)
39 * 1 : Daemon bit mask
40 * Outputs:
41 * 1 : Result, 0 on success, otherwise error code
42 */
43void OverrideDefaultDaemons(Service::Interface* self);
44
45/// Initialize NDM service
46void Init();
47
48/// Shutdown NDM service
49void Shutdown();
50
51}// namespace NDM
52}// namespace Service
diff --git a/src/core/hle/service/ndm_u.cpp b/src/core/hle/service/ndm/ndm_u.cpp
index 8fdf1ef90..bf95cc7aa 100644
--- a/src/core/hle/service/ndm_u.cpp
+++ b/src/core/hle/service/ndm/ndm_u.cpp
@@ -2,12 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/service/ndm_u.h" 5#include "core/hle/service/ndm/ndm.h"
6#include "core/hle/service/ndm/ndm_u.h"
6 7
7//////////////////////////////////////////////////////////////////////////////////////////////////// 8namespace Service {
8// Namespace NDM_U 9namespace NDM {
9
10namespace NDM_U {
11 10
12const Interface::FunctionInfo FunctionTable[] = { 11const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010042, nullptr, "EnterExclusiveState"}, 12 {0x00010042, nullptr, "EnterExclusiveState"},
@@ -15,8 +14,8 @@ const Interface::FunctionInfo FunctionTable[] = {
15 {0x00030000, nullptr, "QueryExclusiveMode"}, 14 {0x00030000, nullptr, "QueryExclusiveMode"},
16 {0x00040002, nullptr, "LockState"}, 15 {0x00040002, nullptr, "LockState"},
17 {0x00050002, nullptr, "UnlockState"}, 16 {0x00050002, nullptr, "UnlockState"},
18 {0x00060040, nullptr, "SuspendDaemons"}, 17 {0x00060040, SuspendDaemons, "SuspendDaemons"},
19 {0x00070040, nullptr, "ResumeDaemons"}, 18 {0x00070040, ResumeDaemons, "ResumeDaemons"},
20 {0x00080040, nullptr, "DisableWifiUsage"}, 19 {0x00080040, nullptr, "DisableWifiUsage"},
21 {0x00090000, nullptr, "EnableWifiUsage"}, 20 {0x00090000, nullptr, "EnableWifiUsage"},
22 {0x000A0000, nullptr, "GetCurrentState"}, 21 {0x000A0000, nullptr, "GetCurrentState"},
@@ -29,17 +28,15 @@ const Interface::FunctionInfo FunctionTable[] = {
29 {0x00110000, nullptr, "GetScanInterval"}, 28 {0x00110000, nullptr, "GetScanInterval"},
30 {0x00120040, nullptr, "SetRetryInterval"}, 29 {0x00120040, nullptr, "SetRetryInterval"},
31 {0x00130000, nullptr, "GetRetryInterval"}, 30 {0x00130000, nullptr, "GetRetryInterval"},
32 {0x00140040, nullptr, "OverrideDefaultDaemons"}, 31 {0x00140040, OverrideDefaultDaemons, "OverrideDefaultDaemons"},
33 {0x00150000, nullptr, "ResetDefaultDaemons"}, 32 {0x00150000, nullptr, "ResetDefaultDaemons"},
34 {0x00160000, nullptr, "GetDefaultDaemons"}, 33 {0x00160000, nullptr, "GetDefaultDaemons"},
35 {0x00170000, nullptr, "ClearHalfAwakeMacFilter"}, 34 {0x00170000, nullptr, "ClearHalfAwakeMacFilter"},
36}; 35};
37 36
38//////////////////////////////////////////////////////////////////////////////////////////////////// 37NDM_U_Interface::NDM_U_Interface() {
39// Interface class
40
41Interface::Interface() {
42 Register(FunctionTable); 38 Register(FunctionTable);
43} 39}
44 40
45} // namespace 41} // namespace NDM
42} // namespace Service
diff --git a/src/core/hle/service/ndm_u.h b/src/core/hle/service/ndm/ndm_u.h
index 51c4b3902..d567abc84 100644
--- a/src/core/hle/service/ndm_u.h
+++ b/src/core/hle/service/ndm/ndm_u.h
@@ -6,20 +6,17 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9//////////////////////////////////////////////////////////////////////////////////////////////////// 9namespace Service {
10// Namespace NDM 10namespace NDM {
11 11
12// No idea what this is 12class NDM_U_Interface : public Service::Interface {
13
14namespace NDM_U {
15
16class Interface : public Service::Interface {
17public: 13public:
18 Interface(); 14 NDM_U_Interface();
19 15
20 std::string GetPortName() const override { 16 std::string GetPortName() const override {
21 return "ndm:u"; 17 return "ndm:u";
22 } 18 }
23}; 19};
24 20
25} // namespace 21} // namespace NDM
22} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
index 6bdee4d9e..94f494690 100644
--- a/src/core/hle/service/ptm/ptm.cpp
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -103,7 +103,7 @@ void Init() {
103 // If the archive didn't exist, create the files inside 103 // If the archive didn't exist, create the files inside
104 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { 104 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
105 // Format the archive to create the directories 105 // Format the archive to create the directories
106 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); 106 Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, FileSys::ArchiveFormatInfo(), archive_path);
107 // Open it again to get a valid archive now that the folder exists 107 // Open it again to get a valid archive now that the folder exists
108 archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); 108 archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
109 ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!"); 109 ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!");
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 0de0b13a3..35b648409 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -16,7 +16,6 @@
16#include "core/hle/service/http_c.h" 16#include "core/hle/service/http_c.h"
17#include "core/hle/service/ldr_ro.h" 17#include "core/hle/service/ldr_ro.h"
18#include "core/hle/service/mic_u.h" 18#include "core/hle/service/mic_u.h"
19#include "core/hle/service/ndm_u.h"
20#include "core/hle/service/ns_s.h" 19#include "core/hle/service/ns_s.h"
21#include "core/hle/service/nwm_uds.h" 20#include "core/hle/service/nwm_uds.h"
22#include "core/hle/service/pm_app.h" 21#include "core/hle/service/pm_app.h"
@@ -35,6 +34,7 @@
35#include "core/hle/service/cfg/cfg.h" 34#include "core/hle/service/cfg/cfg.h"
36#include "core/hle/service/hid/hid.h" 35#include "core/hle/service/hid/hid.h"
37#include "core/hle/service/ir/ir.h" 36#include "core/hle/service/ir/ir.h"
37#include "core/hle/service/ndm/ndm.h"
38#include "core/hle/service/news/news.h" 38#include "core/hle/service/news/news.h"
39#include "core/hle/service/nim/nim.h" 39#include "core/hle/service/nim/nim.h"
40#include "core/hle/service/ptm/ptm.h" 40#include "core/hle/service/ptm/ptm.h"
@@ -114,6 +114,7 @@ void Init() {
114 Service::HID::Init(); 114 Service::HID::Init();
115 Service::IR::Init(); 115 Service::IR::Init();
116 Service::NEWS::Init(); 116 Service::NEWS::Init();
117 Service::NDM::Init();
117 Service::NIM::Init(); 118 Service::NIM::Init();
118 Service::PTM::Init(); 119 Service::PTM::Init();
119 120
@@ -126,7 +127,6 @@ void Init() {
126 AddService(new HTTP_C::Interface); 127 AddService(new HTTP_C::Interface);
127 AddService(new LDR_RO::Interface); 128 AddService(new LDR_RO::Interface);
128 AddService(new MIC_U::Interface); 129 AddService(new MIC_U::Interface);
129 AddService(new NDM_U::Interface);
130 AddService(new NS_S::Interface); 130 AddService(new NS_S::Interface);
131 AddService(new NWM_UDS::Interface); 131 AddService(new NWM_UDS::Interface);
132 AddService(new PM_APP::Interface); 132 AddService(new PM_APP::Interface);
@@ -141,6 +141,7 @@ void Init() {
141void Shutdown() { 141void Shutdown() {
142 142
143 Service::PTM::Shutdown(); 143 Service::PTM::Shutdown();
144 Service::NDM::Shutdown();
144 Service::NIM::Shutdown(); 145 Service::NIM::Shutdown();
145 Service::NEWS::Shutdown(); 146 Service::NEWS::Shutdown();
146 Service::IR::Shutdown(); 147 Service::IR::Shutdown();
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index b52e52d4a..ff0af8f12 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -5,6 +5,7 @@
5#include <algorithm> 5#include <algorithm>
6#include <cstring> 6#include <cstring>
7#include <unordered_map> 7#include <unordered_map>
8#include <vector>
8 9
9#include "common/assert.h" 10#include "common/assert.h"
10#include "common/bit_field.h" 11#include "common/bit_field.h"
@@ -593,17 +594,13 @@ static void Poll(Service::Interface* self) {
593 594
594 // The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different sizes) 595 // The 3ds_pollfd and the pollfd structures may be different (Windows/Linux have different sizes)
595 // so we have to copy the data 596 // so we have to copy the data
596 pollfd* platform_pollfd = new pollfd[nfds]; 597 std::vector<pollfd> platform_pollfd(nfds);
597 for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) 598 std::transform(input_fds, input_fds + nfds, platform_pollfd.begin(), CTRPollFD::ToPlatform);
598 platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]);
599 599
600 int ret = ::poll(platform_pollfd, nfds, timeout); 600 const int ret = ::poll(platform_pollfd.data(), nfds, timeout);
601 601
602 // Now update the output pollfd structure 602 // Now update the output pollfd structure
603 for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) 603 std::transform(platform_pollfd.begin(), platform_pollfd.end(), output_fds, CTRPollFD::FromPlatform);
604 output_fds[current_fds] = CTRPollFD::FromPlatform(platform_pollfd[current_fds]);
605
606 delete[] platform_pollfd;
607 604
608 int result = 0; 605 int result = 0;
609 if (ret == SOCKET_ERROR_VALUE) 606 if (ret == SOCKET_ERROR_VALUE)
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 2e3a9f779..a00adbf53 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -263,17 +263,17 @@ struct Regs {
263 263
264 INSERT_PADDING_WORDS(0x9c3); 264 INSERT_PADDING_WORDS(0x9c3);
265 265
266 static inline size_t NumIds() { 266 static constexpr size_t NumIds() {
267 return sizeof(Regs) / sizeof(u32); 267 return sizeof(Regs) / sizeof(u32);
268 } 268 }
269 269
270 u32& operator [] (int index) const { 270 const u32& operator [] (int index) const {
271 u32* content = (u32*)this; 271 const u32* content = reinterpret_cast<const u32*>(this);
272 return content[index]; 272 return content[index];
273 } 273 }
274 274
275 u32& operator [] (int index) { 275 u32& operator [] (int index) {
276 u32* content = (u32*)this; 276 u32* content = reinterpret_cast<u32*>(this);
277 return content[index]; 277 return content[index];
278 } 278 }
279 279
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index bcce6d8cf..3dd877fbf 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -38,17 +38,17 @@ struct Regs {
38 u32 backlight_bottom; 38 u32 backlight_bottom;
39 INSERT_PADDING_WORDS(0x16F); 39 INSERT_PADDING_WORDS(0x16F);
40 40
41 static inline size_t NumIds() { 41 static constexpr size_t NumIds() {
42 return sizeof(Regs) / sizeof(u32); 42 return sizeof(Regs) / sizeof(u32);
43 } 43 }
44 44
45 u32& operator [] (int index) const { 45 const u32& operator [] (int index) const {
46 u32* content = (u32*)this; 46 const u32* content = reinterpret_cast<const u32*>(this);
47 return content[index]; 47 return content[index];
48 } 48 }
49 49
50 u32& operator [] (int index) { 50 u32& operator [] (int index) {
51 u32* content = (u32*)this; 51 u32* content = reinterpret_cast<u32*>(this);
52 return content[index]; 52 return content[index];
53 } 53 }
54 54
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index a7f2715ba..84a4ce5fc 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -74,7 +74,7 @@ enum class ResultStatus {
74 ErrorEncrypted, 74 ErrorEncrypted,
75}; 75};
76 76
77static inline u32 MakeMagic(char a, char b, char c, char d) { 77constexpr u32 MakeMagic(char a, char b, char c, char d) {
78 return a | b << 8 | c << 16 | d << 24; 78 return a | b << 8 | c << 16 | d << 24;
79} 79}
80 80
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 54721561e..4b59984ad 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -200,7 +200,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
200 for (int loader = 0; loader < 12; ++loader) { 200 for (int loader = 0; loader < 12; ++loader) {
201 const auto& loader_config = attribute_config.attribute_loaders[loader]; 201 const auto& loader_config = attribute_config.attribute_loaders[loader];
202 202
203 u32 load_address = base_address + loader_config.data_offset; 203 u32 offset = 0;
204 204
205 // TODO: What happens if a loader overwrites a previous one's data? 205 // TODO: What happens if a loader overwrites a previous one's data?
206 for (unsigned component = 0; component < loader_config.component_count; ++component) { 206 for (unsigned component = 0; component < loader_config.component_count; ++component) {
@@ -212,17 +212,17 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
212 u32 attribute_index = loader_config.GetComponent(component); 212 u32 attribute_index = loader_config.GetComponent(component);
213 if (attribute_index < 12) { 213 if (attribute_index < 12) {
214 int element_size = attribute_config.GetElementSizeInBytes(attribute_index); 214 int element_size = attribute_config.GetElementSizeInBytes(attribute_index);
215 load_address = Common::AlignUp(load_address, element_size); 215 offset = Common::AlignUp(offset, element_size);
216 vertex_attribute_sources[attribute_index] = load_address; 216 vertex_attribute_sources[attribute_index] = base_address + loader_config.data_offset + offset;
217 vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); 217 vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
218 vertex_attribute_formats[attribute_index] = attribute_config.GetFormat(attribute_index); 218 vertex_attribute_formats[attribute_index] = attribute_config.GetFormat(attribute_index);
219 vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index); 219 vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index);
220 vertex_attribute_element_size[attribute_index] = element_size; 220 vertex_attribute_element_size[attribute_index] = element_size;
221 load_address += attribute_config.GetStride(attribute_index); 221 offset += attribute_config.GetStride(attribute_index);
222 } else if (attribute_index < 16) { 222 } else if (attribute_index < 16) {
223 // Attribute ids 12, 13, 14 and 15 signify 4, 8, 12 and 16-byte paddings, respectively 223 // Attribute ids 12, 13, 14 and 15 signify 4, 8, 12 and 16-byte paddings, respectively
224 load_address = Common::AlignUp(load_address, 4); 224 offset = Common::AlignUp(offset, 4);
225 load_address += (attribute_index - 11) * 4; 225 offset += (attribute_index - 11) * 4;
226 } else { 226 } else {
227 UNREACHABLE(); // This is truly unreachable due to the number of bits for each component 227 UNREACHABLE(); // This is truly unreachable due to the number of bits for each component
228 } 228 }
@@ -234,7 +234,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
234 234
235 const auto& index_info = regs.index_array; 235 const auto& index_info = regs.index_array;
236 const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset); 236 const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
237 const u16* index_address_16 = (u16*)index_address_8; 237 const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
238 bool index_u16 = index_info.format != 0; 238 bool index_u16 = index_info.format != 0;
239 239
240#if PICA_DUMP_GEOMETRY 240#if PICA_DUMP_GEOMETRY
@@ -345,10 +345,11 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
345 : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1); 345 : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1);
346 } 346 }
347 347
348 const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata : 348 const float srcval =
349 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata : 349 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *reinterpret_cast<const s8*>(srcdata) :
350 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *(s16*)srcdata : 350 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *reinterpret_cast<const u8*>(srcdata) :
351 *(float*)srcdata; 351 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *reinterpret_cast<const s16*>(srcdata) :
352 *reinterpret_cast<const float*>(srcdata);
352 353
353 input.attr[i][comp] = float24::FromFloat32(srcval); 354 input.attr[i][comp] = float24::FromFloat32(srcval);
354 LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08x + 0x%04x: %f", 355 LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08x + 0x%04x: %f",
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 271e81ca1..bac6d69c7 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -117,13 +117,13 @@ void GeometryDumper::Dump() {
117void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, const Shader::ShaderSetup& setup, const Regs::VSOutputAttributes* output_attributes) 117void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, const Shader::ShaderSetup& setup, const Regs::VSOutputAttributes* output_attributes)
118{ 118{
119 struct StuffToWrite { 119 struct StuffToWrite {
120 u8* pointer; 120 const u8* pointer;
121 u32 size; 121 u32 size;
122 }; 122 };
123 std::vector<StuffToWrite> writing_queue; 123 std::vector<StuffToWrite> writing_queue;
124 u32 write_offset = 0; 124 u32 write_offset = 0;
125 125
126 auto QueueForWriting = [&writing_queue,&write_offset](u8* pointer, u32 size) { 126 auto QueueForWriting = [&writing_queue,&write_offset](const u8* pointer, u32 size) {
127 writing_queue.push_back({pointer, size}); 127 writing_queue.push_back({pointer, size});
128 u32 old_write_offset = write_offset; 128 u32 old_write_offset = write_offset;
129 write_offset += size; 129 write_offset += size;
@@ -228,27 +228,27 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, c
228 DVLPHeader dvlp{ DVLPHeader::MAGIC_WORD }; 228 DVLPHeader dvlp{ DVLPHeader::MAGIC_WORD };
229 DVLEHeader dvle{ DVLEHeader::MAGIC_WORD }; 229 DVLEHeader dvle{ DVLEHeader::MAGIC_WORD };
230 230
231 QueueForWriting((u8*)&dvlb, sizeof(dvlb)); 231 QueueForWriting(reinterpret_cast<const u8*>(&dvlb), sizeof(dvlb));
232 u32 dvlp_offset = QueueForWriting((u8*)&dvlp, sizeof(dvlp)); 232 u32 dvlp_offset = QueueForWriting(reinterpret_cast<const u8*>(&dvlp), sizeof(dvlp));
233 dvlb.dvle_offset = QueueForWriting((u8*)&dvle, sizeof(dvle)); 233 dvlb.dvle_offset = QueueForWriting(reinterpret_cast<const u8*>(&dvle), sizeof(dvle));
234 234
235 // TODO: Reduce the amount of binary code written to relevant portions 235 // TODO: Reduce the amount of binary code written to relevant portions
236 dvlp.binary_offset = write_offset - dvlp_offset; 236 dvlp.binary_offset = write_offset - dvlp_offset;
237 dvlp.binary_size_words = setup.program_code.size(); 237 dvlp.binary_size_words = setup.program_code.size();
238 QueueForWriting((u8*)setup.program_code.data(), setup.program_code.size() * sizeof(u32)); 238 QueueForWriting(reinterpret_cast<const u8*>(setup.program_code.data()), setup.program_code.size() * sizeof(u32));
239 239
240 dvlp.swizzle_info_offset = write_offset - dvlp_offset; 240 dvlp.swizzle_info_offset = write_offset - dvlp_offset;
241 dvlp.swizzle_info_num_entries = setup.swizzle_data.size(); 241 dvlp.swizzle_info_num_entries = setup.swizzle_data.size();
242 u32 dummy = 0; 242 u32 dummy = 0;
243 for (unsigned int i = 0; i < setup.swizzle_data.size(); ++i) { 243 for (unsigned int i = 0; i < setup.swizzle_data.size(); ++i) {
244 QueueForWriting((u8*)&setup.swizzle_data[i], sizeof(setup.swizzle_data[i])); 244 QueueForWriting(reinterpret_cast<const u8*>(&setup.swizzle_data[i]), sizeof(setup.swizzle_data[i]));
245 QueueForWriting((u8*)&dummy, sizeof(dummy)); 245 QueueForWriting(reinterpret_cast<const u8*>(&dummy), sizeof(dummy));
246 } 246 }
247 247
248 dvle.main_offset_words = config.main_offset; 248 dvle.main_offset_words = config.main_offset;
249 dvle.output_register_table_offset = write_offset - dvlb.dvle_offset; 249 dvle.output_register_table_offset = write_offset - dvlb.dvle_offset;
250 dvle.output_register_table_size = static_cast<u32>(output_info_table.size()); 250 dvle.output_register_table_size = static_cast<u32>(output_info_table.size());
251 QueueForWriting((u8*)output_info_table.data(), static_cast<u32>(output_info_table.size() * sizeof(OutputRegisterInfo))); 251 QueueForWriting(reinterpret_cast<const u8*>(output_info_table.data()), static_cast<u32>(output_info_table.size() * sizeof(OutputRegisterInfo)));
252 252
253 // TODO: Create a label table for "main" 253 // TODO: Create a label table for "main"
254 254
@@ -292,14 +292,14 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config, c
292 dvle.constant_table_offset = write_offset - dvlb.dvle_offset; 292 dvle.constant_table_offset = write_offset - dvlb.dvle_offset;
293 dvle.constant_table_size = constant_table.size(); 293 dvle.constant_table_size = constant_table.size();
294 for (const auto& constant : constant_table) { 294 for (const auto& constant : constant_table) {
295 QueueForWriting((uint8_t*)&constant, sizeof(constant)); 295 QueueForWriting(reinterpret_cast<const u8*>(&constant), sizeof(constant));
296 } 296 }
297 297
298 // Write data to file 298 // Write data to file
299 std::ofstream file(filename, std::ios_base::out | std::ios_base::binary); 299 std::ofstream file(filename, std::ios_base::out | std::ios_base::binary);
300 300
301 for (auto& chunk : writing_queue) { 301 for (const auto& chunk : writing_queue) {
302 file.write((char*)chunk.pointer, chunk.size); 302 file.write(reinterpret_cast<const char*>(chunk.pointer), chunk.size);
303 } 303 }
304} 304}
305 305
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 2e0c33201..4b783ac6b 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -71,7 +71,7 @@ struct Regs {
71 BitField<0, 24, u32> viewport_depth_range; // float24 71 BitField<0, 24, u32> viewport_depth_range; // float24
72 BitField<0, 24, u32> viewport_depth_far_plane; // float24 72 BitField<0, 24, u32> viewport_depth_far_plane; // float24
73 73
74 INSERT_PADDING_WORDS(0x1); 74 BitField<0, 3, u32> vs_output_total;
75 75
76 union VSOutputAttributes { 76 union VSOutputAttributes {
77 // Maps components of output vertex attributes to semantics 77 // Maps components of output vertex attributes to semantics
@@ -117,8 +117,8 @@ struct Regs {
117 INSERT_PADDING_WORDS(0x11); 117 INSERT_PADDING_WORDS(0x11);
118 118
119 union { 119 union {
120 BitField< 0, 16, u32> x; 120 BitField< 0, 10, s32> x;
121 BitField<16, 16, u32> y; 121 BitField<16, 10, s32> y;
122 } viewport_corner; 122 } viewport_corner;
123 123
124 INSERT_PADDING_WORDS(0x17); 124 INSERT_PADDING_WORDS(0x17);
@@ -1157,8 +1157,10 @@ struct Regs {
1157 } 1157 }
1158 } input_register_map; 1158 } input_register_map;
1159 1159
1160 // OUTMAP_MASK, 0x28E, CODETRANSFER_END 1160 BitField<0, 16, u32> output_mask;
1161 INSERT_PADDING_WORDS(0x3); 1161
1162 // 0x28E, CODETRANSFER_END
1163 INSERT_PADDING_WORDS(0x2);
1162 1164
1163 struct { 1165 struct {
1164 enum Format : u32 1166 enum Format : u32
@@ -1221,17 +1223,17 @@ struct Regs {
1221 // Used for debugging purposes, so performance is not an issue here 1223 // Used for debugging purposes, so performance is not an issue here
1222 static std::string GetCommandName(int index); 1224 static std::string GetCommandName(int index);
1223 1225
1224 static inline size_t NumIds() { 1226 static constexpr size_t NumIds() {
1225 return sizeof(Regs) / sizeof(u32); 1227 return sizeof(Regs) / sizeof(u32);
1226 } 1228 }
1227 1229
1228 u32& operator [] (int index) const { 1230 const u32& operator [] (int index) const {
1229 u32* content = (u32*)this; 1231 const u32* content = reinterpret_cast<const u32*>(this);
1230 return content[index]; 1232 return content[index];
1231 } 1233 }
1232 1234
1233 u32& operator [] (int index) { 1235 u32& operator [] (int index) {
1234 u32* content = (u32*)this; 1236 u32* content = reinterpret_cast<u32*>(this);
1235 return content[index]; 1237 return content[index];
1236 } 1238 }
1237 1239
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 5e8930476..eb1db0778 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -32,6 +32,12 @@ namespace Shader {
32static std::unordered_map<u64, CompiledShader*> shader_map; 32static std::unordered_map<u64, CompiledShader*> shader_map;
33static JitCompiler jit; 33static JitCompiler jit;
34static CompiledShader* jit_shader; 34static CompiledShader* jit_shader;
35
36static void ClearCache() {
37 shader_map.clear();
38 jit.Clear();
39 LOG_INFO(HW_GPU, "Shader JIT cache cleared");
40}
35#endif // ARCHITECTURE_x86_64 41#endif // ARCHITECTURE_x86_64
36 42
37void Setup(UnitState<false>& state) { 43void Setup(UnitState<false>& state) {
@@ -45,6 +51,12 @@ void Setup(UnitState<false>& state) {
45 if (iter != shader_map.end()) { 51 if (iter != shader_map.end()) {
46 jit_shader = iter->second; 52 jit_shader = iter->second;
47 } else { 53 } else {
54 // Check if remaining JIT code space is enough for at least one more (massive) shader
55 if (jit.GetSpaceLeft() < jit_shader_size) {
56 // If not, clear the cache of all previously compiled shaders
57 ClearCache();
58 }
59
48 jit_shader = jit.Compile(); 60 jit_shader = jit.Compile();
49 shader_map.emplace(cache_key, jit_shader); 61 shader_map.emplace(cache_key, jit_shader);
50 } 62 }
@@ -54,7 +66,7 @@ void Setup(UnitState<false>& state) {
54 66
55void Shutdown() { 67void Shutdown() {
56#ifdef ARCHITECTURE_x86_64 68#ifdef ARCHITECTURE_x86_64
57 shader_map.clear(); 69 ClearCache();
58#endif // ARCHITECTURE_x86_64 70#endif // ARCHITECTURE_x86_64
59} 71}
60 72
@@ -109,15 +121,23 @@ OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attr
109 OutputVertex ret; 121 OutputVertex ret;
110 // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to 122 // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
111 // figure out what those circumstances are and enable the remaining outputs then. 123 // figure out what those circumstances are and enable the remaining outputs then.
112 for (int i = 0; i < 7; ++i) { 124 unsigned index = 0;
113 const auto& output_register_map = g_state.regs.vs_output_attributes[i]; // TODO: Don't hardcode VS here 125 for (unsigned i = 0; i < 7; ++i) {
126
127 if (index >= g_state.regs.vs_output_total)
128 break;
129
130 if ((g_state.regs.vs.output_mask & (1 << i)) == 0)
131 continue;
132
133 const auto& output_register_map = g_state.regs.vs_output_attributes[index]; // TODO: Don't hardcode VS here
114 134
115 u32 semantics[4] = { 135 u32 semantics[4] = {
116 output_register_map.map_x, output_register_map.map_y, 136 output_register_map.map_x, output_register_map.map_y,
117 output_register_map.map_z, output_register_map.map_w 137 output_register_map.map_z, output_register_map.map_w
118 }; 138 };
119 139
120 for (int comp = 0; comp < 4; ++comp) { 140 for (unsigned comp = 0; comp < 4; ++comp) {
121 float24* out = ((float24*)&ret) + semantics[comp]; 141 float24* out = ((float24*)&ret) + semantics[comp];
122 if (semantics[comp] != Regs::VSOutputAttributes::INVALID) { 142 if (semantics[comp] != Regs::VSOutputAttributes::INVALID) {
123 *out = state.registers.output[i][comp]; 143 *out = state.registers.output[i][comp];
@@ -127,15 +147,17 @@ OutputVertex Run(UnitState<false>& state, const InputVertex& input, int num_attr
127 memset(out, 0, sizeof(*out)); 147 memset(out, 0, sizeof(*out));
128 } 148 }
129 } 149 }
150
151 index++;
130 } 152 }
131 153
132 // The hardware takes the absolute and saturates vertex colors like this, *before* doing interpolation 154 // The hardware takes the absolute and saturates vertex colors like this, *before* doing interpolation
133 for (int i = 0; i < 4; ++i) { 155 for (unsigned i = 0; i < 4; ++i) {
134 ret.color[i] = float24::FromFloat32( 156 ret.color[i] = float24::FromFloat32(
135 std::fmin(std::fabs(ret.color[i].ToFloat32()), 1.0f)); 157 std::fmin(std::fabs(ret.color[i].ToFloat32()), 1.0f));
136 } 158 }
137 159
138 LOG_TRACE(Render_Software, "Output vertex: pos(%.2f, %.2f, %.2f, %.2f), quat(%.2f, %.2f, %.2f, %.2f), " 160 LOG_TRACE(HW_GPU, "Output vertex: pos(%.2f, %.2f, %.2f, %.2f), quat(%.2f, %.2f, %.2f, %.2f), "
139 "col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f), view(%.2f, %.2f, %.2f)", 161 "col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f), view(%.2f, %.2f, %.2f)",
140 ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(), 162 ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(),
141 ret.quat.x.ToFloat32(), ret.quat.y.ToFloat32(), ret.quat.z.ToFloat32(), ret.quat.w.ToFloat32(), 163 ret.quat.x.ToFloat32(), ret.quat.y.ToFloat32(), ret.quat.z.ToFloat32(), ret.quat.w.ToFloat32(),
diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp
index 79fcc56b9..9b978583e 100644
--- a/src/video_core/shader/shader_interpreter.cpp
+++ b/src/video_core/shader/shader_interpreter.cpp
@@ -2,10 +2,10 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <common/file_util.h> 5#include <numeric>
6
7#include <nihstro/shader_bytecode.h> 6#include <nihstro/shader_bytecode.h>
8 7
8#include "common/file_util.h"
9#include "video_core/pica.h" 9#include "video_core/pica.h"
10#include "video_core/pica_state.h" 10#include "video_core/pica_state.h"
11#include "video_core/shader/shader.h" 11#include "video_core/shader/shader.h"
@@ -214,10 +214,8 @@ void RunInterpreter(UnitState<Debug>& state) {
214 if (opcode == OpCode::Id::DPH || opcode == OpCode::Id::DPHI) 214 if (opcode == OpCode::Id::DPH || opcode == OpCode::Id::DPHI)
215 src1[3] = float24::FromFloat32(1.0f); 215 src1[3] = float24::FromFloat32(1.0f);
216 216
217 float24 dot = float24::FromFloat32(0.f);
218 int num_components = (opcode == OpCode::Id::DP3) ? 3 : 4; 217 int num_components = (opcode == OpCode::Id::DP3) ? 3 : 4;
219 for (int i = 0; i < num_components; ++i) 218 float24 dot = std::inner_product(src1, src1 + num_components, src2, float24::FromFloat32(0.f));
220 dot = dot + src1[i] * src2[i];
221 219
222 for (int i = 0; i < 4; ++i) { 220 for (int i = 0; i < 4; ++i) {
223 if (!swizzle.DestComponentEnabled(i)) 221 if (!swizzle.DestComponentEnabled(i))
@@ -409,13 +407,16 @@ void RunInterpreter(UnitState<Debug>& state) {
409 { 407 {
410 if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) || 408 if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) ||
411 (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) { 409 (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) {
412 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.mad.operand_desc_id]; 410 const SwizzlePattern& swizzle = *reinterpret_cast<const SwizzlePattern*>(&swizzle_data[instr.mad.operand_desc_id]);
413 411
414 bool is_inverted = (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI); 412 bool is_inverted = (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI);
415 413
414 const int address_offset = (instr.mad.address_register_index == 0)
415 ? 0 : state.address_registers[instr.mad.address_register_index - 1];
416
416 const float24* src1_ = LookupSourceRegister(instr.mad.GetSrc1(is_inverted)); 417 const float24* src1_ = LookupSourceRegister(instr.mad.GetSrc1(is_inverted));
417 const float24* src2_ = LookupSourceRegister(instr.mad.GetSrc2(is_inverted)); 418 const float24* src2_ = LookupSourceRegister(instr.mad.GetSrc2(is_inverted) + (!is_inverted * address_offset));
418 const float24* src3_ = LookupSourceRegister(instr.mad.GetSrc3(is_inverted)); 419 const float24* src3_ = LookupSourceRegister(instr.mad.GetSrc3(is_inverted) + ( is_inverted * address_offset));
419 420
420 const bool negate_src1 = ((bool)swizzle.negate_src1 != false); 421 const bool negate_src1 = ((bool)swizzle.negate_src1 != false);
421 const bool negate_src2 = ((bool)swizzle.negate_src2 != false); 422 const bool negate_src2 = ((bool)swizzle.negate_src2 != false);
diff --git a/src/video_core/shader/shader_jit_x64.cpp b/src/video_core/shader/shader_jit_x64.cpp
index 5083d7e54..dffe051ef 100644
--- a/src/video_core/shader/shader_jit_x64.cpp
+++ b/src/video_core/shader/shader_jit_x64.cpp
@@ -160,40 +160,41 @@ void JitCompiler::Compile_SwizzleSrc(Instruction instr, unsigned src_num, Source
160 ASSERT_MSG(src_offset == src_offset_disp, "Source register offset too large for int type"); 160 ASSERT_MSG(src_offset == src_offset_disp, "Source register offset too large for int type");
161 161
162 unsigned operand_desc_id; 162 unsigned operand_desc_id;
163
164 const bool is_inverted = (0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed));
165
166 unsigned address_register_index;
167 unsigned offset_src;
168
163 if (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD || 169 if (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD ||
164 instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI) { 170 instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI) {
165 // The MAD and MADI instructions do not use the address offset registers, so loading the
166 // source is a bit simpler here
167
168 operand_desc_id = instr.mad.operand_desc_id; 171 operand_desc_id = instr.mad.operand_desc_id;
169 172 offset_src = is_inverted ? 3 : 2;
170 // Load the source 173 address_register_index = instr.mad.address_register_index;
171 MOVAPS(dest, MDisp(src_ptr, src_offset_disp));
172 } else { 174 } else {
173 operand_desc_id = instr.common.operand_desc_id; 175 operand_desc_id = instr.common.operand_desc_id;
176 offset_src = is_inverted ? 2 : 1;
177 address_register_index = instr.common.address_register_index;
178 }
174 179
175 const bool is_inverted = (0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed)); 180 if (src_num == offset_src && address_register_index != 0) {
176 unsigned offset_src = is_inverted ? 2 : 1; 181 switch (address_register_index) {
177 182 case 1: // address offset 1
178 if (src_num == offset_src && instr.common.address_register_index != 0) { 183 MOVAPS(dest, MComplex(src_ptr, ADDROFFS_REG_0, SCALE_1, src_offset_disp));
179 switch (instr.common.address_register_index) { 184 break;
180 case 1: // address offset 1 185 case 2: // address offset 2
181 MOVAPS(dest, MComplex(src_ptr, ADDROFFS_REG_0, SCALE_1, src_offset_disp)); 186 MOVAPS(dest, MComplex(src_ptr, ADDROFFS_REG_1, SCALE_1, src_offset_disp));
182 break; 187 break;
183 case 2: // address offset 2 188 case 3: // address offset 3
184 MOVAPS(dest, MComplex(src_ptr, ADDROFFS_REG_1, SCALE_1, src_offset_disp)); 189 MOVAPS(dest, MComplex(src_ptr, LOOPCOUNT_REG, SCALE_1, src_offset_disp));
185 break; 190 break;
186 case 3: // address offset 3 191 default:
187 MOVAPS(dest, MComplex(src_ptr, LOOPCOUNT_REG, SCALE_1, src_offset_disp)); 192 UNREACHABLE();
188 break; 193 break;
189 default:
190 UNREACHABLE();
191 break;
192 }
193 } else {
194 // Load the source
195 MOVAPS(dest, MDisp(src_ptr, src_offset_disp));
196 } 194 }
195 } else {
196 // Load the source
197 MOVAPS(dest, MDisp(src_ptr, src_offset_disp));
197 } 198 }
198 199
199 SwizzlePattern swiz = { g_state.vs.swizzle_data[operand_desc_id] }; 200 SwizzlePattern swiz = { g_state.vs.swizzle_data[operand_desc_id] };
@@ -644,7 +645,8 @@ void JitCompiler::Compile_MAD(Instruction instr) {
644} 645}
645 646
646void JitCompiler::Compile_IF(Instruction instr) { 647void JitCompiler::Compile_IF(Instruction instr) {
647 ASSERT_MSG(instr.flow_control.dest_offset > *offset_ptr, "Backwards if-statements not supported"); 648 ASSERT_MSG(instr.flow_control.dest_offset > *offset_ptr, "Backwards if-statements (%d -> %d) not supported",
649 *offset_ptr, instr.flow_control.dest_offset.Value());
648 650
649 // Evaluate the "IF" condition 651 // Evaluate the "IF" condition
650 if (instr.opcode.Value() == OpCode::Id::IFU) { 652 if (instr.opcode.Value() == OpCode::Id::IFU) {
@@ -675,7 +677,8 @@ void JitCompiler::Compile_IF(Instruction instr) {
675} 677}
676 678
677void JitCompiler::Compile_LOOP(Instruction instr) { 679void JitCompiler::Compile_LOOP(Instruction instr) {
678 ASSERT_MSG(instr.flow_control.dest_offset > *offset_ptr, "Backwards loops not supported"); 680 ASSERT_MSG(instr.flow_control.dest_offset > *offset_ptr, "Backwards loops (%d -> %d) not supported",
681 *offset_ptr, instr.flow_control.dest_offset.Value());
679 ASSERT_MSG(!looping, "Nested loops not supported"); 682 ASSERT_MSG(!looping, "Nested loops not supported");
680 683
681 looping = true; 684 looping = true;
@@ -703,7 +706,8 @@ void JitCompiler::Compile_LOOP(Instruction instr) {
703} 706}
704 707
705void JitCompiler::Compile_JMP(Instruction instr) { 708void JitCompiler::Compile_JMP(Instruction instr) {
706 ASSERT_MSG(instr.flow_control.dest_offset > *offset_ptr, "Backwards jumps not supported"); 709 ASSERT_MSG(instr.flow_control.dest_offset > *offset_ptr, "Backwards jumps (%d -> %d) not supported",
710 *offset_ptr, instr.flow_control.dest_offset.Value());
707 711
708 if (instr.opcode.Value() == OpCode::Id::JMPC) 712 if (instr.opcode.Value() == OpCode::Id::JMPC)
709 Compile_EvaluateCondition(instr); 713 Compile_EvaluateCondition(instr);
@@ -747,7 +751,7 @@ void JitCompiler::Compile_NextInstr(unsigned* offset) {
747 } else { 751 } else {
748 // Unhandled instruction 752 // Unhandled instruction
749 LOG_CRITICAL(HW_GPU, "Unhandled instruction: 0x%02x (0x%08x)", 753 LOG_CRITICAL(HW_GPU, "Unhandled instruction: 0x%02x (0x%08x)",
750 instr.opcode.Value().EffectiveOpCode(), instr.hex); 754 instr.opcode.Value().EffectiveOpCode(), instr.hex);
751 } 755 }
752} 756}
753 757
@@ -786,7 +790,7 @@ CompiledShader* JitCompiler::Compile() {
786} 790}
787 791
788JitCompiler::JitCompiler() { 792JitCompiler::JitCompiler() {
789 AllocCodeSpace(1024 * 1024 * 4); 793 AllocCodeSpace(jit_cache_size);
790} 794}
791 795
792void JitCompiler::Clear() { 796void JitCompiler::Clear() {
diff --git a/src/video_core/shader/shader_jit_x64.h b/src/video_core/shader/shader_jit_x64.h
index 5ad2d9606..5357c964b 100644
--- a/src/video_core/shader/shader_jit_x64.h
+++ b/src/video_core/shader/shader_jit_x64.h
@@ -19,6 +19,11 @@ namespace Pica {
19 19
20namespace Shader { 20namespace Shader {
21 21
22/// Memory needed to be available to compile the next shader (otherwise, clear the cache)
23constexpr size_t jit_shader_size = 1024 * 512;
24/// Memory allocated for the JIT code space cache
25constexpr size_t jit_cache_size = 1024 * 1024 * 8;
26
22using CompiledShader = void(void* registers); 27using CompiledShader = void(void* registers);
23 28
24/** 29/**