summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to '')
-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
36 files changed, 1194 insertions, 1155 deletions
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
hle/config_mem.cpp
hle/coprocessor.cpp
hle/svc.cpp
+ hle/kernel/event.cpp
hle/kernel/kernel.cpp
hle/kernel/mutex.cpp
hle/kernel/thread.cpp
hle/service/apt.cpp
hle/service/gsp.cpp
hle/service/hid.cpp
+ hle/service/ndm.cpp
hle/service/service.cpp
hle/service/srv.cpp
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:
*/
virtual void LoadContext(const ThreadContext& ctx) = 0;
+ /// Prepare core for thread reschedule (if needed to correctly handle state)
+ virtual void PrepareReschedule() = 0;
+
/// Getter for num_instructions
u64 GetNumInstructions() {
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 {
* @param num_instructions Number of instructions to executes
*/
void ARM_Interpreter::ExecuteInstructions(int num_instructions) {
- state->NumInstrsToExecute = num_instructions;
+ state->NumInstrsToExecute = num_instructions - 1;
ARMul_Emulate32(state);
}
@@ -118,6 +118,9 @@ void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
ctx.fpscr = state->VFP[1];
ctx.fpexc = state->VFP[2];
+
+ ctx.reg_15 = state->Reg[15];
+ ctx.mode = state->NextInstr;
}
/**
@@ -137,6 +140,11 @@ void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
state->VFP[1] = ctx.fpscr;
state->VFP[2] = ctx.fpexc;
- state->Reg[15] = ctx.pc;
- state->NextInstr = RESUME;
+ state->Reg[15] = ctx.reg_15;
+ state->NextInstr = ctx.mode;
+}
+
+/// Prepare core for thread reschedule (if needed to correctly handle state)
+void ARM_Interpreter::PrepareReschedule() {
+ state->NumInstrsToExecute = 0;
}
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:
*/
void LoadContext(const ThreadContext& ctx);
+ /// Prepare core for thread reschedule (if needed to correctly handle state)
+ void PrepareReschedule();
+
protected:
/**
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)
}
/* Drop through. */
+ case 0xe0:
case 0xe4:
case 0xe6:
case 0xe8:
@@ -4489,7 +4490,6 @@ ARMul_Emulate26 (ARMul_State * state)
/* Co-Processor Register Transfers (MRC) and Data Ops. */
- case 0xe0:
case 0xe1:
case 0xe3:
case 0xe5:
@@ -4533,23 +4533,7 @@ ARMul_Emulate26 (ARMul_State * state)
case 0xfd:
case 0xfe:
case 0xff:
- if (instr == ARMul_ABORTWORD
- && state->AbortAddr == pc) {
- /* A prefetch abort. */
- XScale_set_fsr_far (state,
- ARMul_CP15_R5_MMU_EXCPT,
- pc);
- ARMul_Abort (state,
- ARMul_PrefetchAbortV);
- break;
- }
- //sky_pref_t* pref = get_skyeye_pref();
- //if(pref->user_mode_sim){
- // ARMul_OSHandleSWI (state, BITS (0, 23));
- // break;
- //}
HLE::CallSVC(instr);
- ARMul_Abort (state, ARMul_SWIV);
break;
}
}
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 @@
#include "core/core.h"
#include "core/mem_map.h"
#include "core/hw/hw.h"
+#include "core/hw/gpu.h"
#include "core/arm/disassembler/arm_disasm.h"
#include "core/arm/interpreter/arm_interpreter.h"
+#include "core/hle/hle.h"
#include "core/hle/kernel/thread.h"
namespace Core {
-ARM_Disasm* g_disasm = NULL; ///< ARM disassembler
-ARM_Interface* g_app_core = NULL; ///< ARM11 application core
-ARM_Interface* g_sys_core = NULL; ///< ARM11 system (OS) core
+u64 g_last_ticks = 0; ///< Last CPU ticks
+ARM_Disasm* g_disasm = nullptr; ///< ARM disassembler
+ARM_Interface* g_app_core = nullptr; ///< ARM11 application core
+ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core
/// Run the core CPU loop
void RunLoop() {
for (;;){
- g_app_core->Run(100);
+ g_app_core->Run(GPU::kFrameTicks);
HW::Update();
Kernel::Reschedule();
}
@@ -32,8 +35,14 @@ void RunLoop() {
/// Step the CPU one instruction
void SingleStep() {
g_app_core->Step();
- HW::Update();
- Kernel::Reschedule();
+
+ // Update and reschedule after approx. 1 frame
+ u64 current_ticks = Core::g_app_core->GetTicks();
+ if ((current_ticks - g_last_ticks) >= GPU::kFrameTicks || HLE::g_reschedule) {
+ g_last_ticks = current_ticks;
+ HW::Update();
+ Kernel::Reschedule();
+ }
}
/// Halt the core
@@ -54,6 +63,8 @@ int Init() {
g_app_core = new ARM_Interpreter();
g_sys_core = new ARM_Interpreter();
+ g_last_ticks = Core::g_app_core->GetTicks();
+
return 0;
}
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 @@
<ClCompile Include="hle\config_mem.cpp" />
<ClCompile Include="hle\coprocessor.cpp" />
<ClCompile Include="hle\hle.cpp" />
+ <ClCompile Include="hle\kernel\event.cpp" />
<ClCompile Include="hle\kernel\kernel.cpp" />
<ClCompile Include="hle\kernel\mutex.cpp" />
<ClCompile Include="hle\kernel\thread.cpp" />
<ClCompile Include="hle\service\apt.cpp" />
<ClCompile Include="hle\service\gsp.cpp" />
<ClCompile Include="hle\service\hid.cpp" />
+ <ClCompile Include="hle\service\ndm.cpp" />
<ClCompile Include="hle\service\service.cpp" />
<ClCompile Include="hle\service\srv.cpp" />
<ClCompile Include="hle\svc.cpp" />
@@ -217,12 +219,14 @@
<ClInclude Include="hle\coprocessor.h" />
<ClInclude Include="hle\function_wrappers.h" />
<ClInclude Include="hle\hle.h" />
+ <ClInclude Include="hle\kernel\event.h" />
<ClInclude Include="hle\kernel\kernel.h" />
<ClInclude Include="hle\kernel\mutex.h" />
<ClInclude Include="hle\kernel\thread.h" />
<ClInclude Include="hle\service\apt.h" />
<ClInclude Include="hle\service\gsp.h" />
<ClInclude Include="hle\service\hid.h" />
+ <ClInclude Include="hle\service\ndm.h" />
<ClInclude Include="hle\service\service.h" />
<ClInclude Include="hle\service\srv.h" />
<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 @@
<ClCompile Include="arm\interpreter\armcopro.cpp">
<Filter>arm\interpreter</Filter>
</ClCompile>
+ <ClCompile Include="hle\kernel\event.cpp">
+ <Filter>hle\kernel</Filter>
+ </ClCompile>
+ <ClCompile Include="hle\service\ndm.cpp">
+ <Filter>hle\service</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="arm\disassembler\arm_disasm.h">
@@ -295,6 +301,12 @@
<ClInclude Include="hle\kernel\mutex.h">
<Filter>hle\kernel</Filter>
</ClInclude>
+ <ClInclude Include="hle\kernel\event.h">
+ <Filter>hle\kernel</Filter>
+ </ClInclude>
+ <ClInclude Include="hle\service\ndm.h">
+ <Filter>hle\service</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<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) {
break;
default:
- ERROR_LOG(HLE, "unknown ConfigMem::Read%d @ 0x%08X", sizeof(var) * 8, addr);
+ ERROR_LOG(HLE, "unknown addr=0x%08X", addr);
}
}
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) {
return GetThreadCommandBuffer();
default:
- //DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction);
+ DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction);
break;
}
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 @@
-// Copyright (c) 2012- PPSSPP Project.
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, version 2.0 or later versions.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License 2.0 for more details.
-
-// A copy of the GPL 2.0 should have been included with the program.
-// If not, see http://www.gnu.org/licenses/
-
-// Official git repository and contact information can be found at
-// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
#pragma once
@@ -21,725 +8,107 @@
#include "core/mem_map.h"
#include "core/hle/hle.h"
-// For easy parameter parsing and return value processing.
-
-//32bit wrappers
-template<void func()> void WrapV_V() {
- func();
-}
-
-template<u32 func()> void WrapU_V() {
- RETURN(func());
-}
-
-template<int func(void *, const char *)> void WrapI_VC() {
- u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1)));
- RETURN(retval);
-}
-
-template<u32 func(int, void *, int)> void WrapU_IVI() {
- u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), PARAM(2));
- RETURN(retval);
-}
-
-template<int func(const char *, int, int, u32)> void WrapI_CIIU() {
- u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(int, const char *, u32, void *, void *, u32, int)> void WrapI_ICUVVUI() {
- u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)),Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) );
- RETURN(retval);
-}
-
-// Hm, do so many params get passed in registers?
-template<int func(const char *, int, const char *, int, int, int, int, int)> void WrapI_CICIIIII() {
- u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), Memory::GetCharPointer(PARAM(2)),
- PARAM(3), PARAM(4), PARAM(5), PARAM(6), PARAM(7));
- RETURN(retval);
-}
-
-// Hm, do so many params get passed in registers?
-template<int func(const char *, int, int, int, int, int, int)> void WrapI_CIIIIII() {
- u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
- PARAM(3), PARAM(4), PARAM(5), PARAM(6));
- RETURN(retval);
-}
-
-// Hm, do so many params get passed in registers?
-template<int func(int, int, int, int, int, int, u32)> void WrapI_IIIIIIU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
- RETURN(retval);
-}
-
-// Hm, do so many params get passed in registers?
-template<int func(int, int, int, int, int, int, int, int, u32)> void WrapI_IIIIIIIIU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6), PARAM(7), PARAM(8));
- RETURN(retval);
-}
-
-template<u32 func(int, void *)> void WrapU_IV() {
- u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)));
- RETURN(retval);
-}
-
-template<u32 func(u32)> void WrapU_U() {
- u32 retval = func(PARAM(0));
- RETURN(retval);
-}
-
-template<u32 func(u32, int)> void WrapU_UI() {
- u32 retval = func(PARAM(0), PARAM(1));
- RETURN(retval);
-}
-
-template<int func(u32)> void WrapI_U() {
- int retval = func(PARAM(0));
- RETURN(retval);
-}
-
-template<int func(u32, int)> void WrapI_UI() {
- int retval = func(PARAM(0), PARAM(1));
- RETURN(retval);
-}
-
-template<int func(u32, int, int, u32)> void WrapI_UIIU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<u32 func(int, u32, int)> void WrapU_IUI() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<int func(u32, u32)> void WrapI_UU() {
- int retval = func(PARAM(0), PARAM(1));
- RETURN(retval);
-}
-
-template<int func(u32, u32, u32)> void WrapI_UUU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<int func(u32, u32, u32, int)> void WrapI_UUUI() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(u32, u32, u32, int, int, int,int )> void WrapI_UUUIIII() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
- RETURN(retval);
-}
-
-template<int func(u32, u32, u32, u32)> void WrapI_UUUU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(u32, u32, u32, u32, u32)> void WrapI_UUUUU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<int func(void*)> void WrapI_V() {
- u32 retval = func(Memory::GetPointer(PARAM(0)));
- RETURN(retval);
-}
-
-template<u32 func(int)> void WrapU_I() {
- u32 retval = func(PARAM(0));
- RETURN(retval);
-}
-
-template<u32 func(int, int, u32)> void WrapU_IIU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<int func(int)> void WrapI_I() {
- int retval = func(PARAM(0));
- RETURN(retval);
-}
-
-template<void func(u32)> void WrapV_U() {
- func(PARAM(0));
-}
-
-template<void func(int)> void WrapV_I() {
- func(PARAM(0));
-}
-
-template<void func(u32, u32)> void WrapV_UU() {
- func(PARAM(0), PARAM(1));
-}
-
-template<void func(int, int)> void WrapV_II() {
- func(PARAM(0), PARAM(1));
-}
-
-template<void func(u32, const char *)> void WrapV_UC() {
- func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
-}
-
-template<int func(u32, const char *)> void WrapI_UC() {
- int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
- RETURN(retval);
-}
-
-template<int func(u32, const char *, int)> void WrapI_UCI() {
- int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2));
- RETURN(retval);
-}
-
-template<u32 func(u32, int , int , int, int, int)> void WrapU_UIIIII() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
- RETURN(retval);
-}
-
-template<u32 func(u32, int , int , int, u32)> void WrapU_UIIIU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<u32 func(u32, int , int , int, int, int, int)> void WrapU_UIIIIII() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32)> void WrapU_UU() {
- u32 retval = func(PARAM(0), PARAM(1));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32, int)> void WrapU_UUI() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32, int, int)> void WrapU_UUII() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<u32 func(const char *, u32, u32, u32)> void WrapU_CUUU() {
- u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<void func(u32, int, u32, int, int)> void WrapV_UIUII() {
- func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
-}
-
-template<u32 func(u32, int, u32, int, int)> void WrapU_UIUII() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<int func(u32, int, u32, int, int)> void WrapI_UIUII() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<u32 func(u32, int, u32, int)> void WrapU_UIUI() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(u32, int, u32, int)> void WrapI_UIUI() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<u32 func(u32, int, u32)> void WrapU_UIU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<u32 func(u32, int, u32, u32)> void WrapU_UIUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<u32 func(u32, int, int)> void WrapU_UII() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<u32 func(u32, int, int, u32)> void WrapU_UIIU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(u32, int, int, u32, u32)> void WrapI_UIIUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<int func(u32, u32, int, int)> void WrapI_UUII() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(u32, u32, int, int, int)> void WrapI_UUIII() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<void func(u32, int, int, int)> void WrapV_UIII() {
- func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
-}
-
-template<void func(u32, int, int, int, int, int)> void WrapV_UIIIII() {
- func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
-}
-
-template<void func(u32, int, int)> void WrapV_UII() {
- func(PARAM(0), PARAM(1), PARAM(2));
-}
+namespace HLE {
-template<u32 func(int, u32)> void WrapU_IU() {
- int retval = func(PARAM(0), PARAM(1));
- RETURN(retval);
-}
+#define PARAM(n) Core::g_app_core->GetReg(n)
+#define RETURN(n) Core::g_app_core->SetReg(0, n)
-template<int func(int, u32)> void WrapI_IU() {
- int retval = func(PARAM(0), PARAM(1));
- RETURN(retval);
-}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Function wrappers that return type s32
-template<int func(u32, u32, int)> void WrapI_UUI() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
+template<s32 func(u32, u32, u32, u32)> void Wrap() {
+ RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)));
}
-template<int func(u32, u32, int, u32)> void WrapI_UUIU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
+template<s32 func(u32, u32, u32, u32, u32)> void Wrap() {
+ RETURN(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)));
}
-template<int func(int, int)> void WrapI_II() {
- int retval = func(PARAM(0), PARAM(1));
+template<s32 func(u32*, u32, u32, u32, u32, u32)> void Wrap(){
+ u32 param_1 = 0;
+ u32 retval = func(&param_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
+ Core::g_app_core->SetReg(1, param_1);
RETURN(retval);
}
-template<int func(int, int, int)> void WrapI_III() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2));
+template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() {
+ s32 param_1 = 0;
+ s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
+ (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0)));
+ Core::g_app_core->SetReg(1, (u32)param_1);
RETURN(retval);
}
-template<int func(int, u32, int)> void WrapI_IUI() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
+// TODO(bunnei): Is this correct? Probably not
+template<s32 func(u32, u32, u32, u32, s64)> void Wrap() {
+ RETURN(func(PARAM(5), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(4) << 32) | PARAM(0))));
}
-template<int func(int, int, int, int)> void WrapI_IIII() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
+template<s32 func(u32, s64)> void Wrap() {
+ RETURN(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))));
}
-template<int func(u32, int, int, int)> void WrapI_UIII() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
+template<s32 func(void*, void*, u32)> void Wrap(){
+ RETURN(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)));
}
-template<int func(int, int, int, u32, int)> void WrapI_IIIUI() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
+template<s32 func(s32*, u32)> void Wrap(){
+ s32 param_1 = 0;
+ u32 retval = func(&param_1, PARAM(1));
+ Core::g_app_core->SetReg(1, param_1);
RETURN(retval);
}
-template<int func(int, u32, u32, int, int)> void WrapI_IUUII() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
+template<s32 func(u32, s32)> void Wrap() {
+ RETURN(func(PARAM(0), (s32)PARAM(1)));
}
-template<int func(int, const char *, int, u32, u32)> void WrapI_ICIUU() {
- int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4));
+template<s32 func(u32*, u32)> void Wrap(){
+ u32 param_1 = 0;
+ u32 retval = func(&param_1, PARAM(1));
+ Core::g_app_core->SetReg(1, param_1);
RETURN(retval);
}
-template<int func(int, int, u32)> void WrapI_IIU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
+template<s32 func(u32)> void Wrap() {
+ RETURN(func(PARAM(0)));
}
-template<void func(int, u32)> void WrapV_IU() {
- func(PARAM(0), PARAM(1));
+template<s32 func(void*)> void Wrap() {
+ RETURN(func(Memory::GetPointer(PARAM(0))));
}
-template<void func(u32, int)> void WrapV_UI() {
- func(PARAM(0), PARAM(1));
+template<s32 func(s64*, u32, void*, s32)> void Wrap(){
+ RETURN(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)),
+ (s32)PARAM(3)));
}
-template<u32 func(const char *)> void WrapU_C() {
- u32 retval = func(Memory::GetCharPointer(PARAM(0)));
+template<s32 func(u32*, const char*)> void Wrap() {
+ u32 param_1 = 0;
+ u32 retval = func(&param_1, Memory::GetCharPointer(PARAM(1)));
+ Core::g_app_core->SetReg(1, param_1);
RETURN(retval);
}
-template<u32 func(const char *, const char *, const char *, u32)> void WrapU_CCCU() {
- u32 retval = func(Memory::GetCharPointer(PARAM(0)),
- Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)),
- PARAM(3));
- RETURN(retval);
-}
-
-template<int func(const char *)> void WrapI_C() {
- int retval = func(Memory::GetCharPointer(PARAM(0)));
- RETURN(retval);
-}
-
-template<int func(const char *, u32)> void WrapI_CU() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
- RETURN(retval);
-}
-
-template<int func(const char *, u32, int)> void WrapI_CUI() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
- RETURN(retval);
-}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Function wrappers that return type u32
-template<int func(int, const char *, int, u32)> void WrapI_ICIU() {
- int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(const char *, int, u32)> void WrapI_CIU() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<int func(const char *, u32, u32)> void WrapI_CUU() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<int func(const char *, u32, u32, u32)> void WrapI_CUUU() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
- PARAM(3));
- RETURN(retval);
-}
-
-template<int func(const char *, const char*, int, int)> void WrapI_CCII() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(const char *, u32, u32, int, u32, u32)> void WrapI_CUUIUU() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
- PARAM(3), PARAM(4), PARAM(5));
- RETURN(retval);
-}
-
-template<int func(const char *, int, int, u32, int, int)> void WrapI_CIIUII() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
- PARAM(3), PARAM(4), PARAM(5));
- RETURN(retval);
-}
-
-template<int func(const char *, int, u32, u32, u32)> void WrapI_CIUUU() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
- PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<int func(const char *, u32, u32, u32, u32, u32)> void WrapI_CUUUUU() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
- PARAM(3), PARAM(4), PARAM(5));
- RETURN(retval);
-}
-
-template<u32 func(const char *, u32)> void WrapU_CU() {
- u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
- RETURN((u32) retval);
-}
-
-template<u32 func(u32, const char *)> void WrapU_UC() {
- u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
- RETURN(retval);
-}
-
-template<u32 func(const char *, u32, u32)> void WrapU_CUU() {
- u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
- RETURN((u32) retval);
-}
-
-template<u32 func(int, int, int)> void WrapU_III() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<u32 func(int, int)> void WrapU_II() {
- u32 retval = func(PARAM(0), PARAM(1));
- RETURN(retval);
-}
-
-template<u32 func(int, int, int, int)> void WrapU_IIII() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<u32 func(int, u32, u32)> void WrapU_IUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<u32 func(int, u32, u32, u32)> void WrapU_IUUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<u32 func(int, u32, u32, u32, u32)> void WrapU_IUUUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32, u32)> void WrapU_UUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<void func(int, u32, u32)> void WrapV_IUU() {
- func(PARAM(0), PARAM(1), PARAM(2));
-}
-
-template<void func(int, int, u32)> void WrapV_IIU() {
- func(PARAM(0), PARAM(1), PARAM(2));
-}
-
-template<void func(u32, int, u32)> void WrapV_UIU() {
- func(PARAM(0), PARAM(1), PARAM(2));
-}
-
-template<int func(u32, int, u32)> void WrapI_UIU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<void func(int, u32, u32, u32, u32)> void WrapV_IUUUU() {
- func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
-}
-
-template<void func(u32, u32, u32)> void WrapV_UUU() {
- func(PARAM(0), PARAM(1), PARAM(2));
-}
-
-template<void func(u32, u32, u32, u32)> void WrapV_UUUU() {
- func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
-}
-
-template<void func(const char *, u32, int, u32)> void WrapV_CUIU() {
- func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
-}
-
-template<int func(const char *, u32, int, u32)> void WrapI_CUIU() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<void func(u32, const char *, u32, int, u32)> void WrapV_UCUIU() {
- func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3),
- PARAM(4));
-}
-
-template<int func(u32, const char *, u32, int, u32)> void WrapI_UCUIU() {
- int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2),
- PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<void func(const char *, u32, int, int, u32)> void WrapV_CUIIU() {
- func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3),
- PARAM(4));
-}
-
-template<int func(const char *, u32, int, int, u32)> void WrapI_CUIIU() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
- PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32, u32, u32)> void WrapU_UUUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<u32 func(u32, const char *, u32, u32)> void WrapU_UCUU() {
- u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32, u32, int)> void WrapU_UUUI() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32, u32, int, u32)> void WrapU_UUUIU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32, u32, int, u32, int)> void WrapU_UUUIUI() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32, int, u32)> void WrapU_UUIU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<u32 func(u32, int, int, int)> void WrapU_UIII() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(int, u32, u32, u32, u32)> void WrapI_IUUUU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<int func(int, u32, u32, u32, u32, u32)> void WrapI_IUUUUU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5));
- RETURN(retval);
-}
-
-template<int func(int, u32, int, int)> void WrapI_IUII() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-template<u32 func(u32, u32, u32, u32, u32)> void WrapU_UUUUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
+template<u32 func()> void Wrap() {
+ RETURN(func());
}
-template<void func(u32, u32, u32, u32, u32)> void WrapV_UUUUU() {
- func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
-}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+/// Function wrappers that return type void
-template<u32 func(const char *, const char *)> void WrapU_CC() {
- int retval = func(Memory::GetCharPointer(PARAM(0)),
- Memory::GetCharPointer(PARAM(1)));
- RETURN(retval);
+template<void func(s64)> void Wrap() {
+ func(((s64)PARAM(1) << 32) | PARAM(0));
}
-template<void func(const char*)> void WrapV_C() {
+template<void func(const char*)> void Wrap() {
func(Memory::GetCharPointer(PARAM(0)));
}
-template<void func(const char *, int)> void WrapV_CI() {
- func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
-}
-
-template<u32 func(const char *, int)> void WrapU_CI() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1));
- RETURN(retval);
-}
-
-template<u32 func(const char *, int, int)> void WrapU_CII() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
- RETURN(retval);
-}
+#undef PARAM
+#undef RETURN
-template<int func(const char *, int, u32, int, u32)> void WrapU_CIUIU() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
- PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<u32 func(const char *, int, u32, int, u32, int)> void WrapU_CIUIUI() {
- u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2),
- PARAM(3), PARAM(4), PARAM(5));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4),
- PARAM(5));
- RETURN(retval);
-}
-
-template<int func(int, u32, u32, u32)> void WrapI_IUUU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(int, u32, u32)> void WrapI_IUU() {
- int retval = func(PARAM(0), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template<u32 func(u32, u32, u32, u32, u32, u32, u32)> void WrapU_UUUUUUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
- RETURN(retval);
-}
-
-template<int func(u32, int, u32, u32)> void WrapI_UIUU() {
- u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(int, const char *)> void WrapI_IC() {
- int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)));
- RETURN(retval);
-}
-
-template <int func(int, const char *, const char *, u32, int)> void WrapI_ICCUI() {
- int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template <int func(int, const char *, const char *, int)> void WrapI_ICCI() {
- int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), Memory::GetCharPointer(PARAM(2)), PARAM(3));
- RETURN(retval);
-}
-
-template <int func(const char *, int, int)> void WrapI_CII() {
- int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2));
- RETURN(retval);
-}
-
-template <int func(int, const char *, int)> void WrapI_ICI() {
- int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2));
- RETURN(retval);
-}
-
-template<int func(int, void *, void *, void *, void *, u32, int)> void WrapI_IVVVVUI(){
- 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) );
- RETURN(retval);
-}
-
-template<int func(int, const char *, u32, void *, int, int, int)> void WrapI_ICUVIII(){
- u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)), PARAM(4), PARAM(5), PARAM(6));
- RETURN(retval);
-}
-
-template<int func(void*, u32)> void WrapI_VU(){
- u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1));
- RETURN(retval);
-}
-
-template<int func(void*, void*, u32)> void WrapI_VVU(){
- u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2));
- RETURN(retval);
-}
-
-template<int func(void*, u32, void*, int)> void WrapI_VUVI(){
- u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), PARAM(3));
- RETURN(retval);
-}
-
-template<int func(void*, u32, u32, u32, u32, u32)> void WrapI_VUUUUU(){
- u32 retval = func(NULL, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
-
-template<int func(u32, s64)> void WrapI_US64() {
- int retval = func(PARAM(0), PARAM64(1));
- RETURN(retval);
-}
-
-template<int func(void*, void*, u32, u32, s64)> void WrapI_VVUUS64() {
- int retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4));
- RETURN(retval);
-}
+} // namespace HLE
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 @@
#include "core/mem_map.h"
#include "core/hle/hle.h"
#include "core/hle/svc.h"
+#include "core/hle/kernel/thread.h"
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -15,11 +16,13 @@ namespace HLE {
static std::vector<ModuleDef> g_module_db;
+bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a new thread
+
const FunctionDef* GetSVCInfo(u32 opcode) {
u32 func_num = opcode & 0xFFFFFF; // 8 bits
if (func_num > 0xFF) {
- ERROR_LOG(HLE,"Unknown SVC: 0x%02X", func_num);
- return NULL;
+ ERROR_LOG(HLE,"unknown svc=0x%02X", func_num);
+ return nullptr;
}
return &g_module_db[0].func_table[func_num];
}
@@ -33,19 +36,16 @@ void CallSVC(u32 opcode) {
if (info->func) {
info->func();
} else {
- ERROR_LOG(HLE, "Unimplemented SVC function %s(..)", info->name.c_str());
+ ERROR_LOG(HLE, "unimplemented SVC function %s(..)", info->name.c_str());
}
}
-void EatCycles(u32 cycles) {
- // TODO: ImplementMe
-}
-
-void ReSchedule(const char *reason) {
+void Reschedule(const char *reason) {
#ifdef _DEBUG
- _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "ReSchedule: Invalid or too long reason.");
+ _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
#endif
- // TODO: ImplementMe
+ Core::g_app_core->PrepareReschedule();
+ g_reschedule = true;
}
void 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 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
-#define PARAM(n) Core::g_app_core->GetReg(n)
-#define PARAM64(n) (Core::g_app_core->GetReg(n) | ((u64)Core::g_app_core->GetReg(n + 1) << 32))
-#define RETURN(n) Core::g_app_core->SetReg(0, n)
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
namespace HLE {
+extern bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
+
typedef u32 Addr;
typedef void (*Func)();
@@ -36,9 +32,7 @@ void RegisterModule(std::string name, int num_functions, const FunctionDef *func
void CallSVC(u32 opcode);
-void EatCycles(u32 cycles);
-
-void ReSchedule(const char *reason);
+void Reschedule(const char *reason);
void Init();
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 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include <map>
+#include <algorithm>
+#include <vector>
+
+#include "common/common.h"
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+class Event : public Object {
+public:
+ const char* GetTypeName() const { return "Event"; }
+ const char* GetName() const { return name.c_str(); }
+
+ static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; }
+ Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; }
+
+ ResetType intitial_reset_type; ///< ResetType specified at Event initialization
+ ResetType reset_type; ///< Current ResetType
+
+ bool locked; ///< Event signal wait
+ bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough)
+ std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event
+ std::string name; ///< Name of event (optional)
+
+ /**
+ * Wait for kernel object to synchronize
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ Result WaitSynchronization(bool* wait) {
+ *wait = locked;
+ if (locked) {
+ Handle thread = GetCurrentThreadHandle();
+ if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
+ waiting_threads.push_back(thread);
+ }
+ Kernel::WaitCurrentThread(WAITTYPE_EVENT);
+ }
+ if (reset_type != RESETTYPE_STICKY && !permanent_locked) {
+ locked = true;
+ }
+ return 0;
+ }
+};
+
+/**
+ * Hackish function to set an events permanent lock state, used to pass through synch blocks
+ * @param handle Handle to event to change
+ * @param permanent_locked Boolean permanent locked value to set event
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+Result SetPermanentLock(Handle handle, const bool permanent_locked) {
+ Event* evt = g_object_pool.GetFast<Event>(handle);
+ _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
+
+ evt->permanent_locked = permanent_locked;
+ return 0;
+}
+
+/**
+ * Changes whether an event is locked or not
+ * @param handle Handle to event to change
+ * @param locked Boolean locked value to set event
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+Result SetEventLocked(const Handle handle, const bool locked) {
+ Event* evt = g_object_pool.GetFast<Event>(handle);
+ _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
+
+ if (!evt->permanent_locked) {
+ evt->locked = locked;
+ }
+ return 0;
+}
+
+/**
+ * Signals an event
+ * @param handle Handle to event to signal
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+Result SignalEvent(const Handle handle) {
+ Event* evt = g_object_pool.GetFast<Event>(handle);
+ _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
+
+ // Resume threads waiting for event to signal
+ bool event_caught = false;
+ for (size_t i = 0; i < evt->waiting_threads.size(); ++i) {
+ ResumeThreadFromWait( evt->waiting_threads[i]);
+
+ // If any thread is signalled awake by this event, assume the event was "caught" and reset
+ // the event. This will result in the next thread waiting on the event to block. Otherwise,
+ // the event will not be reset, and the next thread to call WaitSynchronization on it will
+ // not block. Not sure if this is correct behavior, but it seems to work.
+ event_caught = true;
+ }
+ evt->waiting_threads.clear();
+
+ if (!evt->permanent_locked) {
+ evt->locked = event_caught;
+ }
+ return 0;
+}
+
+/**
+ * Clears an event
+ * @param handle Handle to event to clear
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+Result ClearEvent(Handle handle) {
+ Event* evt = g_object_pool.GetFast<Event>(handle);
+ _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!");
+
+ if (!evt->permanent_locked) {
+ evt->locked = true;
+ }
+ return 0;
+}
+
+/**
+ * Creates an event
+ * @param handle Reference to handle for the newly created mutex
+ * @param reset_type ResetType describing how to create event
+ * @param name Optional name of event
+ * @return Newly created Event object
+ */
+Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) {
+ Event* evt = new Event;
+
+ handle = Kernel::g_object_pool.Create(evt);
+
+ evt->locked = true;
+ evt->permanent_locked = false;
+ evt->reset_type = evt->intitial_reset_type = reset_type;
+ evt->name = name;
+
+ return evt;
+}
+
+/**
+ * Creates an event
+ * @param reset_type ResetType describing how to create event
+ * @param name Optional name of event
+ * @return Handle to newly created Event object
+ */
+Handle CreateEvent(const ResetType reset_type, const std::string& name) {
+ Handle handle;
+ Event* evt = CreateEvent(handle, reset_type, name);
+ return handle;
+}
+
+} // 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 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/svc.h"
+
+namespace Kernel {
+
+/**
+ * Changes whether an event is locked or not
+ * @param handle Handle to event to change
+ * @param locked Boolean locked value to set event
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+Result SetEventLocked(const Handle handle, const bool locked);
+
+/**
+ * Hackish function to set an events permanent lock state, used to pass through synch blocks
+ * @param handle Handle to event to change
+ * @param permanent_locked Boolean permanent locked value to set event
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+Result SetPermanentLock(Handle handle, const bool permanent_locked);
+
+/**
+ * Signals an event
+ * @param handle Handle to event to signal
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+Result SignalEvent(const Handle handle);
+
+/**
+ * Clears an event
+ * @param handle Handle to event to clear
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+Result ClearEvent(Handle handle);
+
+/**
+ * Creates an event
+ * @param reset_type ResetType describing how to create event
+ * @param name Optional name of event
+ * @return Handle to newly created Event object
+ */
+Handle CreateEvent(const ResetType reset_type, const std::string& name="Unknown");
+
+} // 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 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
-#pragma once
-
#include <string.h>
#include "common/common.h"
@@ -14,6 +12,7 @@
namespace Kernel {
+Handle g_main_thread = 0;
ObjectPool g_object_pool;
ObjectPool::ObjectPool() {
@@ -127,16 +126,20 @@ Object* ObjectPool::CreateByIDType(int type) {
default:
ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type);
- return NULL;
+ return nullptr;
}
}
+/// Initialize the kernel
void Init() {
Kernel::ThreadingInit();
}
+/// Shutdown the kernel
void Shutdown() {
Kernel::ThreadingShutdown();
+
+ g_object_pool.Clear(); // Free all kernel objects
}
/**
@@ -150,7 +153,7 @@ bool LoadExec(u32 entry_point) {
Core::g_app_core->SetPC(entry_point);
// 0x30 is the typical main thread priority I've seen used so far
- Handle thread = Kernel::SetupMainThread(0x30);
+ g_main_thread = Kernel::SetupMainThread(0x30);
return true;
}
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;
namespace Kernel {
+enum KernelHandle {
+ CurrentThread = 0xFFFF8000,
+ CurrentProcess = 0xFFFF8001,
+};
+
enum class HandleType : u32 {
Unknown = 0,
Port = 1,
@@ -39,9 +44,26 @@ class Object : NonCopyable {
public:
virtual ~Object() {}
Handle GetHandle() const { return handle; }
- virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; }
- virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; }
+ virtual const char* GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; }
+ virtual const char* GetName() const { return "[UNKNOWN KERNEL OBJECT]"; }
virtual Kernel::HandleType GetHandleType() const = 0;
+
+ /**
+ * Synchronize kernel object
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ virtual Result SyncRequest(bool* wait) {
+ ERROR_LOG(KERNEL, "(UNIMPLEMENTED)");
+ return -1;
+ }
+
+ /**
+ * Wait for kernel object to synchronize
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ virtual Result WaitSynchronization(bool* wait) = 0;
};
class ObjectPool : NonCopyable {
@@ -143,6 +165,13 @@ private:
};
extern ObjectPool g_object_pool;
+extern Handle g_main_thread;
+
+/// Initialize the kernel
+void Init();
+
+/// Shutdown the kernel
+void Shutdown();
/**
* 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 @@
#include "common/common.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
class Mutex : public Object {
public:
- const char* GetTypeName() { return "Mutex"; }
+ const char* GetTypeName() const { return "Mutex"; }
+ const char* GetName() const { return name.c_str(); }
- static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
+ static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; }
bool initial_locked; ///< Initial lock state when mutex was created
bool locked; ///< Current locked state
Handle lock_thread; ///< Handle to thread that currently has mutex
std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
+ std::string name; ///< Name of mutex (optional)
+
+ /**
+ * Synchronize kernel object
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ Result SyncRequest(bool* wait) {
+ // TODO(bunnei): ImplementMe
+ locked = true;
+ return 0;
+ }
+
+ /**
+ * Wait for kernel object to synchronize
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ Result WaitSynchronization(bool* wait) {
+ // TODO(bunnei): ImplementMe
+ *wait = locked;
+
+ if (locked) {
+ Kernel::WaitCurrentThread(WAITTYPE_MUTEX);
+ }
+
+ return 0;
+ }
};
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -70,10 +100,10 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
bool ReleaseMutex(Mutex* mutex) {
MutexEraseLock(mutex);
bool woke_threads = false;
- auto iter = mutex->waiting_threads.begin();
// Find the next waiting thread for the mutex...
while (!woke_threads && !mutex->waiting_threads.empty()) {
+ std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
woke_threads |= ReleaseMutexForThread(mutex, *iter);
mutex->waiting_threads.erase(iter);
}
@@ -91,6 +121,9 @@ bool ReleaseMutex(Mutex* mutex) {
*/
Result ReleaseMutex(Handle handle) {
Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle);
+
+ _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!");
+
if (!ReleaseMutex(mutex)) {
return -1;
}
@@ -101,12 +134,15 @@ Result ReleaseMutex(Handle handle) {
* Creates a mutex
* @param handle Reference to handle for the newly created mutex
* @param initial_locked Specifies if the mutex should be locked initially
+ * @param name Optional name of mutex
+ * @return Pointer to new Mutex object
*/
-Mutex* CreateMutex(Handle& handle, bool initial_locked) {
+Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) {
Mutex* mutex = new Mutex;
handle = Kernel::g_object_pool.Create(mutex);
mutex->locked = mutex->initial_locked = initial_locked;
+ mutex->name = name;
// Acquire mutex with current thread if initialized as locked...
if (mutex->locked) {
@@ -122,10 +158,12 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked) {
/**
* Creates a mutex
* @param initial_locked Specifies if the mutex should be locked initially
+ * @param name Optional name of mutex
+ * @return Handle to newly created object
*/
-Handle CreateMutex(bool initial_locked) {
+Handle CreateMutex(bool initial_locked, const std::string& name) {
Handle handle;
- Mutex* mutex = CreateMutex(handle, initial_locked);
+ Mutex* mutex = CreateMutex(handle, initial_locked, name);
return handle;
}
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 {
/**
* Releases a mutex
* @param handle Handle to mutex to release
+ * @return Result of operation, 0 on success, otherwise error code
*/
Result ReleaseMutex(Handle handle);
/**
* Creates a mutex
- * @param handle Reference to handle for the newly created mutex
* @param initial_locked Specifies if the mutex should be locked initially
+ * @param name Optional name of mutex
+ * @return Handle to newly created object
*/
-Handle CreateMutex(bool initial_locked);
+Handle CreateMutex(bool initial_locked, const std::string& name="Unknown");
} // 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 @@
#include <stdio.h>
#include <list>
+#include <algorithm>
#include <vector>
#include <map>
#include <string>
@@ -24,10 +25,10 @@ namespace Kernel {
class Thread : public Kernel::Object {
public:
- const char* GetName() { return name; }
- const char* GetTypeName() { return "Thread"; }
+ const char* GetName() const { return name; }
+ const char* GetTypeName() const { return "Thread"; }
- static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
+ static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; }
inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
@@ -36,6 +37,23 @@ public:
inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
+ /**
+ * Wait for kernel object to synchronize
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ Result WaitSynchronization(bool* wait) {
+ if (status != THREADSTATUS_DORMANT) {
+ Handle thread = GetCurrentThreadHandle();
+ if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
+ waiting_threads.push_back(thread);
+ }
+ WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle());
+ *wait = true;
+ }
+ return 0;
+ }
+
ThreadContext context;
u32 status;
@@ -49,6 +67,9 @@ public:
s32 processor_id;
WaitType wait_type;
+ Handle wait_handle;
+
+ std::vector<Handle> waiting_threads;
char name[Kernel::MAX_NAME_LENGTH + 1];
};
@@ -62,7 +83,6 @@ Common::ThreadQueueList<Handle> g_thread_ready_queue;
Handle g_current_thread_handle;
Thread* g_current_thread;
-
/// Gets the current thread
inline Thread* GetCurrentThread() {
return g_current_thread;
@@ -94,15 +114,15 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
memset(&t->context, 0, sizeof(ThreadContext));
t->context.cpu_registers[0] = arg;
- t->context.pc = t->entry_point;
+ t->context.pc = t->context.reg_15 = t->entry_point;
t->context.sp = t->stack_top;
t->context.cpsr = 0x1F; // Usermode
if (t->current_priority < lowest_priority) {
t->current_priority = t->initial_priority;
}
-
t->wait_type = WAITTYPE_NONE;
+ t->wait_handle = 0;
}
/// Change a thread to "ready" state
@@ -122,6 +142,37 @@ void ChangeReadyState(Thread* t, bool ready) {
}
}
+/// Verify that a thread has not been released from waiting
+inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) {
+ Thread* thread = g_object_pool.GetFast<Thread>(handle);
+ _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
+
+ if (type != thread->wait_type || wait_handle != thread->wait_handle)
+ return false;
+
+ return true;
+}
+
+/// Stops the current thread
+void StopThread(Handle handle, const char* reason) {
+ Thread* thread = g_object_pool.GetFast<Thread>(handle);
+ _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
+
+ ChangeReadyState(thread, false);
+ thread->status = THREADSTATUS_DORMANT;
+ for (size_t i = 0; i < thread->waiting_threads.size(); ++i) {
+ const Handle waiting_thread = thread->waiting_threads[i];
+ if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) {
+ ResumeThreadFromWait(waiting_thread);
+ }
+ }
+ thread->waiting_threads.clear();
+
+ // Stopped threads are never waiting.
+ thread->wait_type = WAITTYPE_NONE;
+ thread->wait_handle = 0;
+}
+
/// Changes a threads state
void ChangeThreadState(Thread* t, ThreadStatus new_status) {
if (!t || t->status == new_status) {
@@ -132,7 +183,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) {
if (new_status == THREADSTATUS_WAIT) {
if (t->wait_type == WAITTYPE_NONE) {
- printf("ERROR: Waittype none not allowed here\n");
+ ERROR_LOG(KERNEL, "Waittype none not allowed");
}
}
}
@@ -166,7 +217,7 @@ void SwitchContext(Thread* t) {
t->wait_type = WAITTYPE_NONE;
LoadContext(t->context);
} else {
- SetCurrentThread(NULL);
+ SetCurrentThread(nullptr);
}
}
@@ -181,26 +232,43 @@ Thread* NextThread() {
next = g_thread_ready_queue.pop_first();
}
if (next == 0) {
- return NULL;
+ return nullptr;
}
return Kernel::g_object_pool.GetFast<Thread>(next);
}
/// Puts the current thread in the wait state for the given type
-void WaitCurrentThread(WaitType wait_type) {
- Thread* t = GetCurrentThread();
- t->wait_type = wait_type;
- ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
+void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
+ Thread* thread = GetCurrentThread();
+ thread->wait_type = wait_type;
+ thread->wait_handle = wait_handle;
+ ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
}
/// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle) {
u32 error;
- Thread* t = Kernel::g_object_pool.Get<Thread>(handle, error);
- if (t) {
- t->status &= ~THREADSTATUS_WAIT;
- if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
- ChangeReadyState(t, true);
+ Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
+ if (thread) {
+ thread->status &= ~THREADSTATUS_WAIT;
+ if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
+ ChangeReadyState(thread, true);
+ }
+ }
+}
+
+/// Prints the thread queue for debugging purposes
+void DebugThreadQueue() {
+ Thread* thread = GetCurrentThread();
+ if (!thread) {
+ return;
+ }
+ INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle());
+ for (u32 i = 0; i < g_thread_queue.size(); i++) {
+ Handle handle = g_thread_queue[i];
+ s32 priority = g_thread_ready_queue.contains(handle);
+ if (priority != -1) {
+ INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle);
}
}
}
@@ -212,32 +280,34 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
_assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
"CreateThread priority=%d, outside of allowable range!", priority)
- Thread* t = new Thread;
-
- handle = Kernel::g_object_pool.Create(t);
-
+ Thread* thread = new Thread;
+
+ handle = Kernel::g_object_pool.Create(thread);
+
g_thread_queue.push_back(handle);
g_thread_ready_queue.prepare(priority);
-
- t->status = THREADSTATUS_DORMANT;
- t->entry_point = entry_point;
- t->stack_top = stack_top;
- t->stack_size = stack_size;
- t->initial_priority = t->current_priority = priority;
- t->processor_id = processor_id;
- t->wait_type = WAITTYPE_NONE;
-
- strncpy(t->name, name, Kernel::MAX_NAME_LENGTH);
- t->name[Kernel::MAX_NAME_LENGTH] = '\0';
-
- return t;
+
+ thread->status = THREADSTATUS_DORMANT;
+ thread->entry_point = entry_point;
+ thread->stack_top = stack_top;
+ thread->stack_size = stack_size;
+ thread->initial_priority = thread->current_priority = priority;
+ thread->processor_id = processor_id;
+ thread->wait_type = WAITTYPE_NONE;
+ thread->wait_handle = 0;
+
+ strncpy(thread->name, name, Kernel::MAX_NAME_LENGTH);
+ thread->name[Kernel::MAX_NAME_LENGTH] = '\0';
+
+ return thread;
}
/// Creates a new thread - wrapper for external user
Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
u32 stack_top, int stack_size) {
- if (name == NULL) {
- ERROR_LOG(KERNEL, "CreateThread(): NULL name");
+
+ if (name == nullptr) {
+ ERROR_LOG(KERNEL, "CreateThread(): nullptr name");
return -1;
}
if ((u32)stack_size < 0x200) {
@@ -258,20 +328,56 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
return -1;
}
Handle handle;
- Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
+ Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
stack_size);
- ResetThread(t, arg, 0);
+ ResetThread(thread, arg, 0);
+ CallThread(thread);
+
+ return handle;
+}
- HLE::EatCycles(32000);
+/// Get the priority of the thread specified by handle
+u32 GetThreadPriority(const Handle handle) {
+ Thread* thread = g_object_pool.GetFast<Thread>(handle);
+ _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
+ return thread->current_priority;
+}
- // This won't schedule to the new thread, but it may to one woken from eating cycles.
- // Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
- HLE::ReSchedule("thread created");
+/// Set the priority of the thread specified by handle
+Result SetThreadPriority(Handle handle, s32 priority) {
+ Thread* thread = nullptr;
+ if (!handle) {
+ thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
+ } else {
+ thread = g_object_pool.GetFast<Thread>(handle);
+ }
+ _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
- CallThread(t);
-
- return handle;
+ // If priority is invalid, clamp to valid range
+ if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
+ s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
+ WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority);
+ // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
+ // validity of this
+ priority = new_priority;
+ }
+
+ // Change thread priority
+ s32 old = thread->current_priority;
+ g_thread_ready_queue.remove(old, handle);
+ thread->current_priority = priority;
+ g_thread_ready_queue.prepare(thread->current_priority);
+
+ // Change thread status to "ready" and push to ready queue
+ if (thread->IsRunning()) {
+ thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY;
+ }
+ if (thread->IsReady()) {
+ g_thread_ready_queue.push_back(thread->current_priority, handle);
+ }
+
+ return 0;
}
/// Sets up the primary application thread
@@ -279,10 +385,10 @@ Handle SetupMainThread(s32 priority, int stack_size) {
Handle handle;
// Initialize new "main" thread
- Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
+ Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
- ResetThread(t, 0, 0);
+ ResetThread(thread, 0, 0);
// If running another thread already, set it to "ready" state
Thread* cur = GetCurrentThread();
@@ -291,24 +397,31 @@ Handle SetupMainThread(s32 priority, int stack_size) {
}
// Run new "main" thread
- SetCurrentThread(t);
- t->status = THREADSTATUS_RUNNING;
- LoadContext(t->context);
+ SetCurrentThread(thread);
+ thread->status = THREADSTATUS_RUNNING;
+ LoadContext(thread->context);
return handle;
}
+
/// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule() {
Thread* prev = GetCurrentThread();
Thread* next = NextThread();
+ HLE::g_reschedule = false;
if (next > 0) {
+ INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
+
SwitchContext(next);
- // Hack - automatically change previous thread (which would have been in "wait" state) to
- // "ready" state, so that we can immediately resume to it when new thread yields. FixMe to
- // actually wait for whatever event it is supposed to be waiting on.
- ChangeReadyState(prev, true);
+ // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep
+ // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again.
+ // This results in the current thread yielding on a VBLANK once, and then it will be
+ // immediately placed back in the queue for execution.
+ if (prev->wait_type == WAITTYPE_VBLANK) {
+ ResumeThreadFromWait(prev->GetHandle());
+ }
}
}
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 {
WAITTYPE_NONE,
WAITTYPE_SLEEP,
WAITTYPE_SEMA,
- WAITTYPE_EVENTFLAG,
+ WAITTYPE_EVENT,
WAITTYPE_THREADEND,
WAITTYPE_VBLANK,
WAITTYPE_MUTEX,
@@ -53,8 +53,8 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
/// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule();
-/// Puts the current thread in the wait state for the given type
-void WaitCurrentThread(WaitType wait_type);
+/// Stops the current thread
+void StopThread(Handle thread, const char* reason);
/// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle);
@@ -62,9 +62,18 @@ void ResumeThreadFromWait(Handle handle);
/// Gets the current thread handle
Handle GetCurrentThreadHandle();
+/// Puts the current thread in the wait state for the given type
+void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle());
+
/// Put current thread in a wait state - on WaitSynchronization
void WaitThread_Synchronization();
+/// Get the priority of the thread specified by handle
+u32 GetThreadPriority(const Handle handle);
+
+/// Set the priority of the thread specified by handle
+Result SetThreadPriority(Handle handle, s32 priority);
+
/// Initialize threading
void ThreadingInit();
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 @@
#include "common/common.h"
#include "core/hle/hle.h"
+#include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/service/apt.h"
@@ -15,96 +16,120 @@
namespace APT_U {
void Initialize(Service::Interface* self) {
- NOTICE_LOG(OSHLE, "APT_U::Sync - Initialize");
+ u32* cmd_buff = Service::GetCommandBuffer();
+ DEBUG_LOG(KERNEL, "called");
+
+ cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu"); // APT menu event handle
+ cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle
+
+ Kernel::SetEventLocked(cmd_buff[3], true);
+ Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event
+
+ cmd_buff[1] = 0; // No error
}
void GetLockHandle(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
cmd_buff[1] = 0; // No error
- cmd_buff[5] = Kernel::CreateMutex(false);
- DEBUG_LOG(KERNEL, "APT_U::GetLockHandle called : created handle 0x%08X", cmd_buff[5]);
+ cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock");
+ DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]);
+}
+
+void Enable(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+ u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
+ cmd_buff[1] = 0; // No error
+ ERROR_LOG(KERNEL, "(UNIMPEMENTED) called unk=0x%08X", unk);
+}
+
+void InquireNotification(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+ u32 app_id = cmd_buff[2];
+ cmd_buff[1] = 0; // No error
+ cmd_buff[3] = 0; // Signal type
+ ERROR_LOG(KERNEL, "(UNIMPEMENTED) called app_id=0x%08X", app_id);
}
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, GetLockHandle, "GetLockHandle"},
- {0x00020080, Initialize, "Initialize"},
- {0x00030040, NULL, "Enable"},
- {0x00040040, NULL, "Finalize"},
- {0x00050040, NULL, "GetAppletManInfo"},
- {0x00060040, NULL, "GetAppletInfo"},
- {0x00070000, NULL, "GetLastSignaledAppletId"},
- {0x00080000, NULL, "CountRegisteredApplet"},
- {0x00090040, NULL, "IsRegistered"},
- {0x000A0040, NULL, "GetAttribute"},
- {0x000B0040, NULL, "InquireNotification"},
- {0x000C0104, NULL, "SendParameter"},
- {0x000D0080, NULL, "ReceiveParameter"},
- {0x000E0080, NULL, "GlanceParameter"},
- {0x000F0100, NULL, "CancelParameter"},
- {0x001000C2, NULL, "DebugFunc"},
- {0x001100C0, NULL, "MapProgramIdForDebug"},
- {0x00120040, NULL, "SetHomeMenuAppletIdForDebug"},
- {0x00130000, NULL, "GetPreparationState"},
- {0x00140040, NULL, "SetPreparationState"},
- {0x00150140, NULL, "PrepareToStartApplication"},
- {0x00160040, NULL, "PreloadLibraryApplet"},
- {0x00170040, NULL, "FinishPreloadingLibraryApplet"},
- {0x00180040, NULL, "PrepareToStartLibraryApplet"},
- {0x00190040, NULL, "PrepareToStartSystemApplet"},
- {0x001A0000, NULL, "PrepareToStartNewestHomeMenu"},
- {0x001B00C4, NULL, "StartApplication"},
- {0x001C0000, NULL, "WakeupApplication"},
- {0x001D0000, NULL, "CancelApplication"},
- {0x001E0084, NULL, "StartLibraryApplet"},
- {0x001F0084, NULL, "StartSystemApplet"},
- {0x00200044, NULL, "StartNewestHomeMenu"},
- {0x00210000, NULL, "OrderToCloseApplication"},
- {0x00220040, NULL, "PrepareToCloseApplication"},
- {0x00230040, NULL, "PrepareToJumpToApplication"},
- {0x00240044, NULL, "JumpToApplication"},
- {0x002500C0, NULL, "PrepareToCloseLibraryApplet"},
- {0x00260000, NULL, "PrepareToCloseSystemApplet"},
- {0x00270044, NULL, "CloseApplication"},
- {0x00280044, NULL, "CloseLibraryApplet"},
- {0x00290044, NULL, "CloseSystemApplet"},
- {0x002A0000, NULL, "OrderToCloseSystemApplet"},
- {0x002B0000, NULL, "PrepareToJumpToHomeMenu"},
- {0x002C0044, NULL, "JumpToHomeMenu"},
- {0x002D0000, NULL, "PrepareToLeaveHomeMenu"},
- {0x002E0044, NULL, "LeaveHomeMenu"},
- {0x002F0040, NULL, "PrepareToLeaveResidentApplet"},
- {0x00300044, NULL, "LeaveResidentApplet"},
- {0x00310100, NULL, "PrepareToDoApplicationJump"},
- {0x00320084, NULL, "DoApplicationJump"},
- {0x00330000, NULL, "GetProgramIdOnApplicationJump"},
- {0x00340084, NULL, "SendDeliverArg"},
- {0x00350080, NULL, "ReceiveDeliverArg"},
- {0x00360040, NULL, "LoadSysMenuArg"},
- {0x00370042, NULL, "StoreSysMenuArg"},
- {0x00380040, NULL, "PreloadResidentApplet"},
- {0x00390040, NULL, "PrepareToStartResidentApplet"},
- {0x003A0044, NULL, "StartResidentApplet"},
- {0x003B0040, NULL, "CancelLibraryApplet"},
- {0x003C0042, NULL, "SendDspSleep"},
- {0x003D0042, NULL, "SendDspWakeUp"},
- {0x003E0080, NULL, "ReplySleepQuery"},
- {0x003F0040, NULL, "ReplySleepNotificationComplete"},
- {0x00400042, NULL, "SendCaptureBufferInfo"},
- {0x00410040, NULL, "ReceiveCaptureBufferInfo"},
- {0x00420080, NULL, "SleepSystem"},
- {0x00430040, NULL, "NotifyToWait"},
- {0x00440000, NULL, "GetSharedFont"},
- {0x00450040, NULL, "GetWirelessRebootInfo"},
- {0x00460104, NULL, "Wrap"},
- {0x00470104, NULL, "Unwrap"},
- {0x00480100, NULL, "GetProgramInfo"},
- {0x00490180, NULL, "Reboot"},
- {0x004A0040, NULL, "GetCaptureInfo"},
- {0x004B00C2, NULL, "AppletUtility"},
- {0x004C0000, NULL, "SetFatalErrDispMode"},
- {0x004D0080, NULL, "GetAppletProgramInfo"},
- {0x004E0000, NULL, "HardwareResetAsync"},
+ {0x00010040, GetLockHandle, "GetLockHandle"},
+ {0x00020080, Initialize, "Initialize"},
+ {0x00030040, Enable, "Enable"},
+ {0x00040040, nullptr, "Finalize"},
+ {0x00050040, nullptr, "GetAppletManInfo"},
+ {0x00060040, nullptr, "GetAppletInfo"},
+ {0x00070000, nullptr, "GetLastSignaledAppletId"},
+ {0x00080000, nullptr, "CountRegisteredApplet"},
+ {0x00090040, nullptr, "IsRegistered"},
+ {0x000A0040, nullptr, "GetAttribute"},
+ {0x000B0040, InquireNotification, "InquireNotification"},
+ {0x000C0104, nullptr, "SendParameter"},
+ {0x000D0080, nullptr, "ReceiveParameter"},
+ {0x000E0080, nullptr, "GlanceParameter"},
+ {0x000F0100, nullptr, "CancelParameter"},
+ {0x001000C2, nullptr, "DebugFunc"},
+ {0x001100C0, nullptr, "MapProgramIdForDebug"},
+ {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
+ {0x00130000, nullptr, "GetPreparationState"},
+ {0x00140040, nullptr, "SetPreparationState"},
+ {0x00150140, nullptr, "PrepareToStartApplication"},
+ {0x00160040, nullptr, "PreloadLibraryApplet"},
+ {0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
+ {0x00180040, nullptr, "PrepareToStartLibraryApplet"},
+ {0x00190040, nullptr, "PrepareToStartSystemApplet"},
+ {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
+ {0x001B00C4, nullptr, "StartApplication"},
+ {0x001C0000, nullptr, "WakeupApplication"},
+ {0x001D0000, nullptr, "CancelApplication"},
+ {0x001E0084, nullptr, "StartLibraryApplet"},
+ {0x001F0084, nullptr, "StartSystemApplet"},
+ {0x00200044, nullptr, "StartNewestHomeMenu"},
+ {0x00210000, nullptr, "OrderToCloseApplication"},
+ {0x00220040, nullptr, "PrepareToCloseApplication"},
+ {0x00230040, nullptr, "PrepareToJumpToApplication"},
+ {0x00240044, nullptr, "JumpToApplication"},
+ {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"},
+ {0x00260000, nullptr, "PrepareToCloseSystemApplet"},
+ {0x00270044, nullptr, "CloseApplication"},
+ {0x00280044, nullptr, "CloseLibraryApplet"},
+ {0x00290044, nullptr, "CloseSystemApplet"},
+ {0x002A0000, nullptr, "OrderToCloseSystemApplet"},
+ {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
+ {0x002C0044, nullptr, "JumpToHomeMenu"},
+ {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"},
+ {0x002E0044, nullptr, "LeaveHomeMenu"},
+ {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"},
+ {0x00300044, nullptr, "LeaveResidentApplet"},
+ {0x00310100, nullptr, "PrepareToDoApplicationJump"},
+ {0x00320084, nullptr, "DoApplicationJump"},
+ {0x00330000, nullptr, "GetProgramIdOnApplicationJump"},
+ {0x00340084, nullptr, "SendDeliverArg"},
+ {0x00350080, nullptr, "ReceiveDeliverArg"},
+ {0x00360040, nullptr, "LoadSysMenuArg"},
+ {0x00370042, nullptr, "StoreSysMenuArg"},
+ {0x00380040, nullptr, "PreloadResidentApplet"},
+ {0x00390040, nullptr, "PrepareToStartResidentApplet"},
+ {0x003A0044, nullptr, "StartResidentApplet"},
+ {0x003B0040, nullptr, "CancelLibraryApplet"},
+ {0x003C0042, nullptr, "SendDspSleep"},
+ {0x003D0042, nullptr, "SendDspWakeUp"},
+ {0x003E0080, nullptr, "ReplySleepQuery"},
+ {0x003F0040, nullptr, "ReplySleepNotificationComplete"},
+ {0x00400042, nullptr, "SendCaptureBufferInfo"},
+ {0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
+ {0x00420080, nullptr, "SleepSystem"},
+ {0x00430040, nullptr, "NotifyToWait"},
+ {0x00440000, nullptr, "GetSharedFont"},
+ {0x00450040, nullptr, "GetWirelessRebootInfo"},
+ {0x00460104, nullptr, "Wrap"},
+ {0x00470104, nullptr, "Unwrap"},
+ {0x00480100, nullptr, "GetProgramInfo"},
+ {0x00490180, nullptr, "Reboot"},
+ {0x004A0040, nullptr, "GetCaptureInfo"},
+ {0x004B00C2, nullptr, "AppletUtility"},
+ {0x004C0000, nullptr, "SetFatalErrDispMode"},
+ {0x004D0080, nullptr, "GetAppletProgramInfo"},
+ {0x004E0000, nullptr, "HardwareResetAsync"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
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 @@
#include "core/mem_map.h"
#include "core/hle/hle.h"
+#include "core/hle/kernel/event.h"
#include "core/hle/service/gsp.h"
#include "core/hw/gpu.h"
@@ -60,6 +61,7 @@ void GX_FinishCommand(u32 thread_id) {
namespace GSP_GPU {
+Handle g_event_handle = 0;
u32 g_thread_id = 0;
enum {
@@ -96,7 +98,7 @@ void ReadHWRegs(Service::Interface* self) {
break;
default:
- ERROR_LOG(GSP, "ReadHWRegs unknown register read at address %08X", reg_addr);
+ ERROR_LOG(GSP, "unknown register read at address %08X", reg_addr);
}
}
@@ -104,7 +106,19 @@ void ReadHWRegs(Service::Interface* self) {
void RegisterInterruptRelayQueue(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 flags = cmd_buff[1];
- u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling
+ u32 event_handle = cmd_buff[3];
+
+ _assert_msg_(GSP, (event_handle != 0), "called, but event is nullptr!");
+
+ g_event_handle = event_handle;
+
+ Kernel::SetEventLocked(event_handle, false);
+
+ // Hack - This function will permanently set the state of the GSP event such that GPU command
+ // synchronization barriers always passthrough. Correct solution would be to set this after the
+ // GPU as processed all queued up commands, but due to the emulator being single-threaded they
+ // will always be ready.
+ Kernel::SetPermanentLock(event_handle, true);
cmd_buff[2] = g_thread_id; // ThreadID
}
@@ -150,43 +164,43 @@ void TriggerCmdReqQueue(Service::Interface* self) {
}
default:
- ERROR_LOG(GSP, "TriggerCmdReqQueue unknown command 0x%08X", cmd_buff[0]);
+ ERROR_LOG(GSP, "unknown command 0x%08X", cmd_buff[0]);
}
GX_FinishCommand(g_thread_id);
}
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010082, NULL, "WriteHWRegs"},
- {0x00020084, NULL, "WriteHWRegsWithMask"},
- {0x00030082, NULL, "WriteHWRegRepeat"},
+ {0x00010082, nullptr, "WriteHWRegs"},
+ {0x00020084, nullptr, "WriteHWRegsWithMask"},
+ {0x00030082, nullptr, "WriteHWRegRepeat"},
{0x00040080, ReadHWRegs, "ReadHWRegs"},
- {0x00050200, NULL, "SetBufferSwap"},
- {0x00060082, NULL, "SetCommandList"},
- {0x000700C2, NULL, "RequestDma"},
- {0x00080082, NULL, "FlushDataCache"},
- {0x00090082, NULL, "InvalidateDataCache"},
- {0x000A0044, NULL, "RegisterInterruptEvents"},
- {0x000B0040, NULL, "SetLcdForceBlack"},
+ {0x00050200, nullptr, "SetBufferSwap"},
+ {0x00060082, nullptr, "SetCommandList"},
+ {0x000700C2, nullptr, "RequestDma"},
+ {0x00080082, nullptr, "FlushDataCache"},
+ {0x00090082, nullptr, "InvalidateDataCache"},
+ {0x000A0044, nullptr, "RegisterInterruptEvents"},
+ {0x000B0040, nullptr, "SetLcdForceBlack"},
{0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"},
- {0x000D0140, NULL, "SetDisplayTransfer"},
- {0x000E0180, NULL, "SetTextureCopy"},
- {0x000F0200, NULL, "SetMemoryFill"},
- {0x00100040, NULL, "SetAxiConfigQoSMode"},
- {0x00110040, NULL, "SetPerfLogMode"},
- {0x00120000, NULL, "GetPerfLog"},
+ {0x000D0140, nullptr, "SetDisplayTransfer"},
+ {0x000E0180, nullptr, "SetTextureCopy"},
+ {0x000F0200, nullptr, "SetMemoryFill"},
+ {0x00100040, nullptr, "SetAxiConfigQoSMode"},
+ {0x00110040, nullptr, "SetPerfLogMode"},
+ {0x00120000, nullptr, "GetPerfLog"},
{0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"},
- {0x00140000, NULL, "UnregisterInterruptRelayQueue"},
- {0x00150002, NULL, "TryAcquireRight"},
- {0x00160042, NULL, "AcquireRight"},
- {0x00170000, NULL, "ReleaseRight"},
- {0x00180000, NULL, "ImportDisplayCaptureInfo"},
- {0x00190000, NULL, "SaveVramSysArea"},
- {0x001A0000, NULL, "RestoreVramSysArea"},
- {0x001B0000, NULL, "ResetGpuCore"},
- {0x001C0040, NULL, "SetLedForceOff"},
- {0x001D0040, NULL, "SetTestCommand"},
- {0x001E0080, NULL, "SetInternalPriorities"},
+ {0x00140000, nullptr, "UnregisterInterruptRelayQueue"},
+ {0x00150002, nullptr, "TryAcquireRight"},
+ {0x00160042, nullptr, "AcquireRight"},
+ {0x00170000, nullptr, "ReleaseRight"},
+ {0x00180000, nullptr, "ImportDisplayCaptureInfo"},
+ {0x00190000, nullptr, "SaveVramSysArea"},
+ {0x001A0000, nullptr, "RestoreVramSysArea"},
+ {0x001B0000, nullptr, "ResetGpuCore"},
+ {0x001C0040, nullptr, "SetLedForceOff"},
+ {0x001D0040, nullptr, "SetTestCommand"},
+ {0x001E0080, nullptr, "SetInternalPriorities"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
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 @@
namespace HID_User {
const Interface::FunctionInfo FunctionTable[] = {
- {0x000A0000, NULL, "GetIPCHandles"},
- {0x00110000, NULL, "EnableAccelerometer"},
- {0x00130000, NULL, "EnableGyroscopeLow"},
- {0x00150000, NULL, "GetGyroscopeLowRawToDpsCoefficient"},
- {0x00160000, NULL, "GetGyroscopeLowCalibrateParam"},
+ {0x000A0000, nullptr, "GetIPCHandles"},
+ {0x00110000, nullptr, "EnableAccelerometer"},
+ {0x00130000, nullptr, "EnableGyroscopeLow"},
+ {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"},
+ {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
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 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+
+#include "core/hle/hle.h"
+#include "core/hle/service/ndm.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace NDM_U
+
+namespace NDM_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00060040, nullptr, "SuspendDaemons"},
+ {0x00080040, nullptr, "DisableWifiUsage"},
+ {0x00090000, nullptr, "EnableWifiUsage"},
+ {0x00140040, nullptr, "OverrideDefaultDaemons"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // 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 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace NDM
+
+// No idea what this is
+
+namespace NDM_U {
+
+class Interface : public Service::Interface {
+public:
+
+ Interface();
+
+ ~Interface();
+
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ const char *GetPortName() const {
+ return "ndm:u";
+ }
+
+};
+
+} // 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 @@
#include "core/hle/service/apt.h"
#include "core/hle/service/gsp.h"
#include "core/hle/service/hid.h"
+#include "core/hle/service/ndm.h"
#include "core/hle/service/srv.h"
#include "core/hle/kernel/kernel.h"
namespace Service {
-Manager* g_manager = NULL; ///< Service manager
+Manager* g_manager = nullptr; ///< Service manager
////////////////////////////////////////////////////////////////////////////////////////////////////
// Service Manager class
@@ -55,7 +56,7 @@ Interface* Manager::FetchFromHandle(Handle handle) {
Interface* Manager::FetchFromPortName(std::string port_name) {
auto itr = m_port_map.find(port_name);
if (itr == m_port_map.end()) {
- return NULL;
+ return nullptr;
}
return FetchFromHandle(itr->second);
}
@@ -72,14 +73,15 @@ void Init() {
g_manager->AddService(new APT_U::Interface);
g_manager->AddService(new GSP_GPU::Interface);
g_manager->AddService(new HID_User::Interface);
+ g_manager->AddService(new NDM_U::Interface);
- NOTICE_LOG(HLE, "Services initialized OK");
+ NOTICE_LOG(HLE, "initialized OK");
}
/// Shutdown ServiceManager
void Shutdown() {
delete g_manager;
- NOTICE_LOG(HLE, "Services shutdown OK");
+ NOTICE_LOG(HLE, "shutdown OK");
}
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 {
friend class Manager;
public:
- const char *GetName() { return GetPortName(); }
- const char *GetTypeName() { return GetPortName(); }
+ const char *GetName() const { return GetPortName(); }
+ const char *GetTypeName() const { return GetPortName(); }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; }
Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; }
@@ -76,22 +76,31 @@ public:
}
/**
- * Called when svcSendSyncRequest is called, loads command buffer and executes comand
- * @return Return result of svcSendSyncRequest passed back to user app
+ * Synchronize kernel object
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
*/
- Result Sync() {
+ Result SyncRequest(bool* wait) {
u32* cmd_buff = GetCommandBuffer();
auto itr = m_functions.find(cmd_buff[0]);
if (itr == m_functions.end()) {
- ERROR_LOG(OSHLE, "Unknown/unimplemented function: port = %s, command = 0x%08X!",
+ ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X",
GetPortName(), cmd_buff[0]);
- return -1;
+
+ // TODO(bunnei): Hack - ignore error
+ u32* cmd_buff = Service::GetCommandBuffer();
+ cmd_buff[1] = 0;
+ return 0;
}
- if (itr->second.func == NULL) {
- ERROR_LOG(OSHLE, "Unimplemented function: port = %s, name = %s!",
+ if (itr->second.func == nullptr) {
+ ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
GetPortName(), itr->second.name.c_str());
- return -1;
+
+ // TODO(bunnei): Hack - ignore error
+ u32* cmd_buff = Service::GetCommandBuffer();
+ cmd_buff[1] = 0;
+ return 0;
}
itr->second.func(this);
@@ -99,6 +108,17 @@ public:
return 0; // TODO: Implement return from actual function
}
+ /**
+ * Wait for kernel object to synchronize
+ * @param wait Boolean wait set if current thread should wait as a result of sync operation
+ * @return Result of operation, 0 on success, otherwise error code
+ */
+ Result WaitSynchronization(bool* wait) {
+ // TODO(bunnei): ImplementMe
+ ERROR_LOG(OSHLE, "unimplemented function");
+ return 0;
+ }
+
protected:
/**
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 @@
#include "core/hle/hle.h"
#include "core/hle/service/srv.h"
#include "core/hle/service/service.h"
-
+#include "core/hle/kernel/mutex.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace SRV
namespace SRV {
+Handle g_mutex = 0;
+
void Initialize(Service::Interface* self) {
- NOTICE_LOG(OSHLE, "SRV::Sync - Initialize");
+ DEBUG_LOG(OSHLE, "called");
+ if (!g_mutex) {
+ g_mutex = Kernel::CreateMutex(true, "SRV:Lock");
+ }
}
void GetProcSemaphore(Service::Interface* self) {
+ DEBUG_LOG(OSHLE, "called");
// Get process semaphore?
u32* cmd_buff = Service::GetCommandBuffer();
- cmd_buff[3] = 0xDEADBEEF; // Return something... 0 == NULL, raises an exception
+ cmd_buff[1] = 0; // No error
+ cmd_buff[3] = g_mutex; // Return something... 0 == nullptr, raises an exception
}
void GetServiceHandle(Service::Interface* self) {
@@ -29,25 +36,21 @@ void GetServiceHandle(Service::Interface* self) {
std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize);
Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
- NOTICE_LOG(OSHLE, "SRV::Sync - GetHandle - port: %s, handle: 0x%08X", port_name.c_str(),
- service->GetHandle());
-
- if (NULL != service) {
+ if (nullptr != service) {
cmd_buff[3] = service->GetHandle();
+ DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
} else {
- ERROR_LOG(OSHLE, "Service %s does not exist", port_name.c_str());
+ ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
res = -1;
}
cmd_buff[1] = res;
-
- //return res;
}
const Interface::FunctionInfo FunctionTable[] = {
{0x00010002, Initialize, "Initialize"},
{0x00020000, GetProcSemaphore, "GetProcSemaphore"},
- {0x00030100, NULL, "RegisterService"},
- {0x000400C0, NULL, "UnregisterService"},
+ {0x00030100, nullptr, "RegisterService"},
+ {0x000400C0, nullptr, "UnregisterService"},
{0x00050100, GetServiceHandle, "GetServiceHandle"},
};
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:
return "srv:";
}
- /**
- * Called when svcSendSyncRequest is called, loads command buffer and executes comand
- * @return Return result of svcSendSyncRequest passed back to user app
- */
- Result Sync();
-
};
} // 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 @@
#include "core/mem_map.h"
+#include "core/hle/kernel/event.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/thread.h"
@@ -16,7 +17,6 @@
#include "core/hle/function_wrappers.h"
#include "core/hle/svc.h"
#include "core/hle/service/service.h"
-#include "core/hle/kernel/thread.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace SVC
@@ -34,40 +34,32 @@ enum MapMemoryPermission {
};
/// Map application or GSP heap memory
-Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
- u32* outaddr = (u32*)_outaddr;
- u32 virtual_address = 0x00000000;
-
- DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
+Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
+ DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
operation, addr0, addr1, size, permissions);
switch (operation) {
// Map normal heap memory
case MEMORY_OPERATION_HEAP:
- virtual_address = Memory::MapBlock_Heap(size, operation, permissions);
+ *out_addr = Memory::MapBlock_Heap(size, operation, permissions);
break;
// Map GSP heap memory
case MEMORY_OPERATION_GSP_HEAP:
- virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions);
+ *out_addr = Memory::MapBlock_HeapGSP(size, operation, permissions);
break;
// Unknown ControlMemory operation
default:
- ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation);
+ ERROR_LOG(SVC, "unknown operation=0x%08X", operation);
}
- if (NULL != outaddr) {
- *outaddr = virtual_address;
- }
- Core::g_app_core->SetReg(1, virtual_address);
-
return 0;
}
/// Maps a memory block to specified address
Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) {
- DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
+ DEBUG_LOG(SVC, "called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
memblock, addr, mypermissions, otherpermission);
switch (mypermissions) {
case MEMORY_PERMISSION_NORMAL:
@@ -76,88 +68,146 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper
Memory::MapBlock_Shared(memblock, addr, mypermissions);
break;
default:
- ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions);
+ ERROR_LOG(OSHLE, "unknown permissions=0x%08X", mypermissions);
}
return 0;
}
/// Connect to an OS service given the port name, returns the handle to the port to out
-Result ConnectToPort(void* out, const char* port_name) {
+Result ConnectToPort(Handle* out, const char* port_name) {
Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
- if (service) {
- Core::g_app_core->SetReg(1, service->GetHandle());
- } else {
- PanicYesNo("ConnectToPort called port_name=%s, but it is not implemented!", port_name);
- }
- DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name);
+
+ DEBUG_LOG(SVC, "called port_name=%s", port_name);
+ _assert_msg_(KERNEL, (service != nullptr), "called, but service is not implemented!");
+
+ *out = service->GetHandle();
+
return 0;
}
/// Synchronize to an OS service
Result SendSyncRequest(Handle handle) {
- DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X");
- Service::Interface* service = Service::g_manager->FetchFromHandle(handle);
- service->Sync();
- return 0;
+ Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
+
+ _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
+ DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName());
+
+ bool wait = false;
+ Result res = object->SyncRequest(&wait);
+ if (wait) {
+ Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
+ }
+
+ return res;
}
/// Close a handle
Result CloseHandle(Handle handle) {
// ImplementMe
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle);
+ ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle);
return 0;
}
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d",
- handle, nano_seconds);
- Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
- return 0;
+ // TODO(bunnei): Do something with nano_seconds, currently ignoring this
+ bool wait = false;
+ bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
+
+ Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
+
+ DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName(),
+ object->GetName(), nano_seconds);
+
+ _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
+
+ Result res = object->WaitSynchronization(&wait);
+
+ // Check for next thread to schedule
+ if (wait) {
+ HLE::Reschedule(__func__);
+ return 0;
+ }
+
+ return res;
}
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
-Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) {
- s32* out = (s32*)_out;
- Handle* handles = (Handle*)_handles;
+Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all,
+ s64 nano_seconds) {
+ // TODO(bunnei): Do something with nano_seconds, currently ignoring this
+ bool unlock_all = true;
+ bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s",
+ DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d",
handle_count, (wait_all ? "true" : "false"), nano_seconds);
- for (u32 i = 0; i < handle_count; i++) {
- DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]);
+ // Iterate through each handle, synchronize kernel object
+ for (s32 i = 0; i < handle_count; i++) {
+ bool wait = false;
+ Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]);
+
+ _assert_msg_(KERNEL, (object != nullptr), "called handle=0x%08X, but kernel object "
+ "is nullptr!", handles[i]);
+
+ DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName(),
+ object->GetName());
+
+ Result res = object->WaitSynchronization(&wait);
+
+ if (!wait && !wait_all) {
+ *out = i;
+ return 0;
+ } else {
+ unlock_all = false;
+ }
}
- Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
+
+ if (wait_all && unlock_all) {
+ *out = handle_count;
+ return 0;
+ }
+
+ // Check for next thread to schedule
+ HLE::Reschedule(__func__);
+
return 0;
}
/// Create an address arbiter (to allocate access to shared resources)
Result CreateAddressArbiter(void* arbiter) {
- // ImplementMe
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called");
+ ERROR_LOG(SVC, "(UNIMPLEMENTED) called");
Core::g_app_core->SetReg(1, 0xFABBDADD);
return 0;
}
+/// Arbitrate address
+Result ArbitrateAddress(Handle arbiter, u32 addr, u32 _type, u32 value, s64 nanoseconds) {
+ ERROR_LOG(SVC, "(UNIMPLEMENTED) called");
+ ArbitrationType type = (ArbitrationType)_type;
+ Memory::Write32(addr, type);
+ return 0;
+}
+
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
void OutputDebugString(const char* string) {
- NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string);
+ OS_LOG(SVC, "%s", string);
}
/// Get resource limit
-Result GetResourceLimit(void* resource_limit, Handle process) {
+Result GetResourceLimit(Handle* resource_limit, Handle process) {
// With regards to proceess values:
// 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
// the current KThread.
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process);
- Core::g_app_core->SetReg(1, 0xDEADBEEF);
+ *resource_limit = 0xDEADBEEF;
+ ERROR_LOG(SVC, "(UNIMPLEMENTED) called process=0x%08X", process);
return 0;
}
/// Get resource limit current values
-Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) {
- //s64* values = (s64*)_values;
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d",
+Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names,
+ s32 name_count) {
+ ERROR_LOG(SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d",
resource_limit, names, name_count);
Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
return 0;
@@ -180,179 +230,234 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p
Core::g_app_core->SetReg(1, thread);
- DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
- "threadpriority=0x%08X, processorid=0x%08X : created handle 0x%08X", entry_point,
+ DEBUG_LOG(SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
+ "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,
name.c_str(), arg, stack_top, priority, processor_id, thread);
return 0;
}
+/// Called when a thread exits
+u32 ExitThread() {
+ Handle thread = Kernel::GetCurrentThreadHandle();
+
+ DEBUG_LOG(SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C
+
+ Kernel::StopThread(thread, __func__);
+ HLE::Reschedule(__func__);
+ return 0;
+}
+
+/// Gets the priority for the specified thread
+Result GetThreadPriority(s32* priority, Handle handle) {
+ *priority = Kernel::GetThreadPriority(handle);
+ return 0;
+}
+
+/// Sets the priority for the specified thread
+Result SetThreadPriority(Handle handle, s32 priority) {
+ return Kernel::SetThreadPriority(handle, priority);
+}
+
/// Create a mutex
-Result CreateMutex(void* _mutex, u32 initial_locked) {
- Handle* mutex = (Handle*)_mutex;
+Result CreateMutex(Handle* mutex, u32 initial_locked) {
*mutex = Kernel::CreateMutex((initial_locked != 0));
- Core::g_app_core->SetReg(1, *mutex);
- DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s : created handle 0x%08X",
+ DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X",
initial_locked ? "true" : "false", *mutex);
return 0;
}
/// Release a mutex
Result ReleaseMutex(Handle handle) {
- DEBUG_LOG(SVC, "ReleaseMutex called handle=0x%08X", handle);
+ DEBUG_LOG(SVC, "called handle=0x%08X", handle);
+ _assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!");
Kernel::ReleaseMutex(handle);
return 0;
}
/// Get current thread ID
-Result GetThreadId(void* thread_id, u32 thread) {
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread);
+Result GetThreadId(u32* thread_id, Handle thread) {
+ ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread);
return 0;
}
/// Query memory
-Result QueryMemory(void *_info, void *_out, u32 addr) {
- MemoryInfo* info = (MemoryInfo*) _info;
- PageInfo* out = (PageInfo*) _out;
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr);
+Result QueryMemory(void* info, void* out, u32 addr) {
+ ERROR_LOG(SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr);
return 0;
}
/// Create an event
-Result CreateEvent(void* _event, u32 reset_type) {
- Handle* event = (Handle*)_event;
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type);
- Core::g_app_core->SetReg(1, 0xBADC0DE0);
+Result CreateEvent(Handle* evt, u32 reset_type) {
+ *evt = Kernel::CreateEvent((ResetType)reset_type);
+ DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X",
+ reset_type, *evt);
+ return 0;
+}
+
+/// Duplicates a kernel handle
+Result DuplicateHandle(Handle* out, Handle handle) {
+ DEBUG_LOG(SVC, "called handle=0x%08X", handle);
+
+ // Translate kernel handles -> real handles
+ if (handle == Kernel::CurrentThread) {
+ handle = Kernel::GetCurrentThreadHandle();
+ }
+ _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess),
+ "(UNIMPLEMENTED) process handle duplication!");
+
+ // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate.
+ *out = handle;
+
return 0;
}
+/// Signals an event
+Result SignalEvent(Handle evt) {
+ Result res = Kernel::SignalEvent(evt);
+ DEBUG_LOG(SVC, "called event=0x%08X", evt);
+ return res;
+}
+
+/// Clears an event
+Result ClearEvent(Handle evt) {
+ Result res = Kernel::ClearEvent(evt);
+ DEBUG_LOG(SVC, "called event=0x%08X", evt);
+ return res;
+}
+
+/// Sleep the current thread
+void SleepThread(s64 nanoseconds) {
+ DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds);
+}
+
const HLE::FunctionDef SVC_Table[] = {
- {0x00, NULL, "Unknown"},
- {0x01, WrapI_VUUUUU<ControlMemory>, "ControlMemory"},
- {0x02, WrapI_VVU<QueryMemory>, "QueryMemory"},
- {0x03, NULL, "ExitProcess"},
- {0x04, NULL, "GetProcessAffinityMask"},
- {0x05, NULL, "SetProcessAffinityMask"},
- {0x06, NULL, "GetProcessIdealProcessor"},
- {0x07, NULL, "SetProcessIdealProcessor"},
- {0x08, WrapI_UUUUU<CreateThread>, "CreateThread"},
- {0x09, NULL, "ExitThread"},
- {0x0A, NULL, "SleepThread"},
- {0x0B, NULL, "GetThreadPriority"},
- {0x0C, NULL, "SetThreadPriority"},
- {0x0D, NULL, "GetThreadAffinityMask"},
- {0x0E, NULL, "SetThreadAffinityMask"},
- {0x0F, NULL, "GetThreadIdealProcessor"},
- {0x10, NULL, "SetThreadIdealProcessor"},
- {0x11, NULL, "GetCurrentProcessorNumber"},
- {0x12, NULL, "Run"},
- {0x13, WrapI_VU<CreateMutex>, "CreateMutex"},
- {0x14, WrapI_U<ReleaseMutex>, "ReleaseMutex"},
- {0x15, NULL, "CreateSemaphore"},
- {0x16, NULL, "ReleaseSemaphore"},
- {0x17, WrapI_VU<CreateEvent>, "CreateEvent"},
- {0x18, NULL, "SignalEvent"},
- {0x19, NULL, "ClearEvent"},
- {0x1A, NULL, "CreateTimer"},
- {0x1B, NULL, "SetTimer"},
- {0x1C, NULL, "CancelTimer"},
- {0x1D, NULL, "ClearTimer"},
- {0x1E, NULL, "CreateMemoryBlock"},
- {0x1F, WrapI_UUUU<MapMemoryBlock>, "MapMemoryBlock"},
- {0x20, NULL, "UnmapMemoryBlock"},
- {0x21, WrapI_V<CreateAddressArbiter>, "CreateAddressArbiter"},
- {0x22, NULL, "ArbitrateAddress"},
- {0x23, WrapI_U<CloseHandle>, "CloseHandle"},
- {0x24, WrapI_US64<WaitSynchronization1>, "WaitSynchronization1"},
- {0x25, WrapI_VVUUS64<WaitSynchronizationN>, "WaitSynchronizationN"},
- {0x26, NULL, "SignalAndWait"},
- {0x27, NULL, "DuplicateHandle"},
- {0x28, NULL, "GetSystemTick"},
- {0x29, NULL, "GetHandleInfo"},
- {0x2A, NULL, "GetSystemInfo"},
- {0x2B, NULL, "GetProcessInfo"},
- {0x2C, NULL, "GetThreadInfo"},
- {0x2D, WrapI_VC<ConnectToPort>, "ConnectToPort"},
- {0x2E, NULL, "SendSyncRequest1"},
- {0x2F, NULL, "SendSyncRequest2"},
- {0x30, NULL, "SendSyncRequest3"},
- {0x31, NULL, "SendSyncRequest4"},
- {0x32, WrapI_U<SendSyncRequest>, "SendSyncRequest"},
- {0x33, NULL, "OpenProcess"},
- {0x34, NULL, "OpenThread"},
- {0x35, NULL, "GetProcessId"},
- {0x36, NULL, "GetProcessIdOfThread"},
- {0x37, WrapI_VU<GetThreadId>, "GetThreadId"},
- {0x38, WrapI_VU<GetResourceLimit>, "GetResourceLimit"},
- {0x39, NULL, "GetResourceLimitLimitValues"},
- {0x3A, WrapI_VUVI<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"},
- {0x3B, NULL, "GetThreadContext"},
- {0x3C, NULL, "Break"},
- {0x3D, WrapV_C<OutputDebugString>, "OutputDebugString"},
- {0x3E, NULL, "ControlPerformanceCounter"},
- {0x3F, NULL, "Unknown"},
- {0x40, NULL, "Unknown"},
- {0x41, NULL, "Unknown"},
- {0x42, NULL, "Unknown"},
- {0x43, NULL, "Unknown"},
- {0x44, NULL, "Unknown"},
- {0x45, NULL, "Unknown"},
- {0x46, NULL, "Unknown"},
- {0x47, NULL, "CreatePort"},
- {0x48, NULL, "CreateSessionToPort"},
- {0x49, NULL, "CreateSession"},
- {0x4A, NULL, "AcceptSession"},
- {0x4B, NULL, "ReplyAndReceive1"},
- {0x4C, NULL, "ReplyAndReceive2"},
- {0x4D, NULL, "ReplyAndReceive3"},
- {0x4E, NULL, "ReplyAndReceive4"},
- {0x4F, NULL, "ReplyAndReceive"},
- {0x50, NULL, "BindInterrupt"},
- {0x51, NULL, "UnbindInterrupt"},
- {0x52, NULL, "InvalidateProcessDataCache"},
- {0x53, NULL, "StoreProcessDataCache"},
- {0x54, NULL, "FlushProcessDataCache"},
- {0x55, NULL, "StartInterProcessDma"},
- {0x56, NULL, "StopDma"},
- {0x57, NULL, "GetDmaState"},
- {0x58, NULL, "RestartDma"},
- {0x59, NULL, "Unknown"},
- {0x5A, NULL, "Unknown"},
- {0x5B, NULL, "Unknown"},
- {0x5C, NULL, "Unknown"},
- {0x5D, NULL, "Unknown"},
- {0x5E, NULL, "Unknown"},
- {0x5F, NULL, "Unknown"},
- {0x60, NULL, "DebugActiveProcess"},
- {0x61, NULL, "BreakDebugProcess"},
- {0x62, NULL, "TerminateDebugProcess"},
- {0x63, NULL, "GetProcessDebugEvent"},
- {0x64, NULL, "ContinueDebugEvent"},
- {0x65, NULL, "GetProcessList"},
- {0x66, NULL, "GetThreadList"},
- {0x67, NULL, "GetDebugThreadContext"},
- {0x68, NULL, "SetDebugThreadContext"},
- {0x69, NULL, "QueryDebugProcessMemory"},
- {0x6A, NULL, "ReadProcessMemory"},
- {0x6B, NULL, "WriteProcessMemory"},
- {0x6C, NULL, "SetHardwareBreakPoint"},
- {0x6D, NULL, "GetDebugThreadParam"},
- {0x6E, NULL, "Unknown"},
- {0x6F, NULL, "Unknown"},
- {0x70, NULL, "ControlProcessMemory"},
- {0x71, NULL, "MapProcessMemory"},
- {0x72, NULL, "UnmapProcessMemory"},
- {0x73, NULL, "Unknown"},
- {0x74, NULL, "Unknown"},
- {0x75, NULL, "Unknown"},
- {0x76, NULL, "TerminateProcess"},
- {0x77, NULL, "Unknown"},
- {0x78, NULL, "CreateResourceLimit"},
- {0x79, NULL, "Unknown"},
- {0x7A, NULL, "Unknown"},
- {0x7B, NULL, "Unknown"},
- {0x7C, NULL, "KernelSetState"},
- {0x7D, NULL, "QueryProcessMemory"},
+ {0x00, nullptr, "Unknown"},
+ {0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
+ {0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
+ {0x03, nullptr, "ExitProcess"},
+ {0x04, nullptr, "GetProcessAffinityMask"},
+ {0x05, nullptr, "SetProcessAffinityMask"},
+ {0x06, nullptr, "GetProcessIdealProcessor"},
+ {0x07, nullptr, "SetProcessIdealProcessor"},
+ {0x08, HLE::Wrap<CreateThread>, "CreateThread"},
+ {0x09, HLE::Wrap<ExitThread>, "ExitThread"},
+ {0x0A, HLE::Wrap<SleepThread>, "SleepThread"},
+ {0x0B, HLE::Wrap<GetThreadPriority>, "GetThreadPriority"},
+ {0x0C, HLE::Wrap<SetThreadPriority>, "SetThreadPriority"},
+ {0x0D, nullptr, "GetThreadAffinityMask"},
+ {0x0E, nullptr, "SetThreadAffinityMask"},
+ {0x0F, nullptr, "GetThreadIdealProcessor"},
+ {0x10, nullptr, "SetThreadIdealProcessor"},
+ {0x11, nullptr, "GetCurrentProcessorNumber"},
+ {0x12, nullptr, "Run"},
+ {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"},
+ {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"},
+ {0x15, nullptr, "CreateSemaphore"},
+ {0x16, nullptr, "ReleaseSemaphore"},
+ {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"},
+ {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"},
+ {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"},
+ {0x1A, nullptr, "CreateTimer"},
+ {0x1B, nullptr, "SetTimer"},
+ {0x1C, nullptr, "CancelTimer"},
+ {0x1D, nullptr, "ClearTimer"},
+ {0x1E, nullptr, "CreateMemoryBlock"},
+ {0x1F, HLE::Wrap<MapMemoryBlock>, "MapMemoryBlock"},
+ {0x20, nullptr, "UnmapMemoryBlock"},
+ {0x21, HLE::Wrap<CreateAddressArbiter>, "CreateAddressArbiter"},
+ {0x22, HLE::Wrap<ArbitrateAddress>, "ArbitrateAddress"},
+ {0x23, HLE::Wrap<CloseHandle>, "CloseHandle"},
+ {0x24, HLE::Wrap<WaitSynchronization1>, "WaitSynchronization1"},
+ {0x25, HLE::Wrap<WaitSynchronizationN>, "WaitSynchronizationN"},
+ {0x26, nullptr, "SignalAndWait"},
+ {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"},
+ {0x28, nullptr, "GetSystemTick"},
+ {0x29, nullptr, "GetHandleInfo"},
+ {0x2A, nullptr, "GetSystemInfo"},
+ {0x2B, nullptr, "GetProcessInfo"},
+ {0x2C, nullptr, "GetThreadInfo"},
+ {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"},
+ {0x2E, nullptr, "SendSyncRequest1"},
+ {0x2F, nullptr, "SendSyncRequest2"},
+ {0x30, nullptr, "SendSyncRequest3"},
+ {0x31, nullptr, "SendSyncRequest4"},
+ {0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"},
+ {0x33, nullptr, "OpenProcess"},
+ {0x34, nullptr, "OpenThread"},
+ {0x35, nullptr, "GetProcessId"},
+ {0x36, nullptr, "GetProcessIdOfThread"},
+ {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"},
+ {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"},
+ {0x39, nullptr, "GetResourceLimitLimitValues"},
+ {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"},
+ {0x3B, nullptr, "GetThreadContext"},
+ {0x3C, nullptr, "Break"},
+ {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"},
+ {0x3E, nullptr, "ControlPerformanceCounter"},
+ {0x3F, nullptr, "Unknown"},
+ {0x40, nullptr, "Unknown"},
+ {0x41, nullptr, "Unknown"},
+ {0x42, nullptr, "Unknown"},
+ {0x43, nullptr, "Unknown"},
+ {0x44, nullptr, "Unknown"},
+ {0x45, nullptr, "Unknown"},
+ {0x46, nullptr, "Unknown"},
+ {0x47, nullptr, "CreatePort"},
+ {0x48, nullptr, "CreateSessionToPort"},
+ {0x49, nullptr, "CreateSession"},
+ {0x4A, nullptr, "AcceptSession"},
+ {0x4B, nullptr, "ReplyAndReceive1"},
+ {0x4C, nullptr, "ReplyAndReceive2"},
+ {0x4D, nullptr, "ReplyAndReceive3"},
+ {0x4E, nullptr, "ReplyAndReceive4"},
+ {0x4F, nullptr, "ReplyAndReceive"},
+ {0x50, nullptr, "BindInterrupt"},
+ {0x51, nullptr, "UnbindInterrupt"},
+ {0x52, nullptr, "InvalidateProcessDataCache"},
+ {0x53, nullptr, "StoreProcessDataCache"},
+ {0x54, nullptr, "FlushProcessDataCache"},
+ {0x55, nullptr, "StartInterProcessDma"},
+ {0x56, nullptr, "StopDma"},
+ {0x57, nullptr, "GetDmaState"},
+ {0x58, nullptr, "RestartDma"},
+ {0x59, nullptr, "Unknown"},
+ {0x5A, nullptr, "Unknown"},
+ {0x5B, nullptr, "Unknown"},
+ {0x5C, nullptr, "Unknown"},
+ {0x5D, nullptr, "Unknown"},
+ {0x5E, nullptr, "Unknown"},
+ {0x5F, nullptr, "Unknown"},
+ {0x60, nullptr, "DebugActiveProcess"},
+ {0x61, nullptr, "BreakDebugProcess"},
+ {0x62, nullptr, "TerminateDebugProcess"},
+ {0x63, nullptr, "GetProcessDebugEvent"},
+ {0x64, nullptr, "ContinueDebugEvent"},
+ {0x65, nullptr, "GetProcessList"},
+ {0x66, nullptr, "GetThreadList"},
+ {0x67, nullptr, "GetDebugThreadContext"},
+ {0x68, nullptr, "SetDebugThreadContext"},
+ {0x69, nullptr, "QueryDebugProcessMemory"},
+ {0x6A, nullptr, "ReadProcessMemory"},
+ {0x6B, nullptr, "WriteProcessMemory"},
+ {0x6C, nullptr, "SetHardwareBreakPoint"},
+ {0x6D, nullptr, "GetDebugThreadParam"},
+ {0x6E, nullptr, "Unknown"},
+ {0x6F, nullptr, "Unknown"},
+ {0x70, nullptr, "ControlProcessMemory"},
+ {0x71, nullptr, "MapProcessMemory"},
+ {0x72, nullptr, "UnmapProcessMemory"},
+ {0x73, nullptr, "Unknown"},
+ {0x74, nullptr, "Unknown"},
+ {0x75, nullptr, "Unknown"},
+ {0x76, nullptr, "TerminateProcess"},
+ {0x77, nullptr, "Unknown"},
+ {0x78, nullptr, "CreateResourceLimit"},
+ {0x79, nullptr, "Unknown"},
+ {0x7A, nullptr, "Unknown"},
+ {0x7B, nullptr, "Unknown"},
+ {0x7C, nullptr, "KernelSetState"},
+ {0x7D, nullptr, "QueryProcessMemory"},
};
void 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 {
u32 fpu_registers[32];
u32 fpscr;
u32 fpexc;
+
+ // These are not part of native ThreadContext, but needed by emu
+ u32 reg_15;
+ u32 mode;
};
enum ResetType {
@@ -38,6 +42,15 @@ enum ResetType {
RESETTYPE_MAX_BIT = (1u << 31),
};
+enum ArbitrationType {
+ ARBITRATIONTYPE_SIGNAL,
+ ARBITRATIONTYPE_WAIT_IF_LESS_THAN,
+ ARBITRATIONTYPE_DECREMENT_AND_WAIT_IF_LESS_THAN,
+ ARBITRATIONTYPE_WAIT_IF_LESS_THAN_WITH_TIMEOUT,
+ ARBITRATIONTYPE_DECREMENT_AND_WAIT_IF_LESS_THAN_WITH_TIMEOUT,
+ ARBITRATIONTYPE_MAX_BIT = (1u << 31)
+};
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace SVC
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 {
Registers g_regs;
-static const u32 kFrameTicks = 268123480 / 60; ///< 268MHz / 60 frames per second
-
u64 g_last_ticks = 0; ///< Last CPU ticks
/**
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 @@
namespace GPU {
+static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second
+static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame
+
struct Registers {
enum Id : u32 {
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) {
var = *((const T*)&g_vram[vaddr & VRAM_MASK]);
} else {
- //_assert_msg_(MEMMAP, false, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr);
+ ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr);
}
}
@@ -136,8 +136,7 @@ inline void _Write(u32 addr, const T data) {
// Error out...
} else {
- _assert_msg_(MEMMAP, false, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8,
- data, vaddr);
+ ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr);
}
}
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 @@
#include "core/system.h"
#include "core/hw/hw.h"
#include "core/hle/hle.h"
+#include "core/hle/kernel/kernel.h"
#include "video_core/video_core.h"
@@ -26,6 +27,7 @@ void Init(EmuWindow* emu_window) {
HLE::Init();
CoreTiming::Init();
VideoCore::Init(emu_window);
+ Kernel::Init();
}
void RunLoopFor(int cycles) {
@@ -42,6 +44,7 @@ void Shutdown() {
HLE::Shutdown();
CoreTiming::Shutdown();
VideoCore::Shutdown();
+ Kernel::Shutdown();
g_ctr_file_system.Shutdown();
}