summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/citra.cpp9
-rw-r--r--src/citra_qt/main.cpp2
-rw-r--r--src/common/common.vcxproj1
-rw-r--r--src/common/common.vcxproj.filters1
-rw-r--r--src/common/common_funcs.h5
-rw-r--r--src/common/log.h4
-rw-r--r--src/common/log_manager.cpp4
-rw-r--r--src/common/thread_queue_list.h216
-rw-r--r--src/core/CMakeLists.txt10
-rw-r--r--src/core/arm/arm_interface.h30
-rw-r--r--src/core/arm/interpreter/arm_interpreter.cpp91
-rw-r--r--src/core/arm/interpreter/arm_interpreter.h20
-rw-r--r--src/core/arm/interpreter/armdefs.h4
-rw-r--r--src/core/arm/interpreter/armemu.cpp5
-rw-r--r--src/core/arm/interpreter/arminit.cpp3
-rw-r--r--src/core/arm/interpreter/vfp/vfp.h2
-rw-r--r--src/core/core.cpp7
-rw-r--r--src/core/core.vcxproj10
-rw-r--r--src/core/core.vcxproj.filters39
-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
-rw-r--r--src/core/hw/lcd.cpp4
-rw-r--r--src/core/loader.cpp20
-rw-r--r--src/core/mem_map.cpp3
-rw-r--r--src/core/mem_map.h7
-rw-r--r--src/core/mem_map_funcs.cpp14
45 files changed, 1571 insertions, 195 deletions
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index 6f3bc6f84..5a8642d1b 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -24,7 +24,14 @@ int __cdecl main(int argc, char **argv) {
24 24
25 System::Init(emu_window); 25 System::Init(emu_window);
26 26
27 std::string boot_filename = "homebrew.elf"; 27 std::string boot_filename;
28
29 if (argc < 2) {
30 ERROR_LOG(BOOT, "Failed to load ROM: No ROM specified");
31 }
32 else {
33 boot_filename = argv[1];
34 }
28 std::string error_str; 35 std::string error_str;
29 36
30 bool res = Loader::LoadFile(boot_filename, &error_str); 37 bool res = Loader::LoadFile(boot_filename, &error_str);
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 76e0c68c3..9be982909 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -142,7 +142,7 @@ void GMainWindow::BootGame(const char* filename)
142 142
143void GMainWindow::OnMenuLoadFile() 143void GMainWindow::OnMenuLoadFile()
144{ 144{
145 QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS homebrew (*.elf *.dat *.bin)")); 145 QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS homebrew (*.elf *.axf *.dat *.bin)"));
146 if (filename.size()) 146 if (filename.size())
147 BootGame(filename.toLatin1().data()); 147 BootGame(filename.toLatin1().data());
148} 148}
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
index 5dc6ff790..86295a480 100644
--- a/src/common/common.vcxproj
+++ b/src/common/common.vcxproj
@@ -190,6 +190,7 @@
190 <ClInclude Include="swap.h" /> 190 <ClInclude Include="swap.h" />
191 <ClInclude Include="symbols.h" /> 191 <ClInclude Include="symbols.h" />
192 <ClInclude Include="thread.h" /> 192 <ClInclude Include="thread.h" />
193 <ClInclude Include="thread_queue_list.h" />
193 <ClInclude Include="thunk.h" /> 194 <ClInclude Include="thunk.h" />
194 <ClInclude Include="timer.h" /> 195 <ClInclude Include="timer.h" />
195 <ClInclude Include="utf8.h" /> 196 <ClInclude Include="utf8.h" />
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
index 268730228..84cfa8837 100644
--- a/src/common/common.vcxproj.filters
+++ b/src/common/common.vcxproj.filters
@@ -40,6 +40,7 @@
40 <ClInclude Include="symbols.h" /> 40 <ClInclude Include="symbols.h" />
41 <ClInclude Include="scm_rev.h" /> 41 <ClInclude Include="scm_rev.h" />
42 <ClInclude Include="bit_field.h" /> 42 <ClInclude Include="bit_field.h" />
43 <ClInclude Include="thread_queue_list.h" />
43 </ItemGroup> 44 </ItemGroup>
44 <ItemGroup> 45 <ItemGroup>
45 <ClCompile Include="break_points.cpp" /> 46 <ClCompile Include="break_points.cpp" />
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index f8d10eb3e..dca4dc47f 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -22,6 +22,11 @@ template<> struct CompileTimeAssert<true> {};
22#define b32(x) (b16(x) | (b16(x) >>16) ) 22#define b32(x) (b16(x) | (b16(x) >>16) )
23#define ROUND_UP_POW2(x) (b32(x - 1) + 1) 23#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
24 24
25#define MIN(a, b) ((a)<(b)?(a):(b))
26#define MAX(a, b) ((a)>(b)?(a):(b))
27
28#define CLAMP(x, min, max) (((x) > max) ? max : (((x) < min) ? min : (x)))
29
25#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 30#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
26 31
27#ifndef _WIN32 32#ifndef _WIN32
diff --git a/src/common/log.h b/src/common/log.h
index d95f51f56..8b39b03a1 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -5,6 +5,8 @@
5#ifndef _LOG_H_ 5#ifndef _LOG_H_
6#define _LOG_H_ 6#define _LOG_H_
7 7
8#define LOGGING
9
8#define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and OSReports. 10#define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and OSReports.
9#define ERROR_LEVEL 2 // Critical errors 11#define ERROR_LEVEL 2 // Critical errors
10#define WARNING_LEVEL 3 // Something is suspicious. 12#define WARNING_LEVEL 3 // Something is suspicious.
@@ -53,7 +55,7 @@ enum LOG_TYPE {
53 WII_IPC_ES, 55 WII_IPC_ES,
54 WII_IPC_FILEIO, 56 WII_IPC_FILEIO,
55 WII_IPC_HID, 57 WII_IPC_HID,
56 WII_IPC_HLE, 58 KERNEL,
57 SVC, 59 SVC,
58 NDMA, 60 NDMA,
59 HLE, 61 HLE,
diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp
index 80fd473b9..146472888 100644
--- a/src/common/log_manager.cpp
+++ b/src/common/log_manager.cpp
@@ -60,13 +60,13 @@ LogManager::LogManager()
60 m_Log[LogTypes::LOADER] = new LogContainer("Loader", "Loader"); 60 m_Log[LogTypes::LOADER] = new LogContainer("Loader", "Loader");
61 m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System"); 61 m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System");
62 m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID"); 62 m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID");
63 m_Log[LogTypes::WII_IPC_HLE] = new LogContainer("WII_IPC_HLE", "WII IPC HLE"); 63 m_Log[LogTypes::KERNEL] = new LogContainer("KERNEL", "KERNEL HLE");
64 m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD"); 64 m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD");
65 m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES"); 65 m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES");
66 m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO"); 66 m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO");
67 m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER"); 67 m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER");
68 m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD"); 68 m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD");
69 m_Log[LogTypes::SVC] = new LogContainer("SVC", "Supervisor Call"); 69 m_Log[LogTypes::SVC] = new LogContainer("SVC", "Supervisor Call HLE");
70 m_Log[LogTypes::NDMA] = new LogContainer("NDMA", "NDMA"); 70 m_Log[LogTypes::NDMA] = new LogContainer("NDMA", "NDMA");
71 m_Log[LogTypes::HLE] = new LogContainer("HLE", "High Level Emulation"); 71 m_Log[LogTypes::HLE] = new LogContainer("HLE", "High Level Emulation");
72 m_Log[LogTypes::HW] = new LogContainer("HW", "Hardware"); 72 m_Log[LogTypes::HW] = new LogContainer("HW", "Hardware");
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
new file mode 100644
index 000000000..4a89572f6
--- /dev/null
+++ b/src/common/thread_queue_list.h
@@ -0,0 +1,216 @@
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
9namespace Common {
10
11template<class IdType>
12struct ThreadQueueList {
13 // Number of queues (number of priority levels starting at 0.)
14 static const int NUM_QUEUES = 128;
15
16 // Initial number of threads a single queue can handle.
17 static const int INITIAL_CAPACITY = 32;
18
19 struct Queue {
20 // Next ever-been-used queue (worse priority.)
21 Queue *next;
22 // First valid item in data.
23 int first;
24 // One after last valid item in data.
25 int end;
26 // A too-large array with room on the front and end.
27 IdType *data;
28 // Size of data array.
29 int capacity;
30 };
31
32 ThreadQueueList() {
33 memset(queues, 0, sizeof(queues));
34 first = invalid();
35 }
36
37 ~ThreadQueueList() {
38 for (int i = 0; i < NUM_QUEUES; ++i)
39 {
40 if (queues[i].data != NULL)
41 free(queues[i].data);
42 }
43 }
44
45 // Only for debugging, returns priority level.
46 int contains(const IdType uid) {
47 for (int i = 0; i < NUM_QUEUES; ++i)
48 {
49 if (queues[i].data == NULL)
50 continue;
51
52 Queue *cur = &queues[i];
53 for (int j = cur->first; j < cur->end; ++j)
54 {
55 if (cur->data[j] == uid)
56 return i;
57 }
58 }
59
60 return -1;
61 }
62
63 inline IdType pop_first() {
64 Queue *cur = first;
65 while (cur != invalid())
66 {
67 if (cur->end - cur->first > 0)
68 return cur->data[cur->first++];
69 cur = cur->next;
70 }
71
72 //_dbg_assert_msg_(SCEKERNEL, false, "ThreadQueueList should not be empty.");
73 return 0;
74 }
75
76 inline IdType pop_first_better(u32 priority) {
77 Queue *cur = first;
78 Queue *stop = &queues[priority];
79 while (cur < stop)
80 {
81 if (cur->end - cur->first > 0)
82 return cur->data[cur->first++];
83 cur = cur->next;
84 }
85
86 return 0;
87 }
88
89 inline void push_front(u32 priority, const IdType threadID) {
90 Queue *cur = &queues[priority];
91 cur->data[--cur->first] = threadID;
92 if (cur->first == 0)
93 rebalance(priority);
94 }
95
96 inline void push_back(u32 priority, const IdType threadID) {
97 Queue *cur = &queues[priority];
98 cur->data[cur->end++] = threadID;
99 if (cur->end == cur->capacity)
100 rebalance(priority);
101 }
102
103 inline void remove(u32 priority, const IdType threadID) {
104 Queue *cur = &queues[priority];
105 //_dbg_assert_msg_(SCEKERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
106
107 for (int i = cur->first; i < cur->end; ++i)
108 {
109 if (cur->data[i] == threadID)
110 {
111 int remaining = --cur->end - i;
112 if (remaining > 0)
113 memmove(&cur->data[i], &cur->data[i + 1], remaining * sizeof(IdType));
114 return;
115 }
116 }
117
118 // Wasn't there.
119 }
120
121 inline void rotate(u32 priority) {
122 Queue *cur = &queues[priority];
123 //_dbg_assert_msg_(SCEKERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
124
125 if (cur->end - cur->first > 1)
126 {
127 cur->data[cur->end++] = cur->data[cur->first++];
128 if (cur->end == cur->capacity)
129 rebalance(priority);
130 }
131 }
132
133 inline void clear() {
134 for (int i = 0; i < NUM_QUEUES; ++i)
135 {
136 if (queues[i].data != NULL)
137 free(queues[i].data);
138 }
139 memset(queues, 0, sizeof(queues));
140 first = invalid();
141 }
142
143 inline bool empty(u32 priority) const {
144 const Queue *cur = &queues[priority];
145 return cur->first == cur->end;
146 }
147
148 inline void prepare(u32 priority) {
149 Queue *cur = &queues[priority];
150 if (cur->next == NULL)
151 link(priority, INITIAL_CAPACITY);
152 }
153
154private:
155 Queue *invalid() const {
156 return (Queue *) -1;
157 }
158
159 void link(u32 priority, int size) {
160 //_dbg_assert_msg_(SCEKERNEL, queues[priority].data == NULL, "ThreadQueueList::Queue should only be initialized once.");
161
162 if (size <= INITIAL_CAPACITY)
163 size = INITIAL_CAPACITY;
164 else
165 {
166 int goal = size;
167 size = INITIAL_CAPACITY;
168 while (size < goal)
169 size *= 2;
170 }
171 Queue *cur = &queues[priority];
172 cur->data = (IdType *) malloc(sizeof(IdType) * size);
173 cur->capacity = size;
174 cur->first = size / 2;
175 cur->end = size / 2;
176
177 for (int i = (int) priority - 1; i >= 0; --i)
178 {
179 if (queues[i].next != NULL)
180 {
181 cur->next = queues[i].next;
182 queues[i].next = cur;
183 return;
184 }
185 }
186
187 cur->next = first;
188 first = cur;
189 }
190
191 void rebalance(u32 priority) {
192 Queue *cur = &queues[priority];
193 int size = cur->end - cur->first;
194 if (size >= cur->capacity - 2) {
195 IdType *new_data = (IdType *)realloc(cur->data, cur->capacity * 2 * sizeof(IdType));
196 if (new_data != NULL) {
197 cur->capacity *= 2;
198 cur->data = new_data;
199 }
200 }
201
202 int newFirst = (cur->capacity - size) / 2;
203 if (newFirst != cur->first) {
204 memmove(&cur->data[newFirst], &cur->data[cur->first], size * sizeof(IdType));
205 cur->first = newFirst;
206 cur->end = newFirst + size;
207 }
208 }
209
210 // The first queue that's ever been used.
211 Queue *first;
212 // The priority level queues of thread ids.
213 Queue queues[NUM_QUEUES];
214};
215
216} // namespace
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 14c598bf3..4086b415b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -33,7 +33,10 @@ set(SRCS core.cpp
33 hle/hle.cpp 33 hle/hle.cpp
34 hle/config_mem.cpp 34 hle/config_mem.cpp
35 hle/coprocessor.cpp 35 hle/coprocessor.cpp
36 hle/syscall.cpp 36 hle/svc.cpp
37 hle/kernel/kernel.cpp
38 hle/kernel/mutex.cpp
39 hle/kernel/thread.cpp
37 hle/service/apt.cpp 40 hle/service/apt.cpp
38 hle/service/gsp.cpp 41 hle/service/gsp.cpp
39 hle/service/hid.cpp 42 hle/service/hid.cpp
@@ -75,7 +78,10 @@ set(HEADERS core.h
75 hle/config_mem.h 78 hle/config_mem.h
76 hle/coprocessor.h 79 hle/coprocessor.h
77 hle/hle.h 80 hle/hle.h
78 hle/syscall.h 81 hle/svc.h
82 hle/kernel/kernel.h
83 hle/kernel/mutex.h
84 hle/kernel/thread.h
79 hle/function_wrappers.h 85 hle/function_wrappers.h
80 hle/service/apt.h 86 hle/service/apt.h
81 hle/service/gsp.h 87 hle/service/gsp.h
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 9fdc7ba3c..b73786ccd 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -7,11 +7,13 @@
7#include "common/common.h" 7#include "common/common.h"
8#include "common/common_types.h" 8#include "common/common_types.h"
9 9
10#include "core/hle/svc.h"
11
10/// Generic ARM11 CPU interface 12/// Generic ARM11 CPU interface
11class ARM_Interface : NonCopyable { 13class ARM_Interface : NonCopyable {
12public: 14public:
13 ARM_Interface() { 15 ARM_Interface() {
14 m_num_instructions = 0; 16 num_instructions = 0;
15 } 17 }
16 18
17 ~ARM_Interface() { 19 ~ARM_Interface() {
@@ -23,7 +25,7 @@ public:
23 */ 25 */
24 void Run(int num_instructions) { 26 void Run(int num_instructions) {
25 ExecuteInstructions(num_instructions); 27 ExecuteInstructions(num_instructions);
26 m_num_instructions += num_instructions; 28 num_instructions += num_instructions;
27 } 29 }
28 30
29 /// Step CPU by one instruction 31 /// Step CPU by one instruction
@@ -64,14 +66,32 @@ public:
64 virtual u32 GetCPSR() const = 0; 66 virtual u32 GetCPSR() const = 0;
65 67
66 /** 68 /**
69 * Set the current CPSR register
70 * @param cpsr Value to set CPSR to
71 */
72 virtual void SetCPSR(u32 cpsr) = 0;
73
74 /**
67 * Returns the number of clock ticks since the last rese 75 * Returns the number of clock ticks since the last rese
68 * @return Returns number of clock ticks 76 * @return Returns number of clock ticks
69 */ 77 */
70 virtual u64 GetTicks() const = 0; 78 virtual u64 GetTicks() const = 0;
71 79
72 /// Getter for m_num_instructions 80 /**
81 * Saves the current CPU context
82 * @param ctx Thread context to save
83 */
84 virtual void SaveContext(ThreadContext& ctx) = 0;
85
86 /**
87 * Loads a CPU context
88 * @param ctx Thread context to load
89 */
90 virtual void LoadContext(const ThreadContext& ctx) = 0;
91
92 /// Getter for num_instructions
73 u64 GetNumInstructions() { 93 u64 GetNumInstructions() {
74 return m_num_instructions; 94 return num_instructions;
75 } 95 }
76 96
77protected: 97protected:
@@ -84,6 +104,6 @@ protected:
84 104
85private: 105private:
86 106
87 u64 m_num_instructions; ///< Number of instructions executed 107 u64 num_instructions; ///< Number of instructions executed
88 108
89}; 109};
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp
index 23d96d292..17f787b86 100644
--- a/src/core/arm/interpreter/arm_interpreter.cpp
+++ b/src/core/arm/interpreter/arm_interpreter.cpp
@@ -9,30 +9,30 @@ const static cpu_config_t s_arm11_cpu_info = {
9}; 9};
10 10
11ARM_Interpreter::ARM_Interpreter() { 11ARM_Interpreter::ARM_Interpreter() {
12 m_state = new ARMul_State; 12 state = new ARMul_State;
13 13
14 ARMul_EmulateInit(); 14 ARMul_EmulateInit();
15 ARMul_NewState(m_state); 15 ARMul_NewState(state);
16 16
17 m_state->abort_model = 0; 17 state->abort_model = 0;
18 m_state->cpu = (cpu_config_t*)&s_arm11_cpu_info; 18 state->cpu = (cpu_config_t*)&s_arm11_cpu_info;
19 m_state->bigendSig = LOW; 19 state->bigendSig = LOW;
20 20
21 ARMul_SelectProcessor(m_state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); 21 ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
22 m_state->lateabtSig = LOW; 22 state->lateabtSig = LOW;
23 mmu_init(m_state); 23 mmu_init(state);
24 24
25 // Reset the core to initial state 25 // Reset the core to initial state
26 ARMul_Reset(m_state); 26 ARMul_Reset(state);
27 m_state->NextInstr = 0; 27 state->NextInstr = 0;
28 m_state->Emulate = 3; 28 state->Emulate = 3;
29 29
30 m_state->pc = m_state->Reg[15] = 0x00000000; 30 state->pc = state->Reg[15] = 0x00000000;
31 m_state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack 31 state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack
32} 32}
33 33
34ARM_Interpreter::~ARM_Interpreter() { 34ARM_Interpreter::~ARM_Interpreter() {
35 delete m_state; 35 delete state;
36} 36}
37 37
38/** 38/**
@@ -40,7 +40,7 @@ ARM_Interpreter::~ARM_Interpreter() {
40 * @param addr Address to set PC to 40 * @param addr Address to set PC to
41 */ 41 */
42void ARM_Interpreter::SetPC(u32 pc) { 42void ARM_Interpreter::SetPC(u32 pc) {
43 m_state->pc = m_state->Reg[15] = pc; 43 state->pc = state->Reg[15] = pc;
44} 44}
45 45
46/* 46/*
@@ -48,7 +48,7 @@ void ARM_Interpreter::SetPC(u32 pc) {
48 * @return Returns current PC 48 * @return Returns current PC
49 */ 49 */
50u32 ARM_Interpreter::GetPC() const { 50u32 ARM_Interpreter::GetPC() const {
51 return m_state->pc; 51 return state->pc;
52} 52}
53 53
54/** 54/**
@@ -57,7 +57,7 @@ u32 ARM_Interpreter::GetPC() const {
57 * @return Returns the value in the register 57 * @return Returns the value in the register
58 */ 58 */
59u32 ARM_Interpreter::GetReg(int index) const { 59u32 ARM_Interpreter::GetReg(int index) const {
60 return m_state->Reg[index]; 60 return state->Reg[index];
61} 61}
62 62
63/** 63/**
@@ -66,7 +66,7 @@ u32 ARM_Interpreter::GetReg(int index) const {
66 * @param value Value to set register to 66 * @param value Value to set register to
67 */ 67 */
68void ARM_Interpreter::SetReg(int index, u32 value) { 68void ARM_Interpreter::SetReg(int index, u32 value) {
69 m_state->Reg[index] = value; 69 state->Reg[index] = value;
70} 70}
71 71
72/** 72/**
@@ -74,7 +74,15 @@ void ARM_Interpreter::SetReg(int index, u32 value) {
74 * @return Returns the value of the CPSR register 74 * @return Returns the value of the CPSR register
75 */ 75 */
76u32 ARM_Interpreter::GetCPSR() const { 76u32 ARM_Interpreter::GetCPSR() const {
77 return m_state->Cpsr; 77 return state->Cpsr;
78}
79
80/**
81 * Set the current CPSR register
82 * @param cpsr Value to set CPSR to
83 */
84void ARM_Interpreter::SetCPSR(u32 cpsr) {
85 state->Cpsr = cpsr;
78} 86}
79 87
80/** 88/**
@@ -82,7 +90,7 @@ u32 ARM_Interpreter::GetCPSR() const {
82 * @return Returns number of clock ticks 90 * @return Returns number of clock ticks
83 */ 91 */
84u64 ARM_Interpreter::GetTicks() const { 92u64 ARM_Interpreter::GetTicks() const {
85 return ARMul_Time(m_state); 93 return ARMul_Time(state);
86} 94}
87 95
88/** 96/**
@@ -90,6 +98,45 @@ u64 ARM_Interpreter::GetTicks() const {
90 * @param num_instructions Number of instructions to executes 98 * @param num_instructions Number of instructions to executes
91 */ 99 */
92void ARM_Interpreter::ExecuteInstructions(int num_instructions) { 100void ARM_Interpreter::ExecuteInstructions(int num_instructions) {
93 m_state->NumInstrsToExecute = num_instructions; 101 state->NumInstrsToExecute = num_instructions;
94 ARMul_Emulate32(m_state); 102 ARMul_Emulate32(state);
103}
104
105/**
106 * Saves the current CPU context
107 * @param ctx Thread context to save
108 * @todo Do we need to save Reg[15] and NextInstr?
109 */
110void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
111 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
112 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));
113
114 ctx.sp = state->Reg[13];
115 ctx.lr = state->Reg[14];
116 ctx.pc = state->pc;
117 ctx.cpsr = state->Cpsr;
118
119 ctx.fpscr = state->VFP[1];
120 ctx.fpexc = state->VFP[2];
121}
122
123/**
124 * Loads a CPU context
125 * @param ctx Thread context to load
126 * @param Do we need to load Reg[15] and NextInstr?
127 */
128void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
129 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
130 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
131
132 state->Reg[13] = ctx.sp;
133 state->Reg[14] = ctx.lr;
134 state->pc = ctx.pc;
135 state->Cpsr = ctx.cpsr;
136
137 state->VFP[1] = ctx.fpscr;
138 state->VFP[2] = ctx.fpexc;
139
140 state->Reg[15] = ctx.pc;
141 state->NextInstr = RESUME;
95} 142}
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h
index 509025080..6a531e497 100644
--- a/src/core/arm/interpreter/arm_interpreter.h
+++ b/src/core/arm/interpreter/arm_interpreter.h
@@ -49,11 +49,29 @@ public:
49 u32 GetCPSR() const; 49 u32 GetCPSR() const;
50 50
51 /** 51 /**
52 * Set the current CPSR register
53 * @param cpsr Value to set CPSR to
54 */
55 void SetCPSR(u32 cpsr);
56
57 /**
52 * Returns the number of clock ticks since the last reset 58 * Returns the number of clock ticks since the last reset
53 * @return Returns number of clock ticks 59 * @return Returns number of clock ticks
54 */ 60 */
55 u64 GetTicks() const; 61 u64 GetTicks() const;
56 62
63 /**
64 * Saves the current CPU context
65 * @param ctx Thread context to save
66 */
67 void SaveContext(ThreadContext& ctx);
68
69 /**
70 * Loads a CPU context
71 * @param ctx Thread context to load
72 */
73 void LoadContext(const ThreadContext& ctx);
74
57protected: 75protected:
58 76
59 /** 77 /**
@@ -64,6 +82,6 @@ protected:
64 82
65private: 83private:
66 84
67 ARMul_State* m_state; 85 ARMul_State* state;
68 86
69}; 87};
diff --git a/src/core/arm/interpreter/armdefs.h b/src/core/arm/interpreter/armdefs.h
index 5b2abc7f7..d8eae4d3f 100644
--- a/src/core/arm/interpreter/armdefs.h
+++ b/src/core/arm/interpreter/armdefs.h
@@ -24,10 +24,6 @@
24 24
25#include "common/platform.h" 25#include "common/platform.h"
26 26
27#if EMU_PLATFORM == PLATFORM_WINDOWS
28#include <windows.h>
29#endif
30
31//teawater add for arm2x86 2005.02.14------------------------------------------- 27//teawater add for arm2x86 2005.02.14-------------------------------------------
32// koodailar remove it for mingw 2005.12.18---------------- 28// koodailar remove it for mingw 2005.12.18----------------
33//anthonylee modify it for portable 2007.01.30 29//anthonylee modify it for portable 2007.01.30
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index 32e315f4b..e5dc7bd44 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -4478,8 +4478,7 @@ ARMul_Emulate26 (ARMul_State * state)
4478 isize) & 4478 isize) &
4479 R15PCBITS)); 4479 R15PCBITS));
4480#endif 4480#endif
4481 } 4481 } else if (instr != 0xDEADC0DE) // thumbemu uses 0xDEADCODE for debugging to catch non updates
4482 else
4483 ARMul_MCR (state, instr, 4482 ARMul_MCR (state, instr,
4484 DEST); 4483 DEST);
4485 } 4484 }
@@ -4549,7 +4548,7 @@ ARMul_Emulate26 (ARMul_State * state)
4549 // ARMul_OSHandleSWI (state, BITS (0, 23)); 4548 // ARMul_OSHandleSWI (state, BITS (0, 23));
4550 // break; 4549 // break;
4551 //} 4550 //}
4552 HLE::CallSyscall(instr); 4551 HLE::CallSVC(instr);
4553 ARMul_Abort (state, ARMul_SWIV); 4552 ARMul_Abort (state, ARMul_SWIV);
4554 break; 4553 break;
4555 } 4554 }
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp
index 2c771cdda..e05667bea 100644
--- a/src/core/arm/interpreter/arminit.cpp
+++ b/src/core/arm/interpreter/arminit.cpp
@@ -17,8 +17,11 @@
17 17
18 18
19#include "common/platform.h" 19#include "common/platform.h"
20
20#if EMU_PLATFORM == PLATFORM_LINUX 21#if EMU_PLATFORM == PLATFORM_LINUX
21#include <unistd.h> 22#include <unistd.h>
23#elif EMU_PLATFORM == PLATFORM_WINDOWS
24#include <windows.h>
22#endif 25#endif
23 26
24#include <math.h> 27#include <math.h>
diff --git a/src/core/arm/interpreter/vfp/vfp.h b/src/core/arm/interpreter/vfp/vfp.h
index f738a615b..bbf4caeb0 100644
--- a/src/core/arm/interpreter/vfp/vfp.h
+++ b/src/core/arm/interpreter/vfp/vfp.h
@@ -21,7 +21,7 @@
21#ifndef __VFP_H__ 21#ifndef __VFP_H__
22#define __VFP_H__ 22#define __VFP_H__
23 23
24#define DBG(...) DEBUG_LOG(ARM11, __VA_ARGS__) 24#define DBG(...) //DEBUG_LOG(ARM11, __VA_ARGS__)
25 25
26#define vfpdebug //printf 26#define vfpdebug //printf
27 27
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 61c237b2c..f88bcd704 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -12,6 +12,8 @@
12#include "core/arm/disassembler/arm_disasm.h" 12#include "core/arm/disassembler/arm_disasm.h"
13#include "core/arm/interpreter/arm_interpreter.h" 13#include "core/arm/interpreter/arm_interpreter.h"
14 14
15#include "core/hle/kernel/thread.h"
16
15namespace Core { 17namespace Core {
16 18
17ARM_Disasm* g_disasm = NULL; ///< ARM disassembler 19ARM_Disasm* g_disasm = NULL; ///< ARM disassembler
@@ -21,14 +23,17 @@ ARM_Interface* g_sys_core = NULL; ///< ARM11 system (OS) core
21/// Run the core CPU loop 23/// Run the core CPU loop
22void RunLoop() { 24void RunLoop() {
23 for (;;){ 25 for (;;){
24 g_app_core->Run(10000); 26 g_app_core->Run(100);
25 HW::Update(); 27 HW::Update();
28 Kernel::Reschedule();
26 } 29 }
27} 30}
28 31
29/// Step the CPU one instruction 32/// Step the CPU one instruction
30void SingleStep() { 33void SingleStep() {
31 g_app_core->Step(); 34 g_app_core->Step();
35 HW::Update();
36 Kernel::Reschedule();
32} 37}
33 38
34/// Halt the core 39/// Halt the core
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index 41af5801d..f271d336e 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -168,12 +168,15 @@
168 <ClCompile Include="hle\config_mem.cpp" /> 168 <ClCompile Include="hle\config_mem.cpp" />
169 <ClCompile Include="hle\coprocessor.cpp" /> 169 <ClCompile Include="hle\coprocessor.cpp" />
170 <ClCompile Include="hle\hle.cpp" /> 170 <ClCompile Include="hle\hle.cpp" />
171 <ClCompile Include="hle\kernel\kernel.cpp" />
172 <ClCompile Include="hle\kernel\mutex.cpp" />
173 <ClCompile Include="hle\kernel\thread.cpp" />
171 <ClCompile Include="hle\service\apt.cpp" /> 174 <ClCompile Include="hle\service\apt.cpp" />
172 <ClCompile Include="hle\service\gsp.cpp" /> 175 <ClCompile Include="hle\service\gsp.cpp" />
173 <ClCompile Include="hle\service\hid.cpp" /> 176 <ClCompile Include="hle\service\hid.cpp" />
174 <ClCompile Include="hle\service\service.cpp" /> 177 <ClCompile Include="hle\service\service.cpp" />
175 <ClCompile Include="hle\service\srv.cpp" /> 178 <ClCompile Include="hle\service\srv.cpp" />
176 <ClCompile Include="hle\syscall.cpp" /> 179 <ClCompile Include="hle\svc.cpp" />
177 <ClCompile Include="hw\hw.cpp" /> 180 <ClCompile Include="hw\hw.cpp" />
178 <ClCompile Include="hw\lcd.cpp" /> 181 <ClCompile Include="hw\lcd.cpp" />
179 <ClCompile Include="hw\ndma.cpp" /> 182 <ClCompile Include="hw\ndma.cpp" />
@@ -214,12 +217,15 @@
214 <ClInclude Include="hle\coprocessor.h" /> 217 <ClInclude Include="hle\coprocessor.h" />
215 <ClInclude Include="hle\function_wrappers.h" /> 218 <ClInclude Include="hle\function_wrappers.h" />
216 <ClInclude Include="hle\hle.h" /> 219 <ClInclude Include="hle\hle.h" />
220 <ClInclude Include="hle\kernel\kernel.h" />
221 <ClInclude Include="hle\kernel\mutex.h" />
222 <ClInclude Include="hle\kernel\thread.h" />
217 <ClInclude Include="hle\service\apt.h" /> 223 <ClInclude Include="hle\service\apt.h" />
218 <ClInclude Include="hle\service\gsp.h" /> 224 <ClInclude Include="hle\service\gsp.h" />
219 <ClInclude Include="hle\service\hid.h" /> 225 <ClInclude Include="hle\service\hid.h" />
220 <ClInclude Include="hle\service\service.h" /> 226 <ClInclude Include="hle\service\service.h" />
221 <ClInclude Include="hle\service\srv.h" /> 227 <ClInclude Include="hle\service\srv.h" />
222 <ClInclude Include="hle\syscall.h" /> 228 <ClInclude Include="hle\svc.h" />
223 <ClInclude Include="hw\hw.h" /> 229 <ClInclude Include="hw\hw.h" />
224 <ClInclude Include="hw\lcd.h" /> 230 <ClInclude Include="hw\lcd.h" />
225 <ClInclude Include="hw\ndma.h" /> 231 <ClInclude Include="hw\ndma.h" />
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index edf34ce2f..b6c1d5b93 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -31,6 +31,9 @@
31 <Filter Include="arm\interpreter\mmu"> 31 <Filter Include="arm\interpreter\mmu">
32 <UniqueIdentifier>{13ef9860-2ba0-47e9-a93d-b4052adab269}</UniqueIdentifier> 32 <UniqueIdentifier>{13ef9860-2ba0-47e9-a93d-b4052adab269}</UniqueIdentifier>
33 </Filter> 33 </Filter>
34 <Filter Include="hle\kernel">
35 <UniqueIdentifier>{8089d94b-5faa-43dc-854b-ffd2fa2e7fe3}</UniqueIdentifier>
36 </Filter>
34 </ItemGroup> 37 </ItemGroup>
35 <ItemGroup> 38 <ItemGroup>
36 <ClCompile Include="arm\disassembler\arm_disasm.cpp"> 39 <ClCompile Include="arm\disassembler\arm_disasm.cpp">
@@ -81,9 +84,6 @@
81 <ClCompile Include="hle\hle.cpp"> 84 <ClCompile Include="hle\hle.cpp">
82 <Filter>hle</Filter> 85 <Filter>hle</Filter>
83 </ClCompile> 86 </ClCompile>
84 <ClCompile Include="hle\syscall.cpp">
85 <Filter>hle</Filter>
86 </ClCompile>
87 <ClCompile Include="hle\service\service.cpp"> 87 <ClCompile Include="hle\service\service.cpp">
88 <Filter>hle\service</Filter> 88 <Filter>hle\service</Filter>
89 </ClCompile> 89 </ClCompile>
@@ -147,12 +147,24 @@
147 <ClCompile Include="arm\interpreter\mmu\wb.cpp"> 147 <ClCompile Include="arm\interpreter\mmu\wb.cpp">
148 <Filter>arm\interpreter\mmu</Filter> 148 <Filter>arm\interpreter\mmu</Filter>
149 </ClCompile> 149 </ClCompile>
150 <ClCompile Include="arm\interpreter\armcopro.cpp">
151 <Filter>arm</Filter>
152 </ClCompile>
153 <ClCompile Include="arm\interpreter\mmu\maverick.cpp"> 150 <ClCompile Include="arm\interpreter\mmu\maverick.cpp">
154 <Filter>arm\interpreter\mmu</Filter> 151 <Filter>arm\interpreter\mmu</Filter>
155 </ClCompile> 152 </ClCompile>
153 <ClCompile Include="hle\kernel\kernel.cpp">
154 <Filter>hle\kernel</Filter>
155 </ClCompile>
156 <ClCompile Include="hle\kernel\thread.cpp">
157 <Filter>hle\kernel</Filter>
158 </ClCompile>
159 <ClCompile Include="hle\svc.cpp">
160 <Filter>hle</Filter>
161 </ClCompile>
162 <ClCompile Include="hle\kernel\mutex.cpp">
163 <Filter>hle\kernel</Filter>
164 </ClCompile>
165 <ClCompile Include="arm\interpreter\armcopro.cpp">
166 <Filter>arm\interpreter</Filter>
167 </ClCompile>
156 </ItemGroup> 168 </ItemGroup>
157 <ItemGroup> 169 <ItemGroup>
158 <ClInclude Include="arm\disassembler\arm_disasm.h"> 170 <ClInclude Include="arm\disassembler\arm_disasm.h">
@@ -217,9 +229,6 @@
217 <ClInclude Include="hle\service\service.h"> 229 <ClInclude Include="hle\service\service.h">
218 <Filter>hle\service</Filter> 230 <Filter>hle\service</Filter>
219 </ClInclude> 231 </ClInclude>
220 <ClInclude Include="hle\syscall.h">
221 <Filter>hle</Filter>
222 </ClInclude>
223 <ClInclude Include="hle\service\apt.h"> 232 <ClInclude Include="hle\service\apt.h">
224 <Filter>hle\service</Filter> 233 <Filter>hle\service</Filter>
225 </ClInclude> 234 </ClInclude>
@@ -274,6 +283,18 @@
274 <ClInclude Include="arm\interpreter\mmu\sa_mmu.h"> 283 <ClInclude Include="arm\interpreter\mmu\sa_mmu.h">
275 <Filter>arm\interpreter\mmu</Filter> 284 <Filter>arm\interpreter\mmu</Filter>
276 </ClInclude> 285 </ClInclude>
286 <ClInclude Include="hle\kernel\kernel.h">
287 <Filter>hle\kernel</Filter>
288 </ClInclude>
289 <ClInclude Include="hle\kernel\thread.h">
290 <Filter>hle\kernel</Filter>
291 </ClInclude>
292 <ClInclude Include="hle\svc.h">
293 <Filter>hle</Filter>
294 </ClInclude>
295 <ClInclude Include="hle\kernel\mutex.h">
296 <Filter>hle\kernel</Filter>
297 </ClInclude>
277 </ItemGroup> 298 </ItemGroup>
278 <ItemGroup> 299 <ItemGroup>
279 <Text Include="CMakeLists.txt" /> 300 <Text Include="CMakeLists.txt" />
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
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 6468053f2..b57563a73 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -11,6 +11,8 @@
11 11
12#include "video_core/video_core.h" 12#include "video_core/video_core.h"
13 13
14#include "core/hle/kernel/thread.h"
15
14namespace LCD { 16namespace LCD {
15 17
16Registers g_regs; 18Registers g_regs;
@@ -130,9 +132,11 @@ template void Write<u8>(u32 addr, const u8 data);
130void Update() { 132void Update() {
131 u64 current_ticks = Core::g_app_core->GetTicks(); 133 u64 current_ticks = Core::g_app_core->GetTicks();
132 134
135 // Fake a vertical blank
133 if ((current_ticks - g_last_ticks) >= kFrameTicks) { 136 if ((current_ticks - g_last_ticks) >= kFrameTicks) {
134 g_last_ticks = current_ticks; 137 g_last_ticks = current_ticks;
135 VideoCore::g_renderer->SwapBuffers(); 138 VideoCore::g_renderer->SwapBuffers();
139 Kernel::WaitCurrentThread(WAITTYPE_VBLANK);
136 } 140 }
137} 141}
138 142
diff --git a/src/core/loader.cpp b/src/core/loader.cpp
index 8756588ae..ff1c873bb 100644
--- a/src/core/loader.cpp
+++ b/src/core/loader.cpp
@@ -10,7 +10,7 @@
10#include "core/core.h" 10#include "core/core.h"
11#include "core/file_sys/directory_file_system.h" 11#include "core/file_sys/directory_file_system.h"
12#include "core/elf/elf_reader.h" 12#include "core/elf/elf_reader.h"
13 13#include "core/hle/kernel/kernel.h"
14#include "core/mem_map.h" 14#include "core/mem_map.h"
15 15
16//////////////////////////////////////////////////////////////////////////////////////////////////// 16////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -56,7 +56,7 @@ bool Load_ELF(std::string &filename) {
56 elf_reader = new ElfReader(buffer); 56 elf_reader = new ElfReader(buffer);
57 elf_reader->LoadInto(0x00100000); 57 elf_reader->LoadInto(0x00100000);
58 58
59 Core::g_app_core->SetPC(elf_reader->GetEntryPoint()); 59 Kernel::LoadExec(elf_reader->GetEntryPoint());
60 60
61 delete[] buffer; 61 delete[] buffer;
62 delete elf_reader; 62 delete elf_reader;
@@ -89,11 +89,11 @@ bool Load_DAT(std::string &filename) {
89 * but for the sake of making it easier... we'll temporarily/hackishly 89 * but for the sake of making it easier... we'll temporarily/hackishly
90 * allow it. No sense in making a proper reader for this. 90 * allow it. No sense in making a proper reader for this.
91 */ 91 */
92 u32 entrypoint = 0x00100000; // write to same entrypoint as elf 92 u32 entry_point = 0x00100000; // write to same entrypoint as elf
93 u32 payload_offset = 0xA150; 93 u32 payload_offset = 0xA150;
94 94
95 const u8 *src = &buffer[payload_offset]; 95 const u8 *src = &buffer[payload_offset];
96 u8 *dst = Memory::GetPointer(entrypoint); 96 u8 *dst = Memory::GetPointer(entry_point);
97 u32 srcSize = size - payload_offset; //just load everything... 97 u32 srcSize = size - payload_offset; //just load everything...
98 u32 *s = (u32*)src; 98 u32 *s = (u32*)src;
99 u32 *d = (u32*)dst; 99 u32 *d = (u32*)dst;
@@ -102,7 +102,8 @@ bool Load_DAT(std::string &filename) {
102 *d++ = (*s++); 102 *d++ = (*s++);
103 } 103 }
104 104
105 Core::g_app_core->SetPC(entrypoint); 105 Kernel::LoadExec(entry_point);
106
106 107
107 delete[] buffer; 108 delete[] buffer;
108 } 109 }
@@ -131,10 +132,10 @@ bool Load_BIN(std::string &filename) {
131 132
132 f.ReadBytes(buffer, size); 133 f.ReadBytes(buffer, size);
133 134
134 u32 entrypoint = 0x00100000; // Hardcoded, read from exheader 135 u32 entry_point = 0x00100000; // Hardcoded, read from exheader
135 136
136 const u8 *src = buffer; 137 const u8 *src = buffer;
137 u8 *dst = Memory::GetPointer(entrypoint); 138 u8 *dst = Memory::GetPointer(entry_point);
138 u32 srcSize = size; 139 u32 srcSize = size;
139 u32 *s = (u32*)src; 140 u32 *s = (u32*)src;
140 u32 *d = (u32*)dst; 141 u32 *d = (u32*)dst;
@@ -143,7 +144,7 @@ bool Load_BIN(std::string &filename) {
143 *d++ = (*s++); 144 *d++ = (*s++);
144 } 145 }
145 146
146 Core::g_app_core->SetPC(entrypoint); 147 Kernel::LoadExec(entry_point);
147 148
148 delete[] buffer; 149 delete[] buffer;
149 } 150 }
@@ -186,6 +187,9 @@ FileType IdentifyFile(std::string &filename) {
186 else if (!strcasecmp(extension.c_str(), ".elf")) { 187 else if (!strcasecmp(extension.c_str(), ".elf")) {
187 return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p 188 return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p
188 } 189 }
190 else if (!strcasecmp(extension.c_str(), ".axf")) {
191 return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p
192 }
189 else if (!strcasecmp(extension.c_str(), ".bin")) { 193 else if (!strcasecmp(extension.c_str(), ".bin")) {
190 return FILETYPE_CTR_BIN; 194 return FILETYPE_CTR_BIN;
191 } 195 }
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index 59560b87d..c45746be9 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -17,6 +17,7 @@ u8* g_base = NULL; ///< The base pointer to the aut
17MemArena g_arena; ///< The MemArena class 17MemArena g_arena; ///< The MemArena class
18 18
19u8* g_exefs_code = NULL; ///< ExeFS:/.code is loaded here 19u8* g_exefs_code = NULL; ///< ExeFS:/.code is loaded here
20u8* g_system_mem = NULL; ///< System memory
20u8* g_heap = NULL; ///< Application heap (main memory) 21u8* g_heap = NULL; ///< Application heap (main memory)
21u8* g_heap_gsp = NULL; ///< GSP heap (main memory) 22u8* g_heap_gsp = NULL; ///< GSP heap (main memory)
22u8* g_vram = NULL; ///< Video memory (VRAM) pointer 23u8* g_vram = NULL; ///< Video memory (VRAM) pointer
@@ -27,6 +28,7 @@ u8* g_physical_bootrom = NULL; ///< Bootrom physical memory
27u8* g_uncached_bootrom = NULL; 28u8* g_uncached_bootrom = NULL;
28 29
29u8* g_physical_exefs_code = NULL; ///< Phsical ExeFS:/.code is loaded here 30u8* g_physical_exefs_code = NULL; ///< Phsical ExeFS:/.code is loaded here
31u8* g_physical_system_mem = NULL; ///< System physical memory
30u8* g_physical_fcram = NULL; ///< Main physical memory (FCRAM) 32u8* g_physical_fcram = NULL; ///< Main physical memory (FCRAM)
31u8* g_physical_heap_gsp = NULL; ///< GSP heap physical memory 33u8* g_physical_heap_gsp = NULL; ///< GSP heap physical memory
32u8* g_physical_vram = NULL; ///< Video physical memory (VRAM) 34u8* g_physical_vram = NULL; ///< Video physical memory (VRAM)
@@ -39,6 +41,7 @@ static MemoryView g_views[] = {
39 {&g_vram, &g_physical_vram, VRAM_VADDR, VRAM_SIZE, 0}, 41 {&g_vram, &g_physical_vram, VRAM_VADDR, VRAM_SIZE, 0},
40 {&g_heap, &g_physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM}, 42 {&g_heap, &g_physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM},
41 {&g_shared_mem, &g_physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0}, 43 {&g_shared_mem, &g_physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0},
44 {&g_system_mem, &g_physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0},
42 {&g_kernel_mem, &g_physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0}, 45 {&g_kernel_mem, &g_physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0},
43 {&g_heap_gsp, &g_physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0}, 46 {&g_heap_gsp, &g_physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0},
44}; 47};
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index af2212a5f..12d497ef3 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -47,6 +47,12 @@ enum {
47 EXEFS_CODE_VADDR_END = (EXEFS_CODE_VADDR + EXEFS_CODE_SIZE), 47 EXEFS_CODE_VADDR_END = (EXEFS_CODE_VADDR + EXEFS_CODE_SIZE),
48 EXEFS_CODE_MASK = 0x03FFFFFF, 48 EXEFS_CODE_MASK = 0x03FFFFFF,
49 49
50 // Region of FCRAM used by system
51 SYSTEM_MEMORY_SIZE = 0x02C00000, ///< 44MB
52 SYSTEM_MEMORY_VADDR = 0x04000000,
53 SYSTEM_MEMORY_VADDR_END = (SYSTEM_MEMORY_VADDR + SYSTEM_MEMORY_SIZE),
54 SYSTEM_MEMORY_MASK = 0x03FFFFFF,
55
50 HEAP_SIZE = FCRAM_SIZE, ///< Application heap size 56 HEAP_SIZE = FCRAM_SIZE, ///< Application heap size
51 //HEAP_PADDR = HEAP_GSP_SIZE, 57 //HEAP_PADDR = HEAP_GSP_SIZE,
52 //HEAP_PADDR_END = (HEAP_PADDR + HEAP_SIZE), 58 //HEAP_PADDR_END = (HEAP_PADDR + HEAP_SIZE),
@@ -116,6 +122,7 @@ extern u8* g_heap; ///< Application heap (main memory)
116extern u8* g_vram; ///< Video memory (VRAM) 122extern u8* g_vram; ///< Video memory (VRAM)
117extern u8* g_shared_mem; ///< Shared memory 123extern u8* g_shared_mem; ///< Shared memory
118extern u8* g_kernel_mem; ///< Kernel memory 124extern u8* g_kernel_mem; ///< Kernel memory
125extern u8* g_system_mem; ///< System memory
119extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here 126extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here
120 127
121void Init(); 128void Init();
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp
index 8ab647714..86e9eaa20 100644
--- a/src/core/mem_map_funcs.cpp
+++ b/src/core/mem_map_funcs.cpp
@@ -73,6 +73,10 @@ inline void _Read(T &var, const u32 addr) {
73 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { 73 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
74 var = *((const T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK]); 74 var = *((const T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK]);
75 75
76 // System memory
77 } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
78 var = *((const T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK]);
79
76 // Config memory 80 // Config memory
77 } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) { 81 } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) {
78 ConfigMem::Read<T>(var, vaddr); 82 ConfigMem::Read<T>(var, vaddr);
@@ -115,6 +119,10 @@ inline void _Write(u32 addr, const T data) {
115 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { 119 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
116 *(T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK] = data; 120 *(T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK] = data;
117 121
122 // System memory
123 } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
124 *(T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK] = data;
125
118 // VRAM 126 // VRAM
119 } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { 127 } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
120 *(T*)&g_vram[vaddr & VRAM_MASK] = data; 128 *(T*)&g_vram[vaddr & VRAM_MASK] = data;
@@ -153,9 +161,13 @@ u8 *GetPointer(const u32 addr) {
153 return g_heap + (vaddr & HEAP_MASK); 161 return g_heap + (vaddr & HEAP_MASK);
154 162
155 // Shared memory 163 // Shared memory
156 } else if ((vaddr > SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { 164 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
157 return g_shared_mem + (vaddr & SHARED_MEMORY_MASK); 165 return g_shared_mem + (vaddr & SHARED_MEMORY_MASK);
158 166
167 // System memory
168 } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
169 return g_system_mem + (vaddr & SYSTEM_MEMORY_MASK);
170
159 // VRAM 171 // VRAM
160 } else if ((vaddr > VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { 172 } else if ((vaddr > VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
161 return g_vram + (vaddr & VRAM_MASK); 173 return g_vram + (vaddr & VRAM_MASK);