summaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/function_wrappers.h14
-rw-r--r--src/core/hle/hle.cpp25
-rw-r--r--src/core/hle/hle.h6
-rw-r--r--src/core/hle/kernel/kernel.cpp158
-rw-r--r--src/core/hle/kernel/kernel.h154
-rw-r--r--src/core/hle/kernel/mutex.cpp132
-rw-r--r--src/core/hle/kernel/mutex.h26
-rw-r--r--src/core/hle/kernel/thread.cpp323
-rw-r--r--src/core/hle/kernel/thread.h74
-rw-r--r--src/core/hle/service/apt.cpp8
-rw-r--r--src/core/hle/service/apt.h2
-rw-r--r--src/core/hle/service/gsp.cpp4
-rw-r--r--src/core/hle/service/gsp.h2
-rw-r--r--src/core/hle/service/hid.h2
-rw-r--r--src/core/hle/service/service.cpp28
-rw-r--r--src/core/hle/service/service.h72
-rw-r--r--src/core/hle/service/srv.cpp14
-rw-r--r--src/core/hle/service/srv.h4
-rw-r--r--src/core/hle/svc.cpp (renamed from src/core/hle/syscall.cpp)140
-rw-r--r--src/core/hle/svc.h48
-rw-r--r--src/core/hle/syscall.h19
21 files changed, 1124 insertions, 131 deletions
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index d934eafb4..801865d49 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -719,17 +719,27 @@ template<int func(void*, u32)> void WrapI_VU(){
719 RETURN(retval); 719 RETURN(retval);
720} 720}
721 721
722template<int func(void*, void*, u32)> void WrapI_VVU(){
723 u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2));
724 RETURN(retval);
725}
726
722template<int func(void*, u32, void*, int)> void WrapI_VUVI(){ 727template<int func(void*, u32, void*, int)> void WrapI_VUVI(){
723 u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), PARAM(3)); 728 u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), PARAM(3));
724 RETURN(retval); 729 RETURN(retval);
725} 730}
726 731
727template<int func(void*, u32, u32, u32, u32, u32)> void WrapI_VUUUUU(){ 732template<int func(void*, u32, u32, u32, u32, u32)> void WrapI_VUUUUU(){
728 u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); 733 u32 retval = func(NULL, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
729 RETURN(retval); 734 RETURN(retval);
730} 735}
731 736
732template<int func(u32, s64)> void WrapI_US64() { 737template<int func(u32, s64)> void WrapI_US64() {
733 int retval = func(PARAM(0), PARAM64(2)); 738 int retval = func(PARAM(0), PARAM64(1));
739 RETURN(retval);
740}
741
742template<int func(void*, void*, u32, u32, s64)> void WrapI_VVUUS64() {
743 int retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4));
734 RETURN(retval); 744 RETURN(retval);
735} 745}
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index be151665b..080c36abf 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -6,7 +6,7 @@
6 6
7#include "core/mem_map.h" 7#include "core/mem_map.h"
8#include "core/hle/hle.h" 8#include "core/hle/hle.h"
9#include "core/hle/syscall.h" 9#include "core/hle/svc.h"
10#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
11 11
12//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -15,17 +15,17 @@ namespace HLE {
15 15
16static std::vector<ModuleDef> g_module_db; 16static std::vector<ModuleDef> g_module_db;
17 17
18const FunctionDef* GetSyscallInfo(u32 opcode) { 18const FunctionDef* GetSVCInfo(u32 opcode) {
19 u32 func_num = opcode & 0xFFFFFF; // 8 bits 19 u32 func_num = opcode & 0xFFFFFF; // 8 bits
20 if (func_num > 0xFF) { 20 if (func_num > 0xFF) {
21 ERROR_LOG(HLE,"Unknown syscall: 0x%02X", func_num); 21 ERROR_LOG(HLE,"Unknown SVC: 0x%02X", func_num);
22 return NULL; 22 return NULL;
23 } 23 }
24 return &g_module_db[0].func_table[func_num]; 24 return &g_module_db[0].func_table[func_num];
25} 25}
26 26
27void CallSyscall(u32 opcode) { 27void CallSVC(u32 opcode) {
28 const FunctionDef *info = GetSyscallInfo(opcode); 28 const FunctionDef *info = GetSVCInfo(opcode);
29 29
30 if (!info) { 30 if (!info) {
31 return; 31 return;
@@ -33,17 +33,28 @@ void CallSyscall(u32 opcode) {
33 if (info->func) { 33 if (info->func) {
34 info->func(); 34 info->func();
35 } else { 35 } else {
36 ERROR_LOG(HLE, "Unimplemented SysCall function %s(..)", info->name.c_str()); 36 ERROR_LOG(HLE, "Unimplemented SVC function %s(..)", info->name.c_str());
37 } 37 }
38} 38}
39 39
40void EatCycles(u32 cycles) {
41 // TODO: ImplementMe
42}
43
44void ReSchedule(const char *reason) {
45#ifdef _DEBUG
46 _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "ReSchedule: Invalid or too long reason.");
47#endif
48 // TODO: ImplementMe
49}
50
40void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) { 51void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) {
41 ModuleDef module = {name, num_functions, func_table}; 52 ModuleDef module = {name, num_functions, func_table};
42 g_module_db.push_back(module); 53 g_module_db.push_back(module);
43} 54}
44 55
45void RegisterAllModules() { 56void RegisterAllModules() {
46 Syscall::Register(); 57 SVC::Register();
47} 58}
48 59
49void Init() { 60void Init() {
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h
index 42f37e29c..c075147c3 100644
--- a/src/core/hle/hle.h
+++ b/src/core/hle/hle.h
@@ -34,7 +34,11 @@ struct ModuleDef {
34 34
35void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table); 35void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table);
36 36
37void CallSyscall(u32 opcode); 37void CallSVC(u32 opcode);
38
39void EatCycles(u32 cycles);
40
41void ReSchedule(const char *reason);
38 42
39void Init(); 43void Init();
40 44
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
new file mode 100644
index 000000000..de80de893
--- /dev/null
+++ b/src/core/hle/kernel/kernel.cpp
@@ -0,0 +1,158 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <string.h>
8
9#include "common/common.h"
10
11#include "core/core.h"
12#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/thread.h"
14
15namespace Kernel {
16
17ObjectPool g_object_pool;
18
19ObjectPool::ObjectPool() {
20 memset(occupied, 0, sizeof(bool) * MAX_COUNT);
21 next_id = INITIAL_NEXT_ID;
22}
23
24Handle ObjectPool::Create(Object* obj, int range_bottom, int range_top) {
25 if (range_top > MAX_COUNT) {
26 range_top = MAX_COUNT;
27 }
28 if (next_id >= range_bottom && next_id < range_top) {
29 range_bottom = next_id++;
30 }
31 for (int i = range_bottom; i < range_top; i++) {
32 if (!occupied[i]) {
33 occupied[i] = true;
34 pool[i] = obj;
35 pool[i]->handle = i + HANDLE_OFFSET;
36 return i + HANDLE_OFFSET;
37 }
38 }
39 ERROR_LOG(HLE, "Unable to allocate kernel object, too many objects slots in use.");
40 return 0;
41}
42
43bool ObjectPool::IsValid(Handle handle) {
44 int index = handle - HANDLE_OFFSET;
45 if (index < 0)
46 return false;
47 if (index >= MAX_COUNT)
48 return false;
49
50 return occupied[index];
51}
52
53void ObjectPool::Clear() {
54 for (int i = 0; i < MAX_COUNT; i++) {
55 //brutally clear everything, no validation
56 if (occupied[i])
57 delete pool[i];
58 occupied[i] = false;
59 }
60 memset(pool, 0, sizeof(Object*)*MAX_COUNT);
61 next_id = INITIAL_NEXT_ID;
62}
63
64Object* &ObjectPool::operator [](Handle handle)
65{
66 _dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ");
67 return pool[handle - HANDLE_OFFSET];
68}
69
70void ObjectPool::List() {
71 for (int i = 0; i < MAX_COUNT; i++) {
72 if (occupied[i]) {
73 if (pool[i]) {
74 INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName(),
75 pool[i]->GetName());
76 }
77 }
78 }
79}
80
81int ObjectPool::GetCount() {
82 int count = 0;
83 for (int i = 0; i < MAX_COUNT; i++) {
84 if (occupied[i])
85 count++;
86 }
87 return count;
88}
89
90Object* ObjectPool::CreateByIDType(int type) {
91 // Used for save states. This is ugly, but what other way is there?
92 switch (type) {
93 //case SCE_KERNEL_TMID_Alarm:
94 // return __KernelAlarmObject();
95 //case SCE_KERNEL_TMID_EventFlag:
96 // return __KernelEventFlagObject();
97 //case SCE_KERNEL_TMID_Mbox:
98 // return __KernelMbxObject();
99 //case SCE_KERNEL_TMID_Fpl:
100 // return __KernelMemoryFPLObject();
101 //case SCE_KERNEL_TMID_Vpl:
102 // return __KernelMemoryVPLObject();
103 //case PPSSPP_KERNEL_TMID_PMB:
104 // return __KernelMemoryPMBObject();
105 //case PPSSPP_KERNEL_TMID_Module:
106 // return __KernelModuleObject();
107 //case SCE_KERNEL_TMID_Mpipe:
108 // return __KernelMsgPipeObject();
109 //case SCE_KERNEL_TMID_Mutex:
110 // return __KernelMutexObject();
111 //case SCE_KERNEL_TMID_LwMutex:
112 // return __KernelLwMutexObject();
113 //case SCE_KERNEL_TMID_Semaphore:
114 // return __KernelSemaphoreObject();
115 //case SCE_KERNEL_TMID_Callback:
116 // return __KernelCallbackObject();
117 //case SCE_KERNEL_TMID_Thread:
118 // return __KernelThreadObject();
119 //case SCE_KERNEL_TMID_VTimer:
120 // return __KernelVTimerObject();
121 //case SCE_KERNEL_TMID_Tlspl:
122 // return __KernelTlsplObject();
123 //case PPSSPP_KERNEL_TMID_File:
124 // return __KernelFileNodeObject();
125 //case PPSSPP_KERNEL_TMID_DirList:
126 // return __KernelDirListingObject();
127
128 default:
129 ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type);
130 return NULL;
131 }
132}
133
134void Init() {
135 Kernel::ThreadingInit();
136}
137
138void Shutdown() {
139 Kernel::ThreadingShutdown();
140}
141
142/**
143 * Loads executable stored at specified address
144 * @entry_point Entry point in memory of loaded executable
145 * @return True on success, otherwise false
146 */
147bool LoadExec(u32 entry_point) {
148 Init();
149
150 Core::g_app_core->SetPC(entry_point);
151
152 // 0x30 is the typical main thread priority I've seen used so far
153 Handle thread = Kernel::SetupMainThread(0x30);
154
155 return true;
156}
157
158} // namespace
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
new file mode 100644
index 000000000..7cd79c2c4
--- /dev/null
+++ b/src/core/hle/kernel/kernel.h
@@ -0,0 +1,154 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common.h"
8
9typedef u32 Handle;
10typedef s32 Result;
11
12namespace Kernel {
13
14enum class HandleType : u32 {
15 Unknown = 0,
16 Port = 1,
17 Service = 2,
18 Event = 3,
19 Mutex = 4,
20 SharedMemory = 5,
21 Redirection = 6,
22 Thread = 7,
23 Process = 8,
24 Arbiter = 9,
25 File = 10,
26 Semaphore = 11,
27};
28
29enum {
30 MAX_NAME_LENGTH = 0x100,
31 DEFAULT_STACK_SIZE = 0x4000,
32};
33
34class ObjectPool;
35
36class Object : NonCopyable {
37 friend class ObjectPool;
38 u32 handle;
39public:
40 virtual ~Object() {}
41 Handle GetHandle() const { return handle; }
42 virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; }
43 virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; }
44 virtual Kernel::HandleType GetHandleType() const = 0;
45};
46
47class ObjectPool : NonCopyable {
48public:
49 ObjectPool();
50 ~ObjectPool() {}
51
52 // Allocates a handle within the range and inserts the object into the map.
53 Handle Create(Object* obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF);
54
55 static Object* CreateByIDType(int type);
56
57 template <class T>
58 u32 Destroy(Handle handle) {
59 u32 error;
60 if (Get<T>(handle, error)) {
61 occupied[handle - HANDLE_OFFSET] = false;
62 delete pool[handle - HANDLE_OFFSET];
63 }
64 return error;
65 };
66
67 bool IsValid(Handle handle);
68
69 template <class T>
70 T* Get(Handle handle, u32& outError) {
71 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) {
72 // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP
73 if (handle != 0 && (u32)handle != 0x80020001) {
74 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
75 }
76 outError = 0;//T::GetMissingErrorCode();
77 return 0;
78 } else {
79 // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally,
80 // it just acted as a static case and everything worked. This means that we will never
81 // see the Wrong type object error below, but we'll just have to live with that danger.
82 T* t = static_cast<T*>(pool[handle - HANDLE_OFFSET]);
83 if (t == 0 || t->GetHandleType() != T::GetStaticHandleType()) {
84 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle);
85 outError = 0;//T::GetMissingErrorCode();
86 return 0;
87 }
88 outError = 0;//SCE_KERNEL_ERROR_OK;
89 return t;
90 }
91 }
92
93 // ONLY use this when you know the handle is valid.
94 template <class T>
95 T *GetFast(Handle handle) {
96 const Handle realHandle = handle - HANDLE_OFFSET;
97 _dbg_assert_(KERNEL, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]);
98 return static_cast<T*>(pool[realHandle]);
99 }
100
101 template <class T, typename ArgT>
102 void Iterate(bool func(T*, ArgT), ArgT arg) {
103 int type = T::GetStaticIDType();
104 for (int i = 0; i < MAX_COUNT; i++)
105 {
106 if (!occupied[i])
107 continue;
108 T* t = static_cast<T*>(pool[i]);
109 if (t->GetIDType() == type) {
110 if (!func(t, arg))
111 break;
112 }
113 }
114 }
115
116 bool GetIDType(Handle handle, HandleType* type) const {
117 if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) ||
118 !occupied[handle - HANDLE_OFFSET]) {
119 ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
120 return false;
121 }
122 Object* t = pool[handle - HANDLE_OFFSET];
123 *type = t->GetHandleType();
124 return true;
125 }
126
127 Object* &operator [](Handle handle);
128 void List();
129 void Clear();
130 int GetCount();
131
132private:
133
134 enum {
135 MAX_COUNT = 0x1000,
136 HANDLE_OFFSET = 0x100,
137 INITIAL_NEXT_ID = 0x10,
138 };
139
140 Object* pool[MAX_COUNT];
141 bool occupied[MAX_COUNT];
142 int next_id;
143};
144
145extern ObjectPool g_object_pool;
146
147/**
148 * Loads executable stored at specified address
149 * @entry_point Entry point in memory of loaded executable
150 * @return True on success, otherwise false
151 */
152bool LoadExec(u32 entry_point);
153
154} // namespace
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
new file mode 100644
index 000000000..019efbc78
--- /dev/null
+++ b/src/core/hle/kernel/mutex.cpp
@@ -0,0 +1,132 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <map>
6#include <vector>
7
8#include "common/common.h"
9
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/thread.h"
12
13namespace Kernel {
14
15class Mutex : public Object {
16public:
17 const char* GetTypeName() { return "Mutex"; }
18
19 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
20 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; }
21
22 bool initial_locked; ///< Initial lock state when mutex was created
23 bool locked; ///< Current locked state
24 Handle lock_thread; ///< Handle to thread that currently has mutex
25 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
26};
27
28////////////////////////////////////////////////////////////////////////////////////////////////////
29
30typedef std::multimap<Handle, Handle> MutexMap;
31static MutexMap g_mutex_held_locks;
32
33void MutexAcquireLock(Mutex* mutex, Handle thread) {
34 g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
35 mutex->lock_thread = thread;
36}
37
38void MutexAcquireLock(Mutex* mutex) {
39 Handle thread = GetCurrentThreadHandle();
40 MutexAcquireLock(mutex, thread);
41}
42
43void MutexEraseLock(Mutex* mutex) {
44 Handle handle = mutex->GetHandle();
45 auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
46 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
47 if ((*iter).second == handle) {
48 g_mutex_held_locks.erase(iter);
49 break;
50 }
51 }
52 mutex->lock_thread = -1;
53}
54
55bool LockMutex(Mutex* mutex) {
56 // Mutex alread locked?
57 if (mutex->locked) {
58 return false;
59 }
60 MutexAcquireLock(mutex);
61 return true;
62}
63
64bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
65 MutexAcquireLock(mutex, thread);
66 Kernel::ResumeThreadFromWait(thread);
67 return true;
68}
69
70bool ReleaseMutex(Mutex* mutex) {
71 MutexEraseLock(mutex);
72 bool woke_threads = false;
73 auto iter = mutex->waiting_threads.begin();
74
75 // Find the next waiting thread for the mutex...
76 while (!woke_threads && !mutex->waiting_threads.empty()) {
77 woke_threads |= ReleaseMutexForThread(mutex, *iter);
78 mutex->waiting_threads.erase(iter);
79 }
80 // Reset mutex lock thread handle, nothing is waiting
81 if (!woke_threads) {
82 mutex->locked = false;
83 mutex->lock_thread = -1;
84 }
85 return woke_threads;
86}
87
88/**
89 * Releases a mutex
90 * @param handle Handle to mutex to release
91 */
92Result ReleaseMutex(Handle handle) {
93 Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle);
94 if (!ReleaseMutex(mutex)) {
95 return -1;
96 }
97 return 0;
98}
99
100/**
101 * Creates a mutex
102 * @param handle Reference to handle for the newly created mutex
103 * @param initial_locked Specifies if the mutex should be locked initially
104 */
105Mutex* CreateMutex(Handle& handle, bool initial_locked) {
106 Mutex* mutex = new Mutex;
107 handle = Kernel::g_object_pool.Create(mutex);
108
109 mutex->locked = mutex->initial_locked = initial_locked;
110
111 // Acquire mutex with current thread if initialized as locked...
112 if (mutex->locked) {
113 MutexAcquireLock(mutex);
114
115 // Otherwise, reset lock thread handle
116 } else {
117 mutex->lock_thread = -1;
118 }
119 return mutex;
120}
121
122/**
123 * Creates a mutex
124 * @param initial_locked Specifies if the mutex should be locked initially
125 */
126Handle CreateMutex(bool initial_locked) {
127 Handle handle;
128 Mutex* mutex = CreateMutex(handle, initial_locked);
129 return handle;
130}
131
132} // namespace
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
new file mode 100644
index 000000000..871e2e562
--- /dev/null
+++ b/src/core/hle/kernel/mutex.h
@@ -0,0 +1,26 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/hle/kernel/kernel.h"
10
11namespace Kernel {
12
13/**
14 * Releases a mutex
15 * @param handle Handle to mutex to release
16 */
17Result ReleaseMutex(Handle handle);
18
19/**
20 * Creates a mutex
21 * @param handle Reference to handle for the newly created mutex
22 * @param initial_locked Specifies if the mutex should be locked initially
23 */
24Handle CreateMutex(bool initial_locked);
25
26} // namespace
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
new file mode 100644
index 000000000..bf4c8353c
--- /dev/null
+++ b/src/core/hle/kernel/thread.cpp
@@ -0,0 +1,323 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <stdio.h>
6
7#include <list>
8#include <vector>
9#include <map>
10#include <string>
11
12#include "common/common.h"
13#include "common/thread_queue_list.h"
14
15#include "core/core.h"
16#include "core/mem_map.h"
17#include "core/hle/hle.h"
18#include "core/hle/svc.h"
19#include "core/hle/kernel/kernel.h"
20#include "core/hle/kernel/thread.h"
21
22namespace Kernel {
23
24class Thread : public Kernel::Object {
25public:
26
27 const char* GetName() { return name; }
28 const char* GetTypeName() { return "Thread"; }
29
30 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
31 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; }
32
33 inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
34 inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; }
35 inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; }
36 inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
37 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
38
39 ThreadContext context;
40
41 u32 status;
42 u32 entry_point;
43 u32 stack_top;
44 u32 stack_size;
45
46 s32 initial_priority;
47 s32 current_priority;
48
49 s32 processor_id;
50
51 WaitType wait_type;
52
53 char name[Kernel::MAX_NAME_LENGTH + 1];
54};
55
56// Lists all thread ids that aren't deleted/etc.
57std::vector<Handle> g_thread_queue;
58
59// Lists only ready thread ids.
60Common::ThreadQueueList<Handle> g_thread_ready_queue;
61
62Handle g_current_thread_handle;
63Thread* g_current_thread;
64
65
66/// Gets the current thread
67inline Thread* GetCurrentThread() {
68 return g_current_thread;
69}
70
71/// Gets the current thread handle
72Handle GetCurrentThreadHandle() {
73 return GetCurrentThread()->GetHandle();
74}
75
76/// Sets the current thread
77inline void SetCurrentThread(Thread* t) {
78 g_current_thread = t;
79 g_current_thread_handle = t->GetHandle();
80}
81
82/// Saves the current CPU context
83void SaveContext(ThreadContext& ctx) {
84 Core::g_app_core->SaveContext(ctx);
85}
86
87/// Loads a CPU context
88void LoadContext(ThreadContext& ctx) {
89 Core::g_app_core->LoadContext(ctx);
90}
91
92/// Resets a thread
93void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
94 memset(&t->context, 0, sizeof(ThreadContext));
95
96 t->context.cpu_registers[0] = arg;
97 t->context.pc = t->entry_point;
98 t->context.sp = t->stack_top;
99 t->context.cpsr = 0x1F; // Usermode
100
101 if (t->current_priority < lowest_priority) {
102 t->current_priority = t->initial_priority;
103 }
104
105 t->wait_type = WAITTYPE_NONE;
106}
107
108/// Change a thread to "ready" state
109void ChangeReadyState(Thread* t, bool ready) {
110 Handle handle = t->GetHandle();
111 if (t->IsReady()) {
112 if (!ready) {
113 g_thread_ready_queue.remove(t->current_priority, handle);
114 }
115 } else if (ready) {
116 if (t->IsRunning()) {
117 g_thread_ready_queue.push_front(t->current_priority, handle);
118 } else {
119 g_thread_ready_queue.push_back(t->current_priority, handle);
120 }
121 t->status = THREADSTATUS_READY;
122 }
123}
124
125/// Changes a threads state
126void ChangeThreadState(Thread* t, ThreadStatus new_status) {
127 if (!t || t->status == new_status) {
128 return;
129 }
130 ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);
131 t->status = new_status;
132
133 if (new_status == THREADSTATUS_WAIT) {
134 if (t->wait_type == WAITTYPE_NONE) {
135 printf("ERROR: Waittype none not allowed here\n");
136 }
137 }
138}
139
140/// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields)
141void CallThread(Thread* t) {
142 // Stop waiting
143 if (t->wait_type != WAITTYPE_NONE) {
144 t->wait_type = WAITTYPE_NONE;
145 }
146 ChangeThreadState(t, THREADSTATUS_READY);
147}
148
149/// Switches CPU context to that of the specified thread
150void SwitchContext(Thread* t) {
151 Thread* cur = GetCurrentThread();
152
153 // Save context for current thread
154 if (cur) {
155 SaveContext(cur->context);
156
157 if (cur->IsRunning()) {
158 ChangeReadyState(cur, true);
159 }
160 }
161 // Load context of new thread
162 if (t) {
163 SetCurrentThread(t);
164 ChangeReadyState(t, false);
165 t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
166 t->wait_type = WAITTYPE_NONE;
167 LoadContext(t->context);
168 } else {
169 SetCurrentThread(NULL);
170 }
171}
172
173/// Gets the next thread that is ready to be run by priority
174Thread* NextThread() {
175 Handle next;
176 Thread* cur = GetCurrentThread();
177
178 if (cur && cur->IsRunning()) {
179 next = g_thread_ready_queue.pop_first_better(cur->current_priority);
180 } else {
181 next = g_thread_ready_queue.pop_first();
182 }
183 if (next == 0) {
184 return NULL;
185 }
186 return Kernel::g_object_pool.GetFast<Thread>(next);
187}
188
189/// Puts the current thread in the wait state for the given type
190void WaitCurrentThread(WaitType wait_type) {
191 Thread* t = GetCurrentThread();
192 t->wait_type = wait_type;
193 ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
194}
195
196/// Resumes a thread from waiting by marking it as "ready"
197void ResumeThreadFromWait(Handle handle) {
198 u32 error;
199 Thread* t = Kernel::g_object_pool.Get<Thread>(handle, error);
200 if (t) {
201 t->status &= ~THREADSTATUS_WAIT;
202 if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
203 ChangeReadyState(t, true);
204 }
205 }
206}
207
208/// Creates a new thread
209Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority,
210 s32 processor_id, u32 stack_top, int stack_size) {
211
212 _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
213 "CreateThread priority=%d, outside of allowable range!", priority)
214
215 Thread* t = new Thread;
216
217 handle = Kernel::g_object_pool.Create(t);
218
219 g_thread_queue.push_back(handle);
220 g_thread_ready_queue.prepare(priority);
221
222 t->status = THREADSTATUS_DORMANT;
223 t->entry_point = entry_point;
224 t->stack_top = stack_top;
225 t->stack_size = stack_size;
226 t->initial_priority = t->current_priority = priority;
227 t->processor_id = processor_id;
228 t->wait_type = WAITTYPE_NONE;
229
230 strncpy(t->name, name, Kernel::MAX_NAME_LENGTH);
231 t->name[Kernel::MAX_NAME_LENGTH] = '\0';
232
233 return t;
234}
235
236/// Creates a new thread - wrapper for external user
237Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
238 u32 stack_top, int stack_size) {
239 if (name == NULL) {
240 ERROR_LOG(KERNEL, "CreateThread(): NULL name");
241 return -1;
242 }
243 if ((u32)stack_size < 0x200) {
244 ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name,
245 stack_size);
246 return -1;
247 }
248 if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
249 s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
250 WARN_LOG(KERNEL, "CreateThread(name=%s): invalid priority=0x%08X, clamping to %08X",
251 name, priority, new_priority);
252 // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
253 // validity of this
254 priority = new_priority;
255 }
256 if (!Memory::GetPointer(entry_point)) {
257 ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid entry %08x", name, entry_point);
258 return -1;
259 }
260 Handle handle;
261 Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
262 stack_size);
263
264 ResetThread(t, arg, 0);
265
266 HLE::EatCycles(32000);
267
268 // This won't schedule to the new thread, but it may to one woken from eating cycles.
269 // Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
270 HLE::ReSchedule("thread created");
271
272 CallThread(t);
273
274 return handle;
275}
276
277/// Sets up the primary application thread
278Handle SetupMainThread(s32 priority, int stack_size) {
279 Handle handle;
280
281 // Initialize new "main" thread
282 Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
283 THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
284
285 ResetThread(t, 0, 0);
286
287 // If running another thread already, set it to "ready" state
288 Thread* cur = GetCurrentThread();
289 if (cur && cur->IsRunning()) {
290 ChangeReadyState(cur, true);
291 }
292
293 // Run new "main" thread
294 SetCurrentThread(t);
295 t->status = THREADSTATUS_RUNNING;
296 LoadContext(t->context);
297
298 return handle;
299}
300
301/// Reschedules to the next available thread (call after current thread is suspended)
302void Reschedule() {
303 Thread* prev = GetCurrentThread();
304 Thread* next = NextThread();
305 if (next > 0) {
306 SwitchContext(next);
307
308 // Hack - automatically change previous thread (which would have been in "wait" state) to
309 // "ready" state, so that we can immediately resume to it when new thread yields. FixMe to
310 // actually wait for whatever event it is supposed to be waiting on.
311 ChangeReadyState(prev, true);
312 }
313}
314
315////////////////////////////////////////////////////////////////////////////////////////////////////
316
317void ThreadingInit() {
318}
319
320void ThreadingShutdown() {
321}
322
323} // namespace
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
new file mode 100644
index 000000000..9628f165d
--- /dev/null
+++ b/src/core/hle/kernel/thread.h
@@ -0,0 +1,74 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h"
9
10enum ThreadPriority {
11 THREADPRIO_HIGHEST = 0, ///< Highest thread priority
12 THREADPRIO_DEFAULT = 16, ///< Default thread priority for userland apps
13 THREADPRIO_LOW = 31, ///< Low range of thread priority for userland apps
14 THREADPRIO_LOWEST = 63, ///< Thread priority max checked by svcCreateThread
15};
16
17enum ThreadProcessorId {
18 THREADPROCESSORID_0 = 0xFFFFFFFE, ///< Enables core appcode
19 THREADPROCESSORID_1 = 0xFFFFFFFD, ///< Enables core syscore
20 THREADPROCESSORID_ALL = 0xFFFFFFFC, ///< Enables both cores
21};
22
23enum ThreadStatus {
24 THREADSTATUS_RUNNING = 1,
25 THREADSTATUS_READY = 2,
26 THREADSTATUS_WAIT = 4,
27 THREADSTATUS_SUSPEND = 8,
28 THREADSTATUS_DORMANT = 16,
29 THREADSTATUS_DEAD = 32,
30 THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
31};
32
33enum WaitType {
34 WAITTYPE_NONE,
35 WAITTYPE_SLEEP,
36 WAITTYPE_SEMA,
37 WAITTYPE_EVENTFLAG,
38 WAITTYPE_THREADEND,
39 WAITTYPE_VBLANK,
40 WAITTYPE_MUTEX,
41 WAITTYPE_SYNCH,
42};
43
44namespace Kernel {
45
46/// Creates a new thread - wrapper for external user
47Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
48 u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE);
49
50/// Sets up the primary application thread
51Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
52
53/// Reschedules to the next available thread (call after current thread is suspended)
54void Reschedule();
55
56/// Puts the current thread in the wait state for the given type
57void WaitCurrentThread(WaitType wait_type);
58
59/// Resumes a thread from waiting by marking it as "ready"
60void ResumeThreadFromWait(Handle handle);
61
62/// Gets the current thread handle
63Handle GetCurrentThreadHandle();
64
65/// Put current thread in a wait state - on WaitSynchronization
66void WaitThread_Synchronization();
67
68/// Initialize threading
69void ThreadingInit();
70
71/// Shutdown threading
72void ThreadingShutdown();
73
74} // namespace
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt.cpp
index 709ac5493..32759a087 100644
--- a/src/core/hle/service/apt.cpp
+++ b/src/core/hle/service/apt.cpp
@@ -3,9 +3,10 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
6#include "common/log.h" 6#include "common/common.h"
7 7
8#include "core/hle/hle.h" 8#include "core/hle/hle.h"
9#include "core/hle/kernel/mutex.h"
9#include "core/hle/service/apt.h" 10#include "core/hle/service/apt.h"
10 11
11//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -19,7 +20,10 @@ void Initialize(Service::Interface* self) {
19 20
20void GetLockHandle(Service::Interface* self) { 21void GetLockHandle(Service::Interface* self) {
21 u32* cmd_buff = Service::GetCommandBuffer(); 22 u32* cmd_buff = Service::GetCommandBuffer();
22 cmd_buff[5] = 0x00000000; // TODO: This should be an actual mutex handle 23 u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
24 cmd_buff[1] = 0; // No error
25 cmd_buff[5] = Kernel::CreateMutex(false);
26 DEBUG_LOG(KERNEL, "APT_U::GetLockHandle called : created handle 0x%08X", cmd_buff[5]);
23} 27}
24 28
25const Interface::FunctionInfo FunctionTable[] = { 29const Interface::FunctionInfo FunctionTable[] = {
diff --git a/src/core/hle/service/apt.h b/src/core/hle/service/apt.h
index 4c7dd07e7..dca3097ed 100644
--- a/src/core/hle/service/apt.h
+++ b/src/core/hle/service/apt.h
@@ -29,7 +29,7 @@ public:
29 * Gets the string port name used by CTROS for the service 29 * Gets the string port name used by CTROS for the service
30 * @return Port name of service 30 * @return Port name of service
31 */ 31 */
32 std::string GetPortName() const { 32 const char *GetPortName() const {
33 return "APT:U"; 33 return "APT:U";
34 } 34 }
35}; 35};
diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp
index 12c7dabcd..50cee2c41 100644
--- a/src/core/hle/service/gsp.cpp
+++ b/src/core/hle/service/gsp.cpp
@@ -27,7 +27,7 @@ union GX_CmdBufferHeader {
27 // <=15 when writing a command to shared memory. This is incremented by the application when 27 // <=15 when writing a command to shared memory. This is incremented by the application when
28 // writing a command to shared memory, after increasing this value TriggerCmdReqQueue is only 28 // writing a command to shared memory, after increasing this value TriggerCmdReqQueue is only
29 // used if this field is value 1. 29 // used if this field is value 1.
30 BitField<8,8,u32> number_commands; 30 BitField<8,8,u32> number_commands;
31 31
32}; 32};
33 33
@@ -101,9 +101,7 @@ void RegisterInterruptRelayQueue(Service::Interface* self) {
101 u32* cmd_buff = Service::GetCommandBuffer(); 101 u32* cmd_buff = Service::GetCommandBuffer();
102 u32 flags = cmd_buff[1]; 102 u32 flags = cmd_buff[1];
103 u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling 103 u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling
104
105 cmd_buff[2] = g_thread_id; // ThreadID 104 cmd_buff[2] = g_thread_id; // ThreadID
106 cmd_buff[4] = self->NewHandle();
107} 105}
108 106
109/// This triggers handling of the GX command written to the command buffer in shared memory. 107/// This triggers handling of the GX command written to the command buffer in shared memory.
diff --git a/src/core/hle/service/gsp.h b/src/core/hle/service/gsp.h
index 5ba09ab70..eb5786cd1 100644
--- a/src/core/hle/service/gsp.h
+++ b/src/core/hle/service/gsp.h
@@ -23,7 +23,7 @@ public:
23 * Gets the string port name used by CTROS for the service 23 * Gets the string port name used by CTROS for the service
24 * @return Port name of service 24 * @return Port name of service
25 */ 25 */
26 std::string GetPortName() const { 26 const char *GetPortName() const {
27 return "gsp::Gpu"; 27 return "gsp::Gpu";
28 } 28 }
29 29
diff --git a/src/core/hle/service/hid.h b/src/core/hle/service/hid.h
index b17fcfa86..81c29eb2e 100644
--- a/src/core/hle/service/hid.h
+++ b/src/core/hle/service/hid.h
@@ -25,7 +25,7 @@ public:
25 * Gets the string port name used by CTROS for the service 25 * Gets the string port name used by CTROS for the service
26 * @return Port name of service 26 * @return Port name of service
27 */ 27 */
28 std::string GetPortName() const { 28 const char *GetPortName() const {
29 return "hid:USER"; 29 return "hid:USER";
30 } 30 }
31 31
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index e6605a398..08d0c43ff 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -7,12 +7,15 @@
7#include "common/string_util.h" 7#include "common/string_util.h"
8 8
9#include "core/hle/hle.h" 9#include "core/hle/hle.h"
10
10#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
11#include "core/hle/service/apt.h" 12#include "core/hle/service/apt.h"
12#include "core/hle/service/gsp.h" 13#include "core/hle/service/gsp.h"
13#include "core/hle/service/hid.h" 14#include "core/hle/service/hid.h"
14#include "core/hle/service/srv.h" 15#include "core/hle/service/srv.h"
15 16
17#include "core/hle/kernel/kernel.h"
18
16namespace Service { 19namespace Service {
17 20
18Manager* g_manager = NULL; ///< Service manager 21Manager* g_manager = NULL; ///< Service manager
@@ -31,32 +34,21 @@ Manager::~Manager() {
31 34
32/// Add a service to the manager (does not create it though) 35/// Add a service to the manager (does not create it though)
33void Manager::AddService(Interface* service) { 36void Manager::AddService(Interface* service) {
34 int index = m_services.size(); 37 m_port_map[service->GetPortName()] = Kernel::g_object_pool.Create(service);
35 u32 new_uid = GetUIDFromIndex(index);
36
37 m_services.push_back(service); 38 m_services.push_back(service);
38
39 m_port_map[service->GetPortName()] = new_uid;
40 service->m_uid = new_uid;
41} 39}
42 40
43/// Removes a service from the manager, also frees memory 41/// Removes a service from the manager, also frees memory
44void Manager::DeleteService(std::string port_name) { 42void Manager::DeleteService(std::string port_name) {
45 auto service = FetchFromPortName(port_name); 43 Interface* service = FetchFromPortName(port_name);
46 44 m_services.erase(std::remove(m_services.begin(), m_services.end(), service), m_services.end());
47 m_services.erase(m_services.begin() + GetIndexFromUID(service->m_uid));
48 m_port_map.erase(port_name); 45 m_port_map.erase(port_name);
49
50 delete service; 46 delete service;
51} 47}
52 48
53/// Get a Service Interface from its UID 49/// Get a Service Interface from its Handle
54Interface* Manager::FetchFromUID(u32 uid) { 50Interface* Manager::FetchFromHandle(Handle handle) {
55 int index = GetIndexFromUID(uid); 51 return Kernel::g_object_pool.GetFast<Interface>(handle);
56 if (index < (int)m_services.size()) {
57 return m_services[index];
58 }
59 return NULL;
60} 52}
61 53
62/// Get a Service Interface from its port 54/// Get a Service Interface from its port
@@ -65,7 +57,7 @@ Interface* Manager::FetchFromPortName(std::string port_name) {
65 if (itr == m_port_map.end()) { 57 if (itr == m_port_map.end()) {
66 return NULL; 58 return NULL;
67 } 59 }
68 return FetchFromUID(itr->second); 60 return FetchFromHandle(itr->second);
69} 61}
70 62
71 63
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index b260a290a..fab51753f 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -4,22 +4,22 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
7#include <vector> 8#include <vector>
8#include <map> 9#include <map>
9#include <string> 10#include <string>
10 11
11#include "common/common.h" 12#include "common/common.h"
12#include "common/common_types.h"
13#include "core/mem_map.h" 13#include "core/mem_map.h"
14#include "core/hle/syscall.h" 14
15#include "core/hle/kernel/kernel.h"
16#include "core/hle/svc.h"
15 17
16//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
17// Namespace Service 19// Namespace Service
18 20
19namespace Service { 21namespace Service {
20 22
21typedef s32 NativeUID; ///< Native handle for a service
22
23static const int kMaxPortSize = 0x08; ///< Maximum size of a port name (8 characters) 23static const int kMaxPortSize = 0x08; ///< Maximum size of a port name (8 characters)
24static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header 24static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
25 25
@@ -35,15 +35,15 @@ inline static u32* GetCommandBuffer(const int offset=0) {
35class Manager; 35class Manager;
36 36
37/// Interface to a CTROS service 37/// Interface to a CTROS service
38class Interface : NonCopyable { 38class Interface : public Kernel::Object {
39 friend class Manager; 39 friend class Manager;
40public: 40public:
41
42 const char *GetName() { return GetPortName(); }
43 const char *GetTypeName() { return GetPortName(); }
41 44
42 Interface() { 45 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; }
43 } 46 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; }
44
45 virtual ~Interface() {
46 }
47 47
48 typedef void (*Function)(Interface*); 48 typedef void (*Function)(Interface*);
49 49
@@ -54,54 +54,43 @@ public:
54 }; 54 };
55 55
56 /** 56 /**
57 * Gets the UID for the serice
58 * @return UID of service in native format
59 */
60 NativeUID GetUID() const {
61 return (NativeUID)m_uid;
62 }
63
64 /**
65 * Gets the string name used by CTROS for a service 57 * Gets the string name used by CTROS for a service
66 * @return Port name of service 58 * @return Port name of service
67 */ 59 */
68 virtual std::string GetPortName() const { 60 virtual const char *GetPortName() const {
69 return "[UNKNOWN SERVICE PORT]"; 61 return "[UNKNOWN SERVICE PORT]";
70 } 62 }
71 63
72 /// Allocates a new handle for the service 64 /// Allocates a new handle for the service
73 Syscall::Handle NewHandle() { 65 Handle CreateHandle(Kernel::Object *obj) {
74 Syscall::Handle handle = (m_handles.size() << 16) | m_uid; 66 Handle handle = Kernel::g_object_pool.Create(obj);
75 m_handles.push_back(handle); 67 m_handles.push_back(handle);
76 return handle; 68 return handle;
77 } 69 }
78 70
79 /// Frees a handle from the service 71 /// Frees a handle from the service
80 void DeleteHandle(Syscall::Handle handle) { 72 template <class T>
81 for(auto iter = m_handles.begin(); iter != m_handles.end(); ++iter) { 73 void DeleteHandle(const Handle handle) {
82 if(*iter == handle) { 74 Kernel::g_object_pool.Destroy<T>(handle);
83 m_handles.erase(iter); 75 m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end());
84 break;
85 }
86 }
87 } 76 }
88 77
89 /** 78 /**
90 * Called when svcSendSyncRequest is called, loads command buffer and executes comand 79 * Called when svcSendSyncRequest is called, loads command buffer and executes comand
91 * @return Return result of svcSendSyncRequest passed back to user app 80 * @return Return result of svcSendSyncRequest passed back to user app
92 */ 81 */
93 Syscall::Result Sync() { 82 Result Sync() {
94 u32* cmd_buff = GetCommandBuffer(); 83 u32* cmd_buff = GetCommandBuffer();
95 auto itr = m_functions.find(cmd_buff[0]); 84 auto itr = m_functions.find(cmd_buff[0]);
96 85
97 if (itr == m_functions.end()) { 86 if (itr == m_functions.end()) {
98 ERROR_LOG(OSHLE, "Unknown/unimplemented function: port = %s, command = 0x%08X!", 87 ERROR_LOG(OSHLE, "Unknown/unimplemented function: port = %s, command = 0x%08X!",
99 GetPortName().c_str(), cmd_buff[0]); 88 GetPortName(), cmd_buff[0]);
100 return -1; 89 return -1;
101 } 90 }
102 if (itr->second.func == NULL) { 91 if (itr->second.func == NULL) {
103 ERROR_LOG(OSHLE, "Unimplemented function: port = %s, name = %s!", 92 ERROR_LOG(OSHLE, "Unimplemented function: port = %s, name = %s!",
104 GetPortName().c_str(), itr->second.name.c_str()); 93 GetPortName(), itr->second.name.c_str());
105 return -1; 94 return -1;
106 } 95 }
107 96
@@ -122,10 +111,10 @@ protected:
122 } 111 }
123 112
124private: 113private:
125 u32 m_uid; 114
126 115 std::vector<Handle> m_handles;
127 std::vector<Syscall::Handle> m_handles; 116 std::map<u32, FunctionInfo> m_functions;
128 std::map<u32, FunctionInfo> m_functions; 117
129}; 118};
130 119
131/// Simple class to manage accessing services from ports and UID handles 120/// Simple class to manage accessing services from ports and UID handles
@@ -143,25 +132,16 @@ public:
143 void DeleteService(std::string port_name); 132 void DeleteService(std::string port_name);
144 133
145 /// Get a Service Interface from its UID 134 /// Get a Service Interface from its UID
146 Interface* FetchFromUID(u32 uid); 135 Interface* FetchFromHandle(u32 uid);
147 136
148 /// Get a Service Interface from its port 137 /// Get a Service Interface from its port
149 Interface* FetchFromPortName(std::string port_name); 138 Interface* FetchFromPortName(std::string port_name);
150 139
151private: 140private:
152 141
153 /// Convert an index into m_services vector into a UID
154 static u32 GetUIDFromIndex(const int index) {
155 return index | 0x10000000;
156 }
157
158 /// Convert a UID into an index into m_services
159 static int GetIndexFromUID(const u32 uid) {
160 return uid & 0x0FFFFFFF;
161 }
162
163 std::vector<Interface*> m_services; 142 std::vector<Interface*> m_services;
164 std::map<std::string, u32> m_port_map; 143 std::map<std::string, u32> m_port_map;
144
165}; 145};
166 146
167/// Initialize ServiceManager 147/// Initialize ServiceManager
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 071741444..ff6da8f1c 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -16,18 +16,24 @@ void Initialize(Service::Interface* self) {
16 NOTICE_LOG(OSHLE, "SRV::Sync - Initialize"); 16 NOTICE_LOG(OSHLE, "SRV::Sync - Initialize");
17} 17}
18 18
19void GetProcSemaphore(Service::Interface* self) {
20 // Get process semaphore?
21 u32* cmd_buff = Service::GetCommandBuffer();
22 cmd_buff[3] = 0xDEADBEEF; // Return something... 0 == NULL, raises an exception
23}
24
19void GetServiceHandle(Service::Interface* self) { 25void GetServiceHandle(Service::Interface* self) {
20 Syscall::Result res = 0; 26 Result res = 0;
21 u32* cmd_buff = Service::GetCommandBuffer(); 27 u32* cmd_buff = Service::GetCommandBuffer();
22 28
23 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); 29 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize);
24 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); 30 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
25 31
26 NOTICE_LOG(OSHLE, "SRV::Sync - GetHandle - port: %s, handle: 0x%08X", port_name.c_str(), 32 NOTICE_LOG(OSHLE, "SRV::Sync - GetHandle - port: %s, handle: 0x%08X", port_name.c_str(),
27 service->GetUID()); 33 service->GetHandle());
28 34
29 if (NULL != service) { 35 if (NULL != service) {
30 cmd_buff[3] = service->GetUID(); 36 cmd_buff[3] = service->GetHandle();
31 } else { 37 } else {
32 ERROR_LOG(OSHLE, "Service %s does not exist", port_name.c_str()); 38 ERROR_LOG(OSHLE, "Service %s does not exist", port_name.c_str());
33 res = -1; 39 res = -1;
@@ -39,7 +45,7 @@ void GetServiceHandle(Service::Interface* self) {
39 45
40const Interface::FunctionInfo FunctionTable[] = { 46const Interface::FunctionInfo FunctionTable[] = {
41 {0x00010002, Initialize, "Initialize"}, 47 {0x00010002, Initialize, "Initialize"},
42 {0x00020000, NULL, "GetProcSemaphore"}, 48 {0x00020000, GetProcSemaphore, "GetProcSemaphore"},
43 {0x00030100, NULL, "RegisterService"}, 49 {0x00030100, NULL, "RegisterService"},
44 {0x000400C0, NULL, "UnregisterService"}, 50 {0x000400C0, NULL, "UnregisterService"},
45 {0x00050100, GetServiceHandle, "GetServiceHandle"}, 51 {0x00050100, GetServiceHandle, "GetServiceHandle"},
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 760c976b4..1e35032ba 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -22,7 +22,7 @@ public:
22 * Gets the string name used by CTROS for the service 22 * Gets the string name used by CTROS for the service
23 * @return Port name of service 23 * @return Port name of service
24 */ 24 */
25 std::string GetPortName() const { 25 const char *GetPortName() const {
26 return "srv:"; 26 return "srv:";
27 } 27 }
28 28
@@ -30,7 +30,7 @@ public:
30 * Called when svcSendSyncRequest is called, loads command buffer and executes comand 30 * Called when svcSendSyncRequest is called, loads command buffer and executes comand
31 * @return Return result of svcSendSyncRequest passed back to user app 31 * @return Return result of svcSendSyncRequest passed back to user app
32 */ 32 */
33 Syscall::Result Sync(); 33 Result Sync();
34 34
35}; 35};
36 36
diff --git a/src/core/hle/syscall.cpp b/src/core/hle/svc.cpp
index d47df6038..90c05cb74 100644
--- a/src/core/hle/syscall.cpp
+++ b/src/core/hle/svc.cpp
@@ -3,17 +3,25 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
6#include <string>
7
8#include "common/symbols.h"
6 9
7#include "core/mem_map.h" 10#include "core/mem_map.h"
8 11
12#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/mutex.h"
14#include "core/hle/kernel/thread.h"
15
9#include "core/hle/function_wrappers.h" 16#include "core/hle/function_wrappers.h"
10#include "core/hle/syscall.h" 17#include "core/hle/svc.h"
11#include "core/hle/service/service.h" 18#include "core/hle/service/service.h"
19#include "core/hle/kernel/thread.h"
12 20
13//////////////////////////////////////////////////////////////////////////////////////////////////// 21////////////////////////////////////////////////////////////////////////////////////////////////////
14// Namespace Syscall 22// Namespace SVC
15 23
16namespace Syscall { 24namespace SVC {
17 25
18enum ControlMemoryOperation { 26enum ControlMemoryOperation {
19 MEMORY_OPERATION_HEAP = 0x00000003, 27 MEMORY_OPERATION_HEAP = 0x00000003,
@@ -26,7 +34,8 @@ enum MapMemoryPermission {
26}; 34};
27 35
28/// Map application or GSP heap memory 36/// Map application or GSP heap memory
29Result ControlMemory(u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { 37Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
38 u32* outaddr = (u32*)_outaddr;
30 u32 virtual_address = 0x00000000; 39 u32 virtual_address = 0x00000000;
31 40
32 DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", 41 DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
@@ -48,7 +57,9 @@ Result ControlMemory(u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissi
48 default: 57 default:
49 ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); 58 ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation);
50 } 59 }
51 60 if (NULL != outaddr) {
61 *outaddr = virtual_address;
62 }
52 Core::g_app_core->SetReg(1, virtual_address); 63 Core::g_app_core->SetReg(1, virtual_address);
53 64
54 return 0; 65 return 0;
@@ -72,17 +83,20 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper
72 83
73/// Connect to an OS service given the port name, returns the handle to the port to out 84/// Connect to an OS service given the port name, returns the handle to the port to out
74Result ConnectToPort(void* out, const char* port_name) { 85Result ConnectToPort(void* out, const char* port_name) {
75
76 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); 86 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
77 Core::g_app_core->SetReg(1, service->GetUID()); 87 if (service) {
88 Core::g_app_core->SetReg(1, service->GetHandle());
89 } else {
90 PanicYesNo("ConnectToPort called port_name=%s, but it is not implemented!", port_name);
91 }
78 DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name); 92 DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name);
79 return 0; 93 return 0;
80} 94}
81 95
82/// Synchronize to an OS service 96/// Synchronize to an OS service
83Result SendSyncRequest(Handle session) { 97Result SendSyncRequest(Handle handle) {
84 DEBUG_LOG(SVC, "SendSyncRequest called session=0x%08X"); 98 DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X");
85 Service::Interface* service = Service::g_manager->FetchFromUID(session); 99 Service::Interface* service = Service::g_manager->FetchFromHandle(handle);
86 service->Sync(); 100 service->Sync();
87 return 0; 101 return 0;
88} 102}
@@ -95,10 +109,25 @@ Result CloseHandle(Handle handle) {
95} 109}
96 110
97/// Wait for a handle to synchronize, timeout after the specified nanoseconds 111/// Wait for a handle to synchronize, timeout after the specified nanoseconds
98Result WaitSynchronization1(Handle handle, s64 nanoseconds) { 112Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
99 // ImplementMe
100 DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", 113 DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d",
101 handle, nanoseconds); 114 handle, nano_seconds);
115 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
116 return 0;
117}
118
119/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
120Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) {
121 s32* out = (s32*)_out;
122 Handle* handles = (Handle*)_handles;
123
124 DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s",
125 handle_count, (wait_all ? "true" : "false"), nano_seconds);
126
127 for (u32 i = 0; i < handle_count; i++) {
128 DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]);
129 }
130 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
102 return 0; 131 return 0;
103} 132}
104 133
@@ -106,7 +135,7 @@ Result WaitSynchronization1(Handle handle, s64 nanoseconds) {
106Result CreateAddressArbiter(void* arbiter) { 135Result CreateAddressArbiter(void* arbiter) {
107 // ImplementMe 136 // ImplementMe
108 DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called"); 137 DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called");
109 Core::g_app_core->SetReg(1, 0xDEADBEEF); 138 Core::g_app_core->SetReg(1, 0xFABBDADD);
110 return 0; 139 return 0;
111} 140}
112 141
@@ -134,16 +163,79 @@ Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void*
134 return 0; 163 return 0;
135} 164}
136 165
137const HLE::FunctionDef Syscall_Table[] = { 166/// Creates a new thread
167Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) {
168 std::string name;
169 if (Symbols::HasSymbol(entry_point)) {
170 TSymbol symbol = Symbols::GetSymbol(entry_point);
171 name = symbol.name;
172 } else {
173 char buff[100];
174 sprintf(buff, "%s", "unknown-%08X", entry_point);
175 name = buff;
176 }
177
178 Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id,
179 stack_top);
180
181 Core::g_app_core->SetReg(1, thread);
182
183 DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
184 "threadpriority=0x%08X, processorid=0x%08X : created handle 0x%08X", entry_point,
185 name.c_str(), arg, stack_top, priority, processor_id, thread);
186
187 return 0;
188}
189
190/// Create a mutex
191Result CreateMutex(void* _mutex, u32 initial_locked) {
192 Handle* mutex = (Handle*)_mutex;
193 *mutex = Kernel::CreateMutex((initial_locked != 0));
194 Core::g_app_core->SetReg(1, *mutex);
195 DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s : created handle 0x%08X",
196 initial_locked ? "true" : "false", *mutex);
197 return 0;
198}
199
200/// Release a mutex
201Result ReleaseMutex(Handle handle) {
202 DEBUG_LOG(SVC, "ReleaseMutex called handle=0x%08X", handle);
203 Kernel::ReleaseMutex(handle);
204 return 0;
205}
206
207/// Get current thread ID
208Result GetThreadId(void* thread_id, u32 thread) {
209 DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread);
210 return 0;
211}
212
213/// Query memory
214Result QueryMemory(void *_info, void *_out, u32 addr) {
215 MemoryInfo* info = (MemoryInfo*) _info;
216 PageInfo* out = (PageInfo*) _out;
217 DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr);
218 return 0;
219}
220
221/// Create an event
222Result CreateEvent(void* _event, u32 reset_type) {
223 Handle* event = (Handle*)_event;
224 DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type);
225 Core::g_app_core->SetReg(1, 0xBADC0DE0);
226 return 0;
227}
228
229const HLE::FunctionDef SVC_Table[] = {
138 {0x00, NULL, "Unknown"}, 230 {0x00, NULL, "Unknown"},
139 {0x01, WrapI_UUUUU<ControlMemory>, "ControlMemory"}, 231 {0x01, WrapI_VUUUUU<ControlMemory>, "ControlMemory"},
140 {0x02, NULL, "QueryMemory"}, 232 {0x02, WrapI_VVU<QueryMemory>, "QueryMemory"},
141 {0x03, NULL, "ExitProcess"}, 233 {0x03, NULL, "ExitProcess"},
142 {0x04, NULL, "GetProcessAffinityMask"}, 234 {0x04, NULL, "GetProcessAffinityMask"},
143 {0x05, NULL, "SetProcessAffinityMask"}, 235 {0x05, NULL, "SetProcessAffinityMask"},
144 {0x06, NULL, "GetProcessIdealProcessor"}, 236 {0x06, NULL, "GetProcessIdealProcessor"},
145 {0x07, NULL, "SetProcessIdealProcessor"}, 237 {0x07, NULL, "SetProcessIdealProcessor"},
146 {0x08, NULL, "CreateThread"}, 238 {0x08, WrapI_UUUUU<CreateThread>, "CreateThread"},
147 {0x09, NULL, "ExitThread"}, 239 {0x09, NULL, "ExitThread"},
148 {0x0A, NULL, "SleepThread"}, 240 {0x0A, NULL, "SleepThread"},
149 {0x0B, NULL, "GetThreadPriority"}, 241 {0x0B, NULL, "GetThreadPriority"},
@@ -154,11 +246,11 @@ const HLE::FunctionDef Syscall_Table[] = {
154 {0x10, NULL, "SetThreadIdealProcessor"}, 246 {0x10, NULL, "SetThreadIdealProcessor"},
155 {0x11, NULL, "GetCurrentProcessorNumber"}, 247 {0x11, NULL, "GetCurrentProcessorNumber"},
156 {0x12, NULL, "Run"}, 248 {0x12, NULL, "Run"},
157 {0x13, NULL, "CreateMutex"}, 249 {0x13, WrapI_VU<CreateMutex>, "CreateMutex"},
158 {0x14, NULL, "ReleaseMutex"}, 250 {0x14, WrapI_U<ReleaseMutex>, "ReleaseMutex"},
159 {0x15, NULL, "CreateSemaphore"}, 251 {0x15, NULL, "CreateSemaphore"},
160 {0x16, NULL, "ReleaseSemaphore"}, 252 {0x16, NULL, "ReleaseSemaphore"},
161 {0x17, NULL, "CreateEvent"}, 253 {0x17, WrapI_VU<CreateEvent>, "CreateEvent"},
162 {0x18, NULL, "SignalEvent"}, 254 {0x18, NULL, "SignalEvent"},
163 {0x19, NULL, "ClearEvent"}, 255 {0x19, NULL, "ClearEvent"},
164 {0x1A, NULL, "CreateTimer"}, 256 {0x1A, NULL, "CreateTimer"},
@@ -172,7 +264,7 @@ const HLE::FunctionDef Syscall_Table[] = {
172 {0x22, NULL, "ArbitrateAddress"}, 264 {0x22, NULL, "ArbitrateAddress"},
173 {0x23, WrapI_U<CloseHandle>, "CloseHandle"}, 265 {0x23, WrapI_U<CloseHandle>, "CloseHandle"},
174 {0x24, WrapI_US64<WaitSynchronization1>, "WaitSynchronization1"}, 266 {0x24, WrapI_US64<WaitSynchronization1>, "WaitSynchronization1"},
175 {0x25, NULL, "WaitSynchronizationN"}, 267 {0x25, WrapI_VVUUS64<WaitSynchronizationN>, "WaitSynchronizationN"},
176 {0x26, NULL, "SignalAndWait"}, 268 {0x26, NULL, "SignalAndWait"},
177 {0x27, NULL, "DuplicateHandle"}, 269 {0x27, NULL, "DuplicateHandle"},
178 {0x28, NULL, "GetSystemTick"}, 270 {0x28, NULL, "GetSystemTick"},
@@ -190,7 +282,7 @@ const HLE::FunctionDef Syscall_Table[] = {
190 {0x34, NULL, "OpenThread"}, 282 {0x34, NULL, "OpenThread"},
191 {0x35, NULL, "GetProcessId"}, 283 {0x35, NULL, "GetProcessId"},
192 {0x36, NULL, "GetProcessIdOfThread"}, 284 {0x36, NULL, "GetProcessIdOfThread"},
193 {0x37, NULL, "GetThreadId"}, 285 {0x37, WrapI_VU<GetThreadId>, "GetThreadId"},
194 {0x38, WrapI_VU<GetResourceLimit>, "GetResourceLimit"}, 286 {0x38, WrapI_VU<GetResourceLimit>, "GetResourceLimit"},
195 {0x39, NULL, "GetResourceLimitLimitValues"}, 287 {0x39, NULL, "GetResourceLimitLimitValues"},
196 {0x3A, WrapI_VUVI<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, 288 {0x3A, WrapI_VUVI<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"},
@@ -264,7 +356,7 @@ const HLE::FunctionDef Syscall_Table[] = {
264}; 356};
265 357
266void Register() { 358void Register() {
267 HLE::RegisterModule("SyscallTable", ARRAY_SIZE(Syscall_Table), Syscall_Table); 359 HLE::RegisterModule("SVC_Table", ARRAY_SIZE(SVC_Table), SVC_Table);
268} 360}
269 361
270} // namespace 362} // namespace
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
new file mode 100644
index 000000000..5c35977d1
--- /dev/null
+++ b/src/core/hle/svc.h
@@ -0,0 +1,48 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// SVC types
11
12struct MemoryInfo {
13 u32 base_address;
14 u32 size;
15 u32 permission;
16 u32 state;
17};
18
19struct PageInfo {
20 u32 flags;
21};
22
23struct ThreadContext {
24 u32 cpu_registers[13];
25 u32 sp;
26 u32 lr;
27 u32 pc;
28 u32 cpsr;
29 u32 fpu_registers[32];
30 u32 fpscr;
31 u32 fpexc;
32};
33
34enum ResetType {
35 RESETTYPE_ONESHOT,
36 RESETTYPE_STICKY,
37 RESETTYPE_PULSE,
38 RESETTYPE_MAX_BIT = (1u << 31),
39};
40
41////////////////////////////////////////////////////////////////////////////////////////////////////
42// Namespace SVC
43
44namespace SVC {
45
46void Register();
47
48} // namespace
diff --git a/src/core/hle/syscall.h b/src/core/hle/syscall.h
deleted file mode 100644
index 7a94e0136..000000000
--- a/src/core/hle/syscall.h
+++ /dev/null
@@ -1,19 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace Syscall
11
12namespace Syscall {
13
14typedef u32 Handle;
15typedef s32 Result;
16
17void Register();
18
19} // namespace