summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/thread.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2014-05-13 22:00:11 -0400
committerGravatar bunnei2014-05-13 22:00:11 -0400
commit3838d46b9022964617b93a45f3feab5052c3538b (patch)
treee9bb520a6e8e86543f0827524c45e0ce2e0edb4a /src/core/hle/kernel/thread.cpp
parentchanged loader to use __KernelLoadExec (diff)
downloadyuzu-3838d46b9022964617b93a45f3feab5052c3538b.tar.gz
yuzu-3838d46b9022964617b93a45f3feab5052c3538b.tar.xz
yuzu-3838d46b9022964617b93a45f3feab5052c3538b.zip
added a bunch of threading code, recycled from PPSSPP, with lots of hacks in for 3DS... doesn't really do much yet. Just a jumping off point
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
-rw-r--r--src/core/hle/kernel/thread.cpp588
1 files changed, 524 insertions, 64 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 0ed35de83..584276eec 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -11,10 +11,212 @@
11 11
12#include "common/common.h" 12#include "common/common.h"
13 13
14#include "core/core.h"
15#include "core/mem_map.h"
14#include "core/hle/kernel/kernel.h" 16#include "core/hle/kernel/kernel.h"
15#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
16 18
17// Real CTR struct, don't change the fields. 19struct ThreadQueueList {
20 // Number of queues (number of priority levels starting at 0.)
21 static const int NUM_QUEUES = 128;
22 // Initial number of threads a single queue can handle.
23 static const int INITIAL_CAPACITY = 32;
24
25 struct Queue {
26 // Next ever-been-used queue (worse priority.)
27 Queue *next;
28 // First valid item in data.
29 int first;
30 // One after last valid item in data.
31 int end;
32 // A too-large array with room on the front and end.
33 UID *data;
34 // Size of data array.
35 int capacity;
36 };
37
38 ThreadQueueList() {
39 memset(queues, 0, sizeof(queues));
40 first = invalid();
41 }
42
43 ~ThreadQueueList() {
44 for (int i = 0; i < NUM_QUEUES; ++i) {
45 if (queues[i].data != NULL) {
46 free(queues[i].data);
47 }
48 }
49 }
50
51 // Only for debugging, returns priority level.
52 int contains(const UID uid) {
53 for (int i = 0; i < NUM_QUEUES; ++i) {
54 if (queues[i].data == NULL) {
55 continue;
56 }
57 Queue *cur = &queues[i];
58 for (int j = cur->first; j < cur->end; ++j) {
59 if (cur->data[j] == uid) {
60 return i;
61 }
62 }
63 }
64 return -1;
65 }
66
67 inline UID pop_first() {
68 Queue *cur = first;
69 while (cur != invalid()) {
70 if (cur->end - cur->first > 0) {
71 return cur->data[cur->first++];
72 }
73 cur = cur->next;
74 }
75
76 _dbg_assert_msg_(KERNEL, false, "ThreadQueueList should not be empty.");
77 return 0;
78 }
79
80 inline UID pop_first_better(u32 priority) {
81 Queue *cur = first;
82 Queue *stop = &queues[priority];
83 while (cur < stop) {
84 if (cur->end - cur->first > 0) {
85 return cur->data[cur->first++];
86 }
87 cur = cur->next;
88 }
89 return 0;
90 }
91
92 inline void push_front(u32 priority, const UID thread_id) {
93 Queue *cur = &queues[priority];
94 cur->data[--cur->first] = thread_id;
95 if (cur->first == 0) {
96 rebalance(priority);
97 }
98 }
99
100 inline void push_back(u32 priority, const UID thread_id)
101 {
102 Queue *cur = &queues[priority];
103 cur->data[cur->end++] = thread_id;
104 if (cur->end == cur->capacity) {
105 rebalance(priority);
106 }
107 }
108
109 inline void remove(u32 priority, const UID thread_id) {
110 Queue *cur = &queues[priority];
111 _dbg_assert_msg_(KERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
112
113 for (int i = cur->first; i < cur->end; ++i) {
114 if (cur->data[i] == thread_id) {
115 int remaining = --cur->end - i;
116 if (remaining > 0) {
117 memmove(&cur->data[i], &cur->data[i + 1], remaining * sizeof(UID));
118 }
119 return;
120 }
121 }
122
123 // Wasn't there.
124 }
125
126 inline void rotate(u32 priority) {
127 Queue *cur = &queues[priority];
128 _dbg_assert_msg_(KERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
129
130 if (cur->end - cur->first > 1) {
131 cur->data[cur->end++] = cur->data[cur->first++];
132 if (cur->end == cur->capacity) {
133 rebalance(priority);
134 }
135 }
136 }
137
138 inline void clear() {
139 for (int i = 0; i < NUM_QUEUES; ++i) {
140 if (queues[i].data != NULL) {
141 free(queues[i].data);
142 }
143 }
144 memset(queues, 0, sizeof(queues));
145 first = invalid();
146 }
147
148 inline bool empty(u32 priority) const {
149 const Queue *cur = &queues[priority];
150 return cur->first == cur->end;
151 }
152
153 inline void prepare(u32 priority) {
154 Queue *cur = &queues[priority];
155 if (cur->next == NULL) {
156 link(priority, INITIAL_CAPACITY);
157 }
158 }
159
160private:
161 Queue *invalid() const {
162 return (Queue *)-1;
163 }
164
165 void link(u32 priority, int size) {
166 _dbg_assert_msg_(KERNEL, queues[priority].data == NULL, "ThreadQueueList::Queue should only be initialized once.");
167
168 if (size <= INITIAL_CAPACITY) {
169 size = INITIAL_CAPACITY;
170 } else {
171 int goal = size;
172 size = INITIAL_CAPACITY;
173 while (size < goal)
174 size *= 2;
175 }
176 Queue *cur = &queues[priority];
177 cur->data = (UID*)malloc(sizeof(UID)* size);
178 cur->capacity = size;
179 cur->first = size / 2;
180 cur->end = size / 2;
181
182 for (int i = (int)priority - 1; i >= 0; --i) {
183 if (queues[i].next != NULL) {
184 cur->next = queues[i].next;
185 queues[i].next = cur;
186 return;
187 }
188 }
189
190 cur->next = first;
191 first = cur;
192 }
193
194 void rebalance(u32 priority) {
195 Queue *cur = &queues[priority];
196 int size = cur->end - cur->first;
197 if (size >= cur->capacity - 2) {
198 UID* new_data = (UID*)realloc(cur->data, cur->capacity * 2 * sizeof(UID));
199 if (new_data != NULL) {
200 cur->capacity *= 2;
201 cur->data = new_data;
202 }
203 }
204
205 int newFirst = (cur->capacity - size) / 2;
206 if (newFirst != cur->first) {
207 memmove(&cur->data[newFirst], &cur->data[cur->first], size * sizeof(UID));
208 cur->first = newFirst;
209 cur->end = newFirst + size;
210 }
211 }
212
213 // The first queue that's ever been used.
214 Queue* first;
215 // The priority level queues of thread ids.
216 Queue queues[NUM_QUEUES];
217};
218
219// Supposed to represent a real CTR struct... but not sure of the correct fields yet.
18struct NativeThread { 220struct NativeThread {
19 //u32 Pointer to vtable 221 //u32 Pointer to vtable
20 //u32 Reference count 222 //u32 Reference count
@@ -25,6 +227,22 @@ struct NativeThread {
25 // if the beginning of this mapped page is 0xFF401000, this ptr would be 0xFF402000. 227 // if the beginning of this mapped page is 0xFF401000, this ptr would be 0xFF402000.
26 //KThread* Previous ? (virtual address) 228 //KThread* Previous ? (virtual address)
27 //KThread* Next ? (virtual address) 229 //KThread* Next ? (virtual address)
230
231 u32_le native_size;
232 char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
233
234 // Threading stuff
235 u32_le status;
236 u32_le entry_point;
237 u32_le initial_stack;
238 u32_le stack_top;
239 u32_le stack_size;
240
241 u32_le arg;
242 u32_le processor_id;
243
244 s32_le initial_priority;
245 s32_le current_priority;
28}; 246};
29 247
30struct ThreadWaitInfo { 248struct ThreadWaitInfo {
@@ -52,42 +270,23 @@ public:
52 //} 270 //}
53 271
54 //static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; } 272 //static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; }
55 //static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; } 273 static KernelIDType GetStaticIDType() { return KERNEL_ID_TYPE_THREAD; }
56 //int GetIDType() const { return SCE_KERNEL_TMID_Thread; } 274 KernelIDType GetIDType() const { return KERNEL_ID_TYPE_THREAD; }
57 275
58 //bool AllocateStack(u32 &stack_size) { 276 bool SetupStack(u32 stack_top, int stack_size) {
59 // FreeStack(); 277 current_stack.start = stack_top;
60 278 nt.initial_stack = current_stack.start;
61 // bool fromTop = (nt.attr & PSP_THREAD_ATTR_LOW_STACK) == 0; 279 nt.stack_size = stack_size;
62 // if (nt.attr & PSP_THREAD_ATTR_KERNEL) 280 return true;
63 // { 281 }
64 // // Allocate stacks for kernel threads (idle) in kernel RAM
65 // currentStack.start = kernelMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str());
66 // }
67 // else
68 // {
69 // currentStack.start = userMemory.Alloc(stack_size, fromTop, (std::string("stack/") + nt.name).c_str());
70 // }
71 // if (currentStack.start == (u32)-1)
72 // {
73 // currentStack.start = 0;
74 // nt.initialStack = 0;
75 // ERROR_LOG(KERNEL, "Failed to allocate stack for thread");
76 // return false;
77 // }
78
79 // nt.initialStack = currentStack.start;
80 // nt.stack_size = stack_size;
81 // return true;
82 //}
83 282
84 //bool FillStack() { 283 //bool FillStack() {
85 // // Fill the stack. 284 // // Fill the stack.
86 // if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) { 285 // if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) {
87 // Memory::Memset(currentStack.start, 0xFF, nt.stack_size); 286 // Memory::Memset(current_stack.start, 0xFF, nt.stack_size);
88 // } 287 // }
89 // context.r[MIPS_REG_SP] = currentStack.start + nt.stack_size; 288 // context.r[MIPS_REG_SP] = current_stack.start + nt.stack_size;
90 // currentStack.end = context.r[MIPS_REG_SP]; 289 // current_stack.end = context.r[MIPS_REG_SP];
91 // // The k0 section is 256 bytes at the top of the stack. 290 // // The k0 section is 256 bytes at the top of the stack.
92 // context.r[MIPS_REG_SP] -= 256; 291 // context.r[MIPS_REG_SP] -= 256;
93 // context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP]; 292 // context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP];
@@ -104,7 +303,7 @@ public:
104 //} 303 //}
105 304
106 //void FreeStack() { 305 //void FreeStack() {
107 // if (currentStack.start != 0) { 306 // if (current_stack.start != 0) {
108 // DEBUG_LOG(KERNEL, "Freeing thread stack %s", nt.name); 307 // DEBUG_LOG(KERNEL, "Freeing thread stack %s", nt.name);
109 308
110 // if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) { 309 // if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) {
@@ -112,12 +311,12 @@ public:
112 // } 311 // }
113 312
114 // if (nt.attr & PSP_THREAD_ATTR_KERNEL) { 313 // if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
115 // kernelMemory.Free(currentStack.start); 314 // kernelMemory.Free(current_stack.start);
116 // } 315 // }
117 // else { 316 // else {
118 // userMemory.Free(currentStack.start); 317 // userMemory.Free(current_stack.start);
119 // } 318 // }
120 // currentStack.start = 0; 319 // current_stack.start = 0;
121 // } 320 // }
122 //} 321 //}
123 322
@@ -126,14 +325,14 @@ public:
126 // if (stack == (u32)-1) 325 // if (stack == (u32)-1)
127 // return false; 326 // return false;
128 327
129 // pushed_stacks.push_back(currentStack); 328 // pushed_stacks.push_back(current_stack);
130 // currentStack.start = stack; 329 // current_stack.start = stack;
131 // currentStack.end = stack + size; 330 // current_stack.end = stack + size;
132 // nt.initialStack = currentStack.start; 331 // nt.initialStack = current_stack.start;
133 // nt.stack_size = currentStack.end - currentStack.start; 332 // nt.stack_size = current_stack.end - current_stack.start;
134 333
135 // // We still drop the threadID at the bottom and fill it, but there's no k0. 334 // // We still drop the thread_id at the bottom and fill it, but there's no k0.
136 // Memory::Memset(currentStack.start, 0xFF, nt.stack_size); 335 // Memory::Memset(current_stack.start, 0xFF, nt.stack_size);
137 // Memory::Write_U32(GetUID(), nt.initialStack); 336 // Memory::Write_U32(GetUID(), nt.initialStack);
138 // return true; 337 // return true;
139 //} 338 //}
@@ -142,16 +341,16 @@ public:
142 // if (pushed_stacks.size() == 0) { 341 // if (pushed_stacks.size() == 0) {
143 // return false; 342 // return false;
144 // } 343 // }
145 // userMemory.Free(currentStack.start); 344 // userMemory.Free(current_stack.start);
146 // currentStack = pushed_stacks.back(); 345 // current_stack = pushed_stacks.back();
147 // pushed_stacks.pop_back(); 346 // pushed_stacks.pop_back();
148 // nt.initialStack = currentStack.start; 347 // nt.initialStack = current_stack.start;
149 // nt.stack_size = currentStack.end - currentStack.start; 348 // nt.stack_size = current_stack.end - current_stack.start;
150 // return true; 349 // return true;
151 //} 350 //}
152 351
153 Thread() { 352 Thread() {
154 currentStack.start = 0; 353 current_stack.start = 0;
155 } 354 }
156 355
157 // Can't use a destructor since savestates will call that too. 356 // Can't use a destructor since savestates will call that too.
@@ -177,20 +376,20 @@ public:
177 ThreadWaitInfo getWaitInfo(); 376 ThreadWaitInfo getWaitInfo();
178 377
179 // Utils 378 // Utils
180 //inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; } 379 inline bool IsRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
181 //inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; } 380 inline bool IsStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
182 //inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; } 381 inline bool IsReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
183 //inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; } 382 inline bool IsWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
184 //inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; } 383 inline bool IsSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
185 384
186 NativeThread nt; 385 NativeThread nt;
187 386
188 ThreadWaitInfo waitInfo; 387 ThreadWaitInfo waitInfo;
189 UID moduleId; 388 UID moduleId;
190 389
191 bool isProcessingCallbacks; 390 //bool isProcessingCallbacks;
192 u32 currentMipscallId; 391 //u32 currentMipscallId;
193 UID currentCallbackId; 392 //UID currentCallbackId;
194 393
195 ThreadContext context; 394 ThreadContext context;
196 395
@@ -206,7 +405,7 @@ public:
206 // These are stacks that aren't "active" right now, but will pop off once the func returns. 405 // These are stacks that aren't "active" right now, but will pop off once the func returns.
207 std::vector<StackInfo> pushed_stacks; 406 std::vector<StackInfo> pushed_stacks;
208 407
209 StackInfo currentStack; 408 StackInfo current_stack;
210 409
211 // For thread end. 410 // For thread end.
212 std::vector<UID> waiting_threads; 411 std::vector<UID> waiting_threads;
@@ -214,15 +413,276 @@ public:
214 std::map<UID, u64> paused_waits; 413 std::map<UID, u64> paused_waits;
215}; 414};
216 415
217void __KernelThreadingInit() { 416void ThreadContext::reset() {
417 for (int i = 0; i < 16; i++) {
418 reg[i] = 0;
419 }
420 reg[13] = Memory::SCRATCHPAD_VADDR_END;
421 cpsr = 0;
218} 422}
219 423
220void __KernelThreadingShutdown() { 424// Lists all thread ids that aren't deleted/etc.
425std::vector<UID> g_thread_queue;
426
427// Lists only ready thread ids
428ThreadQueueList g_thread_ready_queue;
429
430UID g_current_thread;
431Thread* g_current_thread_ptr;
432const char *g_hle_current_thread_name = NULL;
433
434Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority,
435 u32 entrypoint, u32 arg, u32 stack_top, u32 processor_id, int stack_size) {
436
437 Thread *t = new Thread;
438 id = g_kernel_objects.Create(t);
439
440 g_thread_queue.push_back(id);
441 g_thread_ready_queue.prepare(priority);
442
443 memset(&t->nt, 0xCD, sizeof(t->nt));
444
445 t->nt.entry_point = entrypoint;
446 t->nt.native_size = sizeof(t->nt);
447 t->nt.initial_priority = t->nt.current_priority = priority;
448 t->nt.status = THREADSTATUS_DORMANT;
449 t->nt.initial_stack = t->nt.stack_top = stack_top;
450 t->nt.stack_size = stack_size;
451 t->nt.processor_id = processor_id;
452
453 strncpy(t->nt.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
454 t->nt.name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
455
456 t->nt.stack_size = stack_size;
457 t->SetupStack(stack_top, stack_size);
458
459 return t;
460}
461
462void __KernelResetThread(Thread *t, int lowest_priority) {
463 t->context.reset();
464 t->context.pc = t->nt.entry_point;
465
466 // If the thread would be better than lowestPriority, reset to its initial. Yes, kinda odd...
467 if (t->nt.current_priority < lowest_priority)
468 t->nt.current_priority = t->nt.initial_priority;
469
470 //t->nt.wait_type = WAITTYPE_NONE;
471 //t->nt.wait_id = 0;
472 memset(&t->waitInfo, 0, sizeof(t->waitInfo));
473
474 //t->nt.exitStatus = SCE_KERNEL_ERROR_NOT_DORMANT;
475 //t->isProcessingCallbacks = false;
476 //t->currentCallbackId = 0;
477 //t->currentMipscallId = 0;
478 //t->pendingMipsCalls.clear();
479
480 //t->context.r[MIPS_REG_RA] = threadReturnHackAddr; //hack! TODO fix
481 // TODO: Not sure if it's reset here, but this makes sense.
482 //t->context.r[MIPS_REG_GP] = t->nt.gpreg;
483 //t->FillStack();
484
485 //if (!t->waitingThreads.empty())
486 // ERROR_LOG(KERNEL, "Resetting thread with threads waiting on end?");
487}
488
489
490inline Thread *__GetCurrentThread() {
491 return g_current_thread_ptr;
492}
493
494inline void __SetCurrentThread(Thread *thread, UID thread_id, const char *name) {
495 g_current_thread = thread_id;
496 g_current_thread_ptr = thread;
497 g_hle_current_thread_name = name;
498}
499
500// TODO: Use __KernelChangeThreadState instead? It has other affects...
501void __KernelChangeReadyState(Thread *thread, UID thread_id, bool ready) {
502 // Passing the id as a parameter is just an optimization, if it's wrong it will cause havoc.
503 _dbg_assert_msg_(KERNEL, thread->GetUID() == thread_id, "Incorrect thread_id");
504 int prio = thread->nt.current_priority;
505
506 if (thread->IsReady()) {
507 if (!ready)
508 g_thread_ready_queue.remove(prio, thread_id);
509 } else if (ready) {
510 if (thread->IsRunning()) {
511 g_thread_ready_queue.push_front(prio, thread_id);
512 } else {
513 g_thread_ready_queue.push_back(prio, thread_id);
514 }
515 thread->nt.status = THREADSTATUS_READY;
516 }
517}
518
519void __KernelChangeReadyState(UID thread_id, bool ready) {
520 u32 error;
521 Thread *thread = g_kernel_objects.Get<Thread>(thread_id, error);
522 if (thread) {
523 __KernelChangeReadyState(thread, thread_id, ready);
524 } else {
525 WARN_LOG(KERNEL, "Trying to change the ready state of an unknown thread?");
526 }
527}
528
529// Returns NULL if the current thread is fine.
530Thread* __KernelNextThread() {
531 UID bestThread;
532
533 // If the current thread is running, it's a valid candidate.
534 Thread *cur = __GetCurrentThread();
535 if (cur && cur->IsRunning()) {
536 bestThread = g_thread_ready_queue.pop_first_better(cur->nt.current_priority);
537 if (bestThread != 0) {
538 __KernelChangeReadyState(cur, g_current_thread, true);
539 }
540 } else {
541 bestThread = g_thread_ready_queue.pop_first();
542 }
543
544 // Assume g_thread_ready_queue has not become corrupt.
545 if (bestThread != 0) {
546 return g_kernel_objects.GetFast<Thread>(bestThread);
547 } else {
548 return NULL;
549 }
550}
551
552// Saves the current CPU context
553void __KernelSaveContext(ThreadContext *ctx) {
554 ctx->reg[0] = Core::g_app_core->GetReg(0);
555 ctx->reg[1] = Core::g_app_core->GetReg(1);
556 ctx->reg[2] = Core::g_app_core->GetReg(2);
557 ctx->reg[3] = Core::g_app_core->GetReg(3);
558 ctx->reg[4] = Core::g_app_core->GetReg(4);
559 ctx->reg[5] = Core::g_app_core->GetReg(5);
560 ctx->reg[6] = Core::g_app_core->GetReg(6);
561 ctx->reg[7] = Core::g_app_core->GetReg(7);
562 ctx->reg[8] = Core::g_app_core->GetReg(8);
563 ctx->reg[9] = Core::g_app_core->GetReg(9);
564 ctx->reg[10] = Core::g_app_core->GetReg(10);
565 ctx->reg[11] = Core::g_app_core->GetReg(11);
566 ctx->reg[12] = Core::g_app_core->GetReg(12);
567 ctx->reg[13] = Core::g_app_core->GetReg(13);
568 ctx->reg[14] = Core::g_app_core->GetReg(14);
569 ctx->reg[15] = Core::g_app_core->GetReg(15);
570 ctx->pc = Core::g_app_core->GetPC();
571 ctx->cpsr = Core::g_app_core->GetCPSR();
572}
573
574// Loads a CPU context
575void __KernelLoadContext(ThreadContext *ctx) {
576 Core::g_app_core->SetReg(0, ctx->reg[0]);
577 Core::g_app_core->SetReg(1, ctx->reg[1]);
578 Core::g_app_core->SetReg(2, ctx->reg[2]);
579 Core::g_app_core->SetReg(3, ctx->reg[3]);
580 Core::g_app_core->SetReg(4, ctx->reg[4]);
581 Core::g_app_core->SetReg(5, ctx->reg[5]);
582 Core::g_app_core->SetReg(6, ctx->reg[6]);
583 Core::g_app_core->SetReg(7, ctx->reg[7]);
584 Core::g_app_core->SetReg(8, ctx->reg[8]);
585 Core::g_app_core->SetReg(9, ctx->reg[9]);
586 Core::g_app_core->SetReg(10, ctx->reg[10]);
587 Core::g_app_core->SetReg(11, ctx->reg[11]);
588 Core::g_app_core->SetReg(12, ctx->reg[12]);
589 Core::g_app_core->SetReg(13, ctx->reg[13]);
590 Core::g_app_core->SetReg(14, ctx->reg[14]);
591 Core::g_app_core->SetReg(15, ctx->reg[15]);
592 Core::g_app_core->SetPC(ctx->pc);
593 Core::g_app_core->SetCPSR(ctx->cpsr);
594}
595
596void __KernelSwitchContext(Thread *target, const char *reason) {
597 u32 oldPC = 0;
598 UID oldUID = 0;
599 const char *oldName = g_hle_current_thread_name != NULL ? g_hle_current_thread_name : "(none)";
600
601 Thread *cur = __GetCurrentThread();
602 if (cur) { // It might just have been deleted.
603 __KernelSaveContext(&cur->context);
604 oldPC = Core::g_app_core->GetPC();
605 oldUID = cur->GetUID();
606
607 // Normally this is taken care of in __KernelNextThread().
608 if (cur->IsRunning())
609 __KernelChangeReadyState(cur, oldUID, true);
610 }
611
612 if (target) {
613 __SetCurrentThread(target, target->GetUID(), target->nt.name);
614 __KernelChangeReadyState(target, g_current_thread, false);
615 target->nt.status = (target->nt.status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
616
617 __KernelLoadContext(&target->context);
618 } else {
619 __SetCurrentThread(NULL, 0, NULL);
620 }
621
622#if DEBUG_LEVEL <= MAX_LOGLEVEL || DEBUG_LOG == NOTICE_LOG
623 //bool fromIdle = oldUID == threadIdleID[0] || oldUID == threadIdleID[1];
624 //bool toIdle = currentThread == threadIdleID[0] || currentThread == threadIdleID[1];
625 //if (!(fromIdle && toIdle))
626 //{
627 // u64 nowCycles = CoreTiming::GetTicks();
628 // s64 consumedCycles = nowCycles - lastSwitchCycles;
629 // lastSwitchCycles = nowCycles;
630
631 // DEBUG_LOG(SCEKERNEL, "Context switch: %s -> %s (%i->%i, pc: %08x->%08x, %s) +%lldus",
632 // oldName, hleCurrentThreadName,
633 // oldUID, currentThread,
634 // oldPC, currentMIPS->pc,
635 // reason,
636 // cyclesToUs(consumedCycles));
637 //}
638#endif
639
640 if (target) {
641 //// No longer waiting.
642 //target->nt.waitType = WAITTYPE_NONE;
643 //target->nt.waitID = 0;
644
645 //__KernelExecutePendingARMCalls(target, true);
646 }
647}
648
649UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size) {
650 UID id;
651
652 Thread *thread = __KernelCreateThread(id, module_id, "root", prio, Core::g_app_core->GetPC(),
653 arg, Memory::SCRATCHPAD_VADDR_END, 0xFFFFFFFE, stack_size=stack_size);
654
655 if (thread->current_stack.start == 0) {
656 ERROR_LOG(KERNEL, "Unable to allocate stack for root thread.");
657 }
658 __KernelResetThread(thread, 0);
659
660 Thread *prev_thread = __GetCurrentThread();
661 if (prev_thread && prev_thread->IsRunning())
662 __KernelChangeReadyState(g_current_thread, true);
663 __SetCurrentThread(thread, id, "root");
664 thread->nt.status = THREADSTATUS_RUNNING; // do not schedule
665
666 strcpy(thread->nt.name, "root");
667
668 __KernelLoadContext(&thread->context);
669
670 // NOTE(bunnei): Not sure this is really correct, ignore args for now...
671 //Core::g_app_core->SetReg(0, args);
672 //Core::g_app_core->SetReg(13, (args + 0xf) & ~0xf); // Setup SP - probably not correct
673 //u32 location = Core::g_app_core->GetReg(13); // SP
674 //Core::g_app_core->SetReg(1, location);
675
676 //if (argp)
677 // Memory::Memcpy(location, argp, args);
678 //// Let's assume same as starting a new thread, 64 bytes for safety/kernel.
679 //Core::g_app_core->SetReg(13, Core::g_app_core->GetReg(13) - 64);
680
681 return id;
221} 682}
222 683
223//const char *__KernelGetThreadName(UID threadID); 684void __KernelThreadingInit() {
224// 685}
225//void __KernelSaveContext(ThreadContext *ctx);
226//void __KernelLoadContext(ThreadContext *ctx);
227 686
228//void __KernelSwitchContext(Thread *target, const char *reason); \ No newline at end of file 687void __KernelThreadingShutdown() {
688}