summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2014-06-14 12:13:16 -0400
committerGravatar bunnei2014-06-14 12:13:16 -0400
commit004df767953a949817da89bddcd5d1379240f769 (patch)
treeb2d54928dcbf3cb4dde0cd5d3277afe7999b7bd9 /src
parentGPU debugger: Const correctness and build fix. (diff)
parentKernel: Removed unnecessary "#pragma once". (diff)
downloadyuzu-004df767953a949817da89bddcd5d1379240f769.tar.gz
yuzu-004df767953a949817da89bddcd5d1379240f769.tar.xz
yuzu-004df767953a949817da89bddcd5d1379240f769.zip
Merge branch 'threading' of https://github.com/bunnei/citra
Conflicts: src/core/hle/function_wrappers.h src/core/hle/service/gsp.cpp
Diffstat (limited to 'src')
-rw-r--r--src/citra_qt/debugger/disassembler.cpp2
-rw-r--r--src/common/console_listener.cpp16
-rw-r--r--src/common/log.h39
-rw-r--r--src/common/log_manager.cpp30
-rw-r--r--src/common/log_manager.h6
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/arm_interface.h3
-rw-r--r--src/core/arm/interpreter/arm_interpreter.cpp14
-rw-r--r--src/core/arm/interpreter/arm_interpreter.h3
-rw-r--r--src/core/arm/interpreter/armemu.cpp18
-rw-r--r--src/core/core.cpp23
-rw-r--r--src/core/core.vcxproj4
-rw-r--r--src/core/core.vcxproj.filters12
-rw-r--r--src/core/hle/config_mem.cpp2
-rw-r--r--src/core/hle/coprocessor.cpp2
-rw-r--r--src/core/hle/function_wrappers.h753
-rw-r--r--src/core/hle/hle.cpp20
-rw-r--r--src/core/hle/hle.h12
-rw-r--r--src/core/hle/kernel/event.cpp159
-rw-r--r--src/core/hle/kernel/event.h52
-rw-r--r--src/core/hle/kernel/kernel.cpp11
-rw-r--r--src/core/hle/kernel/kernel.h33
-rw-r--r--src/core/hle/kernel/mutex.cpp50
-rw-r--r--src/core/hle/kernel/mutex.h6
-rw-r--r--src/core/hle/kernel/thread.cpp223
-rw-r--r--src/core/hle/kernel/thread.h15
-rw-r--r--src/core/hle/service/apt.cpp187
-rw-r--r--src/core/hle/service/gsp.cpp74
-rw-r--r--src/core/hle/service/hid.cpp10
-rw-r--r--src/core/hle/service/ndm.cpp32
-rw-r--r--src/core/hle/service/ndm.h33
-rw-r--r--src/core/hle/service/service.cpp10
-rw-r--r--src/core/hle/service/service.h40
-rw-r--r--src/core/hle/service/srv.cpp27
-rw-r--r--src/core/hle/service/srv.h6
-rw-r--r--src/core/hle/svc.cpp487
-rw-r--r--src/core/hle/svc.h13
-rw-r--r--src/core/hw/gpu.cpp2
-rw-r--r--src/core/hw/gpu.h3
-rw-r--r--src/core/mem_map_funcs.cpp5
-rw-r--r--src/core/system.cpp3
41 files changed, 1243 insertions, 1199 deletions
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
index ccc83abf2..4e8f841f4 100644
--- a/src/citra_qt/debugger/disassembler.cpp
+++ b/src/citra_qt/debugger/disassembler.cpp
@@ -48,7 +48,7 @@ void DisassemblerWidget::Init()
48 unsigned int curInstAddr = base_addr; 48 unsigned int curInstAddr = base_addr;
49 char result[255]; 49 char result[255];
50 50
51 for (int i = 0; i < 10000; i++) // fixed for now 51 for (int i = 0; i < 20000; i++) // fixed for now
52 { 52 {
53 disasm->disasm(curInstAddr, Memory::Read32(curInstAddr), result); 53 disasm->disasm(curInstAddr, Memory::Read32(curInstAddr), result);
54 model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0')))); 54 model->setItem(i, 0, new QStandardItem(QString("0x%1").arg((uint)(curInstAddr), 8, 16, QLatin1Char('0'))));
diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp
index b5f32d1bd..db48abbf6 100644
--- a/src/common/console_listener.cpp
+++ b/src/common/console_listener.cpp
@@ -259,14 +259,17 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
259 259
260 switch (Level) 260 switch (Level)
261 { 261 {
262 case OS_LEVEL: // light yellow
263 Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
264 break;
262 case NOTICE_LEVEL: // light green 265 case NOTICE_LEVEL: // light green
263 Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY; 266 Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
264 break; 267 break;
265 case ERROR_LEVEL: // light red 268 case ERROR_LEVEL: // light red
266 Color = FOREGROUND_RED | FOREGROUND_INTENSITY; 269 Color = FOREGROUND_RED | FOREGROUND_INTENSITY;
267 break; 270 break;
268 case WARNING_LEVEL: // light yellow 271 case WARNING_LEVEL: // light purple
269 Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; 272 Color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
270 break; 273 break;
271 case INFO_LEVEL: // cyan 274 case INFO_LEVEL: // cyan
272 Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; 275 Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
@@ -278,15 +281,8 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
278 Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; 281 Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
279 break; 282 break;
280 } 283 }
281 if (strlen(Text) > 10)
282 {
283 // First 10 chars white
284 SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
285 WriteConsole(hConsole, Text, 10, &cCharsWritten, NULL);
286 Text += 10;
287 }
288 SetConsoleTextAttribute(hConsole, Color); 284 SetConsoleTextAttribute(hConsole, Color);
289 WriteConsole(hConsole, Text, (DWORD)strlen(Text), &cCharsWritten, NULL); 285 printf(Text);
290#else 286#else
291 char ColorAttr[16] = ""; 287 char ColorAttr[16] = "";
292 char ResetAttr[16] = ""; 288 char ResetAttr[16] = "";
diff --git a/src/common/log.h b/src/common/log.h
index d0da68aad..e923224ed 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -7,11 +7,14 @@
7 7
8#define LOGGING 8#define LOGGING
9 9
10#define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and OSReports. 10enum {
11#define ERROR_LEVEL 2 // Critical errors 11 OS_LEVEL, // Printed by the emulated operating system
12#define WARNING_LEVEL 3 // Something is suspicious. 12 NOTICE_LEVEL, // VERY important information that is NOT errors. Like startup and OSReports.
13#define INFO_LEVEL 4 // General information. 13 ERROR_LEVEL, // Critical errors
14#define DEBUG_LEVEL 5 // Detailed debugging - might make things slow. 14 WARNING_LEVEL, // Something is suspicious.
15 INFO_LEVEL, // General information.
16 DEBUG_LEVEL, // Detailed debugging - might make things slow.
17};
15 18
16namespace LogTypes 19namespace LogTypes
17{ 20{
@@ -70,6 +73,7 @@ enum LOG_TYPE {
70 73
71// FIXME: should this be removed? 74// FIXME: should this be removed?
72enum LOG_LEVELS { 75enum LOG_LEVELS {
76 LOS = OS_LEVEL,
73 LNOTICE = NOTICE_LEVEL, 77 LNOTICE = NOTICE_LEVEL,
74 LERROR = ERROR_LEVEL, 78 LERROR = ERROR_LEVEL,
75 LWARNING = WARNING_LEVEL, 79 LWARNING = WARNING_LEVEL,
@@ -82,31 +86,34 @@ enum LOG_LEVELS {
82 86
83} // namespace 87} // namespace
84 88
85void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, 89void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int line,
86 const char *file, int line, const char *fmt, ...) 90 const char* function, const char* fmt, ...)
87#ifdef __GNUC__ 91#ifdef __GNUC__
88 __attribute__((format(printf, 5, 6))) 92 __attribute__((format(printf, 6, 7)))
89#endif 93#endif
90 ; 94 ;
91 95
92#if defined LOGGING || defined _DEBUG || defined DEBUGFAST 96#if defined LOGGING || defined _DEBUG || defined DEBUGFAST
93#define MAX_LOGLEVEL DEBUG_LEVEL 97#define MAX_LOGLEVEL LDEBUG
94#else 98#else
95#ifndef MAX_LOGLEVEL 99#ifndef MAX_LOGLEVEL
96#define MAX_LOGLEVEL WARNING_LEVEL 100#define MAX_LOGLEVEL LWARNING
97#endif // loglevel 101#endif // loglevel
98#endif // logging 102#endif // logging
99 103
100#ifdef GEKKO 104#ifdef _WIN32
101#define GENERIC_LOG(t, v, ...) 105#ifndef __func__
102#else 106#define __func__ __FUNCTION__
107#endif
108#endif
109
103// Let the compiler optimize this out 110// Let the compiler optimize this out
104#define GENERIC_LOG(t, v, ...) { \ 111#define GENERIC_LOG(t, v, ...) { \
105 if (v <= MAX_LOGLEVEL) \ 112 if (v <= LogTypes::MAX_LOGLEVEL) \
106 GenericLog(v, t, __FILE__, __LINE__, __VA_ARGS__); \ 113 GenericLog(v, t, __FILE__, __LINE__, __func__, __VA_ARGS__); \
107 } 114 }
108#endif
109 115
116#define OS_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LOS, __VA_ARGS__) } while (0)
110#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0) 117#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0)
111#define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0) 118#define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0)
112#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0) 119#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0)
diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp
index b4a761c75..4e1cb60bd 100644
--- a/src/common/log_manager.cpp
+++ b/src/common/log_manager.cpp
@@ -10,14 +10,16 @@
10#include "common/thread.h" 10#include "common/thread.h"
11#include "common/file_util.h" 11#include "common/file_util.h"
12 12
13void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, 13void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
14 const char *file, int line, const char* fmt, ...) 14 const char* function, const char* fmt, ...)
15{ 15{
16 va_list args; 16 va_list args;
17 va_start(args, fmt); 17 va_start(args, fmt);
18 if (LogManager::GetInstance()) 18
19 if (LogManager::GetInstance()) {
19 LogManager::GetInstance()->Log(level, type, 20 LogManager::GetInstance()->Log(level, type,
20 file, line, fmt, args); 21 file, line, function, fmt, args);
22 }
21 va_end(args); 23 va_end(args);
22} 24}
23 25
@@ -88,6 +90,8 @@ LogManager::LogManager()
88 m_Log[i]->AddListener(m_debuggerLog); 90 m_Log[i]->AddListener(m_debuggerLog);
89#endif 91#endif
90 } 92 }
93
94 m_consoleLog->Open();
91} 95}
92 96
93LogManager::~LogManager() 97LogManager::~LogManager()
@@ -107,8 +111,8 @@ LogManager::~LogManager()
107 delete m_debuggerLog; 111 delete m_debuggerLog;
108} 112}
109 113
110void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, 114void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file,
111 const char *file, int line, const char *format, va_list args) 115 int line, const char* function, const char *fmt, va_list args)
112{ 116{
113 char temp[MAX_MSGLEN]; 117 char temp[MAX_MSGLEN];
114 char msg[MAX_MSGLEN * 2]; 118 char msg[MAX_MSGLEN * 2];
@@ -117,17 +121,15 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
117 if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) 121 if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners())
118 return; 122 return;
119 123
120 CharArrayFromFormatV(temp, MAX_MSGLEN, format, args); 124 CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args);
121 125
122 static const char level_to_char[7] = "-NEWID"; 126 static const char level_to_char[7] = "ONEWID";
123 sprintf(msg, "%s %s:%u %c[%s]: %s\n", 127 sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line,
124 Common::Timer::GetTimeFormatted().c_str(), 128 level_to_char[(int)level], log->GetShortName(), function, temp);
125 file, line, level_to_char[(int)level], 129
126 log->GetShortName(), temp);
127#ifdef ANDROID 130#ifdef ANDROID
128 Host_SysMessage(msg); 131 Host_SysMessage(msg);
129#endif 132#endif
130 printf(msg); // TODO(ShizZy): RemoveMe when I no longer need this
131 log->Trigger(level, msg); 133 log->Trigger(level, msg);
132} 134}
133 135
@@ -147,7 +149,7 @@ LogContainer::LogContainer(const char* shortName, const char* fullName, bool ena
147{ 149{
148 strncpy(m_fullName, fullName, 128); 150 strncpy(m_fullName, fullName, 128);
149 strncpy(m_shortName, shortName, 32); 151 strncpy(m_shortName, shortName, 32);
150 m_level = (LogTypes::LOG_LEVELS)MAX_LOGLEVEL; 152 m_level = LogTypes::MAX_LOGLEVEL;
151} 153}
152 154
153// LogContainer 155// LogContainer
diff --git a/src/common/log_manager.h b/src/common/log_manager.h
index 580860b4d..6d3d7c7ff 100644
--- a/src/common/log_manager.h
+++ b/src/common/log_manager.h
@@ -97,10 +97,10 @@ private:
97 ~LogManager(); 97 ~LogManager();
98public: 98public:
99 99
100 static u32 GetMaxLevel() { return MAX_LOGLEVEL; } 100 static u32 GetMaxLevel() { return LogTypes::MAX_LOGLEVEL; }
101 101
102 void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, 102 void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
103 const char *file, int line, const char *fmt, va_list args); 103 const char* function, const char *fmt, va_list args);
104 104
105 void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) 105 void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level)
106 { 106 {
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 1c1a2eeb3..7116b88e9 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -34,12 +34,14 @@ set(SRCS core.cpp
34 hle/config_mem.cpp 34 hle/config_mem.cpp
35 hle/coprocessor.cpp 35 hle/coprocessor.cpp
36 hle/svc.cpp 36 hle/svc.cpp
37 hle/kernel/event.cpp
37 hle/kernel/kernel.cpp 38 hle/kernel/kernel.cpp
38 hle/kernel/mutex.cpp 39 hle/kernel/mutex.cpp
39 hle/kernel/thread.cpp 40 hle/kernel/thread.cpp
40 hle/service/apt.cpp 41 hle/service/apt.cpp
41 hle/service/gsp.cpp 42 hle/service/gsp.cpp
42 hle/service/hid.cpp 43 hle/service/hid.cpp
44 hle/service/ndm.cpp
43 hle/service/service.cpp 45 hle/service/service.cpp
44 hle/service/srv.cpp 46 hle/service/srv.cpp
45 hw/gpu.cpp 47 hw/gpu.cpp
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 34a2eba1b..be677ae20 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -89,6 +89,9 @@ public:
89 */ 89 */
90 virtual void LoadContext(const ThreadContext& ctx) = 0; 90 virtual void LoadContext(const ThreadContext& ctx) = 0;
91 91
92 /// Prepare core for thread reschedule (if needed to correctly handle state)
93 virtual void PrepareReschedule() = 0;
94
92 /// Getter for num_instructions 95 /// Getter for num_instructions
93 u64 GetNumInstructions() { 96 u64 GetNumInstructions() {
94 return num_instructions; 97 return num_instructions;
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp
index 17f787b86..0e893f182 100644
--- a/src/core/arm/interpreter/arm_interpreter.cpp
+++ b/src/core/arm/interpreter/arm_interpreter.cpp
@@ -98,7 +98,7 @@ u64 ARM_Interpreter::GetTicks() const {
98 * @param num_instructions Number of instructions to executes 98 * @param num_instructions Number of instructions to executes
99 */ 99 */
100void ARM_Interpreter::ExecuteInstructions(int num_instructions) { 100void ARM_Interpreter::ExecuteInstructions(int num_instructions) {
101 state->NumInstrsToExecute = num_instructions; 101 state->NumInstrsToExecute = num_instructions - 1;
102 ARMul_Emulate32(state); 102 ARMul_Emulate32(state);
103} 103}
104 104
@@ -118,6 +118,9 @@ void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
118 118
119 ctx.fpscr = state->VFP[1]; 119 ctx.fpscr = state->VFP[1];
120 ctx.fpexc = state->VFP[2]; 120 ctx.fpexc = state->VFP[2];
121
122 ctx.reg_15 = state->Reg[15];
123 ctx.mode = state->NextInstr;
121} 124}
122 125
123/** 126/**
@@ -137,6 +140,11 @@ void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
137 state->VFP[1] = ctx.fpscr; 140 state->VFP[1] = ctx.fpscr;
138 state->VFP[2] = ctx.fpexc; 141 state->VFP[2] = ctx.fpexc;
139 142
140 state->Reg[15] = ctx.pc; 143 state->Reg[15] = ctx.reg_15;
141 state->NextInstr = RESUME; 144 state->NextInstr = ctx.mode;
145}
146
147/// Prepare core for thread reschedule (if needed to correctly handle state)
148void ARM_Interpreter::PrepareReschedule() {
149 state->NumInstrsToExecute = 0;
142} 150}
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h
index 6a531e497..1e82883a2 100644
--- a/src/core/arm/interpreter/arm_interpreter.h
+++ b/src/core/arm/interpreter/arm_interpreter.h
@@ -72,6 +72,9 @@ public:
72 */ 72 */
73 void LoadContext(const ThreadContext& ctx); 73 void LoadContext(const ThreadContext& ctx);
74 74
75 /// Prepare core for thread reschedule (if needed to correctly handle state)
76 void PrepareReschedule();
77
75protected: 78protected:
76 79
77 /** 80 /**
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index e5dc7bd44..f3c14e608 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -4456,6 +4456,7 @@ ARMul_Emulate26 (ARMul_State * state)
4456 } 4456 }
4457 /* Drop through. */ 4457 /* Drop through. */
4458 4458
4459 case 0xe0:
4459 case 0xe4: 4460 case 0xe4:
4460 case 0xe6: 4461 case 0xe6:
4461 case 0xe8: 4462 case 0xe8:
@@ -4489,7 +4490,6 @@ ARMul_Emulate26 (ARMul_State * state)
4489 4490
4490 4491
4491 /* Co-Processor Register Transfers (MRC) and Data Ops. */ 4492 /* Co-Processor Register Transfers (MRC) and Data Ops. */
4492 case 0xe0:
4493 case 0xe1: 4493 case 0xe1:
4494 case 0xe3: 4494 case 0xe3:
4495 case 0xe5: 4495 case 0xe5:
@@ -4533,23 +4533,7 @@ ARMul_Emulate26 (ARMul_State * state)
4533 case 0xfd: 4533 case 0xfd:
4534 case 0xfe: 4534 case 0xfe:
4535 case 0xff: 4535 case 0xff:
4536 if (instr == ARMul_ABORTWORD
4537 && state->AbortAddr == pc) {
4538 /* A prefetch abort. */
4539 XScale_set_fsr_far (state,
4540 ARMul_CP15_R5_MMU_EXCPT,
4541 pc);
4542 ARMul_Abort (state,
4543 ARMul_PrefetchAbortV);
4544 break;
4545 }
4546 //sky_pref_t* pref = get_skyeye_pref();
4547 //if(pref->user_mode_sim){
4548 // ARMul_OSHandleSWI (state, BITS (0, 23));
4549 // break;
4550 //}
4551 HLE::CallSVC(instr); 4536 HLE::CallSVC(instr);
4552 ARMul_Abort (state, ARMul_SWIV);
4553 break; 4537 break;
4554 } 4538 }
4555 } 4539 }
diff --git a/src/core/core.cpp b/src/core/core.cpp
index f88bcd704..7dc0809d0 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -9,21 +9,24 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/mem_map.h" 10#include "core/mem_map.h"
11#include "core/hw/hw.h" 11#include "core/hw/hw.h"
12#include "core/hw/gpu.h"
12#include "core/arm/disassembler/arm_disasm.h" 13#include "core/arm/disassembler/arm_disasm.h"
13#include "core/arm/interpreter/arm_interpreter.h" 14#include "core/arm/interpreter/arm_interpreter.h"
14 15
16#include "core/hle/hle.h"
15#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
16 18
17namespace Core { 19namespace Core {
18 20
19ARM_Disasm* g_disasm = NULL; ///< ARM disassembler 21u64 g_last_ticks = 0; ///< Last CPU ticks
20ARM_Interface* g_app_core = NULL; ///< ARM11 application core 22ARM_Disasm* g_disasm = nullptr; ///< ARM disassembler
21ARM_Interface* g_sys_core = NULL; ///< ARM11 system (OS) core 23ARM_Interface* g_app_core = nullptr; ///< ARM11 application core
24ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core
22 25
23/// Run the core CPU loop 26/// Run the core CPU loop
24void RunLoop() { 27void RunLoop() {
25 for (;;){ 28 for (;;){
26 g_app_core->Run(100); 29 g_app_core->Run(GPU::kFrameTicks);
27 HW::Update(); 30 HW::Update();
28 Kernel::Reschedule(); 31 Kernel::Reschedule();
29 } 32 }
@@ -32,8 +35,14 @@ void RunLoop() {
32/// Step the CPU one instruction 35/// Step the CPU one instruction
33void SingleStep() { 36void SingleStep() {
34 g_app_core->Step(); 37 g_app_core->Step();
35 HW::Update(); 38
36 Kernel::Reschedule(); 39 // Update and reschedule after approx. 1 frame
40 u64 current_ticks = Core::g_app_core->GetTicks();
41 if ((current_ticks - g_last_ticks) >= GPU::kFrameTicks || HLE::g_reschedule) {
42 g_last_ticks = current_ticks;
43 HW::Update();
44 Kernel::Reschedule();
45 }
37} 46}
38 47
39/// Halt the core 48/// Halt the core
@@ -54,6 +63,8 @@ int Init() {
54 g_app_core = new ARM_Interpreter(); 63 g_app_core = new ARM_Interpreter();
55 g_sys_core = new ARM_Interpreter(); 64 g_sys_core = new ARM_Interpreter();
56 65
66 g_last_ticks = Core::g_app_core->GetTicks();
67
57 return 0; 68 return 0;
58} 69}
59 70
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index 8a3ad83ea..8eb189a8b 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -168,12 +168,14 @@
168 <ClCompile Include="hle\config_mem.cpp" /> 168 <ClCompile Include="hle\config_mem.cpp" />
169 <ClCompile Include="hle\coprocessor.cpp" /> 169 <ClCompile Include="hle\coprocessor.cpp" />
170 <ClCompile Include="hle\hle.cpp" /> 170 <ClCompile Include="hle\hle.cpp" />
171 <ClCompile Include="hle\kernel\event.cpp" />
171 <ClCompile Include="hle\kernel\kernel.cpp" /> 172 <ClCompile Include="hle\kernel\kernel.cpp" />
172 <ClCompile Include="hle\kernel\mutex.cpp" /> 173 <ClCompile Include="hle\kernel\mutex.cpp" />
173 <ClCompile Include="hle\kernel\thread.cpp" /> 174 <ClCompile Include="hle\kernel\thread.cpp" />
174 <ClCompile Include="hle\service\apt.cpp" /> 175 <ClCompile Include="hle\service\apt.cpp" />
175 <ClCompile Include="hle\service\gsp.cpp" /> 176 <ClCompile Include="hle\service\gsp.cpp" />
176 <ClCompile Include="hle\service\hid.cpp" /> 177 <ClCompile Include="hle\service\hid.cpp" />
178 <ClCompile Include="hle\service\ndm.cpp" />
177 <ClCompile Include="hle\service\service.cpp" /> 179 <ClCompile Include="hle\service\service.cpp" />
178 <ClCompile Include="hle\service\srv.cpp" /> 180 <ClCompile Include="hle\service\srv.cpp" />
179 <ClCompile Include="hle\svc.cpp" /> 181 <ClCompile Include="hle\svc.cpp" />
@@ -217,12 +219,14 @@
217 <ClInclude Include="hle\coprocessor.h" /> 219 <ClInclude Include="hle\coprocessor.h" />
218 <ClInclude Include="hle\function_wrappers.h" /> 220 <ClInclude Include="hle\function_wrappers.h" />
219 <ClInclude Include="hle\hle.h" /> 221 <ClInclude Include="hle\hle.h" />
222 <ClInclude Include="hle\kernel\event.h" />
220 <ClInclude Include="hle\kernel\kernel.h" /> 223 <ClInclude Include="hle\kernel\kernel.h" />
221 <ClInclude Include="hle\kernel\mutex.h" /> 224 <ClInclude Include="hle\kernel\mutex.h" />
222 <ClInclude Include="hle\kernel\thread.h" /> 225 <ClInclude Include="hle\kernel\thread.h" />
223 <ClInclude Include="hle\service\apt.h" /> 226 <ClInclude Include="hle\service\apt.h" />
224 <ClInclude Include="hle\service\gsp.h" /> 227 <ClInclude Include="hle\service\gsp.h" />
225 <ClInclude Include="hle\service\hid.h" /> 228 <ClInclude Include="hle\service\hid.h" />
229 <ClInclude Include="hle\service\ndm.h" />
226 <ClInclude Include="hle\service\service.h" /> 230 <ClInclude Include="hle\service\service.h" />
227 <ClInclude Include="hle\service\srv.h" /> 231 <ClInclude Include="hle\service\srv.h" />
228 <ClInclude Include="hle\svc.h" /> 232 <ClInclude Include="hle\svc.h" />
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index f7b342f98..da781f816 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -165,6 +165,12 @@
165 <ClCompile Include="arm\interpreter\armcopro.cpp"> 165 <ClCompile Include="arm\interpreter\armcopro.cpp">
166 <Filter>arm\interpreter</Filter> 166 <Filter>arm\interpreter</Filter>
167 </ClCompile> 167 </ClCompile>
168 <ClCompile Include="hle\kernel\event.cpp">
169 <Filter>hle\kernel</Filter>
170 </ClCompile>
171 <ClCompile Include="hle\service\ndm.cpp">
172 <Filter>hle\service</Filter>
173 </ClCompile>
168 </ItemGroup> 174 </ItemGroup>
169 <ItemGroup> 175 <ItemGroup>
170 <ClInclude Include="arm\disassembler\arm_disasm.h"> 176 <ClInclude Include="arm\disassembler\arm_disasm.h">
@@ -295,6 +301,12 @@
295 <ClInclude Include="hle\kernel\mutex.h"> 301 <ClInclude Include="hle\kernel\mutex.h">
296 <Filter>hle\kernel</Filter> 302 <Filter>hle\kernel</Filter>
297 </ClInclude> 303 </ClInclude>
304 <ClInclude Include="hle\kernel\event.h">
305 <Filter>hle\kernel</Filter>
306 </ClInclude>
307 <ClInclude Include="hle\service\ndm.h">
308 <Filter>hle\service</Filter>
309 </ClInclude>
298 </ItemGroup> 310 </ItemGroup>
299 <ItemGroup> 311 <ItemGroup>
300 <Text Include="CMakeLists.txt" /> 312 <Text Include="CMakeLists.txt" />
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp
index 48aa878cc..8c898b265 100644
--- a/src/core/hle/config_mem.cpp
+++ b/src/core/hle/config_mem.cpp
@@ -55,7 +55,7 @@ inline void Read(T &var, const u32 addr) {
55 break; 55 break;
56 56
57 default: 57 default:
58 ERROR_LOG(HLE, "unknown ConfigMem::Read%d @ 0x%08X", sizeof(var) * 8, addr); 58 ERROR_LOG(HLE, "unknown addr=0x%08X", addr);
59 } 59 }
60} 60}
61 61
diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp
index 39674ee64..9a5b0deda 100644
--- a/src/core/hle/coprocessor.cpp
+++ b/src/core/hle/coprocessor.cpp
@@ -25,7 +25,7 @@ s32 CallMRC(u32 instruction) {
25 return GetThreadCommandBuffer(); 25 return GetThreadCommandBuffer();
26 26
27 default: 27 default:
28 //DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction); 28 DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction);
29 break; 29 break;
30 } 30 }
31 return -1; 31 return -1;
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 801865d49..0bed78653 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -1,19 +1,6 @@
1// Copyright (c) 2012- PPSSPP Project. 1// Copyright 2014 Citra Emulator Project
2 2// Licensed under GPLv2
3// This program is free software: you can redistribute it and/or modify 3// Refer to the license.txt file included.
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, version 2.0 or later versions.
6
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10// GNU General Public License 2.0 for more details.
11
12// A copy of the GPL 2.0 should have been included with the program.
13// If not, see http://www.gnu.org/licenses/
14
15// Official git repository and contact information can be found at
16// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17 4
18#pragma once 5#pragma once
19 6
@@ -21,725 +8,107 @@
21#include "core/mem_map.h" 8#include "core/mem_map.h"
22#include "core/hle/hle.h" 9#include "core/hle/hle.h"
23 10
24// For easy parameter parsing and return value processing. 11namespace HLE {
25
26//32bit wrappers
27template<void func()> void WrapV_V() {
28 func();
29}
30
31template<u32 func()> void WrapU_V() {
32 RETURN(func());
33}
34
35template<int func(void *, const char *)> void WrapI_VC() {
36 u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1)));
37 RETURN(retval);
38}
39
40template<u32 func(int, void *, int)> void WrapU_IVI() {
41 u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), PARAM(2));
42 RETURN(retval);
43}
44
45template<int func(const char *, int, int, u32)> void WrapI_CIIU() {
46 u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
47 RETURN(retval);
48}
49
50template<int func(int, const char *, u32, void *, void *, u32, int)> void WrapI_ICUVVUI() {
51 u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)),Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) );
52 RETURN(retval);
53}
54
55// Hm, do so many params get passed in registers?
56template<int func(const char *, int, const char *, int, int, int, int, int)> void WrapI_CICIIIII() {
57 u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), Memory::GetCharPointer(PARAM(2)),
58 PARAM(3), PARAM(4), PARAM(5), PARAM(6), PARAM(7));
59 RETURN(retval);
60}
61
62// Hm, do so many params get passed in registers?
63template<int func(const char *, int, int, int, int, int, int)> void WrapI_CIIIIII() {
64 u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
65 PARAM(3), PARAM(4), PARAM(5), PARAM(6));
66 RETURN(retval);
67}
68
69// Hm, do so many params get passed in registers?
70template<int func(int, int, int, int, int, int, u32)> void WrapI_IIIIIIU() {
71 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
72 RETURN(retval);
73}
74
75// Hm, do so many params get passed in registers?
76template<int func(int, int, int, int, int, int, int, int, u32)> void WrapI_IIIIIIIIU() {
77 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6), PARAM(7), PARAM(8));
78 RETURN(retval);
79}
80
81template<u32 func(int, void *)> void WrapU_IV() {
82 u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)));
83 RETURN(retval);
84}
85
86template<u32 func(u32)> void WrapU_U() {
87 u32 retval = func(PARAM(0));
88 RETURN(retval);
89}
90
91template<u32 func(u32, int)> void WrapU_UI() {
92 u32 retval = func(PARAM(0), PARAM(1));
93 RETURN(retval);
94}
95
96template<int func(u32)> void WrapI_U() {
97 int retval = func(PARAM(0));
98 RETURN(retval);
99}
100
101template<int func(u32, int)> void WrapI_UI() {
102 int retval = func(PARAM(0), PARAM(1));
103 RETURN(retval);
104}
105
106template<int func(u32, int, int, u32)> void WrapI_UIIU() {
107 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
108 RETURN(retval);
109}
110
111template<u32 func(int, u32, int)> void WrapU_IUI() {
112 u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
113 RETURN(retval);
114}
115
116template<int func(u32, u32)> void WrapI_UU() {
117 int retval = func(PARAM(0), PARAM(1));
118 RETURN(retval);
119}
120
121template<int func(u32, u32, u32)> void WrapI_UUU() {
122 int retval = func(PARAM(0), PARAM(1), PARAM(2));
123 RETURN(retval);
124}
125
126template<int func(u32, u32, u32, int)> void WrapI_UUUI() {
127 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
128 RETURN(retval);
129}
130
131template<int func(u32, u32, u32, int, int, int,int )> void WrapI_UUUIIII() {
132 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
133 RETURN(retval);
134}
135
136template<int func(u32, u32, u32, u32)> void WrapI_UUUU() {
137 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
138 RETURN(retval);
139}
140
141template<int func(u32, u32, u32, u32, u32)> void WrapI_UUUUU() {
142 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
143 RETURN(retval);
144}
145
146template<int func(void*)> void WrapI_V() {
147 u32 retval = func(Memory::GetPointer(PARAM(0)));
148 RETURN(retval);
149}
150
151template<u32 func(int)> void WrapU_I() {
152 u32 retval = func(PARAM(0));
153 RETURN(retval);
154}
155
156template<u32 func(int, int, u32)> void WrapU_IIU() {
157 u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
158 RETURN(retval);
159}
160
161template<int func(int)> void WrapI_I() {
162 int retval = func(PARAM(0));
163 RETURN(retval);
164}
165
166template<void func(u32)> void WrapV_U() {
167 func(PARAM(0));
168}
169
170template<void func(int)> void WrapV_I() {
171 func(PARAM(0));
172}
173
174template<void func(u32, u32)> void WrapV_UU() {
175 func(PARAM(0), PARAM(1));
176}
177
178template<void func(int, int)> void WrapV_II() {
179 func(PARAM(0), PARAM(1));
180}
181
182template<void func(u32, const char *)> void WrapV_UC() {
183 func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
184}
185
186template<int func(u32, const char *)> void WrapI_UC() {
187 int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
188 RETURN(retval);
189}
190
191template<int func(u32, const char *, int)> void WrapI_UCI() {
192 int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2));
193 RETURN(retval);
194}
195
196template<u32 func(u32, int , int , int, int, int)> void WrapU_UIIIII() {
197 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
198 RETURN(retval);
199}
200
201template<u32 func(u32, int , int , int, u32)> void WrapU_UIIIU() {
202 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
203 RETURN(retval);
204}
205
206template<u32 func(u32, int , int , int, int, int, int)> void WrapU_UIIIIII() {
207 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
208 RETURN(retval);
209}
210
211template<u32 func(u32, u32)> void WrapU_UU() {
212 u32 retval = func(PARAM(0), PARAM(1));
213 RETURN(retval);
214}
215
216template<u32 func(u32, u32, int)> void WrapU_UUI() {
217 u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
218 RETURN(retval);
219}
220
221template<u32 func(u32, u32, int, int)> void WrapU_UUII() {
222 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
223 RETURN(retval);
224}
225
226template<u32 func(const char *, u32, u32, u32)> void WrapU_CUUU() {
227 u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
228 RETURN(retval);
229}
230
231template<void func(u32, int, u32, int, int)> void WrapV_UIUII() {
232 func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
233}
234
235template<u32 func(u32, int, u32, int, int)> void WrapU_UIUII() {
236 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
237 RETURN(retval);
238}
239
240template<int func(u32, int, u32, int, int)> void WrapI_UIUII() {
241 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
242 RETURN(retval);
243}
244
245template<u32 func(u32, int, u32, int)> void WrapU_UIUI() {
246 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
247 RETURN(retval);
248}
249
250template<int func(u32, int, u32, int)> void WrapI_UIUI() {
251 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
252 RETURN(retval);
253}
254
255template<u32 func(u32, int, u32)> void WrapU_UIU() {
256 u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
257 RETURN(retval);
258}
259
260template<u32 func(u32, int, u32, u32)> void WrapU_UIUU() {
261 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
262 RETURN(retval);
263}
264
265template<u32 func(u32, int, int)> void WrapU_UII() {
266 u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
267 RETURN(retval);
268}
269
270template<u32 func(u32, int, int, u32)> void WrapU_UIIU() {
271 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
272 RETURN(retval);
273}
274
275template<int func(u32, int, int, u32, u32)> void WrapI_UIIUU() {
276 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
277 RETURN(retval);
278}
279
280template<int func(u32, u32, int, int)> void WrapI_UUII() {
281 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
282 RETURN(retval);
283}
284
285template<int func(u32, u32, int, int, int)> void WrapI_UUIII() {
286 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
287 RETURN(retval);
288}
289
290template<void func(u32, int, int, int)> void WrapV_UIII() {
291 func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
292}
293
294template<void func(u32, int, int, int, int, int)> void WrapV_UIIIII() {
295 func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
296}
297
298template<void func(u32, int, int)> void WrapV_UII() {
299 func(PARAM(0), PARAM(1), PARAM(2));
300}
301 12
302template<u32 func(int, u32)> void WrapU_IU() { 13#define PARAM(n) Core::g_app_core->GetReg(n)
303 int retval = func(PARAM(0), PARAM(1)); 14#define RETURN(n) Core::g_app_core->SetReg(0, n)
304 RETURN(retval);
305}
306 15
307template<int func(int, u32)> void WrapI_IU() { 16////////////////////////////////////////////////////////////////////////////////////////////////////
308 int retval = func(PARAM(0), PARAM(1)); 17// Function wrappers that return type s32
309 RETURN(retval);
310}
311 18
312template<int func(u32, u32, int)> void WrapI_UUI() { 19template<s32 func(u32, u32, u32, u32)> void Wrap() {
313 int retval = func(PARAM(0), PARAM(1), PARAM(2)); 20 RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)));
314 RETURN(retval);
315} 21}
316 22
317template<int func(u32, u32, int, u32)> void WrapI_UUIU() { 23template<s32 func(u32, u32, u32, u32, u32)> void Wrap() {
318 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); 24 RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)));
319 RETURN(retval);
320} 25}
321 26
322template<int func(int, int)> void WrapI_II() { 27template<s32 func(u32*, u32, u32, u32, u32, u32)> void Wrap(){
323 int retval = func(PARAM(0), PARAM(1)); 28 u32 param_1 = 0;
29 u32 retval = func(&param_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
30 Core::g_app_core->SetReg(1, param_1);
324 RETURN(retval); 31 RETURN(retval);
325} 32}
326 33
327template<int func(int, int, int)> void WrapI_III() { 34template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() {
328 int retval = func(PARAM(0), PARAM(1), PARAM(2)); 35 s32 param_1 = 0;
36 s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
37 (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0)));
38 Core::g_app_core->SetReg(1, (u32)param_1);
329 RETURN(retval); 39 RETURN(retval);
330} 40}
331 41
332template<int func(int, u32, int)> void WrapI_IUI() { 42// TODO(bunnei): Is this correct? Probably not
333 int retval = func(PARAM(0), PARAM(1), PARAM(2)); 43template<s32 func(u32, u32, u32, u32, s64)> void Wrap() {
334 RETURN(retval); 44 RETURN(func(PARAM(5), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(4) << 32) | PARAM(0))));
335} 45}
336 46
337template<int func(int, int, int, int)> void WrapI_IIII() { 47template<s32 func(u32, s64)> void Wrap() {
338 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); 48 RETURN(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))));
339 RETURN(retval);
340} 49}
341 50
342template<int func(u32, int, int, int)> void WrapI_UIII() { 51template<s32 func(void*, void*, u32)> void Wrap(){
343 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); 52 RETURN(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)));
344 RETURN(retval);
345} 53}
346 54
347template<int func(int, int, int, u32, int)> void WrapI_IIIUI() { 55template<s32 func(s32*, u32)> void Wrap(){
348 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); 56 s32 param_1 = 0;
57 u32 retval = func(&param_1, PARAM(1));
58 Core::g_app_core->SetReg(1, param_1);
349 RETURN(retval); 59 RETURN(retval);
350} 60}
351 61
352template<int func(int, u32, u32, int, int)> void WrapI_IUUII() { 62template<s32 func(u32, s32)> void Wrap() {
353 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); 63 RETURN(func(PARAM(0), (s32)PARAM(1)));
354 RETURN(retval);
355} 64}
356 65
357template<int func(int, const char *, int, u32, u32)> void WrapI_ICIUU() { 66template<s32 func(u32*, u32)> void Wrap(){
358 int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4)); 67 u32 param_1 = 0;
68 u32 retval = func(&param_1, PARAM(1));
69 Core::g_app_core->SetReg(1, param_1);
359 RETURN(retval); 70 RETURN(retval);
360} 71}
361 72
362template<int func(int, int, u32)> void WrapI_IIU() { 73template<s32 func(u32)> void Wrap() {
363 int retval = func(PARAM(0), PARAM(1), PARAM(2)); 74 RETURN(func(PARAM(0)));
364 RETURN(retval);
365} 75}
366 76
367template<void func(int, u32)> void WrapV_IU() { 77template<s32 func(void*)> void Wrap() {
368 func(PARAM(0), PARAM(1)); 78 RETURN(func(Memory::GetPointer(PARAM(0))));
369} 79}
370 80
371template<void func(u32, int)> void WrapV_UI() { 81template<s32 func(s64*, u32, void*, s32)> void Wrap(){
372 func(PARAM(0), PARAM(1)); 82 RETURN(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)),
83 (s32)PARAM(3)));
373} 84}
374 85
375template<u32 func(const char *)> void WrapU_C() { 86template<s32 func(u32*, const char*)> void Wrap() {
376 u32 retval = func(Memory::GetCharPointer(PARAM(0))); 87 u32 param_1 = 0;
88 u32 retval = func(&param_1, Memory::GetCharPointer(PARAM(1)));
89 Core::g_app_core->SetReg(1, param_1);
377 RETURN(retval); 90 RETURN(retval);
378} 91}
379 92
380template<u32 func(const char *, const char *, const char *, u32)> void WrapU_CCCU() { 93////////////////////////////////////////////////////////////////////////////////////////////////////
381 u32 retval = func(Memory::GetCharPointer(PARAM(0)), 94// Function wrappers that return type u32
382 Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)),
383 PARAM(3));
384 RETURN(retval);
385}
386
387template<int func(const char *)> void WrapI_C() {
388 int retval = func(Memory::GetCharPointer(PARAM(0)));
389 RETURN(retval);
390}
391
392template<int func(const char *, u32)> void WrapI_CU() {
393 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
394 RETURN(retval);
395}
396
397template<int func(const char *, u32, int)> void WrapI_CUI() {
398 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
399 RETURN(retval);
400}
401 95
402template<int func(int, const char *, int, u32)> void WrapI_ICIU() { 96template<u32 func()> void Wrap() {
403 int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3)); 97 RETURN(func());
404 RETURN(retval);
405}
406
407template<int func(const char *, int, u32)> void WrapI_CIU() {
408 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
409 RETURN(retval);
410}
411
412template<int func(const char *, u32, u32)> void WrapI_CUU() {
413 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
414 RETURN(retval);
415}
416
417template<int func(const char *, u32, u32, u32)> void WrapI_CUUU() {
418 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
419 PARAM(3));
420 RETURN(retval);
421}
422
423template<int func(const char *, const char*, int, int)> void WrapI_CCII() {
424 int retval = func(Memory::GetCharPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
425 RETURN(retval);
426}
427
428template<int func(const char *, u32, u32, int, u32, u32)> void WrapI_CUUIUU() {
429 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
430 PARAM(3), PARAM(4), PARAM(5));
431 RETURN(retval);
432}
433
434template<int func(const char *, int, int, u32, int, int)> void WrapI_CIIUII() {
435 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
436 PARAM(3), PARAM(4), PARAM(5));
437 RETURN(retval);
438}
439
440template<int func(const char *, int, u32, u32, u32)> void WrapI_CIUUU() {
441 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
442 PARAM(3), PARAM(4));
443 RETURN(retval);
444}
445
446template<int func(const char *, u32, u32, u32, u32, u32)> void WrapI_CUUUUU() {
447 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
448 PARAM(3), PARAM(4), PARAM(5));
449 RETURN(retval);
450}
451
452template<u32 func(const char *, u32)> void WrapU_CU() {
453 u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
454 RETURN((u32) retval);
455}
456
457template<u32 func(u32, const char *)> void WrapU_UC() {
458 u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
459 RETURN(retval);
460}
461
462template<u32 func(const char *, u32, u32)> void WrapU_CUU() {
463 u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
464 RETURN((u32) retval);
465}
466
467template<u32 func(int, int, int)> void WrapU_III() {
468 u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
469 RETURN(retval);
470}
471
472template<u32 func(int, int)> void WrapU_II() {
473 u32 retval = func(PARAM(0), PARAM(1));
474 RETURN(retval);
475}
476
477template<u32 func(int, int, int, int)> void WrapU_IIII() {
478 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
479 RETURN(retval);
480}
481
482template<u32 func(int, u32, u32)> void WrapU_IUU() {
483 u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
484 RETURN(retval);
485}
486
487template<u32 func(int, u32, u32, u32)> void WrapU_IUUU() {
488 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
489 RETURN(retval);
490}
491
492template<u32 func(int, u32, u32, u32, u32)> void WrapU_IUUUU() {
493 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
494 RETURN(retval);
495}
496
497template<u32 func(u32, u32, u32)> void WrapU_UUU() {
498 u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
499 RETURN(retval);
500}
501
502template<void func(int, u32, u32)> void WrapV_IUU() {
503 func(PARAM(0), PARAM(1), PARAM(2));
504}
505
506template<void func(int, int, u32)> void WrapV_IIU() {
507 func(PARAM(0), PARAM(1), PARAM(2));
508}
509
510template<void func(u32, int, u32)> void WrapV_UIU() {
511 func(PARAM(0), PARAM(1), PARAM(2));
512}
513
514template<int func(u32, int, u32)> void WrapI_UIU() {
515 int retval = func(PARAM(0), PARAM(1), PARAM(2));
516 RETURN(retval);
517}
518
519template<void func(int, u32, u32, u32, u32)> void WrapV_IUUUU() {
520 func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
521}
522
523template<void func(u32, u32, u32)> void WrapV_UUU() {
524 func(PARAM(0), PARAM(1), PARAM(2));
525}
526
527template<void func(u32, u32, u32, u32)> void WrapV_UUUU() {
528 func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
529}
530
531template<void func(const char *, u32, int, u32)> void WrapV_CUIU() {
532 func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
533}
534
535template<int func(const char *, u32, int, u32)> void WrapI_CUIU() {
536 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
537 RETURN(retval);
538}
539
540template<void func(u32, const char *, u32, int, u32)> void WrapV_UCUIU() {
541 func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3),
542 PARAM(4));
543}
544
545template<int func(u32, const char *, u32, int, u32)> void WrapI_UCUIU() {
546 int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2),
547 PARAM(3), PARAM(4));
548 RETURN(retval);
549}
550
551template<void func(const char *, u32, int, int, u32)> void WrapV_CUIIU() {
552 func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3),
553 PARAM(4));
554}
555
556template<int func(const char *, u32, int, int, u32)> void WrapI_CUIIU() {
557 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
558 PARAM(3), PARAM(4));
559 RETURN(retval);
560}
561
562template<u32 func(u32, u32, u32, u32)> void WrapU_UUUU() {
563 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
564 RETURN(retval);
565}
566
567template<u32 func(u32, const char *, u32, u32)> void WrapU_UCUU() {
568 u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
569 RETURN(retval);
570}
571
572template<u32 func(u32, u32, u32, int)> void WrapU_UUUI() {
573 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
574 RETURN(retval);
575}
576
577template<u32 func(u32, u32, u32, int, u32)> void WrapU_UUUIU() {
578 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
579 RETURN(retval);
580}
581
582template<u32 func(u32, u32, u32, int, u32, int)> void WrapU_UUUIUI() {
583 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
584 RETURN(retval);
585}
586
587template<u32 func(u32, u32, int, u32)> void WrapU_UUIU() {
588 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
589 RETURN(retval);
590}
591
592template<u32 func(u32, int, int, int)> void WrapU_UIII() {
593 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
594 RETURN(retval);
595}
596
597template<int func(int, u32, u32, u32, u32)> void WrapI_IUUUU() {
598 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
599 RETURN(retval);
600}
601
602template<int func(int, u32, u32, u32, u32, u32)> void WrapI_IUUUUU() {
603 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
604 RETURN(retval);
605}
606
607template<int func(int, u32, int, int)> void WrapI_IUII() {
608 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
609 RETURN(retval);
610}
611template<u32 func(u32, u32, u32, u32, u32)> void WrapU_UUUUU() {
612 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
613 RETURN(retval);
614} 98}
615 99
616template<void func(u32, u32, u32, u32, u32)> void WrapV_UUUUU() { 100////////////////////////////////////////////////////////////////////////////////////////////////////
617 func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); 101/// Function wrappers that return type void
618}
619 102
620template<u32 func(const char *, const char *)> void WrapU_CC() { 103template<void func(s64)> void Wrap() {
621 int retval = func(Memory::GetCharPointer(PARAM(0)), 104 func(((s64)PARAM(1) << 32) | PARAM(0));
622 Memory::GetCharPointer(PARAM(1)));
623 RETURN(retval);
624} 105}
625 106
626template<void func(const char*)> void WrapV_C() { 107template<void func(const char*)> void Wrap() {
627 func(Memory::GetCharPointer(PARAM(0))); 108 func(Memory::GetCharPointer(PARAM(0)));
628} 109}
629 110
630template<void func(const char *, int)> void WrapV_CI() { 111#undef PARAM
631 func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); 112#undef RETURN
632}
633
634template<u32 func(const char *, int)> void WrapU_CI() {
635 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
636 RETURN(retval);
637}
638
639template<u32 func(const char *, int, int)> void WrapU_CII() {
640 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
641 RETURN(retval);
642}
643 113
644template<int func(const char *, int, u32, int, u32)> void WrapU_CIUIU() { 114} // namespace HLE
645 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
646 PARAM(3), PARAM(4));
647 RETURN(retval);
648}
649
650template<u32 func(const char *, int, u32, int, u32, int)> void WrapU_CIUIUI() {
651 u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
652 PARAM(3), PARAM(4), PARAM(5));
653 RETURN(retval);
654}
655
656template<u32 func(u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUU() {
657 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4),
658 PARAM(5));
659 RETURN(retval);
660}
661
662template<int func(int, u32, u32, u32)> void WrapI_IUUU() {
663 int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
664 RETURN(retval);
665}
666
667template<int func(int, u32, u32)> void WrapI_IUU() {
668 int retval = func(PARAM(0), PARAM(1), PARAM(2));
669 RETURN(retval);
670}
671
672template<u32 func(u32, u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUUU() {
673 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
674 RETURN(retval);
675}
676
677template<int func(u32, int, u32, u32)> void WrapI_UIUU() {
678 u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
679 RETURN(retval);
680}
681
682template<int func(int, const char *)> void WrapI_IC() {
683 int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
684 RETURN(retval);
685}
686
687template <int func(int, const char *, const char *, u32, int)> void WrapI_ICCUI() {
688 int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), PARAM(3), PARAM(4));
689 RETURN(retval);
690}
691
692template <int func(int, const char *, const char *, int)> void WrapI_ICCI() {
693 int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), PARAM(3));
694 RETURN(retval);
695}
696
697template <int func(const char *, int, int)> void WrapI_CII() {
698 int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
699 RETURN(retval);
700}
701
702template <int func(int, const char *, int)> void WrapI_ICI() {
703 int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2));
704 RETURN(retval);
705}
706
707template<int func(int, void *, void *, void *, void *, u32, int)> void WrapI_IVVVVUI(){
708 u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), Memory::GetPointer(PARAM(2)), Memory::GetPointer(PARAM(3)), Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) );
709 RETURN(retval);
710}
711
712template<int func(int, const char *, u32, void *, int, int, int)> void WrapI_ICUVIII(){
713 u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)), PARAM(4), PARAM(5), PARAM(6));
714 RETURN(retval);
715}
716
717template<int func(void*, u32)> void WrapI_VU(){
718 u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1));
719 RETURN(retval);
720}
721
722template<int func(void*, void*, u32)> void WrapI_VVU(){
723 u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2));
724 RETURN(retval);
725}
726
727template<int func(void*, u32, void*, int)> void WrapI_VUVI(){
728 u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), PARAM(3));
729 RETURN(retval);
730}
731
732template<int func(void*, u32, u32, u32, u32, u32)> void WrapI_VUUUUU(){
733 u32 retval = func(NULL, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
734 RETURN(retval);
735}
736
737template<int func(u32, s64)> void WrapI_US64() {
738 int retval = func(PARAM(0), PARAM64(1));
739 RETURN(retval);
740}
741
742template<int func(void*, void*, u32, u32, s64)> void WrapI_VVUUS64() {
743 int retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4));
744 RETURN(retval);
745}
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index 080c36abf..53cda4a61 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -7,6 +7,7 @@
7#include "core/mem_map.h" 7#include "core/mem_map.h"
8#include "core/hle/hle.h" 8#include "core/hle/hle.h"
9#include "core/hle/svc.h" 9#include "core/hle/svc.h"
10#include "core/hle/kernel/thread.h"
10#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
11 12
12//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -15,11 +16,13 @@ namespace HLE {
15 16
16static std::vector<ModuleDef> g_module_db; 17static std::vector<ModuleDef> g_module_db;
17 18
19bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a new thread
20
18const FunctionDef* GetSVCInfo(u32 opcode) { 21const FunctionDef* GetSVCInfo(u32 opcode) {
19 u32 func_num = opcode & 0xFFFFFF; // 8 bits 22 u32 func_num = opcode & 0xFFFFFF; // 8 bits
20 if (func_num > 0xFF) { 23 if (func_num > 0xFF) {
21 ERROR_LOG(HLE,"Unknown SVC: 0x%02X", func_num); 24 ERROR_LOG(HLE,"unknown svc=0x%02X", func_num);
22 return NULL; 25 return nullptr;
23 } 26 }
24 return &g_module_db[0].func_table[func_num]; 27 return &g_module_db[0].func_table[func_num];
25} 28}
@@ -33,19 +36,16 @@ void CallSVC(u32 opcode) {
33 if (info->func) { 36 if (info->func) {
34 info->func(); 37 info->func();
35 } else { 38 } else {
36 ERROR_LOG(HLE, "Unimplemented SVC function %s(..)", info->name.c_str()); 39 ERROR_LOG(HLE, "unimplemented SVC function %s(..)", info->name.c_str());
37 } 40 }
38} 41}
39 42
40void EatCycles(u32 cycles) { 43void Reschedule(const char *reason) {
41 // TODO: ImplementMe
42}
43
44void ReSchedule(const char *reason) {
45#ifdef _DEBUG 44#ifdef _DEBUG
46 _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "ReSchedule: Invalid or too long reason."); 45 _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
47#endif 46#endif
48 // TODO: ImplementMe 47 Core::g_app_core->PrepareReschedule();
48 g_reschedule = true;
49} 49}
50 50
51void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) { 51void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) {
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h
index c075147c3..bf4d84575 100644
--- a/src/core/hle/hle.h
+++ b/src/core/hle/hle.h
@@ -9,14 +9,10 @@
9 9
10//////////////////////////////////////////////////////////////////////////////////////////////////// 10////////////////////////////////////////////////////////////////////////////////////////////////////
11 11
12#define PARAM(n) Core::g_app_core->GetReg(n)
13#define PARAM64(n) (Core::g_app_core->GetReg(n) | ((u64)Core::g_app_core->GetReg(n + 1) << 32))
14#define RETURN(n) Core::g_app_core->SetReg(0, n)
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17
18namespace HLE { 12namespace HLE {
19 13
14extern bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
15
20typedef u32 Addr; 16typedef u32 Addr;
21typedef void (*Func)(); 17typedef void (*Func)();
22 18
@@ -36,9 +32,7 @@ void RegisterModule(std::string name, int num_functions, const FunctionDef *func
36 32
37void CallSVC(u32 opcode); 33void CallSVC(u32 opcode);
38 34
39void EatCycles(u32 cycles); 35void Reschedule(const char *reason);
40
41void ReSchedule(const char *reason);
42 36
43void Init(); 37void Init();
44 38
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
new file mode 100644
index 000000000..127c0cfc6
--- /dev/null
+++ b/src/core/hle/kernel/event.cpp
@@ -0,0 +1,159 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <map>
6#include <algorithm>
7#include <vector>
8
9#include "common/common.h"
10
11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/thread.h"
14
15namespace Kernel {
16
17class Event : public Object {
18public:
19 const char* GetTypeName() const { return "Event"; }
20 const char* GetName() const { return name.c_str(); }
21
22 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; }
23 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; }
24
25 ResetType intitial_reset_type; ///< ResetType specified at Event initialization
26 ResetType reset_type; ///< Current ResetType
27
28 bool locked; ///< Event signal wait
29 bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough)
30 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event
31 std::string name; ///< Name of event (optional)
32
33 /**
34 * Wait for kernel object to synchronize
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) {
39 *wait = locked;
40 if (locked) {
41 Handle thread = GetCurrentThreadHandle();
42 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
43 waiting_threads.push_back(thread);
44 }
45 Kernel::WaitCurrentThread(WAITTYPE_EVENT);
46 }
47 if (reset_type != RESETTYPE_STICKY && !permanent_locked) {
48 locked = true;
49 }
50 return 0;
51 }
52};
53
54/**
55 * Hackish function to set an events permanent lock state, used to pass through synch blocks
56 * @param handle Handle to event to change
57 * @param permanent_locked Boolean permanent locked value to set event
58 * @return Result of operation, 0 on success, otherwise error code
59 */
60Result SetPermanentLock(Handle handle, const bool permanent_locked) {
61 Event* evt = g_object_pool.GetFast<Event>(handle);
62 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
63
64 evt->permanent_locked = permanent_locked;
65 return 0;
66}
67
68/**
69 * Changes whether an event is locked or not
70 * @param handle Handle to event to change
71 * @param locked Boolean locked value to set event
72 * @return Result of operation, 0 on success, otherwise error code
73 */
74Result SetEventLocked(const Handle handle, const bool locked) {
75 Event* evt = g_object_pool.GetFast<Event>(handle);
76 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
77
78 if (!evt->permanent_locked) {
79 evt->locked = locked;
80 }
81 return 0;
82}
83
84/**
85 * Signals an event
86 * @param handle Handle to event to signal
87 * @return Result of operation, 0 on success, otherwise error code
88 */
89Result SignalEvent(const Handle handle) {
90 Event* evt = g_object_pool.GetFast<Event>(handle);
91 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
92
93 // Resume threads waiting for event to signal
94 bool event_caught = false;
95 for (size_t i = 0; i < evt->waiting_threads.size(); ++i) {
96 ResumeThreadFromWait( evt->waiting_threads[i]);
97
98 // If any thread is signalled awake by this event, assume the event was "caught" and reset
99 // the event. This will result in the next thread waiting on the event to block. Otherwise,
100 // the event will not be reset, and the next thread to call WaitSynchronization on it will
101 // not block. Not sure if this is correct behavior, but it seems to work.
102 event_caught = true;
103 }
104 evt->waiting_threads.clear();
105
106 if (!evt->permanent_locked) {
107 evt->locked = event_caught;
108 }
109 return 0;
110}
111
112/**
113 * Clears an event
114 * @param handle Handle to event to clear
115 * @return Result of operation, 0 on success, otherwise error code
116 */
117Result ClearEvent(Handle handle) {
118 Event* evt = g_object_pool.GetFast<Event>(handle);
119 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
120
121 if (!evt->permanent_locked) {
122 evt->locked = true;
123 }
124 return 0;
125}
126
127/**
128 * Creates an event
129 * @param handle Reference to handle for the newly created mutex
130 * @param reset_type ResetType describing how to create event
131 * @param name Optional name of event
132 * @return Newly created Event object
133 */
134Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) {
135 Event* evt = new Event;
136
137 handle = Kernel::g_object_pool.Create(evt);
138
139 evt->locked = true;
140 evt->permanent_locked = false;
141 evt->reset_type = evt->intitial_reset_type = reset_type;
142 evt->name = name;
143
144 return evt;
145}
146
147/**
148 * Creates an event
149 * @param reset_type ResetType describing how to create event
150 * @param name Optional name of event
151 * @return Handle to newly created Event object
152 */
153Handle CreateEvent(const ResetType reset_type, const std::string& name) {
154 Handle handle;
155 Event* evt = CreateEvent(handle, reset_type, name);
156 return handle;
157}
158
159} // namespace
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
new file mode 100644
index 000000000..c39b33180
--- /dev/null
+++ b/src/core/hle/kernel/event.h
@@ -0,0 +1,52 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/hle/kernel/kernel.h"
10#include "core/hle/svc.h"
11
12namespace Kernel {
13
14/**
15 * Changes whether an event is locked or not
16 * @param handle Handle to event to change
17 * @param locked Boolean locked value to set event
18 * @return Result of operation, 0 on success, otherwise error code
19 */
20Result SetEventLocked(const Handle handle, const bool locked);
21
22/**
23 * Hackish function to set an events permanent lock state, used to pass through synch blocks
24 * @param handle Handle to event to change
25 * @param permanent_locked Boolean permanent locked value to set event
26 * @return Result of operation, 0 on success, otherwise error code
27 */
28Result SetPermanentLock(Handle handle, const bool permanent_locked);
29
30/**
31 * Signals an event
32 * @param handle Handle to event to signal
33 * @return Result of operation, 0 on success, otherwise error code
34 */
35Result SignalEvent(const Handle handle);
36
37/**
38 * Clears an event
39 * @param handle Handle to event to clear
40 * @return Result of operation, 0 on success, otherwise error code
41 */
42Result ClearEvent(Handle handle);
43
44/**
45 * Creates an event
46 * @param reset_type ResetType describing how to create event
47 * @param name Optional name of event
48 * @return Handle to newly created Event object
49 */
50Handle CreateEvent(const ResetType reset_type, const std::string& name="Unknown");
51
52} // namespace
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index de80de893..cda183add 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -2,8 +2,6 @@
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once
6
7#include <string.h> 5#include <string.h>
8 6
9#include "common/common.h" 7#include "common/common.h"
@@ -14,6 +12,7 @@
14 12
15namespace Kernel { 13namespace Kernel {
16 14
15Handle g_main_thread = 0;
17ObjectPool g_object_pool; 16ObjectPool g_object_pool;
18 17
19ObjectPool::ObjectPool() { 18ObjectPool::ObjectPool() {
@@ -127,16 +126,20 @@ Object* ObjectPool::CreateByIDType(int type) {
127 126
128 default: 127 default:
129 ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type); 128 ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type);
130 return NULL; 129 return nullptr;
131 } 130 }
132} 131}
133 132
133/// Initialize the kernel
134void Init() { 134void Init() {
135 Kernel::ThreadingInit(); 135 Kernel::ThreadingInit();
136} 136}
137 137
138/// Shutdown the kernel
138void Shutdown() { 139void Shutdown() {
139 Kernel::ThreadingShutdown(); 140 Kernel::ThreadingShutdown();
141
142 g_object_pool.Clear(); // Free all kernel objects
140} 143}
141 144
142/** 145/**
@@ -150,7 +153,7 @@ bool LoadExec(u32 entry_point) {
150 Core::g_app_core->SetPC(entry_point); 153 Core::g_app_core->SetPC(entry_point);
151 154
152 // 0x30 is the typical main thread priority I've seen used so far 155 // 0x30 is the typical main thread priority I've seen used so far
153 Handle thread = Kernel::SetupMainThread(0x30); 156 g_main_thread = Kernel::SetupMainThread(0x30);
154 157
155 return true; 158 return true;
156} 159}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 7cd79c2c4..3f15da0ac 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -11,6 +11,11 @@ typedef s32 Result;
11 11
12namespace Kernel { 12namespace Kernel {
13 13
14enum KernelHandle {
15 CurrentThread = 0xFFFF8000,
16 CurrentProcess = 0xFFFF8001,
17};
18
14enum class HandleType : u32 { 19enum class HandleType : u32 {
15 Unknown = 0, 20 Unknown = 0,
16 Port = 1, 21 Port = 1,
@@ -39,9 +44,26 @@ class Object : NonCopyable {
39public: 44public:
40 virtual ~Object() {} 45 virtual ~Object() {}
41 Handle GetHandle() const { return handle; } 46 Handle GetHandle() const { return handle; }
42 virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; } 47 virtual const char* GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; }
43 virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; } 48 virtual const char* GetName() const { return "[UNKNOWN KERNEL OBJECT]"; }
44 virtual Kernel::HandleType GetHandleType() const = 0; 49 virtual Kernel::HandleType GetHandleType() const = 0;
50
51 /**
52 * Synchronize kernel object
53 * @param wait Boolean wait set if current thread should wait as a result of sync operation
54 * @return Result of operation, 0 on success, otherwise error code
55 */
56 virtual Result SyncRequest(bool* wait) {
57 ERROR_LOG(KERNEL, "(UNIMPLEMENTED)");
58 return -1;
59 }
60
61 /**
62 * Wait for kernel object to synchronize
63 * @param wait Boolean wait set if current thread should wait as a result of sync operation
64 * @return Result of operation, 0 on success, otherwise error code
65 */
66 virtual Result WaitSynchronization(bool* wait) = 0;
45}; 67};
46 68
47class ObjectPool : NonCopyable { 69class ObjectPool : NonCopyable {
@@ -143,6 +165,13 @@ private:
143}; 165};
144 166
145extern ObjectPool g_object_pool; 167extern ObjectPool g_object_pool;
168extern Handle g_main_thread;
169
170/// Initialize the kernel
171void Init();
172
173/// Shutdown the kernel
174void Shutdown();
146 175
147/** 176/**
148 * Loads executable stored at specified address 177 * Loads executable stored at specified address
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 019efbc78..1ccf1eb73 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -8,21 +8,51 @@
8#include "common/common.h" 8#include "common/common.h"
9 9
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/mutex.h"
11#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
12 13
13namespace Kernel { 14namespace Kernel {
14 15
15class Mutex : public Object { 16class Mutex : public Object {
16public: 17public:
17 const char* GetTypeName() { return "Mutex"; } 18 const char* GetTypeName() const { return "Mutex"; }
19 const char* GetName() const { return name.c_str(); }
18 20
19 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } 21 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
20 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; } 22 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; }
21 23
22 bool initial_locked; ///< Initial lock state when mutex was created 24 bool initial_locked; ///< Initial lock state when mutex was created
23 bool locked; ///< Current locked state 25 bool locked; ///< Current locked state
24 Handle lock_thread; ///< Handle to thread that currently has mutex 26 Handle lock_thread; ///< Handle to thread that currently has mutex
25 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)
29
30 /**
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) {
36 // TODO(bunnei): ImplementMe
37 locked = true;
38 return 0;
39 }
40
41 /**
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) {
47 // TODO(bunnei): ImplementMe
48 *wait = locked;
49
50 if (locked) {
51 Kernel::WaitCurrentThread(WAITTYPE_MUTEX);
52 }
53
54 return 0;
55 }
26}; 56};
27 57
28//////////////////////////////////////////////////////////////////////////////////////////////////// 58////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -70,10 +100,10 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
70bool ReleaseMutex(Mutex* mutex) { 100bool ReleaseMutex(Mutex* mutex) {
71 MutexEraseLock(mutex); 101 MutexEraseLock(mutex);
72 bool woke_threads = false; 102 bool woke_threads = false;
73 auto iter = mutex->waiting_threads.begin();
74 103
75 // Find the next waiting thread for the mutex... 104 // Find the next waiting thread for the mutex...
76 while (!woke_threads && !mutex->waiting_threads.empty()) { 105 while (!woke_threads && !mutex->waiting_threads.empty()) {
106 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
77 woke_threads |= ReleaseMutexForThread(mutex, *iter); 107 woke_threads |= ReleaseMutexForThread(mutex, *iter);
78 mutex->waiting_threads.erase(iter); 108 mutex->waiting_threads.erase(iter);
79 } 109 }
@@ -91,6 +121,9 @@ bool ReleaseMutex(Mutex* mutex) {
91 */ 121 */
92Result ReleaseMutex(Handle handle) { 122Result ReleaseMutex(Handle handle) {
93 Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); 123 Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle);
124
125 _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!");
126
94 if (!ReleaseMutex(mutex)) { 127 if (!ReleaseMutex(mutex)) {
95 return -1; 128 return -1;
96 } 129 }
@@ -101,12 +134,15 @@ Result ReleaseMutex(Handle handle) {
101 * Creates a mutex 134 * Creates a mutex
102 * @param handle Reference to handle for the newly created mutex 135 * @param handle Reference to handle for the newly created mutex
103 * @param initial_locked Specifies if the mutex should be locked initially 136 * @param initial_locked Specifies if the mutex should be locked initially
137 * @param name Optional name of mutex
138 * @return Pointer to new Mutex object
104 */ 139 */
105Mutex* CreateMutex(Handle& handle, bool initial_locked) { 140Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) {
106 Mutex* mutex = new Mutex; 141 Mutex* mutex = new Mutex;
107 handle = Kernel::g_object_pool.Create(mutex); 142 handle = Kernel::g_object_pool.Create(mutex);
108 143
109 mutex->locked = mutex->initial_locked = initial_locked; 144 mutex->locked = mutex->initial_locked = initial_locked;
145 mutex->name = name;
110 146
111 // Acquire mutex with current thread if initialized as locked... 147 // Acquire mutex with current thread if initialized as locked...
112 if (mutex->locked) { 148 if (mutex->locked) {
@@ -122,10 +158,12 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked) {
122/** 158/**
123 * Creates a mutex 159 * Creates a mutex
124 * @param initial_locked Specifies if the mutex should be locked initially 160 * @param initial_locked Specifies if the mutex should be locked initially
161 * @param name Optional name of mutex
162 * @return Handle to newly created object
125 */ 163 */
126Handle CreateMutex(bool initial_locked) { 164Handle CreateMutex(bool initial_locked, const std::string& name) {
127 Handle handle; 165 Handle handle;
128 Mutex* mutex = CreateMutex(handle, initial_locked); 166 Mutex* mutex = CreateMutex(handle, initial_locked, name);
129 return handle; 167 return handle;
130} 168}
131 169
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 871e2e562..7d7b5137e 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -13,14 +13,16 @@ 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
16 */ 17 */
17Result ReleaseMutex(Handle handle); 18Result ReleaseMutex(Handle handle);
18 19
19/** 20/**
20 * Creates a mutex 21 * Creates a mutex
21 * @param handle Reference to handle for the newly created mutex
22 * @param initial_locked Specifies if the mutex should be locked initially 22 * @param initial_locked Specifies if the mutex should be locked initially
23 * @param name Optional name of mutex
24 * @return Handle to newly created object
23 */ 25 */
24Handle CreateMutex(bool initial_locked); 26Handle CreateMutex(bool initial_locked, const std::string& name="Unknown");
25 27
26} // namespace 28} // namespace
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index bf4c8353c..ab5a5559e 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -5,6 +5,7 @@
5#include <stdio.h> 5#include <stdio.h>
6 6
7#include <list> 7#include <list>
8#include <algorithm>
8#include <vector> 9#include <vector>
9#include <map> 10#include <map>
10#include <string> 11#include <string>
@@ -24,10 +25,10 @@ namespace Kernel {
24class Thread : public Kernel::Object { 25class Thread : public Kernel::Object {
25public: 26public:
26 27
27 const char* GetName() { return name; } 28 const char* GetName() const { return name; }
28 const char* GetTypeName() { return "Thread"; } 29 const char* GetTypeName() const { return "Thread"; }
29 30
30 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } 31 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
31 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } 32 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; }
32 33
33 inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } 34 inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
@@ -36,6 +37,23 @@ public:
36 inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } 37 inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
37 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } 38 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
38 39
40 /**
41 * Wait for kernel object to synchronize
42 * @param wait Boolean wait set if current thread should wait as a result of sync operation
43 * @return Result of operation, 0 on success, otherwise error code
44 */
45 Result WaitSynchronization(bool* wait) {
46 if (status != THREADSTATUS_DORMANT) {
47 Handle thread = GetCurrentThreadHandle();
48 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
49 waiting_threads.push_back(thread);
50 }
51 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle());
52 *wait = true;
53 }
54 return 0;
55 }
56
39 ThreadContext context; 57 ThreadContext context;
40 58
41 u32 status; 59 u32 status;
@@ -49,6 +67,9 @@ public:
49 s32 processor_id; 67 s32 processor_id;
50 68
51 WaitType wait_type; 69 WaitType wait_type;
70 Handle wait_handle;
71
72 std::vector<Handle> waiting_threads;
52 73
53 char name[Kernel::MAX_NAME_LENGTH + 1]; 74 char name[Kernel::MAX_NAME_LENGTH + 1];
54}; 75};
@@ -62,7 +83,6 @@ Common::ThreadQueueList<Handle> g_thread_ready_queue;
62Handle g_current_thread_handle; 83Handle g_current_thread_handle;
63Thread* g_current_thread; 84Thread* g_current_thread;
64 85
65
66/// Gets the current thread 86/// Gets the current thread
67inline Thread* GetCurrentThread() { 87inline Thread* GetCurrentThread() {
68 return g_current_thread; 88 return g_current_thread;
@@ -94,15 +114,15 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
94 memset(&t->context, 0, sizeof(ThreadContext)); 114 memset(&t->context, 0, sizeof(ThreadContext));
95 115
96 t->context.cpu_registers[0] = arg; 116 t->context.cpu_registers[0] = arg;
97 t->context.pc = t->entry_point; 117 t->context.pc = t->context.reg_15 = t->entry_point;
98 t->context.sp = t->stack_top; 118 t->context.sp = t->stack_top;
99 t->context.cpsr = 0x1F; // Usermode 119 t->context.cpsr = 0x1F; // Usermode
100 120
101 if (t->current_priority < lowest_priority) { 121 if (t->current_priority < lowest_priority) {
102 t->current_priority = t->initial_priority; 122 t->current_priority = t->initial_priority;
103 } 123 }
104
105 t->wait_type = WAITTYPE_NONE; 124 t->wait_type = WAITTYPE_NONE;
125 t->wait_handle = 0;
106} 126}
107 127
108/// Change a thread to "ready" state 128/// Change a thread to "ready" state
@@ -122,6 +142,37 @@ void ChangeReadyState(Thread* t, bool ready) {
122 } 142 }
123} 143}
124 144
145/// Verify that a thread has not been released from waiting
146inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) {
147 Thread* thread = g_object_pool.GetFast<Thread>(handle);
148 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
149
150 if (type != thread->wait_type || wait_handle != thread->wait_handle)
151 return false;
152
153 return true;
154}
155
156/// Stops the current thread
157void StopThread(Handle handle, const char* reason) {
158 Thread* thread = g_object_pool.GetFast<Thread>(handle);
159 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
160
161 ChangeReadyState(thread, false);
162 thread->status = THREADSTATUS_DORMANT;
163 for (size_t i = 0; i < thread->waiting_threads.size(); ++i) {
164 const Handle waiting_thread = thread->waiting_threads[i];
165 if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) {
166 ResumeThreadFromWait(waiting_thread);
167 }
168 }
169 thread->waiting_threads.clear();
170
171 // Stopped threads are never waiting.
172 thread->wait_type = WAITTYPE_NONE;
173 thread->wait_handle = 0;
174}
175
125/// Changes a threads state 176/// Changes a threads state
126void ChangeThreadState(Thread* t, ThreadStatus new_status) { 177void ChangeThreadState(Thread* t, ThreadStatus new_status) {
127 if (!t || t->status == new_status) { 178 if (!t || t->status == new_status) {
@@ -132,7 +183,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) {
132 183
133 if (new_status == THREADSTATUS_WAIT) { 184 if (new_status == THREADSTATUS_WAIT) {
134 if (t->wait_type == WAITTYPE_NONE) { 185 if (t->wait_type == WAITTYPE_NONE) {
135 printf("ERROR: Waittype none not allowed here\n"); 186 ERROR_LOG(KERNEL, "Waittype none not allowed");
136 } 187 }
137 } 188 }
138} 189}
@@ -166,7 +217,7 @@ void SwitchContext(Thread* t) {
166 t->wait_type = WAITTYPE_NONE; 217 t->wait_type = WAITTYPE_NONE;
167 LoadContext(t->context); 218 LoadContext(t->context);
168 } else { 219 } else {
169 SetCurrentThread(NULL); 220 SetCurrentThread(nullptr);
170 } 221 }
171} 222}
172 223
@@ -181,26 +232,43 @@ Thread* NextThread() {
181 next = g_thread_ready_queue.pop_first(); 232 next = g_thread_ready_queue.pop_first();
182 } 233 }
183 if (next == 0) { 234 if (next == 0) {
184 return NULL; 235 return nullptr;
185 } 236 }
186 return Kernel::g_object_pool.GetFast<Thread>(next); 237 return Kernel::g_object_pool.GetFast<Thread>(next);
187} 238}
188 239
189/// Puts the current thread in the wait state for the given type 240/// Puts the current thread in the wait state for the given type
190void WaitCurrentThread(WaitType wait_type) { 241void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
191 Thread* t = GetCurrentThread(); 242 Thread* thread = GetCurrentThread();
192 t->wait_type = wait_type; 243 thread->wait_type = wait_type;
193 ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND))); 244 thread->wait_handle = wait_handle;
245 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
194} 246}
195 247
196/// Resumes a thread from waiting by marking it as "ready" 248/// Resumes a thread from waiting by marking it as "ready"
197void ResumeThreadFromWait(Handle handle) { 249void ResumeThreadFromWait(Handle handle) {
198 u32 error; 250 u32 error;
199 Thread* t = Kernel::g_object_pool.Get<Thread>(handle, error); 251 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
200 if (t) { 252 if (thread) {
201 t->status &= ~THREADSTATUS_WAIT; 253 thread->status &= ~THREADSTATUS_WAIT;
202 if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { 254 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
203 ChangeReadyState(t, true); 255 ChangeReadyState(thread, true);
256 }
257 }
258}
259
260/// Prints the thread queue for debugging purposes
261void DebugThreadQueue() {
262 Thread* thread = GetCurrentThread();
263 if (!thread) {
264 return;
265 }
266 INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle());
267 for (u32 i = 0; i < g_thread_queue.size(); i++) {
268 Handle handle = g_thread_queue[i];
269 s32 priority = g_thread_ready_queue.contains(handle);
270 if (priority != -1) {
271 INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle);
204 } 272 }
205 } 273 }
206} 274}
@@ -212,32 +280,34 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
212 _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), 280 _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
213 "CreateThread priority=%d, outside of allowable range!", priority) 281 "CreateThread priority=%d, outside of allowable range!", priority)
214 282
215 Thread* t = new Thread; 283 Thread* thread = new Thread;
216 284
217 handle = Kernel::g_object_pool.Create(t); 285 handle = Kernel::g_object_pool.Create(thread);
218 286
219 g_thread_queue.push_back(handle); 287 g_thread_queue.push_back(handle);
220 g_thread_ready_queue.prepare(priority); 288 g_thread_ready_queue.prepare(priority);
221 289
222 t->status = THREADSTATUS_DORMANT; 290 thread->status = THREADSTATUS_DORMANT;
223 t->entry_point = entry_point; 291 thread->entry_point = entry_point;
224 t->stack_top = stack_top; 292 thread->stack_top = stack_top;
225 t->stack_size = stack_size; 293 thread->stack_size = stack_size;
226 t->initial_priority = t->current_priority = priority; 294 thread->initial_priority = thread->current_priority = priority;
227 t->processor_id = processor_id; 295 thread->processor_id = processor_id;
228 t->wait_type = WAITTYPE_NONE; 296 thread->wait_type = WAITTYPE_NONE;
229 297 thread->wait_handle = 0;
230 strncpy(t->name, name, Kernel::MAX_NAME_LENGTH); 298
231 t->name[Kernel::MAX_NAME_LENGTH] = '\0'; 299 strncpy(thread->name, name, Kernel::MAX_NAME_LENGTH);
232 300 thread->name[Kernel::MAX_NAME_LENGTH] = '\0';
233 return t; 301
302 return thread;
234} 303}
235 304
236/// Creates a new thread - wrapper for external user 305/// Creates a new thread - wrapper for external user
237Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id, 306Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
238 u32 stack_top, int stack_size) { 307 u32 stack_top, int stack_size) {
239 if (name == NULL) { 308
240 ERROR_LOG(KERNEL, "CreateThread(): NULL name"); 309 if (name == nullptr) {
310 ERROR_LOG(KERNEL, "CreateThread(): nullptr name");
241 return -1; 311 return -1;
242 } 312 }
243 if ((u32)stack_size < 0x200) { 313 if ((u32)stack_size < 0x200) {
@@ -258,20 +328,56 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
258 return -1; 328 return -1;
259 } 329 }
260 Handle handle; 330 Handle handle;
261 Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, 331 Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
262 stack_size); 332 stack_size);
263 333
264 ResetThread(t, arg, 0); 334 ResetThread(thread, arg, 0);
335 CallThread(thread);
336
337 return handle;
338}
265 339
266 HLE::EatCycles(32000); 340/// Get the priority of the thread specified by handle
341u32 GetThreadPriority(const Handle handle) {
342 Thread* thread = g_object_pool.GetFast<Thread>(handle);
343 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
344 return thread->current_priority;
345}
267 346
268 // This won't schedule to the new thread, but it may to one woken from eating cycles. 347/// Set the priority of the thread specified by handle
269 // Technically, this should not eat all at once, and reschedule in the middle, but that's hard. 348Result SetThreadPriority(Handle handle, s32 priority) {
270 HLE::ReSchedule("thread created"); 349 Thread* thread = nullptr;
350 if (!handle) {
351 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
352 } else {
353 thread = g_object_pool.GetFast<Thread>(handle);
354 }
355 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
271 356
272 CallThread(t); 357 // If priority is invalid, clamp to valid range
273 358 if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
274 return handle; 359 s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
360 WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority);
361 // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
362 // validity of this
363 priority = new_priority;
364 }
365
366 // Change thread priority
367 s32 old = thread->current_priority;
368 g_thread_ready_queue.remove(old, handle);
369 thread->current_priority = priority;
370 g_thread_ready_queue.prepare(thread->current_priority);
371
372 // Change thread status to "ready" and push to ready queue
373 if (thread->IsRunning()) {
374 thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY;
375 }
376 if (thread->IsReady()) {
377 g_thread_ready_queue.push_back(thread->current_priority, handle);
378 }
379
380 return 0;
275} 381}
276 382
277/// Sets up the primary application thread 383/// Sets up the primary application thread
@@ -279,10 +385,10 @@ Handle SetupMainThread(s32 priority, int stack_size) {
279 Handle handle; 385 Handle handle;
280 386
281 // Initialize new "main" thread 387 // Initialize new "main" thread
282 Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, 388 Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
283 THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); 389 THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
284 390
285 ResetThread(t, 0, 0); 391 ResetThread(thread, 0, 0);
286 392
287 // If running another thread already, set it to "ready" state 393 // If running another thread already, set it to "ready" state
288 Thread* cur = GetCurrentThread(); 394 Thread* cur = GetCurrentThread();
@@ -291,24 +397,31 @@ Handle SetupMainThread(s32 priority, int stack_size) {
291 } 397 }
292 398
293 // Run new "main" thread 399 // Run new "main" thread
294 SetCurrentThread(t); 400 SetCurrentThread(thread);
295 t->status = THREADSTATUS_RUNNING; 401 thread->status = THREADSTATUS_RUNNING;
296 LoadContext(t->context); 402 LoadContext(thread->context);
297 403
298 return handle; 404 return handle;
299} 405}
300 406
407
301/// Reschedules to the next available thread (call after current thread is suspended) 408/// Reschedules to the next available thread (call after current thread is suspended)
302void Reschedule() { 409void Reschedule() {
303 Thread* prev = GetCurrentThread(); 410 Thread* prev = GetCurrentThread();
304 Thread* next = NextThread(); 411 Thread* next = NextThread();
412 HLE::g_reschedule = false;
305 if (next > 0) { 413 if (next > 0) {
414 INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
415
306 SwitchContext(next); 416 SwitchContext(next);
307 417
308 // Hack - automatically change previous thread (which would have been in "wait" state) to 418 // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep
309 // "ready" state, so that we can immediately resume to it when new thread yields. FixMe to 419 // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again.
310 // actually wait for whatever event it is supposed to be waiting on. 420 // This results in the current thread yielding on a VBLANK once, and then it will be
311 ChangeReadyState(prev, true); 421 // immediately placed back in the queue for execution.
422 if (prev->wait_type == WAITTYPE_VBLANK) {
423 ResumeThreadFromWait(prev->GetHandle());
424 }
312 } 425 }
313} 426}
314 427
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 9628f165d..04914ba90 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -34,7 +34,7 @@ enum WaitType {
34 WAITTYPE_NONE, 34 WAITTYPE_NONE,
35 WAITTYPE_SLEEP, 35 WAITTYPE_SLEEP,
36 WAITTYPE_SEMA, 36 WAITTYPE_SEMA,
37 WAITTYPE_EVENTFLAG, 37 WAITTYPE_EVENT,
38 WAITTYPE_THREADEND, 38 WAITTYPE_THREADEND,
39 WAITTYPE_VBLANK, 39 WAITTYPE_VBLANK,
40 WAITTYPE_MUTEX, 40 WAITTYPE_MUTEX,
@@ -53,8 +53,8 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
53/// Reschedules to the next available thread (call after current thread is suspended) 53/// Reschedules to the next available thread (call after current thread is suspended)
54void Reschedule(); 54void Reschedule();
55 55
56/// Puts the current thread in the wait state for the given type 56/// Stops the current thread
57void WaitCurrentThread(WaitType wait_type); 57void StopThread(Handle thread, const char* reason);
58 58
59/// Resumes a thread from waiting by marking it as "ready" 59/// Resumes a thread from waiting by marking it as "ready"
60void ResumeThreadFromWait(Handle handle); 60void ResumeThreadFromWait(Handle handle);
@@ -62,9 +62,18 @@ void ResumeThreadFromWait(Handle handle);
62/// Gets the current thread handle 62/// Gets the current thread handle
63Handle GetCurrentThreadHandle(); 63Handle GetCurrentThreadHandle();
64 64
65/// Puts the current thread in the wait state for the given type
66void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle());
67
65/// Put current thread in a wait state - on WaitSynchronization 68/// Put current thread in a wait state - on WaitSynchronization
66void WaitThread_Synchronization(); 69void WaitThread_Synchronization();
67 70
71/// Get the priority of the thread specified by handle
72u32 GetThreadPriority(const Handle handle);
73
74/// Set the priority of the thread specified by handle
75Result SetThreadPriority(Handle handle, s32 priority);
76
68/// Initialize threading 77/// Initialize threading
69void ThreadingInit(); 78void ThreadingInit();
70 79
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt.cpp
index 32759a087..a0012b5dd 100644
--- a/src/core/hle/service/apt.cpp
+++ b/src/core/hle/service/apt.cpp
@@ -6,6 +6,7 @@
6#include "common/common.h" 6#include "common/common.h"
7 7
8#include "core/hle/hle.h" 8#include "core/hle/hle.h"
9#include "core/hle/kernel/event.h"
9#include "core/hle/kernel/mutex.h" 10#include "core/hle/kernel/mutex.h"
10#include "core/hle/service/apt.h" 11#include "core/hle/service/apt.h"
11 12
@@ -15,96 +16,120 @@
15namespace APT_U { 16namespace APT_U {
16 17
17void Initialize(Service::Interface* self) { 18void Initialize(Service::Interface* self) {
18 NOTICE_LOG(OSHLE, "APT_U::Sync - Initialize"); 19 u32* cmd_buff = Service::GetCommandBuffer();
20 DEBUG_LOG(KERNEL, "called");
21
22 cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu"); // APT menu event handle
23 cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle
24
25 Kernel::SetEventLocked(cmd_buff[3], true);
26 Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event
27
28 cmd_buff[1] = 0; // No error
19} 29}
20 30
21void GetLockHandle(Service::Interface* self) { 31void GetLockHandle(Service::Interface* self) {
22 u32* cmd_buff = Service::GetCommandBuffer(); 32 u32* cmd_buff = Service::GetCommandBuffer();
23 u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field 33 u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
24 cmd_buff[1] = 0; // No error 34 cmd_buff[1] = 0; // No error
25 cmd_buff[5] = Kernel::CreateMutex(false); 35 cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock");
26 DEBUG_LOG(KERNEL, "APT_U::GetLockHandle called : created handle 0x%08X", cmd_buff[5]); 36 DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]);
37}
38
39void Enable(Service::Interface* self) {
40 u32* cmd_buff = Service::GetCommandBuffer();
41 u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
42 cmd_buff[1] = 0; // No error
43 ERROR_LOG(KERNEL, "(UNIMPEMENTED) called unk=0x%08X", unk);
44}
45
46void InquireNotification(Service::Interface* self) {
47 u32* cmd_buff = Service::GetCommandBuffer();
48 u32 app_id = cmd_buff[2];
49 cmd_buff[1] = 0; // No error
50 cmd_buff[3] = 0; // Signal type
51 ERROR_LOG(KERNEL, "(UNIMPEMENTED) called app_id=0x%08X", app_id);
27} 52}
28 53
29const Interface::FunctionInfo FunctionTable[] = { 54const Interface::FunctionInfo FunctionTable[] = {
30 {0x00010040, GetLockHandle, "GetLockHandle"}, 55 {0x00010040, GetLockHandle, "GetLockHandle"},
31 {0x00020080, Initialize, "Initialize"}, 56 {0x00020080, Initialize, "Initialize"},
32 {0x00030040, NULL, "Enable"}, 57 {0x00030040, Enable, "Enable"},
33 {0x00040040, NULL, "Finalize"}, 58 {0x00040040, nullptr, "Finalize"},
34 {0x00050040, NULL, "GetAppletManInfo"}, 59 {0x00050040, nullptr, "GetAppletManInfo"},
35 {0x00060040, NULL, "GetAppletInfo"}, 60 {0x00060040, nullptr, "GetAppletInfo"},
36 {0x00070000, NULL, "GetLastSignaledAppletId"}, 61 {0x00070000, nullptr, "GetLastSignaledAppletId"},
37 {0x00080000, NULL, "CountRegisteredApplet"}, 62 {0x00080000, nullptr, "CountRegisteredApplet"},
38 {0x00090040, NULL, "IsRegistered"}, 63 {0x00090040, nullptr, "IsRegistered"},
39 {0x000A0040, NULL, "GetAttribute"}, 64 {0x000A0040, nullptr, "GetAttribute"},
40 {0x000B0040, NULL, "InquireNotification"}, 65 {0x000B0040, InquireNotification, "InquireNotification"},
41 {0x000C0104, NULL, "SendParameter"}, 66 {0x000C0104, nullptr, "SendParameter"},
42 {0x000D0080, NULL, "ReceiveParameter"}, 67 {0x000D0080, nullptr, "ReceiveParameter"},
43 {0x000E0080, NULL, "GlanceParameter"}, 68 {0x000E0080, nullptr, "GlanceParameter"},
44 {0x000F0100, NULL, "CancelParameter"}, 69 {0x000F0100, nullptr, "CancelParameter"},
45 {0x001000C2, NULL, "DebugFunc"}, 70 {0x001000C2, nullptr, "DebugFunc"},
46 {0x001100C0, NULL, "MapProgramIdForDebug"}, 71 {0x001100C0, nullptr, "MapProgramIdForDebug"},
47 {0x00120040, NULL, "SetHomeMenuAppletIdForDebug"}, 72 {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
48 {0x00130000, NULL, "GetPreparationState"}, 73 {0x00130000, nullptr, "GetPreparationState"},
49 {0x00140040, NULL, "SetPreparationState"}, 74 {0x00140040, nullptr, "SetPreparationState"},
50 {0x00150140, NULL, "PrepareToStartApplication"}, 75 {0x00150140, nullptr, "PrepareToStartApplication"},
51 {0x00160040, NULL, "PreloadLibraryApplet"}, 76 {0x00160040, nullptr, "PreloadLibraryApplet"},
52 {0x00170040, NULL, "FinishPreloadingLibraryApplet"}, 77 {0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
53 {0x00180040, NULL, "PrepareToStartLibraryApplet"}, 78 {0x00180040, nullptr, "PrepareToStartLibraryApplet"},
54 {0x00190040, NULL, "PrepareToStartSystemApplet"}, 79 {0x00190040, nullptr, "PrepareToStartSystemApplet"},
55 {0x001A0000, NULL, "PrepareToStartNewestHomeMenu"}, 80 {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
56 {0x001B00C4, NULL, "StartApplication"}, 81 {0x001B00C4, nullptr, "StartApplication"},
57 {0x001C0000, NULL, "WakeupApplication"}, 82 {0x001C0000, nullptr, "WakeupApplication"},
58 {0x001D0000, NULL, "CancelApplication"}, 83 {0x001D0000, nullptr, "CancelApplication"},
59 {0x001E0084, NULL, "StartLibraryApplet"}, 84 {0x001E0084, nullptr, "StartLibraryApplet"},
60 {0x001F0084, NULL, "StartSystemApplet"}, 85 {0x001F0084, nullptr, "StartSystemApplet"},
61 {0x00200044, NULL, "StartNewestHomeMenu"}, 86 {0x00200044, nullptr, "StartNewestHomeMenu"},
62 {0x00210000, NULL, "OrderToCloseApplication"}, 87 {0x00210000, nullptr, "OrderToCloseApplication"},
63 {0x00220040, NULL, "PrepareToCloseApplication"}, 88 {0x00220040, nullptr, "PrepareToCloseApplication"},
64 {0x00230040, NULL, "PrepareToJumpToApplication"}, 89 {0x00230040, nullptr, "PrepareToJumpToApplication"},
65 {0x00240044, NULL, "JumpToApplication"}, 90 {0x00240044, nullptr, "JumpToApplication"},
66 {0x002500C0, NULL, "PrepareToCloseLibraryApplet"}, 91 {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"},
67 {0x00260000, NULL, "PrepareToCloseSystemApplet"}, 92 {0x00260000, nullptr, "PrepareToCloseSystemApplet"},
68 {0x00270044, NULL, "CloseApplication"}, 93 {0x00270044, nullptr, "CloseApplication"},
69 {0x00280044, NULL, "CloseLibraryApplet"}, 94 {0x00280044, nullptr, "CloseLibraryApplet"},
70 {0x00290044, NULL, "CloseSystemApplet"}, 95 {0x00290044, nullptr, "CloseSystemApplet"},
71 {0x002A0000, NULL, "OrderToCloseSystemApplet"}, 96 {0x002A0000, nullptr, "OrderToCloseSystemApplet"},
72 {0x002B0000, NULL, "PrepareToJumpToHomeMenu"}, 97 {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
73 {0x002C0044, NULL, "JumpToHomeMenu"}, 98 {0x002C0044, nullptr, "JumpToHomeMenu"},
74 {0x002D0000, NULL, "PrepareToLeaveHomeMenu"}, 99 {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"},
75 {0x002E0044, NULL, "LeaveHomeMenu"}, 100 {0x002E0044, nullptr, "LeaveHomeMenu"},
76 {0x002F0040, NULL, "PrepareToLeaveResidentApplet"}, 101 {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"},
77 {0x00300044, NULL, "LeaveResidentApplet"}, 102 {0x00300044, nullptr, "LeaveResidentApplet"},
78 {0x00310100, NULL, "PrepareToDoApplicationJump"}, 103 {0x00310100, nullptr, "PrepareToDoApplicationJump"},
79 {0x00320084, NULL, "DoApplicationJump"}, 104 {0x00320084, nullptr, "DoApplicationJump"},
80 {0x00330000, NULL, "GetProgramIdOnApplicationJump"}, 105 {0x00330000, nullptr, "GetProgramIdOnApplicationJump"},
81 {0x00340084, NULL, "SendDeliverArg"}, 106 {0x00340084, nullptr, "SendDeliverArg"},
82 {0x00350080, NULL, "ReceiveDeliverArg"}, 107 {0x00350080, nullptr, "ReceiveDeliverArg"},
83 {0x00360040, NULL, "LoadSysMenuArg"}, 108 {0x00360040, nullptr, "LoadSysMenuArg"},
84 {0x00370042, NULL, "StoreSysMenuArg"}, 109 {0x00370042, nullptr, "StoreSysMenuArg"},
85 {0x00380040, NULL, "PreloadResidentApplet"}, 110 {0x00380040, nullptr, "PreloadResidentApplet"},
86 {0x00390040, NULL, "PrepareToStartResidentApplet"}, 111 {0x00390040, nullptr, "PrepareToStartResidentApplet"},
87 {0x003A0044, NULL, "StartResidentApplet"}, 112 {0x003A0044, nullptr, "StartResidentApplet"},
88 {0x003B0040, NULL, "CancelLibraryApplet"}, 113 {0x003B0040, nullptr, "CancelLibraryApplet"},
89 {0x003C0042, NULL, "SendDspSleep"}, 114 {0x003C0042, nullptr, "SendDspSleep"},
90 {0x003D0042, NULL, "SendDspWakeUp"}, 115 {0x003D0042, nullptr, "SendDspWakeUp"},
91 {0x003E0080, NULL, "ReplySleepQuery"}, 116 {0x003E0080, nullptr, "ReplySleepQuery"},
92 {0x003F0040, NULL, "ReplySleepNotificationComplete"}, 117 {0x003F0040, nullptr, "ReplySleepNotificationComplete"},
93 {0x00400042, NULL, "SendCaptureBufferInfo"}, 118 {0x00400042, nullptr, "SendCaptureBufferInfo"},
94 {0x00410040, NULL, "ReceiveCaptureBufferInfo"}, 119 {0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
95 {0x00420080, NULL, "SleepSystem"}, 120 {0x00420080, nullptr, "SleepSystem"},
96 {0x00430040, NULL, "NotifyToWait"}, 121 {0x00430040, nullptr, "NotifyToWait"},
97 {0x00440000, NULL, "GetSharedFont"}, 122 {0x00440000, nullptr, "GetSharedFont"},
98 {0x00450040, NULL, "GetWirelessRebootInfo"}, 123 {0x00450040, nullptr, "GetWirelessRebootInfo"},
99 {0x00460104, NULL, "Wrap"}, 124 {0x00460104, nullptr, "Wrap"},
100 {0x00470104, NULL, "Unwrap"}, 125 {0x00470104, nullptr, "Unwrap"},
101 {0x00480100, NULL, "GetProgramInfo"}, 126 {0x00480100, nullptr, "GetProgramInfo"},
102 {0x00490180, NULL, "Reboot"}, 127 {0x00490180, nullptr, "Reboot"},
103 {0x004A0040, NULL, "GetCaptureInfo"}, 128 {0x004A0040, nullptr, "GetCaptureInfo"},
104 {0x004B00C2, NULL, "AppletUtility"}, 129 {0x004B00C2, nullptr, "AppletUtility"},
105 {0x004C0000, NULL, "SetFatalErrDispMode"}, 130 {0x004C0000, nullptr, "SetFatalErrDispMode"},
106 {0x004D0080, NULL, "GetAppletProgramInfo"}, 131 {0x004D0080, nullptr, "GetAppletProgramInfo"},
107 {0x004E0000, NULL, "HardwareResetAsync"}, 132 {0x004E0000, nullptr, "HardwareResetAsync"},
108}; 133};
109 134
110//////////////////////////////////////////////////////////////////////////////////////////////////// 135////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp
index aabcb48db..f75ba75c2 100644
--- a/src/core/hle/service/gsp.cpp
+++ b/src/core/hle/service/gsp.cpp
@@ -8,6 +8,7 @@
8 8
9#include "core/mem_map.h" 9#include "core/mem_map.h"
10#include "core/hle/hle.h" 10#include "core/hle/hle.h"
11#include "core/hle/kernel/event.h"
11#include "core/hle/service/gsp.h" 12#include "core/hle/service/gsp.h"
12 13
13#include "core/hw/gpu.h" 14#include "core/hw/gpu.h"
@@ -60,6 +61,7 @@ void GX_FinishCommand(u32 thread_id) {
60 61
61namespace GSP_GPU { 62namespace GSP_GPU {
62 63
64Handle g_event_handle = 0;
63u32 g_thread_id = 0; 65u32 g_thread_id = 0;
64 66
65enum { 67enum {
@@ -96,7 +98,7 @@ void ReadHWRegs(Service::Interface* self) {
96 break; 98 break;
97 99
98 default: 100 default:
99 ERROR_LOG(GSP, "ReadHWRegs unknown register read at address %08X", reg_addr); 101 ERROR_LOG(GSP, "unknown register read at address %08X", reg_addr);
100 } 102 }
101 103
102} 104}
@@ -104,7 +106,19 @@ void ReadHWRegs(Service::Interface* self) {
104void RegisterInterruptRelayQueue(Service::Interface* self) { 106void RegisterInterruptRelayQueue(Service::Interface* self) {
105 u32* cmd_buff = Service::GetCommandBuffer(); 107 u32* cmd_buff = Service::GetCommandBuffer();
106 u32 flags = cmd_buff[1]; 108 u32 flags = cmd_buff[1];
107 u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling 109 u32 event_handle = cmd_buff[3];
110
111 _assert_msg_(GSP, (event_handle != 0), "called, but event is nullptr!");
112
113 g_event_handle = event_handle;
114
115 Kernel::SetEventLocked(event_handle, false);
116
117 // Hack - This function will permanently set the state of the GSP event such that GPU command
118 // synchronization barriers always passthrough. Correct solution would be to set this after the
119 // GPU as processed all queued up commands, but due to the emulator being single-threaded they
120 // will always be ready.
121 Kernel::SetPermanentLock(event_handle, true);
108 122
109 cmd_buff[2] = g_thread_id; // ThreadID 123 cmd_buff[2] = g_thread_id; // ThreadID
110} 124}
@@ -150,43 +164,43 @@ void TriggerCmdReqQueue(Service::Interface* self) {
150 } 164 }
151 165
152 default: 166 default:
153 ERROR_LOG(GSP, "TriggerCmdReqQueue unknown command 0x%08X", cmd_buff[0]); 167 ERROR_LOG(GSP, "unknown command 0x%08X", cmd_buff[0]);
154 } 168 }
155 169
156 GX_FinishCommand(g_thread_id); 170 GX_FinishCommand(g_thread_id);
157} 171}
158 172
159const Interface::FunctionInfo FunctionTable[] = { 173const Interface::FunctionInfo FunctionTable[] = {
160 {0x00010082, NULL, "WriteHWRegs"}, 174 {0x00010082, nullptr, "WriteHWRegs"},
161 {0x00020084, NULL, "WriteHWRegsWithMask"}, 175 {0x00020084, nullptr, "WriteHWRegsWithMask"},
162 {0x00030082, NULL, "WriteHWRegRepeat"}, 176 {0x00030082, nullptr, "WriteHWRegRepeat"},
163 {0x00040080, ReadHWRegs, "ReadHWRegs"}, 177 {0x00040080, ReadHWRegs, "ReadHWRegs"},
164 {0x00050200, NULL, "SetBufferSwap"}, 178 {0x00050200, nullptr, "SetBufferSwap"},
165 {0x00060082, NULL, "SetCommandList"}, 179 {0x00060082, nullptr, "SetCommandList"},
166 {0x000700C2, NULL, "RequestDma"}, 180 {0x000700C2, nullptr, "RequestDma"},
167 {0x00080082, NULL, "FlushDataCache"}, 181 {0x00080082, nullptr, "FlushDataCache"},
168 {0x00090082, NULL, "InvalidateDataCache"}, 182 {0x00090082, nullptr, "InvalidateDataCache"},
169 {0x000A0044, NULL, "RegisterInterruptEvents"}, 183 {0x000A0044, nullptr, "RegisterInterruptEvents"},
170 {0x000B0040, NULL, "SetLcdForceBlack"}, 184 {0x000B0040, nullptr, "SetLcdForceBlack"},
171 {0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"}, 185 {0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"},
172 {0x000D0140, NULL, "SetDisplayTransfer"}, 186 {0x000D0140, nullptr, "SetDisplayTransfer"},
173 {0x000E0180, NULL, "SetTextureCopy"}, 187 {0x000E0180, nullptr, "SetTextureCopy"},
174 {0x000F0200, NULL, "SetMemoryFill"}, 188 {0x000F0200, nullptr, "SetMemoryFill"},
175 {0x00100040, NULL, "SetAxiConfigQoSMode"}, 189 {0x00100040, nullptr, "SetAxiConfigQoSMode"},
176 {0x00110040, NULL, "SetPerfLogMode"}, 190 {0x00110040, nullptr, "SetPerfLogMode"},
177 {0x00120000, NULL, "GetPerfLog"}, 191 {0x00120000, nullptr, "GetPerfLog"},
178 {0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"}, 192 {0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"},
179 {0x00140000, NULL, "UnregisterInterruptRelayQueue"}, 193 {0x00140000, nullptr, "UnregisterInterruptRelayQueue"},
180 {0x00150002, NULL, "TryAcquireRight"}, 194 {0x00150002, nullptr, "TryAcquireRight"},
181 {0x00160042, NULL, "AcquireRight"}, 195 {0x00160042, nullptr, "AcquireRight"},
182 {0x00170000, NULL, "ReleaseRight"}, 196 {0x00170000, nullptr, "ReleaseRight"},
183 {0x00180000, NULL, "ImportDisplayCaptureInfo"}, 197 {0x00180000, nullptr, "ImportDisplayCaptureInfo"},
184 {0x00190000, NULL, "SaveVramSysArea"}, 198 {0x00190000, nullptr, "SaveVramSysArea"},
185 {0x001A0000, NULL, "RestoreVramSysArea"}, 199 {0x001A0000, nullptr, "RestoreVramSysArea"},
186 {0x001B0000, NULL, "ResetGpuCore"}, 200 {0x001B0000, nullptr, "ResetGpuCore"},
187 {0x001C0040, NULL, "SetLedForceOff"}, 201 {0x001C0040, nullptr, "SetLedForceOff"},
188 {0x001D0040, NULL, "SetTestCommand"}, 202 {0x001D0040, nullptr, "SetTestCommand"},
189 {0x001E0080, NULL, "SetInternalPriorities"}, 203 {0x001E0080, nullptr, "SetInternalPriorities"},
190}; 204};
191 205
192//////////////////////////////////////////////////////////////////////////////////////////////////// 206////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/hid.cpp b/src/core/hle/service/hid.cpp
index 5542e5bf2..ab78f47d7 100644
--- a/src/core/hle/service/hid.cpp
+++ b/src/core/hle/service/hid.cpp
@@ -13,11 +13,11 @@
13namespace HID_User { 13namespace HID_User {
14 14
15const Interface::FunctionInfo FunctionTable[] = { 15const Interface::FunctionInfo FunctionTable[] = {
16 {0x000A0000, NULL, "GetIPCHandles"}, 16 {0x000A0000, nullptr, "GetIPCHandles"},
17 {0x00110000, NULL, "EnableAccelerometer"}, 17 {0x00110000, nullptr, "EnableAccelerometer"},
18 {0x00130000, NULL, "EnableGyroscopeLow"}, 18 {0x00130000, nullptr, "EnableGyroscopeLow"},
19 {0x00150000, NULL, "GetGyroscopeLowRawToDpsCoefficient"}, 19 {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"},
20 {0x00160000, NULL, "GetGyroscopeLowCalibrateParam"}, 20 {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"},
21}; 21};
22 22
23//////////////////////////////////////////////////////////////////////////////////////////////////// 23////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/ndm.cpp b/src/core/hle/service/ndm.cpp
new file mode 100644
index 000000000..48755b6a7
--- /dev/null
+++ b/src/core/hle/service/ndm.cpp
@@ -0,0 +1,32 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6
7#include "core/hle/hle.h"
8#include "core/hle/service/ndm.h"
9
10////////////////////////////////////////////////////////////////////////////////////////////////////
11// Namespace NDM_U
12
13namespace NDM_U {
14
15const Interface::FunctionInfo FunctionTable[] = {
16 {0x00060040, nullptr, "SuspendDaemons"},
17 {0x00080040, nullptr, "DisableWifiUsage"},
18 {0x00090000, nullptr, "EnableWifiUsage"},
19 {0x00140040, nullptr, "OverrideDefaultDaemons"},
20};
21
22////////////////////////////////////////////////////////////////////////////////////////////////////
23// Interface class
24
25Interface::Interface() {
26 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
27}
28
29Interface::~Interface() {
30}
31
32} // namespace
diff --git a/src/core/hle/service/ndm.h b/src/core/hle/service/ndm.h
new file mode 100644
index 000000000..fbe88fb8f
--- /dev/null
+++ b/src/core/hle/service/ndm.h
@@ -0,0 +1,33 @@
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 "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace NDM
11
12// No idea what this is
13
14namespace NDM_U {
15
16class Interface : public Service::Interface {
17public:
18
19 Interface();
20
21 ~Interface();
22
23 /**
24 * Gets the string port name used by CTROS for the service
25 * @return Port name of service
26 */
27 const char *GetPortName() const {
28 return "ndm:u";
29 }
30
31};
32
33} // namespace
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 08d0c43ff..4a1ac857e 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -12,13 +12,14 @@
12#include "core/hle/service/apt.h" 12#include "core/hle/service/apt.h"
13#include "core/hle/service/gsp.h" 13#include "core/hle/service/gsp.h"
14#include "core/hle/service/hid.h" 14#include "core/hle/service/hid.h"
15#include "core/hle/service/ndm.h"
15#include "core/hle/service/srv.h" 16#include "core/hle/service/srv.h"
16 17
17#include "core/hle/kernel/kernel.h" 18#include "core/hle/kernel/kernel.h"
18 19
19namespace Service { 20namespace Service {
20 21
21Manager* g_manager = NULL; ///< Service manager 22Manager* g_manager = nullptr; ///< Service manager
22 23
23//////////////////////////////////////////////////////////////////////////////////////////////////// 24////////////////////////////////////////////////////////////////////////////////////////////////////
24// Service Manager class 25// Service Manager class
@@ -55,7 +56,7 @@ Interface* Manager::FetchFromHandle(Handle handle) {
55Interface* Manager::FetchFromPortName(std::string port_name) { 56Interface* Manager::FetchFromPortName(std::string port_name) {
56 auto itr = m_port_map.find(port_name); 57 auto itr = m_port_map.find(port_name);
57 if (itr == m_port_map.end()) { 58 if (itr == m_port_map.end()) {
58 return NULL; 59 return nullptr;
59 } 60 }
60 return FetchFromHandle(itr->second); 61 return FetchFromHandle(itr->second);
61} 62}
@@ -72,14 +73,15 @@ void Init() {
72 g_manager->AddService(new APT_U::Interface); 73 g_manager->AddService(new APT_U::Interface);
73 g_manager->AddService(new GSP_GPU::Interface); 74 g_manager->AddService(new GSP_GPU::Interface);
74 g_manager->AddService(new HID_User::Interface); 75 g_manager->AddService(new HID_User::Interface);
76 g_manager->AddService(new NDM_U::Interface);
75 77
76 NOTICE_LOG(HLE, "Services initialized OK"); 78 NOTICE_LOG(HLE, "initialized OK");
77} 79}
78 80
79/// Shutdown ServiceManager 81/// Shutdown ServiceManager
80void Shutdown() { 82void Shutdown() {
81 delete g_manager; 83 delete g_manager;
82 NOTICE_LOG(HLE, "Services shutdown OK"); 84 NOTICE_LOG(HLE, "shutdown OK");
83} 85}
84 86
85 87
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index fab51753f..dcd525727 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -39,8 +39,8 @@ class Interface : public Kernel::Object {
39 friend class Manager; 39 friend class Manager;
40public: 40public:
41 41
42 const char *GetName() { return GetPortName(); } 42 const char *GetName() const { return GetPortName(); }
43 const char *GetTypeName() { return GetPortName(); } 43 const char *GetTypeName() const { return GetPortName(); }
44 44
45 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } 45 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; }
46 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } 46 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; }
@@ -76,22 +76,31 @@ public:
76 } 76 }
77 77
78 /** 78 /**
79 * Called when svcSendSyncRequest is called, loads command buffer and executes comand 79 * Synchronize kernel object
80 * @return Return result of svcSendSyncRequest passed back to user app 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
81 */ 82 */
82 Result Sync() { 83 Result SyncRequest(bool* wait) {
83 u32* cmd_buff = GetCommandBuffer(); 84 u32* cmd_buff = GetCommandBuffer();
84 auto itr = m_functions.find(cmd_buff[0]); 85 auto itr = m_functions.find(cmd_buff[0]);
85 86
86 if (itr == m_functions.end()) { 87 if (itr == m_functions.end()) {
87 ERROR_LOG(OSHLE, "Unknown/unimplemented function: port = %s, command = 0x%08X!", 88 ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X",
88 GetPortName(), cmd_buff[0]); 89 GetPortName(), cmd_buff[0]);
89 return -1; 90
91 // TODO(bunnei): Hack - ignore error
92 u32* cmd_buff = Service::GetCommandBuffer();
93 cmd_buff[1] = 0;
94 return 0;
90 } 95 }
91 if (itr->second.func == NULL) { 96 if (itr->second.func == nullptr) {
92 ERROR_LOG(OSHLE, "Unimplemented function: port = %s, name = %s!", 97 ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
93 GetPortName(), itr->second.name.c_str()); 98 GetPortName(), itr->second.name.c_str());
94 return -1; 99
100 // TODO(bunnei): Hack - ignore error
101 u32* cmd_buff = Service::GetCommandBuffer();
102 cmd_buff[1] = 0;
103 return 0;
95 } 104 }
96 105
97 itr->second.func(this); 106 itr->second.func(this);
@@ -99,6 +108,17 @@ public:
99 return 0; // TODO: Implement return from actual function 108 return 0; // TODO: Implement return from actual function
100 } 109 }
101 110
111 /**
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) {
117 // TODO(bunnei): ImplementMe
118 ERROR_LOG(OSHLE, "unimplemented function");
119 return 0;
120 }
121
102protected: 122protected:
103 123
104 /** 124 /**
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index ff6da8f1c..f45c0efc2 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -5,21 +5,28 @@
5#include "core/hle/hle.h" 5#include "core/hle/hle.h"
6#include "core/hle/service/srv.h" 6#include "core/hle/service/srv.h"
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8#include "core/hle/kernel/mutex.h"
9 9
10//////////////////////////////////////////////////////////////////////////////////////////////////// 10////////////////////////////////////////////////////////////////////////////////////////////////////
11// Namespace SRV 11// Namespace SRV
12 12
13namespace SRV { 13namespace SRV {
14 14
15Handle g_mutex = 0;
16
15void Initialize(Service::Interface* self) { 17void Initialize(Service::Interface* self) {
16 NOTICE_LOG(OSHLE, "SRV::Sync - Initialize"); 18 DEBUG_LOG(OSHLE, "called");
19 if (!g_mutex) {
20 g_mutex = Kernel::CreateMutex(true, "SRV:Lock");
21 }
17} 22}
18 23
19void GetProcSemaphore(Service::Interface* self) { 24void GetProcSemaphore(Service::Interface* self) {
25 DEBUG_LOG(OSHLE, "called");
20 // Get process semaphore? 26 // Get process semaphore?
21 u32* cmd_buff = Service::GetCommandBuffer(); 27 u32* cmd_buff = Service::GetCommandBuffer();
22 cmd_buff[3] = 0xDEADBEEF; // Return something... 0 == NULL, raises an exception 28 cmd_buff[1] = 0; // No error
29 cmd_buff[3] = g_mutex; // Return something... 0 == nullptr, raises an exception
23} 30}
24 31
25void GetServiceHandle(Service::Interface* self) { 32void GetServiceHandle(Service::Interface* self) {
@@ -29,25 +36,21 @@ void GetServiceHandle(Service::Interface* self) {
29 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); 36 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize);
30 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); 37 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
31 38
32 NOTICE_LOG(OSHLE, "SRV::Sync - GetHandle - port: %s, handle: 0x%08X", port_name.c_str(), 39 if (nullptr != service) {
33 service->GetHandle());
34
35 if (NULL != service) {
36 cmd_buff[3] = service->GetHandle(); 40 cmd_buff[3] = service->GetHandle();
41 DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
37 } else { 42 } else {
38 ERROR_LOG(OSHLE, "Service %s does not exist", port_name.c_str()); 43 ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
39 res = -1; 44 res = -1;
40 } 45 }
41 cmd_buff[1] = res; 46 cmd_buff[1] = res;
42
43 //return res;
44} 47}
45 48
46const Interface::FunctionInfo FunctionTable[] = { 49const Interface::FunctionInfo FunctionTable[] = {
47 {0x00010002, Initialize, "Initialize"}, 50 {0x00010002, Initialize, "Initialize"},
48 {0x00020000, GetProcSemaphore, "GetProcSemaphore"}, 51 {0x00020000, GetProcSemaphore, "GetProcSemaphore"},
49 {0x00030100, NULL, "RegisterService"}, 52 {0x00030100, nullptr, "RegisterService"},
50 {0x000400C0, NULL, "UnregisterService"}, 53 {0x000400C0, nullptr, "UnregisterService"},
51 {0x00050100, GetServiceHandle, "GetServiceHandle"}, 54 {0x00050100, GetServiceHandle, "GetServiceHandle"},
52}; 55};
53 56
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 1e35032ba..81109a2a8 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -26,12 +26,6 @@ public:
26 return "srv:"; 26 return "srv:";
27 } 27 }
28 28
29 /**
30 * Called when svcSendSyncRequest is called, loads command buffer and executes comand
31 * @return Return result of svcSendSyncRequest passed back to user app
32 */
33 Result Sync();
34
35}; 29};
36 30
37} // namespace 31} // namespace
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 90c05cb74..441d8ce8d 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -9,6 +9,7 @@
9 9
10#include "core/mem_map.h" 10#include "core/mem_map.h"
11 11
12#include "core/hle/kernel/event.h"
12#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/mutex.h" 14#include "core/hle/kernel/mutex.h"
14#include "core/hle/kernel/thread.h" 15#include "core/hle/kernel/thread.h"
@@ -16,7 +17,6 @@
16#include "core/hle/function_wrappers.h" 17#include "core/hle/function_wrappers.h"
17#include "core/hle/svc.h" 18#include "core/hle/svc.h"
18#include "core/hle/service/service.h" 19#include "core/hle/service/service.h"
19#include "core/hle/kernel/thread.h"
20 20
21//////////////////////////////////////////////////////////////////////////////////////////////////// 21////////////////////////////////////////////////////////////////////////////////////////////////////
22// Namespace SVC 22// Namespace SVC
@@ -34,40 +34,32 @@ enum MapMemoryPermission {
34}; 34};
35 35
36/// Map application or GSP heap memory 36/// Map application or GSP heap memory
37Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { 37Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
38 u32* outaddr = (u32*)_outaddr; 38 DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
39 u32 virtual_address = 0x00000000;
40
41 DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
42 operation, addr0, addr1, size, permissions); 39 operation, addr0, addr1, size, permissions);
43 40
44 switch (operation) { 41 switch (operation) {
45 42
46 // Map normal heap memory 43 // Map normal heap memory
47 case MEMORY_OPERATION_HEAP: 44 case MEMORY_OPERATION_HEAP:
48 virtual_address = Memory::MapBlock_Heap(size, operation, permissions); 45 *out_addr = Memory::MapBlock_Heap(size, operation, permissions);
49 break; 46 break;
50 47
51 // Map GSP heap memory 48 // Map GSP heap memory
52 case MEMORY_OPERATION_GSP_HEAP: 49 case MEMORY_OPERATION_GSP_HEAP:
53 virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions); 50 *out_addr = Memory::MapBlock_HeapGSP(size, operation, permissions);
54 break; 51 break;
55 52
56 // Unknown ControlMemory operation 53 // Unknown ControlMemory operation
57 default: 54 default:
58 ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); 55 ERROR_LOG(SVC, "unknown operation=0x%08X", operation);
59 } 56 }
60 if (NULL != outaddr) {
61 *outaddr = virtual_address;
62 }
63 Core::g_app_core->SetReg(1, virtual_address);
64
65 return 0; 57 return 0;
66} 58}
67 59
68/// Maps a memory block to specified address 60/// Maps a memory block to specified address
69Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { 61Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) {
70 DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", 62 DEBUG_LOG(SVC, "called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
71 memblock, addr, mypermissions, otherpermission); 63 memblock, addr, mypermissions, otherpermission);
72 switch (mypermissions) { 64 switch (mypermissions) {
73 case MEMORY_PERMISSION_NORMAL: 65 case MEMORY_PERMISSION_NORMAL:
@@ -76,88 +68,146 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper
76 Memory::MapBlock_Shared(memblock, addr, mypermissions); 68 Memory::MapBlock_Shared(memblock, addr, mypermissions);
77 break; 69 break;
78 default: 70 default:
79 ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions); 71 ERROR_LOG(OSHLE, "unknown permissions=0x%08X", mypermissions);
80 } 72 }
81 return 0; 73 return 0;
82} 74}
83 75
84/// Connect to an OS service given the port name, returns the handle to the port to out 76/// Connect to an OS service given the port name, returns the handle to the port to out
85Result ConnectToPort(void* out, const char* port_name) { 77Result ConnectToPort(Handle* out, const char* port_name) {
86 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); 78 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
87 if (service) { 79
88 Core::g_app_core->SetReg(1, service->GetHandle()); 80 DEBUG_LOG(SVC, "called port_name=%s", port_name);
89 } else { 81 _assert_msg_(KERNEL, (service != nullptr), "called, but service is not implemented!");
90 PanicYesNo("ConnectToPort called port_name=%s, but it is not implemented!", port_name); 82
91 } 83 *out = service->GetHandle();
92 DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name); 84
93 return 0; 85 return 0;
94} 86}
95 87
96/// Synchronize to an OS service 88/// Synchronize to an OS service
97Result SendSyncRequest(Handle handle) { 89Result SendSyncRequest(Handle handle) {
98 DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X"); 90 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
99 Service::Interface* service = Service::g_manager->FetchFromHandle(handle); 91
100 service->Sync(); 92 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
101 return 0; 93 DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName());
94
95 bool wait = false;
96 Result res = object->SyncRequest(&wait);
97 if (wait) {
98 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
99 }
100
101 return res;
102} 102}
103 103
104/// Close a handle 104/// Close a handle
105Result CloseHandle(Handle handle) { 105Result CloseHandle(Handle handle) {
106 // ImplementMe 106 // ImplementMe
107 DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle); 107 ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle);
108 return 0; 108 return 0;
109} 109}
110 110
111/// Wait for a handle to synchronize, timeout after the specified nanoseconds 111/// Wait for a handle to synchronize, timeout after the specified nanoseconds
112Result WaitSynchronization1(Handle handle, s64 nano_seconds) { 112Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
113 DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", 113 // TODO(bunnei): Do something with nano_seconds, currently ignoring this
114 handle, nano_seconds); 114 bool wait = false;
115 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? 115 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
116 return 0; 116
117 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
118
119 DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName(),
120 object->GetName(), nano_seconds);
121
122 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
123
124 Result res = object->WaitSynchronization(&wait);
125
126 // Check for next thread to schedule
127 if (wait) {
128 HLE::Reschedule(__func__);
129 return 0;
130 }
131
132 return res;
117} 133}
118 134
119/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 135/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
120Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) { 136Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all,
121 s32* out = (s32*)_out; 137 s64 nano_seconds) {
122 Handle* handles = (Handle*)_handles; 138 // TODO(bunnei): Do something with nano_seconds, currently ignoring this
139 bool unlock_all = true;
140 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
123 141
124 DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s", 142 DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d",
125 handle_count, (wait_all ? "true" : "false"), nano_seconds); 143 handle_count, (wait_all ? "true" : "false"), nano_seconds);
126 144
127 for (u32 i = 0; i < handle_count; i++) { 145 // Iterate through each handle, synchronize kernel object
128 DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]); 146 for (s32 i = 0; i < handle_count; i++) {
147 bool wait = false;
148 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]);
149
150 _assert_msg_(KERNEL, (object != nullptr), "called handle=0x%08X, but kernel object "
151 "is nullptr!", handles[i]);
152
153 DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName(),
154 object->GetName());
155
156 Result res = object->WaitSynchronization(&wait);
157
158 if (!wait && !wait_all) {
159 *out = i;
160 return 0;
161 } else {
162 unlock_all = false;
163 }
129 } 164 }
130 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? 165
166 if (wait_all && unlock_all) {
167 *out = handle_count;
168 return 0;
169 }
170
171 // Check for next thread to schedule
172 HLE::Reschedule(__func__);
173
131 return 0; 174 return 0;
132} 175}
133 176
134/// Create an address arbiter (to allocate access to shared resources) 177/// Create an address arbiter (to allocate access to shared resources)
135Result CreateAddressArbiter(void* arbiter) { 178Result CreateAddressArbiter(void* arbiter) {
136 // ImplementMe 179 ERROR_LOG(SVC, "(UNIMPLEMENTED) called");
137 DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called");
138 Core::g_app_core->SetReg(1, 0xFABBDADD); 180 Core::g_app_core->SetReg(1, 0xFABBDADD);
139 return 0; 181 return 0;
140} 182}
141 183
184/// Arbitrate address
185Result ArbitrateAddress(Handle arbiter, u32 addr, u32 _type, u32 value, s64 nanoseconds) {
186 ERROR_LOG(SVC, "(UNIMPLEMENTED) called");
187 ArbitrationType type = (ArbitrationType)_type;
188 Memory::Write32(addr, type);
189 return 0;
190}
191
142/// Used to output a message on a debug hardware unit - does nothing on a retail unit 192/// Used to output a message on a debug hardware unit - does nothing on a retail unit
143void OutputDebugString(const char* string) { 193void OutputDebugString(const char* string) {
144 NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string); 194 OS_LOG(SVC, "%s", string);
145} 195}
146 196
147/// Get resource limit 197/// Get resource limit
148Result GetResourceLimit(void* resource_limit, Handle process) { 198Result GetResourceLimit(Handle* resource_limit, Handle process) {
149 // With regards to proceess values: 199 // With regards to proceess values:
150 // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for 200 // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
151 // the current KThread. 201 // the current KThread.
152 DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process); 202 *resource_limit = 0xDEADBEEF;
153 Core::g_app_core->SetReg(1, 0xDEADBEEF); 203 ERROR_LOG(SVC, "(UNIMPLEMENTED) called process=0x%08X", process);
154 return 0; 204 return 0;
155} 205}
156 206
157/// Get resource limit current values 207/// Get resource limit current values
158Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) { 208Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names,
159 //s64* values = (s64*)_values; 209 s32 name_count) {
160 DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d", 210 ERROR_LOG(SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d",
161 resource_limit, names, name_count); 211 resource_limit, names, name_count);
162 Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now 212 Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
163 return 0; 213 return 0;
@@ -180,179 +230,234 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p
180 230
181 Core::g_app_core->SetReg(1, thread); 231 Core::g_app_core->SetReg(1, thread);
182 232
183 DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " 233 DEBUG_LOG(SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
184 "threadpriority=0x%08X, processorid=0x%08X : created handle 0x%08X", entry_point, 234 "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,
185 name.c_str(), arg, stack_top, priority, processor_id, thread); 235 name.c_str(), arg, stack_top, priority, processor_id, thread);
186 236
187 return 0; 237 return 0;
188} 238}
189 239
240/// Called when a thread exits
241u32 ExitThread() {
242 Handle thread = Kernel::GetCurrentThreadHandle();
243
244 DEBUG_LOG(SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C
245
246 Kernel::StopThread(thread, __func__);
247 HLE::Reschedule(__func__);
248 return 0;
249}
250
251/// Gets the priority for the specified thread
252Result GetThreadPriority(s32* priority, Handle handle) {
253 *priority = Kernel::GetThreadPriority(handle);
254 return 0;
255}
256
257/// Sets the priority for the specified thread
258Result SetThreadPriority(Handle handle, s32 priority) {
259 return Kernel::SetThreadPriority(handle, priority);
260}
261
190/// Create a mutex 262/// Create a mutex
191Result CreateMutex(void* _mutex, u32 initial_locked) { 263Result CreateMutex(Handle* mutex, u32 initial_locked) {
192 Handle* mutex = (Handle*)_mutex;
193 *mutex = Kernel::CreateMutex((initial_locked != 0)); 264 *mutex = Kernel::CreateMutex((initial_locked != 0));
194 Core::g_app_core->SetReg(1, *mutex); 265 DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X",
195 DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s : created handle 0x%08X",
196 initial_locked ? "true" : "false", *mutex); 266 initial_locked ? "true" : "false", *mutex);
197 return 0; 267 return 0;
198} 268}
199 269
200/// Release a mutex 270/// Release a mutex
201Result ReleaseMutex(Handle handle) { 271Result ReleaseMutex(Handle handle) {
202 DEBUG_LOG(SVC, "ReleaseMutex called handle=0x%08X", handle); 272 DEBUG_LOG(SVC, "called handle=0x%08X", handle);
273 _assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!");
203 Kernel::ReleaseMutex(handle); 274 Kernel::ReleaseMutex(handle);
204 return 0; 275 return 0;
205} 276}
206 277
207/// Get current thread ID 278/// Get current thread ID
208Result GetThreadId(void* thread_id, u32 thread) { 279Result GetThreadId(u32* thread_id, Handle thread) {
209 DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread); 280 ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread);
210 return 0; 281 return 0;
211} 282}
212 283
213/// Query memory 284/// Query memory
214Result QueryMemory(void *_info, void *_out, u32 addr) { 285Result QueryMemory(void* info, void* out, u32 addr) {
215 MemoryInfo* info = (MemoryInfo*) _info; 286 ERROR_LOG(SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr);
216 PageInfo* out = (PageInfo*) _out;
217 DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr);
218 return 0; 287 return 0;
219} 288}
220 289
221/// Create an event 290/// Create an event
222Result CreateEvent(void* _event, u32 reset_type) { 291Result CreateEvent(Handle* evt, u32 reset_type) {
223 Handle* event = (Handle*)_event; 292 *evt = Kernel::CreateEvent((ResetType)reset_type);
224 DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type); 293 DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X",
225 Core::g_app_core->SetReg(1, 0xBADC0DE0); 294 reset_type, *evt);
295 return 0;
296}
297
298/// Duplicates a kernel handle
299Result DuplicateHandle(Handle* out, Handle handle) {
300 DEBUG_LOG(SVC, "called handle=0x%08X", handle);
301
302 // Translate kernel handles -> real handles
303 if (handle == Kernel::CurrentThread) {
304 handle = Kernel::GetCurrentThreadHandle();
305 }
306 _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess),
307 "(UNIMPLEMENTED) process handle duplication!");
308
309 // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate.
310 *out = handle;
311
226 return 0; 312 return 0;
227} 313}
228 314
315/// Signals an event
316Result SignalEvent(Handle evt) {
317 Result res = Kernel::SignalEvent(evt);
318 DEBUG_LOG(SVC, "called event=0x%08X", evt);
319 return res;
320}
321
322/// Clears an event
323Result ClearEvent(Handle evt) {
324 Result res = Kernel::ClearEvent(evt);
325 DEBUG_LOG(SVC, "called event=0x%08X", evt);
326 return res;
327}
328
329/// Sleep the current thread
330void SleepThread(s64 nanoseconds) {
331 DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds);
332}
333
229const HLE::FunctionDef SVC_Table[] = { 334const HLE::FunctionDef SVC_Table[] = {
230 {0x00, NULL, "Unknown"}, 335 {0x00, nullptr, "Unknown"},
231 {0x01, WrapI_VUUUUU<ControlMemory>, "ControlMemory"}, 336 {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
232 {0x02, WrapI_VVU<QueryMemory>, "QueryMemory"}, 337 {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
233 {0x03, NULL, "ExitProcess"}, 338 {0x03, nullptr, "ExitProcess"},
234 {0x04, NULL, "GetProcessAffinityMask"}, 339 {0x04, nullptr, "GetProcessAffinityMask"},
235 {0x05, NULL, "SetProcessAffinityMask"}, 340 {0x05, nullptr, "SetProcessAffinityMask"},
236 {0x06, NULL, "GetProcessIdealProcessor"}, 341 {0x06, nullptr, "GetProcessIdealProcessor"},
237 {0x07, NULL, "SetProcessIdealProcessor"}, 342 {0x07, nullptr, "SetProcessIdealProcessor"},
238 {0x08, WrapI_UUUUU<CreateThread>, "CreateThread"}, 343 {0x08, HLE::Wrap<CreateThread>, "CreateThread"},
239 {0x09, NULL, "ExitThread"}, 344 {0x09, HLE::Wrap<ExitThread>, "ExitThread"},
240 {0x0A, NULL, "SleepThread"}, 345 {0x0A, HLE::Wrap<SleepThread>, "SleepThread"},
241 {0x0B, NULL, "GetThreadPriority"}, 346 {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"},
242 {0x0C, NULL, "SetThreadPriority"}, 347 {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"},
243 {0x0D, NULL, "GetThreadAffinityMask"}, 348 {0x0D, nullptr, "GetThreadAffinityMask"},
244 {0x0E, NULL, "SetThreadAffinityMask"}, 349 {0x0E, nullptr, "SetThreadAffinityMask"},
245 {0x0F, NULL, "GetThreadIdealProcessor"}, 350 {0x0F, nullptr, "GetThreadIdealProcessor"},
246 {0x10, NULL, "SetThreadIdealProcessor"}, 351 {0x10, nullptr, "SetThreadIdealProcessor"},
247 {0x11, NULL, "GetCurrentProcessorNumber"}, 352 {0x11, nullptr, "GetCurrentProcessorNumber"},
248 {0x12, NULL, "Run"}, 353 {0x12, nullptr, "Run"},
249 {0x13, WrapI_VU<CreateMutex>, "CreateMutex"}, 354 {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"},
250 {0x14, WrapI_U<ReleaseMutex>, "ReleaseMutex"}, 355 {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"},
251 {0x15, NULL, "CreateSemaphore"}, 356 {0x15, nullptr, "CreateSemaphore"},
252 {0x16, NULL, "ReleaseSemaphore"}, 357 {0x16, nullptr, "ReleaseSemaphore"},
253 {0x17, WrapI_VU<CreateEvent>, "CreateEvent"}, 358 {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"},
254 {0x18, NULL, "SignalEvent"}, 359 {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"},
255 {0x19, NULL, "ClearEvent"}, 360 {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"},
256 {0x1A, NULL, "CreateTimer"}, 361 {0x1A, nullptr, "CreateTimer"},
257 {0x1B, NULL, "SetTimer"}, 362 {0x1B, nullptr, "SetTimer"},
258 {0x1C, NULL, "CancelTimer"}, 363 {0x1C, nullptr, "CancelTimer"},
259 {0x1D, NULL, "ClearTimer"}, 364 {0x1D, nullptr, "ClearTimer"},
260 {0x1E, NULL, "CreateMemoryBlock"}, 365 {0x1E, nullptr, "CreateMemoryBlock"},
261 {0x1F, WrapI_UUUU<MapMemoryBlock>, "MapMemoryBlock"}, 366 {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"},
262 {0x20, NULL, "UnmapMemoryBlock"}, 367 {0x20, nullptr, "UnmapMemoryBlock"},
263 {0x21, WrapI_V<CreateAddressArbiter>, "CreateAddressArbiter"}, 368 {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"},
264 {0x22, NULL, "ArbitrateAddress"}, 369 {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"},
265 {0x23, WrapI_U<CloseHandle>, "CloseHandle"}, 370 {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"},
266 {0x24, WrapI_US64<WaitSynchronization1>, "WaitSynchronization1"}, 371 {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"},
267 {0x25, WrapI_VVUUS64<WaitSynchronizationN>, "WaitSynchronizationN"}, 372 {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"},
268 {0x26, NULL, "SignalAndWait"}, 373 {0x26, nullptr, "SignalAndWait"},
269 {0x27, NULL, "DuplicateHandle"}, 374 {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"},
270 {0x28, NULL, "GetSystemTick"}, 375 {0x28, nullptr, "GetSystemTick"},
271 {0x29, NULL, "GetHandleInfo"}, 376 {0x29, nullptr, "GetHandleInfo"},
272 {0x2A, NULL, "GetSystemInfo"}, 377 {0x2A, nullptr, "GetSystemInfo"},
273 {0x2B, NULL, "GetProcessInfo"}, 378 {0x2B, nullptr, "GetProcessInfo"},
274 {0x2C, NULL, "GetThreadInfo"}, 379 {0x2C, nullptr, "GetThreadInfo"},
275 {0x2D, WrapI_VC<ConnectToPort>, "ConnectToPort"}, 380 {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"},
276 {0x2E, NULL, "SendSyncRequest1"}, 381 {0x2E, nullptr, "SendSyncRequest1"},
277 {0x2F, NULL, "SendSyncRequest2"}, 382 {0x2F, nullptr, "SendSyncRequest2"},
278 {0x30, NULL, "SendSyncRequest3"}, 383 {0x30, nullptr, "SendSyncRequest3"},
279 {0x31, NULL, "SendSyncRequest4"}, 384 {0x31, nullptr, "SendSyncRequest4"},
280 {0x32, WrapI_U<SendSyncRequest>, "SendSyncRequest"}, 385 {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"},
281 {0x33, NULL, "OpenProcess"}, 386 {0x33, nullptr, "OpenProcess"},
282 {0x34, NULL, "OpenThread"}, 387 {0x34, nullptr, "OpenThread"},
283 {0x35, NULL, "GetProcessId"}, 388 {0x35, nullptr, "GetProcessId"},
284 {0x36, NULL, "GetProcessIdOfThread"}, 389 {0x36, nullptr, "GetProcessIdOfThread"},
285 {0x37, WrapI_VU<GetThreadId>, "GetThreadId"}, 390 {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"},
286 {0x38, WrapI_VU<GetResourceLimit>, "GetResourceLimit"}, 391 {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"},
287 {0x39, NULL, "GetResourceLimitLimitValues"}, 392 {0x39, nullptr, "GetResourceLimitLimitValues"},
288 {0x3A, WrapI_VUVI<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, 393 {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"},
289 {0x3B, NULL, "GetThreadContext"}, 394 {0x3B, nullptr, "GetThreadContext"},
290 {0x3C, NULL, "Break"}, 395 {0x3C, nullptr, "Break"},
291 {0x3D, WrapV_C<OutputDebugString>, "OutputDebugString"}, 396 {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"},
292 {0x3E, NULL, "ControlPerformanceCounter"}, 397 {0x3E, nullptr, "ControlPerformanceCounter"},
293 {0x3F, NULL, "Unknown"}, 398 {0x3F, nullptr, "Unknown"},
294 {0x40, NULL, "Unknown"}, 399 {0x40, nullptr, "Unknown"},
295 {0x41, NULL, "Unknown"}, 400 {0x41, nullptr, "Unknown"},
296 {0x42, NULL, "Unknown"}, 401 {0x42, nullptr, "Unknown"},
297 {0x43, NULL, "Unknown"}, 402 {0x43, nullptr, "Unknown"},
298 {0x44, NULL, "Unknown"}, 403 {0x44, nullptr, "Unknown"},
299 {0x45, NULL, "Unknown"}, 404 {0x45, nullptr, "Unknown"},
300 {0x46, NULL, "Unknown"}, 405 {0x46, nullptr, "Unknown"},
301 {0x47, NULL, "CreatePort"}, 406 {0x47, nullptr, "CreatePort"},
302 {0x48, NULL, "CreateSessionToPort"}, 407 {0x48, nullptr, "CreateSessionToPort"},
303 {0x49, NULL, "CreateSession"}, 408 {0x49, nullptr, "CreateSession"},
304 {0x4A, NULL, "AcceptSession"}, 409 {0x4A, nullptr, "AcceptSession"},
305 {0x4B, NULL, "ReplyAndReceive1"}, 410 {0x4B, nullptr, "ReplyAndReceive1"},
306 {0x4C, NULL, "ReplyAndReceive2"}, 411 {0x4C, nullptr, "ReplyAndReceive2"},
307 {0x4D, NULL, "ReplyAndReceive3"}, 412 {0x4D, nullptr, "ReplyAndReceive3"},
308 {0x4E, NULL, "ReplyAndReceive4"}, 413 {0x4E, nullptr, "ReplyAndReceive4"},
309 {0x4F, NULL, "ReplyAndReceive"}, 414 {0x4F, nullptr, "ReplyAndReceive"},
310 {0x50, NULL, "BindInterrupt"}, 415 {0x50, nullptr, "BindInterrupt"},
311 {0x51, NULL, "UnbindInterrupt"}, 416 {0x51, nullptr, "UnbindInterrupt"},
312 {0x52, NULL, "InvalidateProcessDataCache"}, 417 {0x52, nullptr, "InvalidateProcessDataCache"},
313 {0x53, NULL, "StoreProcessDataCache"}, 418 {0x53, nullptr, "StoreProcessDataCache"},
314 {0x54, NULL, "FlushProcessDataCache"}, 419 {0x54, nullptr, "FlushProcessDataCache"},
315 {0x55, NULL, "StartInterProcessDma"}, 420 {0x55, nullptr, "StartInterProcessDma"},
316 {0x56, NULL, "StopDma"}, 421 {0x56, nullptr, "StopDma"},
317 {0x57, NULL, "GetDmaState"}, 422 {0x57, nullptr, "GetDmaState"},
318 {0x58, NULL, "RestartDma"}, 423 {0x58, nullptr, "RestartDma"},
319 {0x59, NULL, "Unknown"}, 424 {0x59, nullptr, "Unknown"},
320 {0x5A, NULL, "Unknown"}, 425 {0x5A, nullptr, "Unknown"},
321 {0x5B, NULL, "Unknown"}, 426 {0x5B, nullptr, "Unknown"},
322 {0x5C, NULL, "Unknown"}, 427 {0x5C, nullptr, "Unknown"},
323 {0x5D, NULL, "Unknown"}, 428 {0x5D, nullptr, "Unknown"},
324 {0x5E, NULL, "Unknown"}, 429 {0x5E, nullptr, "Unknown"},
325 {0x5F, NULL, "Unknown"}, 430 {0x5F, nullptr, "Unknown"},
326 {0x60, NULL, "DebugActiveProcess"}, 431 {0x60, nullptr, "DebugActiveProcess"},
327 {0x61, NULL, "BreakDebugProcess"}, 432 {0x61, nullptr, "BreakDebugProcess"},
328 {0x62, NULL, "TerminateDebugProcess"}, 433 {0x62, nullptr, "TerminateDebugProcess"},
329 {0x63, NULL, "GetProcessDebugEvent"}, 434 {0x63, nullptr, "GetProcessDebugEvent"},
330 {0x64, NULL, "ContinueDebugEvent"}, 435 {0x64, nullptr, "ContinueDebugEvent"},
331 {0x65, NULL, "GetProcessList"}, 436 {0x65, nullptr, "GetProcessList"},
332 {0x66, NULL, "GetThreadList"}, 437 {0x66, nullptr, "GetThreadList"},
333 {0x67, NULL, "GetDebugThreadContext"}, 438 {0x67, nullptr, "GetDebugThreadContext"},
334 {0x68, NULL, "SetDebugThreadContext"}, 439 {0x68, nullptr, "SetDebugThreadContext"},
335 {0x69, NULL, "QueryDebugProcessMemory"}, 440 {0x69, nullptr, "QueryDebugProcessMemory"},
336 {0x6A, NULL, "ReadProcessMemory"}, 441 {0x6A, nullptr, "ReadProcessMemory"},
337 {0x6B, NULL, "WriteProcessMemory"}, 442 {0x6B, nullptr, "WriteProcessMemory"},
338 {0x6C, NULL, "SetHardwareBreakPoint"}, 443 {0x6C, nullptr, "SetHardwareBreakPoint"},
339 {0x6D, NULL, "GetDebugThreadParam"}, 444 {0x6D, nullptr, "GetDebugThreadParam"},
340 {0x6E, NULL, "Unknown"}, 445 {0x6E, nullptr, "Unknown"},
341 {0x6F, NULL, "Unknown"}, 446 {0x6F, nullptr, "Unknown"},
342 {0x70, NULL, "ControlProcessMemory"}, 447 {0x70, nullptr, "ControlProcessMemory"},
343 {0x71, NULL, "MapProcessMemory"}, 448 {0x71, nullptr, "MapProcessMemory"},
344 {0x72, NULL, "UnmapProcessMemory"}, 449 {0x72, nullptr, "UnmapProcessMemory"},
345 {0x73, NULL, "Unknown"}, 450 {0x73, nullptr, "Unknown"},
346 {0x74, NULL, "Unknown"}, 451 {0x74, nullptr, "Unknown"},
347 {0x75, NULL, "Unknown"}, 452 {0x75, nullptr, "Unknown"},
348 {0x76, NULL, "TerminateProcess"}, 453 {0x76, nullptr, "TerminateProcess"},
349 {0x77, NULL, "Unknown"}, 454 {0x77, nullptr, "Unknown"},
350 {0x78, NULL, "CreateResourceLimit"}, 455 {0x78, nullptr, "CreateResourceLimit"},
351 {0x79, NULL, "Unknown"}, 456 {0x79, nullptr, "Unknown"},
352 {0x7A, NULL, "Unknown"}, 457 {0x7A, nullptr, "Unknown"},
353 {0x7B, NULL, "Unknown"}, 458 {0x7B, nullptr, "Unknown"},
354 {0x7C, NULL, "KernelSetState"}, 459 {0x7C, nullptr, "KernelSetState"},
355 {0x7D, NULL, "QueryProcessMemory"}, 460 {0x7D, nullptr, "QueryProcessMemory"},
356}; 461};
357 462
358void Register() { 463void Register() {
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
index 5c35977d1..1d125faf6 100644
--- a/src/core/hle/svc.h
+++ b/src/core/hle/svc.h
@@ -29,6 +29,10 @@ struct ThreadContext {
29 u32 fpu_registers[32]; 29 u32 fpu_registers[32];
30 u32 fpscr; 30 u32 fpscr;
31 u32 fpexc; 31 u32 fpexc;
32
33 // These are not part of native ThreadContext, but needed by emu
34 u32 reg_15;
35 u32 mode;
32}; 36};
33 37
34enum ResetType { 38enum ResetType {
@@ -38,6 +42,15 @@ enum ResetType {
38 RESETTYPE_MAX_BIT = (1u << 31), 42 RESETTYPE_MAX_BIT = (1u << 31),
39}; 43};
40 44
45enum ArbitrationType {
46 ARBITRATIONTYPE_SIGNAL,
47 ARBITRATIONTYPE_WAIT_IF_LESS_THAN,
48 ARBITRATIONTYPE_DECREMENT_AND_WAIT_IF_LESS_THAN,
49 ARBITRATIONTYPE_WAIT_IF_LESS_THAN_WITH_TIMEOUT,
50 ARBITRATIONTYPE_DECREMENT_AND_WAIT_IF_LESS_THAN_WITH_TIMEOUT,
51 ARBITRATIONTYPE_MAX_BIT = (1u << 31)
52};
53
41//////////////////////////////////////////////////////////////////////////////////////////////////// 54////////////////////////////////////////////////////////////////////////////////////////////////////
42// Namespace SVC 55// Namespace SVC
43 56
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index ec2d0e156..f0ca4eada 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -17,8 +17,6 @@ namespace GPU {
17 17
18Registers g_regs; 18Registers g_regs;
19 19
20static const u32 kFrameTicks = 268123480 / 60; ///< 268MHz / 60 frames per second
21
22u64 g_last_ticks = 0; ///< Last CPU ticks 20u64 g_last_ticks = 0; ///< Last CPU ticks
23 21
24/** 22/**
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index f26f25e98..3314ba989 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -8,6 +8,9 @@
8 8
9namespace GPU { 9namespace GPU {
10 10
11static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second
12static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame
13
11struct Registers { 14struct Registers {
12 enum Id : u32 { 15 enum Id : u32 {
13 FramebufferTopLeft1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left 16 FramebufferTopLeft1 = 0x1EF00468, // Main LCD, first framebuffer for 3D left
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp
index 86e9eaa20..ab014a596 100644
--- a/src/core/mem_map_funcs.cpp
+++ b/src/core/mem_map_funcs.cpp
@@ -86,7 +86,7 @@ inline void _Read(T &var, const u32 addr) {
86 var = *((const T*)&g_vram[vaddr & VRAM_MASK]); 86 var = *((const T*)&g_vram[vaddr & VRAM_MASK]);
87 87
88 } else { 88 } else {
89 //_assert_msg_(MEMMAP, false, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); 89 ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr);
90 } 90 }
91} 91}
92 92
@@ -136,8 +136,7 @@ inline void _Write(u32 addr, const T data) {
136 136
137 // Error out... 137 // Error out...
138 } else { 138 } else {
139 _assert_msg_(MEMMAP, false, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, 139 ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr);
140 data, vaddr);
141 } 140 }
142} 141}
143 142
diff --git a/src/core/system.cpp b/src/core/system.cpp
index c77092327..9b1e96888 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -8,6 +8,7 @@
8#include "core/system.h" 8#include "core/system.h"
9#include "core/hw/hw.h" 9#include "core/hw/hw.h"
10#include "core/hle/hle.h" 10#include "core/hle/hle.h"
11#include "core/hle/kernel/kernel.h"
11 12
12#include "video_core/video_core.h" 13#include "video_core/video_core.h"
13 14
@@ -26,6 +27,7 @@ void Init(EmuWindow* emu_window) {
26 HLE::Init(); 27 HLE::Init();
27 CoreTiming::Init(); 28 CoreTiming::Init();
28 VideoCore::Init(emu_window); 29 VideoCore::Init(emu_window);
30 Kernel::Init();
29} 31}
30 32
31void RunLoopFor(int cycles) { 33void RunLoopFor(int cycles) {
@@ -42,6 +44,7 @@ void Shutdown() {
42 HLE::Shutdown(); 44 HLE::Shutdown();
43 CoreTiming::Shutdown(); 45 CoreTiming::Shutdown();
44 VideoCore::Shutdown(); 46 VideoCore::Shutdown();
47 Kernel::Shutdown();
45 g_ctr_file_system.Shutdown(); 48 g_ctr_file_system.Shutdown();
46} 49}
47 50