summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/config.cpp17
-rw-r--r--src/citra/config.h5
-rw-r--r--src/citra/emu_window/emu_window_glfw.cpp8
-rw-r--r--src/citra_qt/config.cpp52
-rw-r--r--src/citra_qt/config.h11
-rw-r--r--src/common/log_manager.cpp1
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp54
-rw-r--r--src/core/arm/skyeye_common/armcpu.h2
-rw-r--r--src/core/arm/skyeye_common/armdefs.h34
-rw-r--r--src/core/arm/skyeye_common/armemu.h18
-rw-r--r--src/core/file_sys/archive.h16
-rw-r--r--src/core/file_sys/archive_romfs.cpp20
-rw-r--r--src/core/file_sys/archive_romfs.h14
-rw-r--r--src/core/file_sys/archive_sdmc.cpp20
-rw-r--r--src/core/file_sys/archive_sdmc.h14
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp15
-rw-r--r--src/core/hle/kernel/address_arbiter.h2
-rw-r--r--src/core/hle/kernel/archive.cpp206
-rw-r--r--src/core/hle/kernel/archive.h39
-rw-r--r--src/core/hle/kernel/event.cpp43
-rw-r--r--src/core/hle/kernel/event.h12
-rw-r--r--src/core/hle/kernel/kernel.h44
-rw-r--r--src/core/hle/kernel/mutex.cpp50
-rw-r--r--src/core/hle/kernel/mutex.h3
-rw-r--r--src/core/hle/kernel/shared_memory.cpp43
-rw-r--r--src/core/hle/kernel/shared_memory.h5
-rw-r--r--src/core/hle/kernel/thread.cpp78
-rw-r--r--src/core/hle/kernel/thread.h7
-rw-r--r--src/core/hle/result.h400
-rw-r--r--src/core/hle/service/cfg_u.cpp88
-rw-r--r--src/core/hle/service/dsp_dsp.cpp131
-rw-r--r--src/core/hle/service/dsp_dsp.h2
-rw-r--r--src/core/hle/service/fs_user.cpp164
-rw-r--r--src/core/hle/service/gsp_gpu.cpp17
-rw-r--r--src/core/hle/service/hid_user.cpp5
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/service.h22
-rw-r--r--src/core/hle/service/srv.cpp6
-rw-r--r--src/core/hle/svc.cpp73
-rw-r--r--src/core/hw/gpu.cpp6
-rw-r--r--src/core/hw/hw.cpp2
-rw-r--r--src/core/hw/ndma.cpp2
-rw-r--r--src/core/mem_map_funcs.cpp4
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp4
45 files changed, 1159 insertions, 603 deletions
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index f45d09fc2..1f8f5922b 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -36,7 +36,8 @@ bool Config::LoadINI(INIReader* config, const char* location, const std::string&
36 return true; 36 return true;
37} 37}
38 38
39void Config::ReadControls() { 39void Config::ReadValues() {
40 // Controls
40 Settings::values.pad_a_key = glfw_config->GetInteger("Controls", "pad_a", GLFW_KEY_A); 41 Settings::values.pad_a_key = glfw_config->GetInteger("Controls", "pad_a", GLFW_KEY_A);
41 Settings::values.pad_b_key = glfw_config->GetInteger("Controls", "pad_b", GLFW_KEY_S); 42 Settings::values.pad_b_key = glfw_config->GetInteger("Controls", "pad_b", GLFW_KEY_S);
42 Settings::values.pad_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z); 43 Settings::values.pad_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z);
@@ -54,27 +55,21 @@ void Config::ReadControls() {
54 Settings::values.pad_sdown_key = glfw_config->GetInteger("Controls", "pad_sdown", GLFW_KEY_DOWN); 55 Settings::values.pad_sdown_key = glfw_config->GetInteger("Controls", "pad_sdown", GLFW_KEY_DOWN);
55 Settings::values.pad_sleft_key = glfw_config->GetInteger("Controls", "pad_sleft", GLFW_KEY_LEFT); 56 Settings::values.pad_sleft_key = glfw_config->GetInteger("Controls", "pad_sleft", GLFW_KEY_LEFT);
56 Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT); 57 Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT);
57}
58 58
59void Config::ReadCore() { 59 // Core
60 Settings::values.cpu_core = glfw_config->GetInteger("Core", "cpu_core", Core::CPU_Interpreter); 60 Settings::values.cpu_core = glfw_config->GetInteger("Core", "cpu_core", Core::CPU_Interpreter);
61 Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 60); 61 Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 60);
62}
63 62
64void Config::ReadData() { 63 // Data Storage
65 Settings::values.use_virtual_sd = glfw_config->GetBoolean("Data Storage", "use_virtual_sd", true); 64 Settings::values.use_virtual_sd = glfw_config->GetBoolean("Data Storage", "use_virtual_sd", true);
66}
67 65
68void Config::ReadMiscellaneous() { 66 // Miscellaneous
69 Settings::values.enable_log = glfw_config->GetBoolean("Miscellaneous", "enable_log", true); 67 Settings::values.enable_log = glfw_config->GetBoolean("Miscellaneous", "enable_log", true);
70} 68}
71 69
72void Config::Reload() { 70void Config::Reload() {
73 LoadINI(glfw_config, glfw_config_loc.c_str(), DefaultINI::glfw_config_file); 71 LoadINI(glfw_config, glfw_config_loc.c_str(), DefaultINI::glfw_config_file);
74 ReadControls(); 72 ReadValues();
75 ReadCore();
76 ReadData();
77 ReadMiscellaneous();
78} 73}
79 74
80Config::~Config() { 75Config::~Config() {
diff --git a/src/citra/config.h b/src/citra/config.h
index 19bb83700..2b46fa8aa 100644
--- a/src/citra/config.h
+++ b/src/citra/config.h
@@ -15,10 +15,7 @@ class Config {
15 std::string glfw_config_loc; 15 std::string glfw_config_loc;
16 16
17 bool LoadINI(INIReader* config, const char* location, const std::string& default_contents="", bool retry=true); 17 bool LoadINI(INIReader* config, const char* location, const std::string& default_contents="", bool retry=true);
18 void ReadControls(); 18 void ReadValues();
19 void ReadCore();
20 void ReadData();
21 void ReadMiscellaneous();
22public: 19public:
23 Config(); 20 Config();
24 ~Config(); 21 ~Config();
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 8efb39e2e..697bf4693 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -58,9 +58,13 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
58 58
59 ReloadSetKeymaps(); 59 ReloadSetKeymaps();
60 60
61 glfwSetErrorCallback([](int error, const char *desc){
62 ERROR_LOG(GUI, "GLFW 0x%08x: %s", error, desc);
63 });
64
61 // Initialize the window 65 // Initialize the window
62 if(glfwInit() != GL_TRUE) { 66 if(glfwInit() != GL_TRUE) {
63 printf("Failed to initialize GLFW! Exiting..."); 67 ERROR_LOG(GUI, "Failed to initialize GLFW! Exiting...");
64 exit(1); 68 exit(1);
65 } 69 }
66 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 70 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
@@ -75,7 +79,7 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
75 window_title.c_str(), NULL, NULL); 79 window_title.c_str(), NULL, NULL);
76 80
77 if (m_render_window == NULL) { 81 if (m_render_window == NULL) {
78 printf("Failed to create GLFW window! Exiting..."); 82 ERROR_LOG(GUI, "Failed to create GLFW window! Exiting...");
79 exit(1); 83 exit(1);
80 } 84 }
81 85
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 09fce4d6f..3209e5900 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -21,7 +21,7 @@ Config::Config() {
21 Reload(); 21 Reload();
22} 22}
23 23
24void Config::ReadControls() { 24void Config::ReadValues() {
25 qt_config->beginGroup("Controls"); 25 qt_config->beginGroup("Controls");
26 Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt(); 26 Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt();
27 Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt(); 27 Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt();
@@ -41,9 +41,22 @@ void Config::ReadControls() {
41 Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt(); 41 Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt();
42 Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt(); 42 Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt();
43 qt_config->endGroup(); 43 qt_config->endGroup();
44
45 qt_config->beginGroup("Core");
46 Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt();
47 Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 60).toInt();
48 qt_config->endGroup();
49
50 qt_config->beginGroup("Data Storage");
51 Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
52 qt_config->endGroup();
53
54 qt_config->beginGroup("Miscellaneous");
55 Settings::values.enable_log = qt_config->value("enable_log", true).toBool();
56 qt_config->endGroup();
44} 57}
45 58
46void Config::SaveControls() { 59void Config::SaveValues() {
47 qt_config->beginGroup("Controls"); 60 qt_config->beginGroup("Controls");
48 qt_config->setValue("pad_a", Settings::values.pad_a_key); 61 qt_config->setValue("pad_a", Settings::values.pad_a_key);
49 qt_config->setValue("pad_b", Settings::values.pad_b_key); 62 qt_config->setValue("pad_b", Settings::values.pad_b_key);
@@ -63,58 +76,27 @@ void Config::SaveControls() {
63 qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key); 76 qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key);
64 qt_config->setValue("pad_sright", Settings::values.pad_sright_key); 77 qt_config->setValue("pad_sright", Settings::values.pad_sright_key);
65 qt_config->endGroup(); 78 qt_config->endGroup();
66}
67
68void Config::ReadCore() {
69 qt_config->beginGroup("Core");
70 Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt();
71 Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 60).toInt();
72 qt_config->endGroup();
73}
74 79
75void Config::SaveCore() {
76 qt_config->beginGroup("Core"); 80 qt_config->beginGroup("Core");
77 qt_config->setValue("cpu_core", Settings::values.cpu_core); 81 qt_config->setValue("cpu_core", Settings::values.cpu_core);
78 qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate); 82 qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate);
79 qt_config->endGroup(); 83 qt_config->endGroup();
80}
81
82void Config::ReadData() {
83 qt_config->beginGroup("Data Storage");
84 Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
85 qt_config->endGroup();
86}
87 84
88void Config::SaveData() {
89 qt_config->beginGroup("Data Storage"); 85 qt_config->beginGroup("Data Storage");
90 qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); 86 qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
91 qt_config->endGroup(); 87 qt_config->endGroup();
92}
93
94void Config::ReadMiscellaneous() {
95 qt_config->beginGroup("Miscellaneous");
96 Settings::values.enable_log = qt_config->value("enable_log", true).toBool();
97 qt_config->endGroup();
98}
99 88
100void Config::SaveMiscellaneous() {
101 qt_config->beginGroup("Miscellaneous"); 89 qt_config->beginGroup("Miscellaneous");
102 qt_config->setValue("enable_log", Settings::values.enable_log); 90 qt_config->setValue("enable_log", Settings::values.enable_log);
103 qt_config->endGroup(); 91 qt_config->endGroup();
104} 92}
105 93
106void Config::Reload() { 94void Config::Reload() {
107 ReadControls(); 95 ReadValues();
108 ReadCore();
109 ReadData();
110 ReadMiscellaneous();
111} 96}
112 97
113void Config::Save() { 98void Config::Save() {
114 SaveControls(); 99 SaveValues();
115 SaveCore();
116 SaveData();
117 SaveMiscellaneous();
118} 100}
119 101
120Config::~Config() { 102Config::~Config() {
diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h
index 8c6568cb2..4c95d0cb9 100644
--- a/src/citra_qt/config.h
+++ b/src/citra_qt/config.h
@@ -12,15 +12,8 @@ class Config {
12 QSettings* qt_config; 12 QSettings* qt_config;
13 std::string qt_config_loc; 13 std::string qt_config_loc;
14 14
15 void ReadControls(); 15 void ReadValues();
16 void SaveControls(); 16 void SaveValues();
17 void ReadCore();
18 void SaveCore();
19 void ReadData();
20 void SaveData();
21
22 void ReadMiscellaneous();
23 void SaveMiscellaneous();
24public: 17public:
25 Config(); 18 Config();
26 ~Config(); 19 ~Config();
diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp
index 38c681ee0..2ef7d98c0 100644
--- a/src/common/log_manager.cpp
+++ b/src/common/log_manager.cpp
@@ -7,7 +7,6 @@
7#include "common/log_manager.h" 7#include "common/log_manager.h"
8#include "common/console_listener.h" 8#include "common/console_listener.h"
9#include "common/timer.h" 9#include "common/timer.h"
10#include "common/thread.h"
11 10
12void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, 11void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
13 const char* function, const char* fmt, ...) 12 const char* function, const char* fmt, ...)
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index b3bfbca9e..48241c3d4 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -133,6 +133,7 @@ set(HEADERS
133 hle/service/srv.h 133 hle/service/srv.h
134 hle/service/ssl_c.h 134 hle/service/ssl_c.h
135 hle/config_mem.h 135 hle/config_mem.h
136 hle/result.h
136 hle/function_wrappers.h 137 hle/function_wrappers.h
137 hle/hle.h 138 hle/hle.h
138 hle/svc.h 139 hle/svc.h
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index f899e2e8a..233cd3e3a 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -26,7 +26,7 @@
26#define CITRA_IGNORE_EXIT(x) 26#define CITRA_IGNORE_EXIT(x)
27 27
28#include <algorithm> 28#include <algorithm>
29#include <map> 29#include <unordered_map>
30#include <stdio.h> 30#include <stdio.h>
31#include <assert.h> 31#include <assert.h>
32#include <cstdio> 32#include <cstdio>
@@ -94,9 +94,8 @@ typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper);
94 94
95/* exclusive memory access */ 95/* exclusive memory access */
96static int exclusive_detect(ARMul_State* state, ARMword addr){ 96static int exclusive_detect(ARMul_State* state, ARMword addr){
97 int i;
98 #if 0 97 #if 0
99 for(i = 0; i < 128; i++){ 98 for(int i = 0; i < 128; i++){
100 if(state->exclusive_tag_array[i] == addr) 99 if(state->exclusive_tag_array[i] == addr)
101 return 0; 100 return 0;
102 } 101 }
@@ -108,9 +107,8 @@ static int exclusive_detect(ARMul_State* state, ARMword addr){
108} 107}
109 108
110static void add_exclusive_addr(ARMul_State* state, ARMword addr){ 109static void add_exclusive_addr(ARMul_State* state, ARMword addr){
111 int i;
112 #if 0 110 #if 0
113 for(i = 0; i < 128; i++){ 111 for(int i = 0; i < 128; i++){
114 if(state->exclusive_tag_array[i] == 0xffffffff){ 112 if(state->exclusive_tag_array[i] == 0xffffffff){
115 state->exclusive_tag_array[i] = addr; 113 state->exclusive_tag_array[i] = addr;
116 //DEBUG_LOG(ARM11, "In %s, add addr 0x%x\n", __func__, addr); 114 //DEBUG_LOG(ARM11, "In %s, add addr 0x%x\n", __func__, addr);
@@ -3309,9 +3307,8 @@ const transop_fp_t arm_instruction_trans[] = {
3309 INTERPRETER_TRANSLATE(blx_1_thumb) 3307 INTERPRETER_TRANSLATE(blx_1_thumb)
3310}; 3308};
3311 3309
3312typedef map<unsigned int, int> bb_map; 3310typedef std::unordered_map<u32, int> bb_map;
3313bb_map CreamCache[65536]; 3311bb_map CreamCache;
3314bb_map ProfileCache[65536];
3315 3312
3316//#define USE_DUMMY_CACHE 3313//#define USE_DUMMY_CACHE
3317 3314
@@ -3319,14 +3316,12 @@ bb_map ProfileCache[65536];
3319unsigned int DummyCache[0x100000]; 3316unsigned int DummyCache[0x100000];
3320#endif 3317#endif
3321 3318
3322#define HASH(x) ((x + (x << 3) + (x >> 6)) % 65536)
3323void insert_bb(unsigned int addr, int start) 3319void insert_bb(unsigned int addr, int start)
3324{ 3320{
3325#ifdef USE_DUMMY_CACHE 3321#ifdef USE_DUMMY_CACHE
3326 DummyCache[addr] = start; 3322 DummyCache[addr] = start;
3327#else 3323#else
3328// CreamCache[addr] = start; 3324 CreamCache[addr] = start;
3329 CreamCache[HASH(addr)][addr] = start;
3330#endif 3325#endif
3331} 3326}
3332 3327
@@ -3341,8 +3336,8 @@ int find_bb(unsigned int addr, int &start)
3341 } else 3336 } else
3342 ret = -1; 3337 ret = -1;
3343#else 3338#else
3344 bb_map::const_iterator it = CreamCache[HASH(addr)].find(addr); 3339 bb_map::const_iterator it = CreamCache.find(addr);
3345 if (it != CreamCache[HASH(addr)].end()) { 3340 if (it != CreamCache.end()) {
3346 start = static_cast<int>(it->second); 3341 start = static_cast<int>(it->second);
3347 ret = 0; 3342 ret = 0;
3348#if HYBRID_MODE 3343#if HYBRID_MODE
@@ -3473,30 +3468,15 @@ void flush_bb(uint32_t addr)
3473 uint32_t start; 3468 uint32_t start;
3474 3469
3475 addr &= 0xfffff000; 3470 addr &= 0xfffff000;
3476 for (int i = 0; i < 65536; i ++) { 3471 for (it = CreamCache.begin(); it != CreamCache.end(); ) {
3477 for (it = CreamCache[i].begin(); it != CreamCache[i].end(); ) { 3472 start = static_cast<uint32_t>(it->first);
3478 start = static_cast<uint32_t>(it->first); 3473 //start = (start >> 12) << 12;
3479 //start = (start >> 12) << 12; 3474 start &= 0xfffff000;
3480 start &= 0xfffff000; 3475 if (start == addr) {
3481 if (start == addr) { 3476 //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first));
3482 //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first)); 3477 CreamCache.erase(it++);
3483 CreamCache[i].erase(it ++); 3478 } else
3484 } else 3479 ++it;
3485 ++it;
3486 }
3487 }
3488
3489 for (int i = 0; i < 65536; i ++) {
3490 for (it = ProfileCache[i].begin(); it != ProfileCache[i].end(); ) {
3491 start = static_cast<uint32_t>(it->first);
3492 //start = (start >> 12) << 12;
3493 start &= 0xfffff000;
3494 if (start == addr) {
3495 //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first));
3496 ProfileCache[i].erase(it ++);
3497 } else
3498 ++it;
3499 }
3500 } 3480 }
3501 3481
3502 //DEBUG_LOG(ARM11, "flush bb @ %x\n", addr); 3482 //DEBUG_LOG(ARM11, "flush bb @ %x\n", addr);
diff --git a/src/core/arm/skyeye_common/armcpu.h b/src/core/arm/skyeye_common/armcpu.h
index 3a029f0e7..2b756c5bc 100644
--- a/src/core/arm/skyeye_common/armcpu.h
+++ b/src/core/arm/skyeye_common/armcpu.h
@@ -24,8 +24,6 @@
24#include <stddef.h> 24#include <stddef.h>
25#include <stdio.h> 25#include <stdio.h>
26 26
27#include "common/thread.h"
28
29#include "core/arm/skyeye_common/armdefs.h" 27#include "core/arm/skyeye_common/armdefs.h"
30 28
31typedef struct ARM_CPU_State_s { 29typedef struct ARM_CPU_State_s {
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 8e71948c6..8343aaa01 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -799,22 +799,24 @@ pascal void SpinCursor (short increment); /* copied from CursorCtl.h */
799#include "list.h" 799#include "list.h"
800#include "tb.h" 800#include "tb.h"
801*/ 801*/
802#define EQ 0 802enum ConditionCode {
803#define NE 1 803 EQ = 0,
804#define CS 2 804 NE = 1,
805#define CC 3 805 CS = 2,
806#define MI 4 806 CC = 3,
807#define PL 5 807 MI = 4,
808#define VS 6 808 PL = 5,
809#define VC 7 809 VS = 6,
810#define HI 8 810 VC = 7,
811#define LS 9 811 HI = 8,
812#define GE 10 812 LS = 9,
813#define LT 11 813 GE = 10,
814#define GT 12 814 LT = 11,
815#define LE 13 815 GT = 12,
816#define AL 14 816 LE = 13,
817#define NV 15 817 AL = 14,
818 NV = 15,
819};
818 820
819#ifndef NFLAG 821#ifndef NFLAG
820#define NFLAG state->NFlag 822#define NFLAG state->NFlag
diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h
index c0f0270fe..075fc7e9e 100644
--- a/src/core/arm/skyeye_common/armemu.h
+++ b/src/core/arm/skyeye_common/armemu.h
@@ -25,24 +25,6 @@
25 25
26#define DEBUG(...) DEBUG_LOG(ARM11, __VA_ARGS__) 26#define DEBUG(...) DEBUG_LOG(ARM11, __VA_ARGS__)
27 27
28/* Condition code values. */
29#define EQ 0
30#define NE 1
31#define CS 2
32#define CC 3
33#define MI 4
34#define PL 5
35#define VS 6
36#define VC 7
37#define HI 8
38#define LS 9
39#define GE 10
40#define LT 11
41#define GT 12
42#define LE 13
43#define AL 14
44#define NV 15
45
46/* Shift Opcodes. */ 28/* Shift Opcodes. */
47#define LSL 0 29#define LSL 0
48#define LSR 1 30#define LSR 1
diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h
index 1135d8804..c2426a153 100644
--- a/src/core/file_sys/archive.h
+++ b/src/core/file_sys/archive.h
@@ -67,6 +67,8 @@ public:
67 u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated. 67 u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated.
68 break; 68 break;
69 } 69 }
70 default:
71 break;
70 } 72 }
71 } 73 }
72 74
@@ -185,6 +187,20 @@ public:
185 virtual std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const = 0; 187 virtual std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const = 0;
186 188
187 /** 189 /**
190 * Delete a file specified by its path
191 * @param path Path relative to the archive
192 * @return Whether the file could be deleted
193 */
194 virtual bool DeleteFile(const FileSys::Path& path) const = 0;
195
196 /**
197 * Delete a directory specified by its path
198 * @param path Path relative to the archive
199 * @return Whether the directory could be deleted
200 */
201 virtual bool DeleteDirectory(const FileSys::Path& path) const = 0;
202
203 /**
188 * Create a directory specified by its path 204 * Create a directory specified by its path
189 * @param path Path relative to the archive 205 * @param path Path relative to the archive
190 * @return Whether the directory could be created 206 * @return Whether the directory could be created
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index 551913a42..53dc57954 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -34,6 +34,26 @@ std::unique_ptr<File> Archive_RomFS::OpenFile(const Path& path, const Mode mode)
34} 34}
35 35
36/** 36/**
37 * Delete a file specified by its path
38 * @param path Path relative to the archive
39 * @return Whether the file could be deleted
40 */
41bool Archive_RomFS::DeleteFile(const FileSys::Path& path) const {
42 ERROR_LOG(FILESYS, "Attempted to delete a file from ROMFS.");
43 return false;
44}
45
46/**
47 * Delete a directory specified by its path
48 * @param path Path relative to the archive
49 * @return Whether the directory could be deleted
50 */
51bool Archive_RomFS::DeleteDirectory(const FileSys::Path& path) const {
52 ERROR_LOG(FILESYS, "Attempted to delete a directory from ROMFS.");
53 return false;
54}
55
56/**
37 * Create a directory specified by its path 57 * Create a directory specified by its path
38 * @param path Path relative to the archive 58 * @param path Path relative to the archive
39 * @return Whether the directory could be created 59 * @return Whether the directory could be created
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index f05327f51..0649dde99 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -37,6 +37,20 @@ public:
37 std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override; 37 std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override;
38 38
39 /** 39 /**
40 * Delete a file specified by its path
41 * @param path Path relative to the archive
42 * @return Whether the file could be deleted
43 */
44 bool DeleteFile(const FileSys::Path& path) const override;
45
46 /**
47 * Delete a directory specified by its path
48 * @param path Path relative to the archive
49 * @return Whether the directory could be deleted
50 */
51 bool DeleteDirectory(const FileSys::Path& path) const override;
52
53 /**
40 * Create a directory specified by its path 54 * Create a directory specified by its path
41 * @param path Path relative to the archive 55 * @param path Path relative to the archive
42 * @return Whether the directory could be created 56 * @return Whether the directory could be created
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index ecdb7f211..789212b17 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -50,7 +50,7 @@ bool Archive_SDMC::Initialize() {
50 * @return Opened file, or nullptr 50 * @return Opened file, or nullptr
51 */ 51 */
52std::unique_ptr<File> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const { 52std::unique_ptr<File> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const {
53 DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.DebugStr().c_str(), mode); 53 DEBUG_LOG(FILESYS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex);
54 File_SDMC* file = new File_SDMC(this, path, mode); 54 File_SDMC* file = new File_SDMC(this, path, mode);
55 if (!file->Open()) 55 if (!file->Open())
56 return nullptr; 56 return nullptr;
@@ -58,6 +58,24 @@ std::unique_ptr<File> Archive_SDMC::OpenFile(const Path& path, const Mode mode)
58} 58}
59 59
60/** 60/**
61 * Delete a file specified by its path
62 * @param path Path relative to the archive
63 * @return Whether the file could be deleted
64 */
65bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const {
66 return FileUtil::Delete(GetMountPoint() + path.AsString());
67}
68
69/**
70 * Delete a directory specified by its path
71 * @param path Path relative to the archive
72 * @return Whether the directory could be deleted
73 */
74bool Archive_SDMC::DeleteDirectory(const FileSys::Path& path) const {
75 return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
76}
77
78/**
61 * Create a directory specified by its path 79 * Create a directory specified by its path
62 * @param path Path relative to the archive 80 * @param path Path relative to the archive
63 * @return Whether the directory could be created 81 * @return Whether the directory could be created
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 17b9209b4..74ce29c0d 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -41,6 +41,20 @@ public:
41 std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override; 41 std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override;
42 42
43 /** 43 /**
44 * Delete a file specified by its path
45 * @param path Path relative to the archive
46 * @return Whether the file could be deleted
47 */
48 bool DeleteFile(const FileSys::Path& path) const override;
49
50 /**
51 * Delete a directory specified by its path
52 * @param path Path relative to the archive
53 * @return Whether the directory could be deleted
54 */
55 bool DeleteDirectory(const FileSys::Path& path) const override;
56
57 /**
44 * Create a directory specified by its path 58 * Create a directory specified by its path
45 * @param path Path relative to the archive 59 * @param path Path relative to the archive
46 * @return Whether the directory could be created 60 * @return Whether the directory could be created
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 2b21657da..db571b895 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -25,22 +25,17 @@ public:
25 25
26 std::string name; ///< Name of address arbiter object (optional) 26 std::string name; ///< Name of address arbiter object (optional)
27 27
28 /** 28 ResultVal<bool> WaitSynchronization() override {
29 * Wait for kernel object to synchronize
30 * @param wait Boolean wait set if current thread should wait as a result of sync operation
31 * @return Result of operation, 0 on success, otherwise error code
32 */
33 Result WaitSynchronization(bool* wait) override {
34 // TODO(bunnei): ImplementMe 29 // TODO(bunnei): ImplementMe
35 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 30 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
36 return 0; 31 return UnimplementedFunction(ErrorModule::OS);
37 } 32 }
38}; 33};
39 34
40//////////////////////////////////////////////////////////////////////////////////////////////////// 35////////////////////////////////////////////////////////////////////////////////////////////////////
41 36
42/// Arbitrate an address 37/// Arbitrate an address
43Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { 38ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) {
44 switch (type) { 39 switch (type) {
45 40
46 // Signal thread(s) waiting for arbitrate address... 41 // Signal thread(s) waiting for arbitrate address...
@@ -65,9 +60,9 @@ Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 va
65 60
66 default: 61 default:
67 ERROR_LOG(KERNEL, "unknown type=%d", type); 62 ERROR_LOG(KERNEL, "unknown type=%d", type);
68 return -1; 63 return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage);
69 } 64 }
70 return 0; 65 return RESULT_SUCCESS;
71} 66}
72 67
73/// Create an address arbiter 68/// Create an address arbiter
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 6886e479d..8a5fb10b4 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -28,7 +28,7 @@ enum class ArbitrationType : u32 {
28}; 28};
29 29
30/// Arbitrate an address 30/// Arbitrate an address
31Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value); 31ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value);
32 32
33/// Create an address arbiter 33/// Create an address arbiter
34Handle CreateAddressArbiter(const std::string& name = "Unknown"); 34Handle CreateAddressArbiter(const std::string& name = "Unknown");
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
index d9ee4682a..e273444c9 100644
--- a/src/core/hle/kernel/archive.cpp
+++ b/src/core/hle/kernel/archive.cpp
@@ -9,8 +9,9 @@
9#include "core/file_sys/archive.h" 9#include "core/file_sys/archive.h"
10#include "core/file_sys/archive_sdmc.h" 10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory.h" 11#include "core/file_sys/directory.h"
12#include "core/hle/service/service.h"
13#include "core/hle/kernel/archive.h" 12#include "core/hle/kernel/archive.h"
13#include "core/hle/result.h"
14#include "core/hle/service/service.h"
14 15
15//////////////////////////////////////////////////////////////////////////////////////////////////// 16////////////////////////////////////////////////////////////////////////////////////////////////////
16// Kernel namespace 17// Kernel namespace
@@ -51,12 +52,7 @@ public:
51 std::string name; ///< Name of archive (optional) 52 std::string name; ///< Name of archive (optional)
52 FileSys::Archive* backend; ///< Archive backend interface 53 FileSys::Archive* backend; ///< Archive backend interface
53 54
54 /** 55 ResultVal<bool> SyncRequest() override {
55 * Synchronize kernel object
56 * @param wait Boolean wait set if current thread should wait as a result of sync operation
57 * @return Result of operation, 0 on success, otherwise error code
58 */
59 Result SyncRequest(bool* wait) override {
60 u32* cmd_buff = Service::GetCommandBuffer(); 56 u32* cmd_buff = Service::GetCommandBuffer();
61 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 57 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
62 58
@@ -106,22 +102,17 @@ public:
106 default: 102 default:
107 { 103 {
108 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 104 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
109 return -1; 105 return UnimplementedFunction(ErrorModule::FS);
110 } 106 }
111 } 107 }
112 cmd_buff[1] = 0; // No error 108 cmd_buff[1] = 0; // No error
113 return 0; 109 return MakeResult<bool>(false);
114 } 110 }
115 111
116 /** 112 ResultVal<bool> WaitSynchronization() override {
117 * Wait for kernel object to synchronize
118 * @param wait Boolean wait set if current thread should wait as a result of sync operation
119 * @return Result of operation, 0 on success, otherwise error code
120 */
121 Result WaitSynchronization(bool* wait) override {
122 // TODO(bunnei): ImplementMe 113 // TODO(bunnei): ImplementMe
123 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 114 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
124 return 0; 115 return UnimplementedFunction(ErrorModule::FS);
125 } 116 }
126}; 117};
127 118
@@ -136,12 +127,7 @@ public:
136 FileSys::Path path; ///< Path of the file 127 FileSys::Path path; ///< Path of the file
137 std::unique_ptr<FileSys::File> backend; ///< File backend interface 128 std::unique_ptr<FileSys::File> backend; ///< File backend interface
138 129
139 /** 130 ResultVal<bool> SyncRequest() override {
140 * Synchronize kernel object
141 * @param wait Boolean wait set if current thread should wait as a result of sync operation
142 * @return Result of operation, 0 on success, otherwise error code
143 */
144 Result SyncRequest(bool* wait) override {
145 u32* cmd_buff = Service::GetCommandBuffer(); 131 u32* cmd_buff = Service::GetCommandBuffer();
146 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 132 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
147 switch (cmd) { 133 switch (cmd) {
@@ -183,7 +169,8 @@ public:
183 case FileCommand::SetSize: 169 case FileCommand::SetSize:
184 { 170 {
185 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); 171 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
186 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); 172 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu",
173 GetTypeName().c_str(), GetName().c_str(), size);
187 backend->SetSize(size); 174 backend->SetSize(size);
188 break; 175 break;
189 } 176 }
@@ -198,22 +185,18 @@ public:
198 // Unknown command... 185 // Unknown command...
199 default: 186 default:
200 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 187 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
201 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. 188 ResultCode error = UnimplementedFunction(ErrorModule::FS);
202 return -1; 189 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
190 return error;
203 } 191 }
204 cmd_buff[1] = 0; // No error 192 cmd_buff[1] = 0; // No error
205 return 0; 193 return MakeResult<bool>(false);
206 } 194 }
207 195
208 /** 196 ResultVal<bool> WaitSynchronization() override {
209 * Wait for kernel object to synchronize
210 * @param wait Boolean wait set if current thread should wait as a result of sync operation
211 * @return Result of operation, 0 on success, otherwise error code
212 */
213 Result WaitSynchronization(bool* wait) override {
214 // TODO(bunnei): ImplementMe 197 // TODO(bunnei): ImplementMe
215 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 198 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
216 return 0; 199 return UnimplementedFunction(ErrorModule::FS);
217 } 200 }
218}; 201};
219 202
@@ -228,12 +211,7 @@ public:
228 FileSys::Path path; ///< Path of the directory 211 FileSys::Path path; ///< Path of the directory
229 std::unique_ptr<FileSys::Directory> backend; ///< File backend interface 212 std::unique_ptr<FileSys::Directory> backend; ///< File backend interface
230 213
231 /** 214 ResultVal<bool> SyncRequest() override {
232 * Synchronize kernel object
233 * @param wait Boolean wait set if current thread should wait as a result of sync operation
234 * @return Result of operation, 0 on success, otherwise error code
235 */
236 Result SyncRequest(bool* wait) override {
237 u32* cmd_buff = Service::GetCommandBuffer(); 215 u32* cmd_buff = Service::GetCommandBuffer();
238 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); 216 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
239 switch (cmd) { 217 switch (cmd) {
@@ -243,8 +221,9 @@ public:
243 { 221 {
244 u32 count = cmd_buff[1]; 222 u32 count = cmd_buff[1];
245 u32 address = cmd_buff[3]; 223 u32 address = cmd_buff[3];
246 FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); 224 auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
247 DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); 225 DEBUG_LOG(KERNEL, "Read %s %s: count=%d",
226 GetTypeName().c_str(), GetName().c_str(), count);
248 227
249 // Number of entries actually read 228 // Number of entries actually read
250 cmd_buff[2] = backend->Read(count, entries); 229 cmd_buff[2] = backend->Read(count, entries);
@@ -261,22 +240,18 @@ public:
261 // Unknown command... 240 // Unknown command...
262 default: 241 default:
263 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 242 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
264 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. 243 ResultCode error = UnimplementedFunction(ErrorModule::FS);
265 return -1; 244 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
245 return error;
266 } 246 }
267 cmd_buff[1] = 0; // No error 247 cmd_buff[1] = 0; // No error
268 return 0; 248 return MakeResult<bool>(false);
269 } 249 }
270 250
271 /** 251 ResultVal<bool> WaitSynchronization() override {
272 * Wait for kernel object to synchronize
273 * @param wait Boolean wait set if current thread should wait as a result of sync operation
274 * @return Result of operation, 0 on success, otherwise error code
275 */
276 Result WaitSynchronization(bool* wait) override {
277 // TODO(bunnei): ImplementMe 252 // TODO(bunnei): ImplementMe
278 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 253 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
279 return 0; 254 return UnimplementedFunction(ErrorModule::FS);
280 } 255 }
281}; 256};
282 257
@@ -284,89 +259,58 @@ public:
284 259
285std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode 260std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode
286 261
287/** 262ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) {
288 * Opens an archive
289 * @param id_code IdCode of the archive to open
290 * @return Handle to archive if it exists, otherwise a null handle (0)
291 */
292Handle OpenArchive(FileSys::Archive::IdCode id_code) {
293 auto itr = g_archive_map.find(id_code); 263 auto itr = g_archive_map.find(id_code);
294 if (itr == g_archive_map.end()) { 264 if (itr == g_archive_map.end()) {
295 return 0; 265 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
266 ErrorSummary::NotFound, ErrorLevel::Permanent);
296 } 267 }
297 return itr->second; 268
269 return MakeResult<Handle>(itr->second);
298} 270}
299 271
300/** 272ResultCode CloseArchive(FileSys::Archive::IdCode id_code) {
301 * Closes an archive
302 * @param id_code IdCode of the archive to open
303 * @return Result of operation, 0 on success, otherwise error code
304 */
305Result CloseArchive(FileSys::Archive::IdCode id_code) {
306 auto itr = g_archive_map.find(id_code); 273 auto itr = g_archive_map.find(id_code);
307 if (itr == g_archive_map.end()) { 274 if (itr == g_archive_map.end()) {
308 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); 275 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code);
309 return -1; 276 return InvalidHandle(ErrorModule::FS);
310 } 277 }
311 278
312 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); 279 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code);
313 return 0; 280 return RESULT_SUCCESS;
314} 281}
315 282
316/** 283/**
317 * Mounts an archive 284 * Mounts an archive
318 * @param archive Pointer to the archive to mount 285 * @param archive Pointer to the archive to mount
319 * @return Result of operation, 0 on success, otherwise error code
320 */ 286 */
321Result MountArchive(Archive* archive) { 287ResultCode MountArchive(Archive* archive) {
322 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); 288 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode();
323 if (0 != OpenArchive(id_code)) { 289 ResultVal<Handle> archive_handle = OpenArchive(id_code);
290 if (archive_handle.Succeeded()) {
324 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); 291 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code);
325 return -1; 292 return archive_handle.Code();
326 } 293 }
327 g_archive_map[id_code] = archive->GetHandle(); 294 g_archive_map[id_code] = archive->GetHandle();
328 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); 295 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str());
329 return 0; 296 return RESULT_SUCCESS;
330} 297}
331 298
332/** 299ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) {
333 * Creates an Archive
334 * @param handle Handle to newly created archive object
335 * @param backend File system backend interface to the archive
336 * @param name Optional name of Archive
337 * @return Newly created Archive object
338 */
339Archive* CreateArchive(Handle& handle, FileSys::Archive* backend, const std::string& name) {
340 Archive* archive = new Archive; 300 Archive* archive = new Archive;
341 handle = Kernel::g_object_pool.Create(archive); 301 Handle handle = Kernel::g_object_pool.Create(archive);
342 archive->name = name; 302 archive->name = name;
343 archive->backend = backend; 303 archive->backend = backend;
344 304
345 MountArchive(archive); 305 ResultCode result = MountArchive(archive);
346 306 if (result.IsError()) {
347 return archive; 307 return result;
348} 308 }
349 309
350/** 310 return RESULT_SUCCESS;
351 * Creates an Archive
352 * @param backend File system backend interface to the archive
353 * @param name Optional name of Archive
354 * @return Handle to newly created Archive object
355 */
356Handle CreateArchive(FileSys::Archive* backend, const std::string& name) {
357 Handle handle;
358 CreateArchive(handle, backend, name);
359 return handle;
360} 311}
361 312
362/** 313ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
363 * Open a File from an Archive
364 * @param archive_handle Handle to an open Archive object
365 * @param path Path to the File inside of the Archive
366 * @param mode Mode under which to open the File
367 * @return Opened File object
368 */
369Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
370 // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create 314 // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create
371 // the archive file handles at app loading, and then keep them persistent throughout execution. 315 // the archive file handles at app loading, and then keep them persistent throughout execution.
372 // Archives file handles are just reused and not actually freed until emulation shut down. 316 // Archives file handles are just reused and not actually freed until emulation shut down.
@@ -376,26 +320,61 @@ Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, con
376 // design. While the functionally of this is OK, our implementation decision to separate 320 // design. While the functionally of this is OK, our implementation decision to separate
377 // normal files from archive file pointers is very likely wrong. 321 // normal files from archive file pointers is very likely wrong.
378 // See https://github.com/citra-emu/citra/issues/205 322 // See https://github.com/citra-emu/citra/issues/205
379 return archive_handle; 323 return MakeResult<Handle>(archive_handle);
380 324
381 File* file = new File; 325 File* file = new File;
382 Handle handle = Kernel::g_object_pool.Create(file); 326 Handle handle = Kernel::g_object_pool.Create(file);
383 327
384 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 328 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
329 if (archive == nullptr) {
330 return InvalidHandle(ErrorModule::FS);
331 }
385 file->path = path; 332 file->path = path;
386 file->backend = archive->backend->OpenFile(path, mode); 333 file->backend = archive->backend->OpenFile(path, mode);
387 334
388 if (!file->backend) 335 if (!file->backend) {
336 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
337 ErrorSummary::NotFound, ErrorLevel::Permanent);
338 }
339
340 return MakeResult<Handle>(handle);
341}
342
343/**
344 * Delete a File from an Archive
345 * @param archive_handle Handle to an open Archive object
346 * @param path Path to the File inside of the Archive
347 * @return Whether deletion succeeded
348 */
349Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) {
350 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
351 if (archive == nullptr)
352 return -1;
353 if (archive->backend->DeleteFile(path))
389 return 0; 354 return 0;
355 return -1;
356}
390 357
391 return handle; 358/**
359 * Delete a Directory from an Archive
360 * @param archive_handle Handle to an open Archive object
361 * @param path Path to the Directory inside of the Archive
362 * @return Whether deletion succeeded
363 */
364Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
365 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
366 if (archive == nullptr)
367 return -1;
368 if (archive->backend->DeleteDirectory(path))
369 return 0;
370 return -1;
392} 371}
393 372
394/** 373/**
395 * Create a Directory from an Archive 374 * Create a Directory from an Archive
396 * @param archive_handle Handle to an open Archive object 375 * @param archive_handle Handle to an open Archive object
397 * @param path Path to the Directory inside of the Archive 376 * @param path Path to the Directory inside of the Archive
398 * @return Opened Directory object 377 * @return Whether creation succeeded
399 */ 378 */
400Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { 379Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
401 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 380 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
@@ -412,15 +391,18 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa
412 * @param path Path to the Directory inside of the Archive 391 * @param path Path to the Directory inside of the Archive
413 * @return Opened Directory object 392 * @return Opened Directory object
414 */ 393 */
415Handle OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { 394ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
416 Directory* directory = new Directory; 395 Directory* directory = new Directory;
417 Handle handle = Kernel::g_object_pool.Create(directory); 396 Handle handle = Kernel::g_object_pool.Create(directory);
418 397
419 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 398 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
399 if (archive == nullptr) {
400 return InvalidHandle(ErrorModule::FS);
401 }
420 directory->path = path; 402 directory->path = path;
421 directory->backend = archive->backend->OpenDirectory(path); 403 directory->backend = archive->backend->OpenDirectory(path);
422 404
423 return handle; 405 return MakeResult<Handle>(handle);
424} 406}
425 407
426/// Initialize archives 408/// Initialize archives
diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h
index 9c6015506..6fc4f0f25 100644
--- a/src/core/hle/kernel/archive.h
+++ b/src/core/hle/kernel/archive.h
@@ -6,8 +6,9 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/hle/kernel/kernel.h"
10#include "core/file_sys/archive.h" 9#include "core/file_sys/archive.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/result.h"
11 12
12//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
13// Kernel namespace 14// Kernel namespace
@@ -17,33 +18,47 @@ namespace Kernel {
17/** 18/**
18 * Opens an archive 19 * Opens an archive
19 * @param id_code IdCode of the archive to open 20 * @param id_code IdCode of the archive to open
20 * @return Handle to archive if it exists, otherwise a null handle (0) 21 * @return Handle to the opened archive
21 */ 22 */
22Handle OpenArchive(FileSys::Archive::IdCode id_code); 23ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code);
23 24
24/** 25/**
25 * Closes an archive 26 * Closes an archive
26 * @param id_code IdCode of the archive to open 27 * @param id_code IdCode of the archive to open
27 * @return true if it worked fine
28 */ 28 */
29Result CloseArchive(FileSys::Archive::IdCode id_code); 29ResultCode CloseArchive(FileSys::Archive::IdCode id_code);
30 30
31/** 31/**
32 * Creates an Archive 32 * Creates an Archive
33 * @param backend File system backend interface to the archive 33 * @param backend File system backend interface to the archive
34 * @param name Optional name of Archive 34 * @param name Name of Archive
35 * @return Handle to newly created Archive object
36 */ 35 */
37Handle CreateArchive(FileSys::Archive* backend, const std::string& name); 36ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name);
38 37
39/** 38/**
40 * Open a File from an Archive 39 * Open a File from an Archive
41 * @param archive_handle Handle to an open Archive object 40 * @param archive_handle Handle to an open Archive object
42 * @param path Path to the File inside of the Archive 41 * @param path Path to the File inside of the Archive
43 * @param mode Mode under which to open the File 42 * @param mode Mode under which to open the File
44 * @return Opened File object 43 * @return Handle to the opened File object
44 */
45ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode);
46
47/**
48 * Delete a File from an Archive
49 * @param archive_handle Handle to an open Archive object
50 * @param path Path to the File inside of the Archive
51 * @return Whether deletion succeeded
52 */
53Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path);
54
55/**
56 * Delete a Directory from an Archive
57 * @param archive_handle Handle to an open Archive object
58 * @param path Path to the Directory inside of the Archive
59 * @return Whether deletion succeeded
45 */ 60 */
46Handle OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); 61Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
47 62
48/** 63/**
49 * Create a Directory from an Archive 64 * Create a Directory from an Archive
@@ -57,9 +72,9 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& pa
57 * Open a Directory from an Archive 72 * Open a Directory from an Archive
58 * @param archive_handle Handle to an open Archive object 73 * @param archive_handle Handle to an open Archive object
59 * @param path Path to the Directory inside of the Archive 74 * @param path Path to the Directory inside of the Archive
60 * @return Opened Directory object 75 * @return Handle to the opened File object
61 */ 76 */
62Handle OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); 77ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
63 78
64/// Initialize archives 79/// Initialize archives
65void ArchiveInit(); 80void ArchiveInit();
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index e0117c0bc..288080209 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -30,13 +30,8 @@ public:
30 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event 30 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event
31 std::string name; ///< Name of event (optional) 31 std::string name; ///< Name of event (optional)
32 32
33 /** 33 ResultVal<bool> WaitSynchronization() override {
34 * Wait for kernel object to synchronize 34 bool wait = locked;
35 * @param wait Boolean wait set if current thread should wait as a result of sync operation
36 * @return Result of operation, 0 on success, otherwise error code
37 */
38 Result WaitSynchronization(bool* wait) override {
39 *wait = locked;
40 if (locked) { 35 if (locked) {
41 Handle thread = GetCurrentThreadHandle(); 36 Handle thread = GetCurrentThreadHandle();
42 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { 37 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
@@ -47,7 +42,7 @@ public:
47 if (reset_type != RESETTYPE_STICKY && !permanent_locked) { 42 if (reset_type != RESETTYPE_STICKY && !permanent_locked) {
48 locked = true; 43 locked = true;
49 } 44 }
50 return 0; 45 return MakeResult<bool>(wait);
51 } 46 }
52}; 47};
53 48
@@ -57,12 +52,12 @@ public:
57 * @param permanent_locked Boolean permanent locked value to set event 52 * @param permanent_locked Boolean permanent locked value to set event
58 * @return Result of operation, 0 on success, otherwise error code 53 * @return Result of operation, 0 on success, otherwise error code
59 */ 54 */
60Result SetPermanentLock(Handle handle, const bool permanent_locked) { 55ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) {
61 Event* evt = g_object_pool.GetFast<Event>(handle); 56 Event* evt = g_object_pool.Get<Event>(handle);
62 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 57 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
63 58
64 evt->permanent_locked = permanent_locked; 59 evt->permanent_locked = permanent_locked;
65 return 0; 60 return RESULT_SUCCESS;
66} 61}
67 62
68/** 63/**
@@ -71,14 +66,14 @@ Result SetPermanentLock(Handle handle, const bool permanent_locked) {
71 * @param locked Boolean locked value to set event 66 * @param locked Boolean locked value to set event
72 * @return Result of operation, 0 on success, otherwise error code 67 * @return Result of operation, 0 on success, otherwise error code
73 */ 68 */
74Result SetEventLocked(const Handle handle, const bool locked) { 69ResultCode SetEventLocked(const Handle handle, const bool locked) {
75 Event* evt = g_object_pool.GetFast<Event>(handle); 70 Event* evt = g_object_pool.Get<Event>(handle);
76 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 71 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
77 72
78 if (!evt->permanent_locked) { 73 if (!evt->permanent_locked) {
79 evt->locked = locked; 74 evt->locked = locked;
80 } 75 }
81 return 0; 76 return RESULT_SUCCESS;
82} 77}
83 78
84/** 79/**
@@ -86,9 +81,9 @@ Result SetEventLocked(const Handle handle, const bool locked) {
86 * @param handle Handle to event to signal 81 * @param handle Handle to event to signal
87 * @return Result of operation, 0 on success, otherwise error code 82 * @return Result of operation, 0 on success, otherwise error code
88 */ 83 */
89Result SignalEvent(const Handle handle) { 84ResultCode SignalEvent(const Handle handle) {
90 Event* evt = g_object_pool.GetFast<Event>(handle); 85 Event* evt = g_object_pool.Get<Event>(handle);
91 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 86 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
92 87
93 // Resume threads waiting for event to signal 88 // Resume threads waiting for event to signal
94 bool event_caught = false; 89 bool event_caught = false;
@@ -106,7 +101,7 @@ Result SignalEvent(const Handle handle) {
106 if (!evt->permanent_locked) { 101 if (!evt->permanent_locked) {
107 evt->locked = event_caught; 102 evt->locked = event_caught;
108 } 103 }
109 return 0; 104 return RESULT_SUCCESS;
110} 105}
111 106
112/** 107/**
@@ -114,14 +109,14 @@ Result SignalEvent(const Handle handle) {
114 * @param handle Handle to event to clear 109 * @param handle Handle to event to clear
115 * @return Result of operation, 0 on success, otherwise error code 110 * @return Result of operation, 0 on success, otherwise error code
116 */ 111 */
117Result ClearEvent(Handle handle) { 112ResultCode ClearEvent(Handle handle) {
118 Event* evt = g_object_pool.GetFast<Event>(handle); 113 Event* evt = g_object_pool.Get<Event>(handle);
119 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 114 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
120 115
121 if (!evt->permanent_locked) { 116 if (!evt->permanent_locked) {
122 evt->locked = true; 117 evt->locked = true;
123 } 118 }
124 return 0; 119 return RESULT_SUCCESS;
125} 120}
126 121
127/** 122/**
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 6add72897..73aec4e79 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -15,31 +15,27 @@ namespace Kernel {
15 * Changes whether an event is locked or not 15 * Changes whether an event is locked or not
16 * @param handle Handle to event to change 16 * @param handle Handle to event to change
17 * @param locked Boolean locked value to set event 17 * @param locked Boolean locked value to set event
18 * @return Result of operation, 0 on success, otherwise error code
19 */ 18 */
20Result SetEventLocked(const Handle handle, const bool locked); 19ResultCode SetEventLocked(const Handle handle, const bool locked);
21 20
22/** 21/**
23 * Hackish function to set an events permanent lock state, used to pass through synch blocks 22 * Hackish function to set an events permanent lock state, used to pass through synch blocks
24 * @param handle Handle to event to change 23 * @param handle Handle to event to change
25 * @param permanent_locked Boolean permanent locked value to set event 24 * @param permanent_locked Boolean permanent locked value to set event
26 * @return Result of operation, 0 on success, otherwise error code
27 */ 25 */
28Result SetPermanentLock(Handle handle, const bool permanent_locked); 26ResultCode SetPermanentLock(Handle handle, const bool permanent_locked);
29 27
30/** 28/**
31 * Signals an event 29 * Signals an event
32 * @param handle Handle to event to signal 30 * @param handle Handle to event to signal
33 * @return Result of operation, 0 on success, otherwise error code
34 */ 31 */
35Result SignalEvent(const Handle handle); 32ResultCode SignalEvent(const Handle handle);
36 33
37/** 34/**
38 * Clears an event 35 * Clears an event
39 * @param handle Handle to event to clear 36 * @param handle Handle to event to clear
40 * @return Result of operation, 0 on success, otherwise error code
41 */ 37 */
42Result ClearEvent(Handle handle); 38ResultCode ClearEvent(Handle handle);
43 39
44/** 40/**
45 * Creates an event 41 * Creates an event
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index e0c94f186..8d3937ce8 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <string> 8#include <string>
9#include "common/common.h" 9#include "common/common.h"
10#include "core/hle/result.h"
10 11
11typedef u32 Handle; 12typedef u32 Handle;
12typedef s32 Result; 13typedef s32 Result;
@@ -52,21 +53,19 @@ public:
52 virtual Kernel::HandleType GetHandleType() const = 0; 53 virtual Kernel::HandleType GetHandleType() const = 0;
53 54
54 /** 55 /**
55 * Synchronize kernel object 56 * Synchronize kernel object.
56 * @param wait Boolean wait set if current thread should wait as a result of sync operation 57 * @return True if the current thread should wait as a result of the sync
57 * @return Result of operation, 0 on success, otherwise error code
58 */ 58 */
59 virtual Result SyncRequest(bool* wait) { 59 virtual ResultVal<bool> SyncRequest() {
60 ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); 60 ERROR_LOG(KERNEL, "(UNIMPLEMENTED)");
61 return -1; 61 return UnimplementedFunction(ErrorModule::Kernel);
62 } 62 }
63 63
64 /** 64 /**
65 * Wait for kernel object to synchronize 65 * Wait for kernel object to synchronize.
66 * @param wait Boolean wait set if current thread should wait as a result of sync operation 66 * @return True if the current thread should wait as a result of the wait
67 * @return Result of operation, 0 on success, otherwise error code
68 */ 67 */
69 virtual Result WaitSynchronization(bool* wait) = 0; 68 virtual ResultVal<bool> WaitSynchronization() = 0;
70}; 69};
71 70
72class ObjectPool : NonCopyable { 71class ObjectPool : NonCopyable {
@@ -80,38 +79,29 @@ public:
80 static Object* CreateByIDType(int type); 79 static Object* CreateByIDType(int type);
81 80
82 template <class T> 81 template <class T>
83 u32 Destroy(Handle handle) { 82 void Destroy(Handle handle) {
84 u32 error; 83 if (Get<T>(handle)) {
85 if (Get<T>(handle, error)) {
86 occupied[handle - HANDLE_OFFSET] = false; 84 occupied[handle - HANDLE_OFFSET] = false;
87 delete pool[handle - HANDLE_OFFSET]; 85 delete pool[handle - HANDLE_OFFSET];
88 } 86 }
89 return error;
90 } 87 }
91 88
92 bool IsValid(Handle handle); 89 bool IsValid(Handle handle);
93 90
94 template <class T> 91 template <class T>
95 T* Get(Handle handle, u32& outError) { 92 T* Get(Handle handle) {
96 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { 93 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) {
97 // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP 94 if (handle != 0) {
98 if (handle != 0 && (u32)handle != 0x80020001) {
99 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); 95 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
100 } 96 }
101 outError = 0;//T::GetMissingErrorCode(); 97 return nullptr;
102 return 0;
103 } else { 98 } else {
104 // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally, 99 Object* t = pool[handle - HANDLE_OFFSET];
105 // it just acted as a static case and everything worked. This means that we will never 100 if (t->GetHandleType() != T::GetStaticHandleType()) {
106 // see the Wrong type object error below, but we'll just have to live with that danger.
107 T* t = static_cast<T*>(pool[handle - HANDLE_OFFSET]);
108 if (t == 0 || t->GetHandleType() != T::GetStaticHandleType()) {
109 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); 101 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle);
110 outError = 0;//T::GetMissingErrorCode(); 102 return nullptr;
111 return 0;
112 } 103 }
113 outError = 0;//SCE_KERNEL_ERROR_OK; 104 return static_cast<T*>(t);
114 return t;
115 } 105 }
116 } 106 }
117 107
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 31129fd86..d07e9761b 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -27,31 +27,20 @@ public:
27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex 27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
28 std::string name; ///< Name of mutex (optional) 28 std::string name; ///< Name of mutex (optional)
29 29
30 /** 30 ResultVal<bool> SyncRequest() override {
31 * Synchronize kernel object
32 * @param wait Boolean wait set if current thread should wait as a result of sync operation
33 * @return Result of operation, 0 on success, otherwise error code
34 */
35 Result SyncRequest(bool* wait) override {
36 // TODO(bunnei): ImplementMe 31 // TODO(bunnei): ImplementMe
37 locked = true; 32 locked = true;
38 return 0; 33 return MakeResult<bool>(false);
39 } 34 }
40 35
41 /** 36 ResultVal<bool> WaitSynchronization() override {
42 * Wait for kernel object to synchronize
43 * @param wait Boolean wait set if current thread should wait as a result of sync operation
44 * @return Result of operation, 0 on success, otherwise error code
45 */
46 Result WaitSynchronization(bool* wait) override {
47 // TODO(bunnei): ImplementMe 37 // TODO(bunnei): ImplementMe
48 *wait = locked; 38 bool wait = locked;
49
50 if (locked) { 39 if (locked) {
51 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle()); 40 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
52 } 41 }
53 42
54 return 0; 43 return MakeResult<bool>(wait);
55 } 44 }
56}; 45};
57 46
@@ -99,35 +88,36 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
99 88
100bool ReleaseMutex(Mutex* mutex) { 89bool ReleaseMutex(Mutex* mutex) {
101 MutexEraseLock(mutex); 90 MutexEraseLock(mutex);
102 bool woke_threads = false;
103 91
104 // Find the next waiting thread for the mutex... 92 // Find the next waiting thread for the mutex...
105 while (!woke_threads && !mutex->waiting_threads.empty()) { 93 while (!mutex->waiting_threads.empty()) {
106 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin(); 94 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
107 woke_threads |= ReleaseMutexForThread(mutex, *iter); 95 ReleaseMutexForThread(mutex, *iter);
108 mutex->waiting_threads.erase(iter); 96 mutex->waiting_threads.erase(iter);
109 } 97 }
98
110 // Reset mutex lock thread handle, nothing is waiting 99 // Reset mutex lock thread handle, nothing is waiting
111 if (!woke_threads) { 100 mutex->locked = false;
112 mutex->locked = false; 101 mutex->lock_thread = -1;
113 mutex->lock_thread = -1; 102
114 } 103 return true;
115 return woke_threads;
116} 104}
117 105
118/** 106/**
119 * Releases a mutex 107 * Releases a mutex
120 * @param handle Handle to mutex to release 108 * @param handle Handle to mutex to release
121 */ 109 */
122Result ReleaseMutex(Handle handle) { 110ResultCode ReleaseMutex(Handle handle) {
123 Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); 111 Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle);
124 112 if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel);
125 _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!");
126 113
127 if (!ReleaseMutex(mutex)) { 114 if (!ReleaseMutex(mutex)) {
128 return -1; 115 // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure
116 // what error condition this is supposed to be signaling.
117 return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel,
118 ErrorSummary::NothingHappened, ErrorLevel::Temporary);
129 } 119 }
130 return 0; 120 return RESULT_SUCCESS;
131} 121}
132 122
133/** 123/**
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 313ba6fee..155449f95 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -13,9 +13,8 @@ namespace Kernel {
13/** 13/**
14 * Releases a mutex 14 * Releases a mutex
15 * @param handle Handle to mutex to release 15 * @param handle Handle to mutex to release
16 * @return Result of operation, 0 on success, otherwise error code
17 */ 16 */
18Result ReleaseMutex(Handle handle); 17ResultCode ReleaseMutex(Handle handle);
19 18
20/** 19/**
21 * Creates a mutex 20 * Creates a mutex
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 7ef3e54cc..cfcc0e0b7 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -16,15 +16,10 @@ public:
16 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } 16 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; }
17 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } 17 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; }
18 18
19 /** 19 ResultVal<bool> WaitSynchronization() override {
20 * Wait for kernel object to synchronize
21 * @param wait Boolean wait set if current thread should wait as a result of sync operation
22 * @return Result of operation, 0 on success, otherwise error code
23 */
24 Result WaitSynchronization(bool* wait) override {
25 // TODO(bunnei): ImplementMe 20 // TODO(bunnei): ImplementMe
26 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 21 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
27 return 0; 22 return UnimplementedFunction(ErrorModule::OS);
28 } 23 }
29 24
30 u32 base_address; ///< Address of shared memory block in RAM 25 u32 base_address; ///< Address of shared memory block in RAM
@@ -48,11 +43,6 @@ SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) {
48 return shared_memory; 43 return shared_memory;
49} 44}
50 45
51/**
52 * Creates a shared memory object
53 * @param name Optional name of shared memory object
54 * @return Handle of newly created shared memory object
55 */
56Handle CreateSharedMemory(const std::string& name) { 46Handle CreateSharedMemory(const std::string& name) {
57 Handle handle; 47 Handle handle;
58 CreateSharedMemory(handle, name); 48 CreateSharedMemory(handle, name);
@@ -67,39 +57,36 @@ Handle CreateSharedMemory(const std::string& name) {
67 * @param other_permissions Memory block map other permissions (specified by SVC field) 57 * @param other_permissions Memory block map other permissions (specified by SVC field)
68 * @return Result of operation, 0 on success, otherwise error code 58 * @return Result of operation, 0 on success, otherwise error code
69 */ 59 */
70Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, 60ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions,
71 MemoryPermission other_permissions) { 61 MemoryPermission other_permissions) {
72 62
73 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { 63 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) {
74 ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", 64 ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!",
75 handle, address); 65 handle, address);
76 return -1; 66 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
67 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
77 } 68 }
78 SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); 69 SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle);
79 _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); 70 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
80 71
81 shared_memory->base_address = address; 72 shared_memory->base_address = address;
82 shared_memory->permissions = permissions; 73 shared_memory->permissions = permissions;
83 shared_memory->other_permissions = other_permissions; 74 shared_memory->other_permissions = other_permissions;
84 75
85 return 0; 76 return RESULT_SUCCESS;
86} 77}
87 78
88/** 79ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) {
89 * Gets a pointer to the shared memory block 80 SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle);
90 * @param handle Shared memory block handle 81 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
91 * @param offset Offset from the start of the shared memory block to get pointer
92 * @return Pointer to the shared memory block from the specified offset
93 */
94u8* GetSharedMemoryPointer(Handle handle, u32 offset) {
95 SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle);
96 _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle);
97 82
98 if (0 != shared_memory->base_address) 83 if (0 != shared_memory->base_address)
99 return Memory::GetPointer(shared_memory->base_address + offset); 84 return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset));
100 85
101 ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle); 86 ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle);
102 return nullptr; 87 // TODO(yuriks): Verify error code.
88 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
89 ErrorSummary::InvalidState, ErrorLevel::Permanent);
103} 90}
104 91
105} // namespace 92} // namespace
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 0aec03538..304cf5b67 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -32,9 +32,8 @@ Handle CreateSharedMemory(const std::string& name="Unknown");
32 * @param address Address in system memory to map shared memory block to 32 * @param address Address in system memory to map shared memory block to
33 * @param permissions Memory block map permissions (specified by SVC field) 33 * @param permissions Memory block map permissions (specified by SVC field)
34 * @param other_permissions Memory block map other permissions (specified by SVC field) 34 * @param other_permissions Memory block map other permissions (specified by SVC field)
35 * @return Result of operation, 0 on success, otherwise error code
36 */ 35 */
37Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, 36ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions,
38 MemoryPermission other_permissions); 37 MemoryPermission other_permissions);
39 38
40/** 39/**
@@ -43,6 +42,6 @@ Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions,
43 * @param offset Offset from the start of the shared memory block to get pointer 42 * @param offset Offset from the start of the shared memory block to get pointer
44 * @return Pointer to the shared memory block from the specified offset 43 * @return Pointer to the shared memory block from the specified offset
45 */ 44 */
46u8* GetSharedMemoryPointer(Handle handle, u32 offset); 45ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset);
47 46
48} // namespace 47} // namespace
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index cc70cbca7..f59795901 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -11,10 +11,11 @@
11#include "common/thread_queue_list.h" 11#include "common/thread_queue_list.h"
12 12
13#include "core/core.h" 13#include "core/core.h"
14#include "core/mem_map.h"
15#include "core/hle/hle.h" 14#include "core/hle/hle.h"
16#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
17#include "core/hle/result.h"
18#include "core/mem_map.h"
18 19
19namespace Kernel { 20namespace Kernel {
20 21
@@ -33,21 +34,17 @@ public:
33 inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } 34 inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
34 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } 35 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
35 36
36 /** 37 ResultVal<bool> WaitSynchronization() override {
37 * Wait for kernel object to synchronize 38 const bool wait = status != THREADSTATUS_DORMANT;
38 * @param wait Boolean wait set if current thread should wait as a result of sync operation 39 if (wait) {
39 * @return Result of operation, 0 on success, otherwise error code
40 */
41 Result WaitSynchronization(bool* wait) override {
42 if (status != THREADSTATUS_DORMANT) {
43 Handle thread = GetCurrentThreadHandle(); 40 Handle thread = GetCurrentThreadHandle();
44 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { 41 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
45 waiting_threads.push_back(thread); 42 waiting_threads.push_back(thread);
46 } 43 }
47 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); 44 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle());
48 *wait = true;
49 } 45 }
50 return 0; 46
47 return MakeResult<bool>(wait);
51 } 48 }
52 49
53 ThreadContext context; 50 ThreadContext context;
@@ -144,27 +141,22 @@ void ChangeReadyState(Thread* t, bool ready) {
144} 141}
145 142
146/// Verify that a thread has not been released from waiting 143/// Verify that a thread has not been released from waiting
147inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) { 144inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) {
148 Thread* thread = g_object_pool.GetFast<Thread>(handle); 145 _dbg_assert_(KERNEL, thread != nullptr);
149 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 146 return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting());
150
151 if (type != thread->wait_type || wait_handle != thread->wait_handle)
152 return false;
153
154 return true;
155} 147}
156 148
157/// Stops the current thread 149/// Stops the current thread
158void StopThread(Handle handle, const char* reason) { 150ResultCode StopThread(Handle handle, const char* reason) {
159 Thread* thread = g_object_pool.GetFast<Thread>(handle); 151 Thread* thread = g_object_pool.Get<Thread>(handle);
160 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 152 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
161 153
162 ChangeReadyState(thread, false); 154 ChangeReadyState(thread, false);
163 thread->status = THREADSTATUS_DORMANT; 155 thread->status = THREADSTATUS_DORMANT;
164 for (size_t i = 0; i < thread->waiting_threads.size(); ++i) { 156 for (Handle waiting_handle : thread->waiting_threads) {
165 const Handle waiting_thread = thread->waiting_threads[i]; 157 Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle);
166 if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { 158 if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) {
167 ResumeThreadFromWait(waiting_thread); 159 ResumeThreadFromWait(waiting_handle);
168 } 160 }
169 } 161 }
170 thread->waiting_threads.clear(); 162 thread->waiting_threads.clear();
@@ -172,6 +164,8 @@ void StopThread(Handle handle, const char* reason) {
172 // Stopped threads are never waiting. 164 // Stopped threads are never waiting.
173 thread->wait_type = WAITTYPE_NONE; 165 thread->wait_type = WAITTYPE_NONE;
174 thread->wait_handle = 0; 166 thread->wait_handle = 0;
167
168 return RESULT_SUCCESS;
175} 169}
176 170
177/// Changes a threads state 171/// Changes a threads state
@@ -195,13 +189,15 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
195 s32 priority = THREADPRIO_LOWEST; 189 s32 priority = THREADPRIO_LOWEST;
196 190
197 // Iterate through threads, find highest priority thread that is waiting to be arbitrated... 191 // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
198 for (const auto& handle : thread_queue) { 192 for (Handle handle : thread_queue) {
193 Thread* thread = g_object_pool.Get<Thread>(handle);
199 194
200 // TODO(bunnei): Verify arbiter address... 195 // TODO(bunnei): Verify arbiter address...
201 if (!VerifyWait(handle, WAITTYPE_ARB, arbiter)) 196 if (!VerifyWait(thread, WAITTYPE_ARB, arbiter))
202 continue; 197 continue;
203 198
204 Thread* thread = g_object_pool.GetFast<Thread>(handle); 199 if (thread == nullptr)
200 continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up.
205 if(thread->current_priority <= priority) { 201 if(thread->current_priority <= priority) {
206 highest_priority_thread = handle; 202 highest_priority_thread = handle;
207 priority = thread->current_priority; 203 priority = thread->current_priority;
@@ -218,10 +214,11 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
218void ArbitrateAllThreads(u32 arbiter, u32 address) { 214void ArbitrateAllThreads(u32 arbiter, u32 address) {
219 215
220 // Iterate through threads, find highest priority thread that is waiting to be arbitrated... 216 // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
221 for (const auto& handle : thread_queue) { 217 for (Handle handle : thread_queue) {
218 Thread* thread = g_object_pool.Get<Thread>(handle);
222 219
223 // TODO(bunnei): Verify arbiter address... 220 // TODO(bunnei): Verify arbiter address...
224 if (VerifyWait(handle, WAITTYPE_ARB, arbiter)) 221 if (VerifyWait(thread, WAITTYPE_ARB, arbiter))
225 ResumeThreadFromWait(handle); 222 ResumeThreadFromWait(handle);
226 } 223 }
227} 224}
@@ -272,7 +269,7 @@ Thread* NextThread() {
272 if (next == 0) { 269 if (next == 0) {
273 return nullptr; 270 return nullptr;
274 } 271 }
275 return Kernel::g_object_pool.GetFast<Thread>(next); 272 return Kernel::g_object_pool.Get<Thread>(next);
276} 273}
277 274
278/** 275/**
@@ -289,8 +286,7 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
289 286
290/// Resumes a thread from waiting by marking it as "ready" 287/// Resumes a thread from waiting by marking it as "ready"
291void ResumeThreadFromWait(Handle handle) { 288void ResumeThreadFromWait(Handle handle) {
292 u32 error; 289 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
293 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
294 if (thread) { 290 if (thread) {
295 thread->status &= ~THREADSTATUS_WAIT; 291 thread->status &= ~THREADSTATUS_WAIT;
296 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { 292 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
@@ -378,19 +374,23 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
378} 374}
379 375
380/// Get the priority of the thread specified by handle 376/// Get the priority of the thread specified by handle
381u32 GetThreadPriority(const Handle handle) { 377ResultVal<u32> GetThreadPriority(const Handle handle) {
382 Thread* thread = g_object_pool.GetFast<Thread>(handle); 378 Thread* thread = g_object_pool.Get<Thread>(handle);
383 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 379 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
384 return thread->current_priority; 380
381 return MakeResult<u32>(thread->current_priority);
385} 382}
386 383
387/// Set the priority of the thread specified by handle 384/// Set the priority of the thread specified by handle
388Result SetThreadPriority(Handle handle, s32 priority) { 385ResultCode SetThreadPriority(Handle handle, s32 priority) {
389 Thread* thread = nullptr; 386 Thread* thread = nullptr;
390 if (!handle) { 387 if (!handle) {
391 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? 388 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
392 } else { 389 } else {
393 thread = g_object_pool.GetFast<Thread>(handle); 390 thread = g_object_pool.Get<Thread>(handle);
391 if (thread == nullptr) {
392 return InvalidHandle(ErrorModule::Kernel);
393 }
394 } 394 }
395 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 395 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
396 396
@@ -417,7 +417,7 @@ Result SetThreadPriority(Handle handle, s32 priority) {
417 thread_ready_queue.push_back(thread->current_priority, handle); 417 thread_ready_queue.push_back(thread->current_priority, handle);
418 } 418 }
419 419
420 return 0; 420 return RESULT_SUCCESS;
421} 421}
422 422
423/// Sets up the primary application thread 423/// Sets up the primary application thread
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 2a43797ee..ce63a70d3 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -6,6 +6,7 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
9#include "core/hle/result.h"
9 10
10enum ThreadPriority { 11enum ThreadPriority {
11 THREADPRIO_HIGHEST = 0, ///< Highest thread priority 12 THREADPRIO_HIGHEST = 0, ///< Highest thread priority
@@ -55,7 +56,7 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
55void Reschedule(); 56void Reschedule();
56 57
57/// Stops the current thread 58/// Stops the current thread
58void StopThread(Handle thread, const char* reason); 59ResultCode StopThread(Handle thread, const char* reason);
59 60
60/// Resumes a thread from waiting by marking it as "ready" 61/// Resumes a thread from waiting by marking it as "ready"
61void ResumeThreadFromWait(Handle handle); 62void ResumeThreadFromWait(Handle handle);
@@ -80,10 +81,10 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHa
80void WaitThread_Synchronization(); 81void WaitThread_Synchronization();
81 82
82/// Get the priority of the thread specified by handle 83/// Get the priority of the thread specified by handle
83u32 GetThreadPriority(const Handle handle); 84ResultVal<u32> GetThreadPriority(const Handle handle);
84 85
85/// Set the priority of the thread specified by handle 86/// Set the priority of the thread specified by handle
86Result SetThreadPriority(Handle handle, s32 priority); 87ResultCode SetThreadPriority(Handle handle, s32 priority);
87 88
88/// Initialize threading 89/// Initialize threading
89void ThreadingInit(); 90void ThreadingInit();
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
new file mode 100644
index 000000000..15c4a2677
--- /dev/null
+++ b/src/core/hle/result.h
@@ -0,0 +1,400 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cassert>
8#include <cstddef>
9#include <type_traits>
10#include <utility>
11
12#include "common/common_types.h"
13#include "common/bit_field.h"
14
15// All the constants in this file come from http://3dbrew.org/wiki/Error_codes
16
17/// Detailed description of the error. This listing is likely incomplete.
18enum class ErrorDescription : u32 {
19 Success = 0,
20 InvalidSection = 1000,
21 TooLarge = 1001,
22 NotAuthorized = 1002,
23 AlreadyDone = 1003,
24 InvalidSize = 1004,
25 InvalidEnumValue = 1005,
26 InvalidCombination = 1006,
27 NoData = 1007,
28 Busy = 1008,
29 MisalignedAddress = 1009,
30 MisalignedSize = 1010,
31 OutOfMemory = 1011,
32 NotImplemented = 1012,
33 InvalidAddress = 1013,
34 InvalidPointer = 1014,
35 InvalidHandle = 1015,
36 NotInitialized = 1016,
37 AlreadyInitialized = 1017,
38 NotFound = 1018,
39 CancelRequested = 1019,
40 AlreadyExists = 1020,
41 OutOfRange = 1021,
42 Timeout = 1022,
43 InvalidResultValue = 1023,
44};
45
46/**
47 * Identifies the module which caused the error. Error codes can be propagated through a call
48 * chain, meaning that this doesn't always correspond to the module where the API call made is
49 * contained.
50 */
51enum class ErrorModule : u32 {
52 Common = 0,
53 Kernel = 1,
54 Util = 2,
55 FileServer = 3,
56 LoaderServer = 4,
57 TCB = 5,
58 OS = 6,
59 DBG = 7,
60 DMNT = 8,
61 PDN = 9,
62 GX = 10,
63 I2C = 11,
64 GPIO = 12,
65 DD = 13,
66 CODEC = 14,
67 SPI = 15,
68 PXI = 16,
69 FS = 17,
70 DI = 18,
71 HID = 19,
72 CAM = 20,
73 PI = 21,
74 PM = 22,
75 PM_LOW = 23,
76 FSI = 24,
77 SRV = 25,
78 NDM = 26,
79 NWM = 27,
80 SOC = 28,
81 LDR = 29,
82 ACC = 30,
83 RomFS = 31,
84 AM = 32,
85 HIO = 33,
86 Updater = 34,
87 MIC = 35,
88 FND = 36,
89 MP = 37,
90 MPWL = 38,
91 AC = 39,
92 HTTP = 40,
93 DSP = 41,
94 SND = 42,
95 DLP = 43,
96 HIO_LOW = 44,
97 CSND = 45,
98 SSL = 46,
99 AM_LOW = 47,
100 NEX = 48,
101 Friends = 49,
102 RDT = 50,
103 Applet = 51,
104 NIM = 52,
105 PTM = 53,
106 MIDI = 54,
107 MC = 55,
108 SWC = 56,
109 FatFS = 57,
110 NGC = 58,
111 CARD = 59,
112 CARDNOR = 60,
113 SDMC = 61,
114 BOSS = 62,
115 DBM = 63,
116 Config = 64,
117 PS = 65,
118 CEC = 66,
119 IR = 67,
120 UDS = 68,
121 PL = 69,
122 CUP = 70,
123 Gyroscope = 71,
124 MCU = 72,
125 NS = 73,
126 News = 74,
127 RO_1 = 75,
128 GD = 76,
129 CardSPI = 77,
130 EC = 78,
131 RO_2 = 79,
132 WebBrowser = 80,
133 Test = 81,
134 ENC = 82,
135 PIA = 83,
136
137 Application = 254,
138 InvalidResult = 255
139};
140
141/// A less specific error cause.
142enum class ErrorSummary : u32 {
143 Success = 0,
144 NothingHappened = 1,
145 WouldBlock = 2,
146 OutOfResource = 3, ///< There are no more kernel resources (memory, table slots) to
147 ///< execute the operation.
148 NotFound = 4, ///< A file or resource was not found.
149 InvalidState = 5,
150 NotSupported = 6, ///< The operation is not supported or not implemented.
151 InvalidArgument = 7, ///< Returned when a passed argument is invalid in the current runtime
152 ///< context. (Invalid handle, out-of-bounds pointer or size, etc.)
153 WrongArgument = 8, ///< Returned when a passed argument is in an incorrect format for use
154 ///< with the function. (E.g. Invalid enum value)
155 Canceled = 9,
156 StatusChanged = 10,
157 Internal = 11,
158
159 InvalidResult = 63
160};
161
162/// The severity of the error.
163enum class ErrorLevel : u32 {
164 Success = 0,
165 Info = 1,
166
167 Status = 25,
168 Temporary = 26,
169 Permanent = 27,
170 Usage = 28,
171 Reinitialize = 29,
172 Reset = 30,
173 Fatal = 31
174};
175
176/// Encapsulates a CTR-OS error code, allowing it to be separated into its constituent fields.
177union ResultCode {
178 u32 raw;
179
180 BitField<0, 10, ErrorDescription> description;
181 BitField<10, 8, ErrorModule> module;
182
183 BitField<21, 6, ErrorSummary> summary;
184 BitField<27, 5, ErrorLevel> level;
185
186 // The last bit of `level` is checked by apps and the kernel to determine if a result code is an error
187 BitField<31, 1, u32> is_error;
188
189 explicit ResultCode(u32 raw) : raw(raw) {}
190 ResultCode(ErrorDescription description_, ErrorModule module_,
191 ErrorSummary summary_, ErrorLevel level_) : raw(0) {
192 description = description_;
193 module = module_;
194 summary = summary_;
195 level = level_;
196 }
197
198 ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; }
199
200 bool IsSuccess() const {
201 return is_error == 0;
202 }
203
204 bool IsError() const {
205 return is_error == 1;
206 }
207};
208
209inline bool operator==(const ResultCode a, const ResultCode b) {
210 return a.raw == b.raw;
211}
212
213inline bool operator!=(const ResultCode a, const ResultCode b) {
214 return a.raw != b.raw;
215}
216
217// Convenience functions for creating some common kinds of errors:
218
219/// The default success `ResultCode`.
220const ResultCode RESULT_SUCCESS(0);
221
222/// Might be returned instead of a dummy success for unimplemented APIs.
223inline ResultCode UnimplementedFunction(ErrorModule module) {
224 return ResultCode(ErrorDescription::NotImplemented, module,
225 ErrorSummary::NotSupported, ErrorLevel::Permanent);
226}
227/// Returned when a function is passed an invalid handle.
228inline ResultCode InvalidHandle(ErrorModule module) {
229 return ResultCode(ErrorDescription::InvalidHandle, module,
230 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
231}
232
233/**
234 * This is an optional value type. It holds a `ResultCode` and, if that code is a success code,
235 * also holds a result of type `T`. If the code is an error code then trying to access the inner
236 * value fails, thus ensuring that the ResultCode of functions is always checked properly before
237 * their return value is used. It is similar in concept to the `std::optional` type
238 * (http://en.cppreference.com/w/cpp/experimental/optional) originally proposed for inclusion in
239 * C++14, or the `Result` type in Rust (http://doc.rust-lang.org/std/result/index.html).
240 *
241 * An example of how it could be used:
242 * \code
243 * ResultVal<int> Frobnicate(float strength) {
244 * if (strength < 0.f || strength > 1.0f) {
245 * // Can't frobnicate too weakly or too strongly
246 * return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Common,
247 * ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
248 * } else {
249 * // Frobnicated! Give caller a cookie
250 * return MakeResult<int>(42);
251 * }
252 * }
253 * \endcode
254 *
255 * \code
256 * ResultVal<int> frob_result = Frobnicate(0.75f);
257 * if (frob_result) {
258 * // Frobbed ok
259 * printf("My cookie is %d\n", *frob_result);
260 * } else {
261 * printf("Guess I overdid it. :( Error code: %ux\n", frob_result.code().hex);
262 * }
263 * \endcode
264 */
265template <typename T>
266class ResultVal {
267public:
268 /// Constructs an empty `ResultVal` with the given error code. The code must not be a success code.
269 ResultVal(ResultCode error_code = ResultCode(-1))
270 : result_code(error_code)
271 {
272 assert(error_code.IsError());
273 UpdateDebugPtr();
274 }
275
276 /**
277 * Similar to the non-member function `MakeResult`, with the exception that you can manually
278 * specify the success code. `success_code` must not be an error code.
279 */
280 template <typename... Args>
281 static ResultVal WithCode(ResultCode success_code, Args&&... args) {
282 ResultVal<T> result;
283 result.emplace(success_code, std::forward<Args>(args)...);
284 return result;
285 }
286
287 ResultVal(const ResultVal& o)
288 : result_code(o.result_code)
289 {
290 if (!o.empty()) {
291 new (&storage) T(*o.GetPointer());
292 }
293 UpdateDebugPtr();
294 }
295
296 ResultVal(ResultVal&& o)
297 : result_code(o.result_code)
298 {
299 if (!o.empty()) {
300 new (&storage) T(std::move(*o.GetPointer()));
301 }
302 UpdateDebugPtr();
303 }
304
305 ~ResultVal() {
306 if (!empty()) {
307 GetPointer()->~T();
308 }
309 }
310
311 ResultVal& operator=(const ResultVal& o) {
312 if (*this) {
313 if (o) {
314 *GetPointer() = *o.GetPointer();
315 } else {
316 GetPointer()->~T();
317 }
318 } else {
319 if (o) {
320 new (&storage) T(*o.GetPointer());
321 }
322 }
323 result_code = o.result_code;
324 UpdateDebugPtr();
325
326 return *this;
327 }
328
329 /**
330 * Replaces the current result with a new constructed result value in-place. The code must not
331 * be an error code.
332 */
333 template <typename... Args>
334 void emplace(ResultCode success_code, Args&&... args) {
335 assert(success_code.IsSuccess());
336 if (!empty()) {
337 GetPointer()->~T();
338 }
339 new (&storage) T(std::forward<Args>(args)...);
340 result_code = success_code;
341 UpdateDebugPtr();
342 }
343
344 /// Returns true if the `ResultVal` contains an error code and no value.
345 bool empty() const { return result_code.IsError(); }
346
347 /// Returns true if the `ResultVal` contains a return value.
348 bool Succeeded() const { return result_code.IsSuccess(); }
349 /// Returns true if the `ResultVal` contains an error code and no value.
350 bool Failed() const { return empty(); }
351
352 ResultCode Code() const { return result_code; }
353
354 const T& operator* () const { return *GetPointer(); }
355 T& operator* () { return *GetPointer(); }
356 const T* operator->() const { return GetPointer(); }
357 T* operator->() { return GetPointer(); }
358
359 /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing.
360 template <typename U>
361 T ValueOr(U&& value) const {
362 return !empty() ? *GetPointer() : std::move(value);
363 }
364
365private:
366 typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType;
367
368 StorageType storage;
369 ResultCode result_code;
370#if _DEBUG
371 // The purpose of this pointer is to aid inspecting the type with a debugger, eliminating the
372 // need to cast `storage` to a pointer or pay attention to `result_code`.
373 const T* debug_ptr;
374#endif
375
376 void UpdateDebugPtr() {
377#if _DEBUG
378 debug_ptr = empty() ? nullptr : static_cast<const T*>(static_cast<const void*>(&storage));
379#endif
380 }
381
382 const T* GetPointer() const {
383 assert(!empty());
384 return static_cast<const T*>(static_cast<const void*>(&storage));
385 }
386
387 T* GetPointer() {
388 assert(!empty());
389 return static_cast<T*>(static_cast<void*>(&storage));
390 }
391};
392
393/**
394 * This function is a helper used to construct `ResultVal`s. It receives the arguments to construct
395 * `T` with and creates a success `ResultVal` contained the constructed value.
396 */
397template <typename T, typename... Args>
398ResultVal<T> MakeResult(Args&&... args) {
399 return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...);
400}
diff --git a/src/core/hle/service/cfg_u.cpp b/src/core/hle/service/cfg_u.cpp
index 822b0e2b8..d6b586ea0 100644
--- a/src/core/hle/service/cfg_u.cpp
+++ b/src/core/hle/service/cfg_u.cpp
@@ -11,6 +11,90 @@
11 11
12namespace CFG_U { 12namespace CFG_U {
13 13
14static const std::array<const char*, 187> country_codes = {
15 nullptr, "JP", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 0-7
16 "AI", "AG", "AR", "AW", "BS", "BB", "BZ", "BO", // 8-15
17 "BR", "VG", "CA", "KY", "CL", "CO", "CR", "DM", // 16-23
18 "DO", "EC", "SV", "GF", "GD", "GP", "GT", "GY", // 24-31
19 "HT", "HN", "JM", "MQ", "MX", "MS", "AN", "NI", // 32-39
20 "PA", "PY", "PE", "KN", "LC", "VC", "SR", "TT", // 40-47
21 "TC", "US", "UY", "VI", "VE", nullptr, nullptr, nullptr, // 48-55
22 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 56-63
23 "AL", "AU", "AT", "BE", "BA", "BW", "BG", "HR", // 64-71
24 "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", // 72-79
25 "HU", "IS", "IE", "IT", "LV", "LS", "LI", "LT", // 80-87
26 "LU", "MK", "MT", "ME", "MZ", "NA", "NL", "NZ", // 88-95
27 "NO", "PL", "PT", "RO", "RU", "RS", "SK", "SI", // 96-103
28 "ZA", "ES", "SZ", "SE", "CH", "TR", "GB", "ZM", // 104-111
29 "ZW", "AZ", "MR", "ML", "NE", "TD", "SD", "ER", // 112-119
30 "DJ", "SO", "AD", "GI", "GG", "IM", "JE", "MC", // 120-127
31 "TW", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 128-135
32 "KR", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 136-143
33 "HK", "MO", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 144-151
34 "ID", "SG", "TH", "PH", "MY", nullptr, nullptr, nullptr, // 152-159
35 "CN", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 160-167
36 "AE", "IN", "EG", "OM", "QA", "KW", "SA", "SY", // 168-175
37 "BH", "JO", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 176-183
38 "SM", "VA", "BM", // 184-186
39};
40
41/**
42 * CFG_User::GetCountryCodeString service function
43 * Inputs:
44 * 1 : Country Code ID
45 * Outputs:
46 * 1 : Result of function, 0 on success, otherwise error code
47 * 2 : Country's 2-char string
48 */
49static void GetCountryCodeString(Service::Interface* self) {
50 u32* cmd_buffer = Service::GetCommandBuffer();
51 u32 country_code_id = cmd_buffer[1];
52
53 if (country_code_id >= country_codes.size()) {
54 ERROR_LOG(KERNEL, "requested country code id=%d is invalid", country_code_id);
55 cmd_buffer[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
56 return;
57 }
58
59 const char* code = country_codes[country_code_id];
60 if (code != nullptr) {
61 cmd_buffer[1] = 0;
62 cmd_buffer[2] = code[0] | (code[1] << 8);
63 } else {
64 cmd_buffer[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
65 DEBUG_LOG(KERNEL, "requested country code id=%d is not set", country_code_id);
66 }
67}
68
69/**
70 * CFG_User::GetCountryCodeID service function
71 * Inputs:
72 * 1 : Country Code 2-char string
73 * Outputs:
74 * 1 : Result of function, 0 on success, otherwise error code
75 * 2 : Country Code ID
76 */
77static void GetCountryCodeID(Service::Interface* self) {
78 u32* cmd_buffer = Service::GetCommandBuffer();
79 u16 country_code = cmd_buffer[1];
80 u16 country_code_id = -1;
81
82 for (u32 i = 0; i < country_codes.size(); ++i) {
83 const char* code_string = country_codes[i];
84
85 if (code_string != nullptr) {
86 u16 code = code_string[0] | (code_string[1] << 8);
87 if (code == country_code) {
88 country_code_id = i;
89 break;
90 }
91 }
92 }
93
94 cmd_buffer[1] = 0;
95 cmd_buffer[2] = country_code_id;
96}
97
14const Interface::FunctionInfo FunctionTable[] = { 98const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010082, nullptr, "GetConfigInfoBlk2"}, 99 {0x00010082, nullptr, "GetConfigInfoBlk2"},
16 {0x00020000, nullptr, "SecureInfoGetRegion"}, 100 {0x00020000, nullptr, "SecureInfoGetRegion"},
@@ -20,8 +104,8 @@ const Interface::FunctionInfo FunctionTable[] = {
20 {0x00060000, nullptr, "GetModelNintendo2DS"}, 104 {0x00060000, nullptr, "GetModelNintendo2DS"},
21 {0x00070040, nullptr, "unknown"}, 105 {0x00070040, nullptr, "unknown"},
22 {0x00080080, nullptr, "unknown"}, 106 {0x00080080, nullptr, "unknown"},
23 {0x00090080, nullptr, "GetCountryCodeString"}, 107 {0x00090040, GetCountryCodeString, "GetCountryCodeString"},
24 {0x000A0040, nullptr, "GetCountryCodeID"}, 108 {0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
25}; 109};
26//////////////////////////////////////////////////////////////////////////////////////////////////// 110////////////////////////////////////////////////////////////////////////////////////////////////////
27// Interface class 111// Interface class
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index bbcf26f61..a2b68cac8 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/log.h" 5#include "common/log.h"
6#include "core/hle/hle.h" 6#include "core/hle/hle.h"
7#include "core/hle/kernel/event.h"
7#include "core/hle/service/dsp_dsp.h" 8#include "core/hle/service/dsp_dsp.h"
8 9
9//////////////////////////////////////////////////////////////////////////////////////////////////// 10////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -11,38 +12,118 @@
11 12
12namespace DSP_DSP { 13namespace DSP_DSP {
13 14
15static Handle semaphore_event;
16static Handle interrupt_event;
17
18/**
19 * DSP_DSP::LoadComponent service function
20 * Inputs:
21 * 1 : Size
22 * 2 : Unknown (observed only half word used)
23 * 3 : Unknown (observed only half word used)
24 * 4 : (size << 4) | 0xA
25 * 5 : Buffer address
26 * Outputs:
27 * 1 : Result of function, 0 on success, otherwise error code
28 * 2 : Component loaded, 0 on not loaded, 1 on loaded
29 */
30void LoadComponent(Service::Interface* self) {
31 u32* cmd_buff = Service::GetCommandBuffer();
32
33 cmd_buff[1] = 0; // No error
34 cmd_buff[2] = 1; // Pretend that we actually loaded the DSP firmware
35
36 // TODO(bunnei): Implement real DSP firmware loading
37
38 DEBUG_LOG(KERNEL, "(STUBBED) called");
39}
40
41/**
42 * DSP_DSP::GetSemaphoreEventHandle service function
43 * Outputs:
44 * 1 : Result of function, 0 on success, otherwise error code
45 * 3 : Semaphore event handle
46 */
47void GetSemaphoreEventHandle(Service::Interface* self) {
48 u32* cmd_buff = Service::GetCommandBuffer();
49
50 cmd_buff[1] = 0; // No error
51 cmd_buff[3] = semaphore_event; // Event handle
52
53 DEBUG_LOG(KERNEL, "(STUBBED) called");
54}
55
56/**
57 * DSP_DSP::RegisterInterruptEvents service function
58 * Inputs:
59 * 1 : Parameter 0 (purpose unknown)
60 * 2 : Parameter 1 (purpose unknown)
61 * 4 : Interrupt event handle
62 * Outputs:
63 * 1 : Result of function, 0 on success, otherwise error code
64 */
65void RegisterInterruptEvents(Service::Interface* self) {
66 u32* cmd_buff = Service::GetCommandBuffer();
67
68 interrupt_event = static_cast<Handle>(cmd_buff[4]);
69
70 cmd_buff[1] = 0; // No error
71
72 DEBUG_LOG(KERNEL, "(STUBBED) called");
73}
74
75/**
76 * DSP_DSP::WriteReg0x10 service function
77 * Inputs:
78 * 1 : Unknown (observed only half word used)
79 * Outputs:
80 * 1 : Result of function, 0 on success, otherwise error code
81 */
82void WriteReg0x10(Service::Interface* self) {
83 u32* cmd_buff = Service::GetCommandBuffer();
84
85 Kernel::SignalEvent(interrupt_event);
86
87 cmd_buff[1] = 0; // No error
88
89 DEBUG_LOG(KERNEL, "(STUBBED) called");
90}
91
14const Interface::FunctionInfo FunctionTable[] = { 92const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010040, nullptr, "RecvData"}, 93 {0x00010040, nullptr, "RecvData"},
16 {0x00020040, nullptr, "RecvDataIsReady"}, 94 {0x00020040, nullptr, "RecvDataIsReady"},
17 {0x00030080, nullptr, "SendData"}, 95 {0x00030080, nullptr, "SendData"},
18 {0x00040040, nullptr, "SendDataIsEmpty"}, 96 {0x00040040, nullptr, "SendDataIsEmpty"},
19 {0x00070040, nullptr, "WriteReg0x10"}, 97 {0x00070040, WriteReg0x10, "WriteReg0x10"},
20 {0x00080000, nullptr, "GetSemaphore"}, 98 {0x00080000, nullptr, "GetSemaphore"},
21 {0x00090040, nullptr, "ClearSemaphore"}, 99 {0x00090040, nullptr, "ClearSemaphore"},
22 {0x000B0000, nullptr, "CheckSemaphoreRequest"}, 100 {0x000B0000, nullptr, "CheckSemaphoreRequest"},
23 {0x000C0040, nullptr, "ConvertProcessAddressFromDspDram"}, 101 {0x000C0040, nullptr, "ConvertProcessAddressFromDspDram"},
24 {0x000D0082, nullptr, "WriteProcessPipe"}, 102 {0x000D0082, nullptr, "WriteProcessPipe"},
25 {0x001000C0, nullptr, "ReadPipeIfPossible"}, 103 {0x001000C0, nullptr, "ReadPipeIfPossible"},
26 {0x001100C2, nullptr, "LoadComponent"}, 104 {0x001100C2, LoadComponent, "LoadComponent"},
27 {0x00120000, nullptr, "UnloadComponent"}, 105 {0x00120000, nullptr, "UnloadComponent"},
28 {0x00130082, nullptr, "FlushDataCache"}, 106 {0x00130082, nullptr, "FlushDataCache"},
29 {0x00140082, nullptr, "InvalidateDCache"}, 107 {0x00140082, nullptr, "InvalidateDCache"},
30 {0x00150082, nullptr, "RegisterInterruptEvents"}, 108 {0x00150082, RegisterInterruptEvents, "RegisterInterruptEvents"},
31 {0x00160000, nullptr, "GetSemaphoreEventHandle"}, 109 {0x00160000, GetSemaphoreEventHandle, "GetSemaphoreEventHandle"},
32 {0x00170040, nullptr, "SetSemaphoreMask"}, 110 {0x00170040, nullptr, "SetSemaphoreMask"},
33 {0x00180040, nullptr, "GetPhysicalAddress"}, 111 {0x00180040, nullptr, "GetPhysicalAddress"},
34 {0x00190040, nullptr, "GetVirtualAddress"}, 112 {0x00190040, nullptr, "GetVirtualAddress"},
35 {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"}, 113 {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"},
36 {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"}, 114 {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"},
37 {0x001C0082, nullptr, "SetIirFilterEQ"}, 115 {0x001C0082, nullptr, "SetIirFilterEQ"},
38 {0x001F0000, nullptr, "GetHeadphoneStatus"}, 116 {0x001F0000, nullptr, "GetHeadphoneStatus"},
39 {0x00210000, nullptr, "GetIsDspOccupied"}, 117 {0x00210000, nullptr, "GetIsDspOccupied"},
40}; 118};
41 119
42//////////////////////////////////////////////////////////////////////////////////////////////////// 120////////////////////////////////////////////////////////////////////////////////////////////////////
43// Interface class 121// Interface class
44 122
45Interface::Interface() { 123Interface::Interface() {
124 semaphore_event = Kernel::CreateEvent(RESETTYPE_ONESHOT, "DSP_DSP::semaphore_event");
125 interrupt_event = 0;
126
46 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 127 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
47} 128}
48 129
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index c4ce44245..9431b62f6 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -20,7 +20,7 @@ public:
20 * @return Port name of service 20 * @return Port name of service
21 */ 21 */
22 std::string GetPortName() const override { 22 std::string GetPortName() const override {
23 return "dsp:DSP"; 23 return "dsp::DSP";
24 } 24 }
25}; 25};
26 26
diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs_user.cpp
index dadc89ef8..34af78cb9 100644
--- a/src/core/hle/service/fs_user.cpp
+++ b/src/core/hle/service/fs_user.cpp
@@ -4,26 +4,24 @@
4 4
5#include "common/common.h" 5#include "common/common.h"
6 6
7#include "fs_user.h"
8#include "common/string_util.h" 7#include "common/string_util.h"
9#include "core/settings.h"
10#include "core/hle/kernel/archive.h" 8#include "core/hle/kernel/archive.h"
9#include "core/hle/kernel/archive.h"
10#include "core/hle/result.h"
11#include "core/hle/service/fs_user.h"
12#include "core/settings.h"
11 13
12//////////////////////////////////////////////////////////////////////////////////////////////////// 14////////////////////////////////////////////////////////////////////////////////////////////////////
13// Namespace FS_User 15// Namespace FS_User
14 16
15namespace FS_User { 17namespace FS_User {
16 18
17// We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it
18// puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make
19// sure we don't mislead the application into thinking something worked.
20
21static void Initialize(Service::Interface* self) { 19static void Initialize(Service::Interface* self) {
22 u32* cmd_buff = Service::GetCommandBuffer(); 20 u32* cmd_buff = Service::GetCommandBuffer();
23 21
24 // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per 22 // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per
25 // http://3dbrew.org/wiki/FS:Initialize#Request 23 // http://3dbrew.org/wiki/FS:Initialize#Request
26 cmd_buff[1] = 0; 24 cmd_buff[1] = RESULT_SUCCESS.raw;
27 25
28 DEBUG_LOG(KERNEL, "called"); 26 DEBUG_LOG(KERNEL, "called");
29} 27}
@@ -57,16 +55,14 @@ static void OpenFile(Service::Interface* self) {
57 u32 filename_ptr = cmd_buff[9]; 55 u32 filename_ptr = cmd_buff[9];
58 FileSys::Path file_path(filename_type, filename_size, filename_ptr); 56 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
59 57
60 DEBUG_LOG(KERNEL, "path=%s, mode=%d attrs=%d", file_path.DebugStr().c_str(), mode, attributes); 58 DEBUG_LOG(KERNEL, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes);
61 59
62 Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); 60 ResultVal<Handle> handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode);
63 if (handle) { 61 cmd_buff[1] = handle.Code().raw;
64 cmd_buff[1] = 0; 62 if (handle.Succeeded()) {
65 cmd_buff[3] = handle; 63 cmd_buff[3] = *handle;
66 } else { 64 } else {
67 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); 65 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str());
68 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
69 cmd_buff[1] = -1;
70 } 66 }
71 67
72 DEBUG_LOG(KERNEL, "called"); 68 DEBUG_LOG(KERNEL, "called");
@@ -106,38 +102,100 @@ static void OpenFileDirectly(Service::Interface* self) {
106 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); 102 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
107 FileSys::Path file_path(filename_type, filename_size, filename_ptr); 103 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
108 104
109 DEBUG_LOG(KERNEL, "archive_path=%s file_path=%s, mode=%d attributes=%d", 105 DEBUG_LOG(KERNEL, "archive_path=%s file_path=%s, mode=%u attributes=%d",
110 archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode, attributes); 106 archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes);
111 107
112 if (archive_path.GetType() != FileSys::Empty) { 108 if (archive_path.GetType() != FileSys::Empty) {
113 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); 109 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
114 cmd_buff[1] = -1; 110 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
115 return; 111 return;
116 } 112 }
117 113
118 // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it 114 // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it
119 Handle archive_handle = Kernel::OpenArchive(archive_id); 115 // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here?
120 if (!archive_handle) { 116 ResultVal<Handle> archive_handle = Kernel::OpenArchive(archive_id);
117 cmd_buff[1] = archive_handle.Code().raw;
118 if (archive_handle.Failed()) {
121 ERROR_LOG(KERNEL, "failed to get a handle for archive"); 119 ERROR_LOG(KERNEL, "failed to get a handle for archive");
122 // TODO(Link Mauve): Check for the actual error values, this one was just chosen arbitrarily
123 cmd_buff[1] = -1;
124 return; 120 return;
125 } 121 }
122 // cmd_buff[2] isn't used according to 3dmoo's implementation.
123 cmd_buff[3] = *archive_handle;
126 124
127 Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); 125 ResultVal<Handle> handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode);
128 if (handle) { 126 cmd_buff[1] = handle.Code().raw;
129 cmd_buff[1] = 0; 127 if (handle.Succeeded()) {
130 cmd_buff[3] = handle; 128 cmd_buff[3] = *handle;
131 } else { 129 } else {
132 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str()); 130 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str());
133 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
134 cmd_buff[1] = -1;
135 } 131 }
136 132
137 DEBUG_LOG(KERNEL, "called"); 133 DEBUG_LOG(KERNEL, "called");
138} 134}
139 135
140/* 136/*
137 * FS_User::DeleteFile service function
138 * Inputs:
139 * 2 : Archive handle lower word
140 * 3 : Archive handle upper word
141 * 4 : File path string type
142 * 5 : File path string size
143 * 7 : File path string data
144 * Outputs:
145 * 1 : Result of function, 0 on success, otherwise error code
146 */
147void DeleteFile(Service::Interface* self) {
148 u32* cmd_buff = Service::GetCommandBuffer();
149
150 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
151 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
152 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
153 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
154 u32 filename_size = cmd_buff[5];
155 u32 filename_ptr = cmd_buff[7];
156
157 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
158
159 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s",
160 filename_type, filename_size, file_path.DebugStr().c_str());
161
162 cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path);
163
164 DEBUG_LOG(KERNEL, "called");
165}
166
167/*
168 * FS_User::DeleteDirectory service function
169 * Inputs:
170 * 2 : Archive handle lower word
171 * 3 : Archive handle upper word
172 * 4 : Directory path string type
173 * 5 : Directory path string size
174 * 7 : Directory path string data
175 * Outputs:
176 * 1 : Result of function, 0 on success, otherwise error code
177 */
178void DeleteDirectory(Service::Interface* self) {
179 u32* cmd_buff = Service::GetCommandBuffer();
180
181 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
182 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
183 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
184 auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
185 u32 dirname_size = cmd_buff[5];
186 u32 dirname_ptr = cmd_buff[7];
187
188 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
189
190 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s",
191 dirname_type, dirname_size, dir_path.DebugStr().c_str());
192
193 cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path);
194
195 DEBUG_LOG(KERNEL, "called");
196}
197
198/*
141 * FS_User::CreateDirectory service function 199 * FS_User::CreateDirectory service function
142 * Inputs: 200 * Inputs:
143 * 2 : Archive handle lower word 201 * 2 : Archive handle lower word
@@ -159,18 +217,8 @@ static void CreateDirectory(Service::Interface* self) {
159 u32 dirname_ptr = cmd_buff[8]; 217 u32 dirname_ptr = cmd_buff[8];
160 218
161 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); 219 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
162 std::string dir_string;
163 switch (dir_path.GetType()) {
164 case FileSys::Char:
165 case FileSys::Wchar:
166 dir_string = dir_path.AsString();
167 break;
168 default:
169 cmd_buff[1] = -1;
170 return;
171 }
172 220
173 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); 221 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
174 222
175 cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path); 223 cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path);
176 224
@@ -188,27 +236,15 @@ static void OpenDirectory(Service::Interface* self) {
188 u32 dirname_ptr = cmd_buff[6]; 236 u32 dirname_ptr = cmd_buff[6];
189 237
190 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); 238 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
191 std::string dir_string;
192 switch (dir_path.GetType()) {
193 case FileSys::Char:
194 case FileSys::Wchar:
195 dir_string = dir_path.AsString();
196 break;
197 default:
198 cmd_buff[1] = -1;
199 return;
200 }
201 239
202 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); 240 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
203 241
204 Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path); 242 ResultVal<Handle> handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path);
205 if (handle) { 243 cmd_buff[1] = handle.Code().raw;
206 cmd_buff[1] = 0; 244 if (handle.Succeeded()) {
207 cmd_buff[3] = handle; 245 cmd_buff[3] = *handle;
208 } else { 246 } else {
209 ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_string.c_str()); 247 ERROR_LOG(KERNEL, "failed to get a handle for directory");
210 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
211 cmd_buff[1] = -1;
212 } 248 }
213 249
214 DEBUG_LOG(KERNEL, "called"); 250 DEBUG_LOG(KERNEL, "called");
@@ -240,19 +276,17 @@ static void OpenArchive(Service::Interface* self) {
240 276
241 if (archive_path.GetType() != FileSys::Empty) { 277 if (archive_path.GetType() != FileSys::Empty) {
242 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); 278 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
243 cmd_buff[1] = -1; 279 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
244 return; 280 return;
245 } 281 }
246 282
247 Handle handle = Kernel::OpenArchive(archive_id); 283 ResultVal<Handle> handle = Kernel::OpenArchive(archive_id);
248 if (handle) { 284 cmd_buff[1] = handle.Code().raw;
249 cmd_buff[1] = 0; 285 if (handle.Succeeded()) {
250 // cmd_buff[2] isn't used according to 3dmoo's implementation. 286 // cmd_buff[2] isn't used according to 3dmoo's implementation.
251 cmd_buff[3] = handle; 287 cmd_buff[3] = *handle;
252 } else { 288 } else {
253 ERROR_LOG(KERNEL, "failed to get a handle for archive"); 289 ERROR_LOG(KERNEL, "failed to get a handle for archive");
254 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
255 cmd_buff[1] = -1;
256 } 290 }
257 291
258 DEBUG_LOG(KERNEL, "called"); 292 DEBUG_LOG(KERNEL, "called");
@@ -279,9 +313,9 @@ const Interface::FunctionInfo FunctionTable[] = {
279 {0x08010002, Initialize, "Initialize"}, 313 {0x08010002, Initialize, "Initialize"},
280 {0x080201C2, OpenFile, "OpenFile"}, 314 {0x080201C2, OpenFile, "OpenFile"},
281 {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, 315 {0x08030204, OpenFileDirectly, "OpenFileDirectly"},
282 {0x08040142, nullptr, "DeleteFile"}, 316 {0x08040142, DeleteFile, "DeleteFile"},
283 {0x08050244, nullptr, "RenameFile"}, 317 {0x08050244, nullptr, "RenameFile"},
284 {0x08060142, nullptr, "DeleteDirectory"}, 318 {0x08060142, DeleteDirectory, "DeleteDirectory"},
285 {0x08070142, nullptr, "DeleteDirectoryRecursively"}, 319 {0x08070142, nullptr, "DeleteDirectoryRecursively"},
286 {0x08080202, nullptr, "CreateFile"}, 320 {0x08080202, nullptr, "CreateFile"},
287 {0x08090182, CreateDirectory, "CreateDirectory"}, 321 {0x08090182, CreateDirectory, "CreateDirectory"},
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 66daded94..de1bd3f61 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -28,28 +28,23 @@ u32 g_thread_id = 1; ///< Thread index into interrupt relay queue, 1
28 28
29/// Gets a pointer to a thread command buffer in GSP shared memory 29/// Gets a pointer to a thread command buffer in GSP shared memory
30static inline u8* GetCommandBuffer(u32 thread_id) { 30static inline u8* GetCommandBuffer(u32 thread_id) {
31 if (0 == g_shared_memory) 31 ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, 0x800 + (thread_id * sizeof(CommandBuffer)));
32 return nullptr; 32 return ptr.ValueOr(nullptr);
33
34 return Kernel::GetSharedMemoryPointer(g_shared_memory,
35 0x800 + (thread_id * sizeof(CommandBuffer)));
36} 33}
37 34
38static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { 35static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
39 if (0 == g_shared_memory)
40 return nullptr;
41
42 _dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index"); 36 _dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index");
43 37
44 // For each thread there are two FrameBufferUpdate fields 38 // For each thread there are two FrameBufferUpdate fields
45 u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); 39 u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate);
46 return (FrameBufferUpdate*)Kernel::GetSharedMemoryPointer(g_shared_memory, offset); 40 ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, offset);
41 return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr));
47} 42}
48 43
49/// Gets a pointer to the interrupt relay queue for a given thread index 44/// Gets a pointer to the interrupt relay queue for a given thread index
50static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { 45static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
51 return (InterruptRelayQueue*)Kernel::GetSharedMemoryPointer(g_shared_memory, 46 ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, sizeof(InterruptRelayQueue) * thread_id);
52 sizeof(InterruptRelayQueue) * thread_id); 47 return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr));
53} 48}
54 49
55static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { 50static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
diff --git a/src/core/hle/service/hid_user.cpp b/src/core/hle/service/hid_user.cpp
index 5f6bf1eff..d29de1a52 100644
--- a/src/core/hle/service/hid_user.cpp
+++ b/src/core/hle/service/hid_user.cpp
@@ -34,10 +34,7 @@ static s16 next_circle_y = 0;
34 * Gets a pointer to the PadData structure inside HID shared memory 34 * Gets a pointer to the PadData structure inside HID shared memory
35 */ 35 */
36static inline PadData* GetPadData() { 36static inline PadData* GetPadData() {
37 if (0 == shared_mem) 37 return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0).ValueOr(nullptr));
38 return nullptr;
39
40 return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0));
41} 38}
42 39
43/** 40/**
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index abc8d5edb..fed2268a0 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -62,7 +62,7 @@ void Manager::DeleteService(const std::string& port_name) {
62 62
63/// Get a Service Interface from its Handle 63/// Get a Service Interface from its Handle
64Interface* Manager::FetchFromHandle(Handle handle) { 64Interface* Manager::FetchFromHandle(Handle handle) {
65 return Kernel::g_object_pool.GetFast<Interface>(handle); 65 return Kernel::g_object_pool.Get<Interface>(handle);
66} 66}
67 67
68/// Get a Service Interface from its port 68/// Get a Service Interface from its port
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 55aa84e83..20e7fb4d3 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -75,12 +75,7 @@ public:
75 m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); 75 m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end());
76 } 76 }
77 77
78 /** 78 ResultVal<bool> SyncRequest() override {
79 * Synchronize kernel object
80 * @param wait Boolean wait set if current thread should wait as a result of sync operation
81 * @return Result of operation, 0 on success, otherwise error code
82 */
83 Result SyncRequest(bool* wait) override {
84 u32* cmd_buff = GetCommandBuffer(); 79 u32* cmd_buff = GetCommandBuffer();
85 auto itr = m_functions.find(cmd_buff[0]); 80 auto itr = m_functions.find(cmd_buff[0]);
86 81
@@ -91,7 +86,7 @@ public:
91 // TODO(bunnei): Hack - ignore error 86 // TODO(bunnei): Hack - ignore error
92 u32* cmd_buff = Service::GetCommandBuffer(); 87 u32* cmd_buff = Service::GetCommandBuffer();
93 cmd_buff[1] = 0; 88 cmd_buff[1] = 0;
94 return 0; 89 return MakeResult<bool>(false);
95 } 90 }
96 if (itr->second.func == nullptr) { 91 if (itr->second.func == nullptr) {
97 ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s", 92 ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
@@ -100,23 +95,18 @@ public:
100 // TODO(bunnei): Hack - ignore error 95 // TODO(bunnei): Hack - ignore error
101 u32* cmd_buff = Service::GetCommandBuffer(); 96 u32* cmd_buff = Service::GetCommandBuffer();
102 cmd_buff[1] = 0; 97 cmd_buff[1] = 0;
103 return 0; 98 return MakeResult<bool>(false);
104 } 99 }
105 100
106 itr->second.func(this); 101 itr->second.func(this);
107 102
108 return 0; // TODO: Implement return from actual function 103 return MakeResult<bool>(false); // TODO: Implement return from actual function
109 } 104 }
110 105
111 /** 106 ResultVal<bool> WaitSynchronization() override {
112 * Wait for kernel object to synchronize
113 * @param wait Boolean wait set if current thread should wait as a result of sync operation
114 * @return Result of operation, 0 on success, otherwise error code
115 */
116 Result WaitSynchronization(bool* wait) override {
117 // TODO(bunnei): ImplementMe 107 // TODO(bunnei): ImplementMe
118 ERROR_LOG(OSHLE, "unimplemented function"); 108 ERROR_LOG(OSHLE, "unimplemented function");
119 return 0; 109 return UnimplementedFunction(ErrorModule::OS);
120 } 110 }
121 111
122protected: 112protected:
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index df38bd93c..0e7fa9e3b 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -35,7 +35,7 @@ static void GetProcSemaphore(Service::Interface* self) {
35} 35}
36 36
37static void GetServiceHandle(Service::Interface* self) { 37static void GetServiceHandle(Service::Interface* self) {
38 Result res = 0; 38 ResultCode res = RESULT_SUCCESS;
39 u32* cmd_buff = Service::GetCommandBuffer(); 39 u32* cmd_buff = Service::GetCommandBuffer();
40 40
41 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); 41 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize);
@@ -46,9 +46,9 @@ static void GetServiceHandle(Service::Interface* self) {
46 DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); 46 DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
47 } else { 47 } else {
48 ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); 48 ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
49 res = -1; 49 res = UnimplementedFunction(ErrorModule::SRV);
50 } 50 }
51 cmd_buff[1] = res; 51 cmd_buff[1] = res.raw;
52} 52}
53 53
54const Interface::FunctionInfo FunctionTable[] = { 54const Interface::FunctionInfo FunctionTable[] = {
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 3a06d6765..43a3cbe03 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -16,6 +16,7 @@
16#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
17 17
18#include "core/hle/function_wrappers.h" 18#include "core/hle/function_wrappers.h"
19#include "core/hle/result.h"
19#include "core/hle/service/service.h" 20#include "core/hle/service/service.h"
20 21
21//////////////////////////////////////////////////////////////////////////////////////////////////// 22////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -86,18 +87,22 @@ static Result ConnectToPort(Handle* out, const char* port_name) {
86 87
87/// Synchronize to an OS service 88/// Synchronize to an OS service
88static Result SendSyncRequest(Handle handle) { 89static Result SendSyncRequest(Handle handle) {
90 // TODO(yuriks): ObjectPool::Get tries to check the Object type, which fails since this is a generic base Object,
91 // so we are forced to use GetFast and manually verify the handle.
92 if (!Kernel::g_object_pool.IsValid(handle)) {
93 return InvalidHandle(ErrorModule::Kernel).raw;
94 }
89 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); 95 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
90 96
91 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); 97 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
92 DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str()); 98 DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str());
93 99
94 bool wait = false; 100 ResultVal<bool> wait = object->SyncRequest();
95 Result res = object->SyncRequest(&wait); 101 if (wait.Succeeded() && *wait) {
96 if (wait) {
97 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? 102 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
98 } 103 }
99 104
100 return res; 105 return wait.Code().raw;
101} 106}
102 107
103/// Close a handle 108/// Close a handle
@@ -110,25 +115,25 @@ static Result CloseHandle(Handle handle) {
110/// Wait for a handle to synchronize, timeout after the specified nanoseconds 115/// Wait for a handle to synchronize, timeout after the specified nanoseconds
111static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { 116static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
112 // TODO(bunnei): Do something with nano_seconds, currently ignoring this 117 // TODO(bunnei): Do something with nano_seconds, currently ignoring this
113 bool wait = false;
114 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated 118 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
115 119
120 if (!Kernel::g_object_pool.IsValid(handle)) {
121 return InvalidHandle(ErrorModule::Kernel).raw;
122 }
116 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); 123 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
124 _dbg_assert_(KERNEL, object != nullptr);
117 125
118 DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), 126 DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(),
119 object->GetName().c_str(), nano_seconds); 127 object->GetName().c_str(), nano_seconds);
120 128
121 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); 129 ResultVal<bool> wait = object->WaitSynchronization();
122
123 Result res = object->WaitSynchronization(&wait);
124 130
125 // Check for next thread to schedule 131 // Check for next thread to schedule
126 if (wait) { 132 if (wait.Succeeded() && *wait) {
127 HLE::Reschedule(__func__); 133 HLE::Reschedule(__func__);
128 return 0;
129 } 134 }
130 135
131 return res; 136 return wait.Code().raw;
132} 137}
133 138
134/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 139/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
@@ -143,20 +148,21 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count,
143 148
144 // Iterate through each handle, synchronize kernel object 149 // Iterate through each handle, synchronize kernel object
145 for (s32 i = 0; i < handle_count; i++) { 150 for (s32 i = 0; i < handle_count; i++) {
146 bool wait = false; 151 if (!Kernel::g_object_pool.IsValid(handles[i])) {
152 return InvalidHandle(ErrorModule::Kernel).raw;
153 }
147 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); 154 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]);
148 155
149 _assert_msg_(KERNEL, (object != nullptr), "called handle=0x%08X, but kernel object "
150 "is nullptr!", handles[i]);
151
152 DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(), 156 DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(),
153 object->GetName().c_str()); 157 object->GetName().c_str());
154 158
155 Result res = object->WaitSynchronization(&wait); 159 // TODO(yuriks): Verify how the real function behaves when an error happens here
160 ResultVal<bool> wait_result = object->WaitSynchronization();
161 bool wait = wait_result.Succeeded() && *wait_result;
156 162
157 if (!wait && !wait_all) { 163 if (!wait && !wait_all) {
158 *out = i; 164 *out = i;
159 return 0; 165 return RESULT_SUCCESS.raw;
160 } else { 166 } else {
161 unlock_all = false; 167 unlock_all = false;
162 } 168 }
@@ -164,13 +170,13 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count,
164 170
165 if (wait_all && unlock_all) { 171 if (wait_all && unlock_all) {
166 *out = handle_count; 172 *out = handle_count;
167 return 0; 173 return RESULT_SUCCESS.raw;
168 } 174 }
169 175
170 // Check for next thread to schedule 176 // Check for next thread to schedule
171 HLE::Reschedule(__func__); 177 HLE::Reschedule(__func__);
172 178
173 return 0; 179 return RESULT_SUCCESS.raw;
174} 180}
175 181
176/// Create an address arbiter (to allocate access to shared resources) 182/// Create an address arbiter (to allocate access to shared resources)
@@ -183,8 +189,10 @@ static Result CreateAddressArbiter(u32* arbiter) {
183 189
184/// Arbitrate address 190/// Arbitrate address
185static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { 191static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) {
186 return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), address, 192 DEBUG_LOG(SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", arbiter,
187 value); 193 address, type, value);
194 return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type),
195 address, value).raw;
188} 196}
189 197
190/// Used to output a message on a debug hardware unit - does nothing on a retail unit 198/// Used to output a message on a debug hardware unit - does nothing on a retail unit
@@ -246,13 +254,16 @@ static u32 ExitThread() {
246 254
247/// Gets the priority for the specified thread 255/// Gets the priority for the specified thread
248static Result GetThreadPriority(s32* priority, Handle handle) { 256static Result GetThreadPriority(s32* priority, Handle handle) {
249 *priority = Kernel::GetThreadPriority(handle); 257 ResultVal<u32> priority_result = Kernel::GetThreadPriority(handle);
250 return 0; 258 if (priority_result.Succeeded()) {
259 *priority = *priority_result;
260 }
261 return priority_result.Code().raw;
251} 262}
252 263
253/// Sets the priority for the specified thread 264/// Sets the priority for the specified thread
254static Result SetThreadPriority(Handle handle, s32 priority) { 265static Result SetThreadPriority(Handle handle, s32 priority) {
255 return Kernel::SetThreadPriority(handle, priority); 266 return Kernel::SetThreadPriority(handle, priority).raw;
256} 267}
257 268
258/// Create a mutex 269/// Create a mutex
@@ -266,9 +277,8 @@ static Result CreateMutex(Handle* mutex, u32 initial_locked) {
266/// Release a mutex 277/// Release a mutex
267static Result ReleaseMutex(Handle handle) { 278static Result ReleaseMutex(Handle handle) {
268 DEBUG_LOG(SVC, "called handle=0x%08X", handle); 279 DEBUG_LOG(SVC, "called handle=0x%08X", handle);
269 _assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!"); 280 ResultCode res = Kernel::ReleaseMutex(handle);
270 Kernel::ReleaseMutex(handle); 281 return res.raw;
271 return 0;
272} 282}
273 283
274/// Get current thread ID 284/// Get current thread ID
@@ -310,21 +320,22 @@ static Result DuplicateHandle(Handle* out, Handle handle) {
310 320
311/// Signals an event 321/// Signals an event
312static Result SignalEvent(Handle evt) { 322static Result SignalEvent(Handle evt) {
313 Result res = Kernel::SignalEvent(evt);
314 DEBUG_LOG(SVC, "called event=0x%08X", evt); 323 DEBUG_LOG(SVC, "called event=0x%08X", evt);
315 return res; 324 return Kernel::SignalEvent(evt).raw;
316} 325}
317 326
318/// Clears an event 327/// Clears an event
319static Result ClearEvent(Handle evt) { 328static Result ClearEvent(Handle evt) {
320 Result res = Kernel::ClearEvent(evt);
321 DEBUG_LOG(SVC, "called event=0x%08X", evt); 329 DEBUG_LOG(SVC, "called event=0x%08X", evt);
322 return res; 330 return Kernel::ClearEvent(evt).raw;
323} 331}
324 332
325/// Sleep the current thread 333/// Sleep the current thread
326static void SleepThread(s64 nanoseconds) { 334static void SleepThread(s64 nanoseconds) {
327 DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds); 335 DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds);
336
337 // Check for next thread to schedule
338 HLE::Reschedule(__func__);
328} 339}
329 340
330/// This returns the total CPU ticks elapsed since the CPU was powered-on 341/// This returns the total CPU ticks elapsed since the CPU was powered-on
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 3ad801c63..af5e1b39b 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -49,7 +49,7 @@ inline void Write(u32 addr, const T data) {
49 49
50 // Writes other than u32 are untested, so I'd rather have them abort than silently fail 50 // Writes other than u32 are untested, so I'd rather have them abort than silently fail
51 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { 51 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) {
52 ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 52 ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
53 return; 53 return;
54 } 54 }
55 55
@@ -140,8 +140,8 @@ inline void Write(u32 addr, const T data) {
140 140
141 DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x", 141 DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x",
142 config.output_height * config.output_width * 4, 142 config.output_height * config.output_width * 4,
143 config.GetPhysicalInputAddress(), config.input_width, config.input_height, 143 config.GetPhysicalInputAddress(), (u32)config.input_width, (u32)config.input_height,
144 config.GetPhysicalOutputAddress(), config.output_width, config.output_height, 144 config.GetPhysicalOutputAddress(), (u32)config.output_width, (u32)config.output_height,
145 config.output_format.Value()); 145 config.output_format.Value());
146 } 146 }
147 break; 147 break;
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index 4d0719263..ea001673a 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -68,7 +68,7 @@ inline void Write(u32 addr, const T data) {
68 break; 68 break;
69 69
70 default: 70 default:
71 ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 71 ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
72 } 72 }
73} 73}
74 74
diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp
index e29a773f1..593e5de30 100644
--- a/src/core/hw/ndma.cpp
+++ b/src/core/hw/ndma.cpp
@@ -15,7 +15,7 @@ inline void Read(T &var, const u32 addr) {
15 15
16template <typename T> 16template <typename T>
17inline void Write(u32 addr, const T data) { 17inline void Write(u32 addr, const T data) {
18 ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 18 ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
19} 19}
20 20
21// Explicitly instantiate template functions because we aren't defining this in the header: 21// Explicitly instantiate template functions because we aren't defining this in the header:
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp
index 443d5ad7e..e8747840c 100644
--- a/src/core/mem_map_funcs.cpp
+++ b/src/core/mem_map_funcs.cpp
@@ -92,7 +92,7 @@ inline void Read(T &var, const VAddr vaddr) {
92 var = *((const T*)&g_vram[vaddr & VRAM_MASK]); 92 var = *((const T*)&g_vram[vaddr & VRAM_MASK]);
93 93
94 } else { 94 } else {
95 ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); 95 ERROR_LOG(MEMMAP, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, vaddr);
96 } 96 }
97} 97}
98 98
@@ -141,7 +141,7 @@ inline void Write(const VAddr vaddr, const T data) {
141 141
142 // Error out... 142 // Error out...
143 } else { 143 } else {
144 ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr); 144 ERROR_LOG(MEMMAP, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, vaddr);
145 } 145 }
146} 146}
147 147
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index abbb4c2cb..fd44c3f68 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -240,14 +240,14 @@ MathUtil::Rectangle<unsigned> RendererOpenGL::GetViewportExtent() {
240 MathUtil::Rectangle<unsigned> viewport_extent; 240 MathUtil::Rectangle<unsigned> viewport_extent;
241 if (window_aspect_ratio > emulation_aspect_ratio) { 241 if (window_aspect_ratio > emulation_aspect_ratio) {
242 // Window is narrower than the emulation content => apply borders to the top and bottom 242 // Window is narrower than the emulation content => apply borders to the top and bottom
243 unsigned viewport_height = emulation_aspect_ratio * framebuffer_width; 243 unsigned viewport_height = std::round(emulation_aspect_ratio * framebuffer_width);
244 viewport_extent.left = 0; 244 viewport_extent.left = 0;
245 viewport_extent.top = (framebuffer_height - viewport_height) / 2; 245 viewport_extent.top = (framebuffer_height - viewport_height) / 2;
246 viewport_extent.right = viewport_extent.left + framebuffer_width; 246 viewport_extent.right = viewport_extent.left + framebuffer_width;
247 viewport_extent.bottom = viewport_extent.top + viewport_height; 247 viewport_extent.bottom = viewport_extent.top + viewport_height;
248 } else { 248 } else {
249 // Otherwise, apply borders to the left and right sides of the window. 249 // Otherwise, apply borders to the left and right sides of the window.
250 unsigned viewport_width = framebuffer_height / emulation_aspect_ratio; 250 unsigned viewport_width = std::round(framebuffer_height / emulation_aspect_ratio);
251 viewport_extent.left = (framebuffer_width - viewport_width) / 2; 251 viewport_extent.left = (framebuffer_width - viewport_width) / 2;
252 viewport_extent.top = 0; 252 viewport_extent.top = 0;
253 viewport_extent.right = viewport_extent.left + viewport_width; 253 viewport_extent.right = viewport_extent.left + viewport_width;