thread.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // Copyright 2014 Citra Emulator Project / PPSSPP Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4. #include <stdio.h>
  5. #include <list>
  6. #include <vector>
  7. #include <map>
  8. #include <string>
  9. #include "common/common.h"
  10. #include "core/core.h"
  11. #include "core/mem_map.h"
  12. #include "core/hle/kernel/kernel.h"
  13. #include "core/hle/kernel/thread.h"
  14. struct ThreadQueueList {
  15. // Number of queues (number of priority levels starting at 0.)
  16. static const int NUM_QUEUES = 128;
  17. // Initial number of threads a single queue can handle.
  18. static const int INITIAL_CAPACITY = 32;
  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. UID *data;
  28. // Size of data array.
  29. int capacity;
  30. };
  31. ThreadQueueList() {
  32. memset(queues, 0, sizeof(queues));
  33. first = invalid();
  34. }
  35. ~ThreadQueueList() {
  36. for (int i = 0; i < NUM_QUEUES; ++i) {
  37. if (queues[i].data != NULL) {
  38. free(queues[i].data);
  39. }
  40. }
  41. }
  42. // Only for debugging, returns priority level.
  43. int contains(const UID uid) {
  44. for (int i = 0; i < NUM_QUEUES; ++i) {
  45. if (queues[i].data == NULL) {
  46. continue;
  47. }
  48. Queue *cur = &queues[i];
  49. for (int j = cur->first; j < cur->end; ++j) {
  50. if (cur->data[j] == uid) {
  51. return i;
  52. }
  53. }
  54. }
  55. return -1;
  56. }
  57. inline UID pop_first() {
  58. Queue *cur = first;
  59. while (cur != invalid()) {
  60. if (cur->end - cur->first > 0) {
  61. return cur->data[cur->first++];
  62. }
  63. cur = cur->next;
  64. }
  65. _dbg_assert_msg_(KERNEL, false, "ThreadQueueList should not be empty.");
  66. return 0;
  67. }
  68. inline UID pop_first_better(u32 priority) {
  69. Queue *cur = first;
  70. Queue *stop = &queues[priority];
  71. while (cur < stop) {
  72. if (cur->end - cur->first > 0) {
  73. return cur->data[cur->first++];
  74. }
  75. cur = cur->next;
  76. }
  77. return 0;
  78. }
  79. inline void push_front(u32 priority, const UID thread_id) {
  80. Queue *cur = &queues[priority];
  81. cur->data[--cur->first] = thread_id;
  82. if (cur->first == 0) {
  83. rebalance(priority);
  84. }
  85. }
  86. inline void push_back(u32 priority, const UID thread_id)
  87. {
  88. Queue *cur = &queues[priority];
  89. cur->data[cur->end++] = thread_id;
  90. if (cur->end == cur->capacity) {
  91. rebalance(priority);
  92. }
  93. }
  94. inline void remove(u32 priority, const UID thread_id) {
  95. Queue *cur = &queues[priority];
  96. _dbg_assert_msg_(KERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
  97. for (int i = cur->first; i < cur->end; ++i) {
  98. if (cur->data[i] == thread_id) {
  99. int remaining = --cur->end - i;
  100. if (remaining > 0) {
  101. memmove(&cur->data[i], &cur->data[i + 1], remaining * sizeof(UID));
  102. }
  103. return;
  104. }
  105. }
  106. // Wasn't there.
  107. }
  108. inline void rotate(u32 priority) {
  109. Queue *cur = &queues[priority];
  110. _dbg_assert_msg_(KERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
  111. if (cur->end - cur->first > 1) {
  112. cur->data[cur->end++] = cur->data[cur->first++];
  113. if (cur->end == cur->capacity) {
  114. rebalance(priority);
  115. }
  116. }
  117. }
  118. inline void clear() {
  119. for (int i = 0; i < NUM_QUEUES; ++i) {
  120. if (queues[i].data != NULL) {
  121. free(queues[i].data);
  122. }
  123. }
  124. memset(queues, 0, sizeof(queues));
  125. first = invalid();
  126. }
  127. inline bool empty(u32 priority) const {
  128. const Queue *cur = &queues[priority];
  129. return cur->first == cur->end;
  130. }
  131. inline void prepare(u32 priority) {
  132. Queue *cur = &queues[priority];
  133. if (cur->next == NULL) {
  134. link(priority, INITIAL_CAPACITY);
  135. }
  136. }
  137. private:
  138. Queue *invalid() const {
  139. return (Queue *)-1;
  140. }
  141. void link(u32 priority, int size) {
  142. _dbg_assert_msg_(KERNEL, queues[priority].data == NULL, "ThreadQueueList::Queue should only be initialized once.");
  143. if (size <= INITIAL_CAPACITY) {
  144. size = INITIAL_CAPACITY;
  145. } else {
  146. int goal = size;
  147. size = INITIAL_CAPACITY;
  148. while (size < goal)
  149. size *= 2;
  150. }
  151. Queue *cur = &queues[priority];
  152. cur->data = (UID*)malloc(sizeof(UID)* size);
  153. cur->capacity = size;
  154. cur->first = size / 2;
  155. cur->end = size / 2;
  156. for (int i = (int)priority - 1; i >= 0; --i) {
  157. if (queues[i].next != NULL) {
  158. cur->next = queues[i].next;
  159. queues[i].next = cur;
  160. return;
  161. }
  162. }
  163. cur->next = first;
  164. first = cur;
  165. }
  166. void rebalance(u32 priority) {
  167. Queue *cur = &queues[priority];
  168. int size = cur->end - cur->first;
  169. if (size >= cur->capacity - 2) {
  170. UID* new_data = (UID*)realloc(cur->data, cur->capacity * 2 * sizeof(UID));
  171. if (new_data != NULL) {
  172. cur->capacity *= 2;
  173. cur->data = new_data;
  174. }
  175. }
  176. int newFirst = (cur->capacity - size) / 2;
  177. if (newFirst != cur->first) {
  178. memmove(&cur->data[newFirst], &cur->data[cur->first], size * sizeof(UID));
  179. cur->first = newFirst;
  180. cur->end = newFirst + size;
  181. }
  182. }
  183. // The first queue that's ever been used.
  184. Queue* first;
  185. // The priority level queues of thread ids.
  186. Queue queues[NUM_QUEUES];
  187. };
  188. // Supposed to represent a real CTR struct... but not sure of the correct fields yet.
  189. struct NativeThread {
  190. //u32 Pointer to vtable
  191. //u32 Reference count
  192. //KProcess* Process the thread belongs to (virtual address)
  193. //u32 Thread id
  194. //u32* ptr = *(KThread+0x8C) - 0xB0
  195. //u32* End-address of the page for this thread allocated in the 0xFF4XX000 region. Thus,
  196. // if the beginning of this mapped page is 0xFF401000, this ptr would be 0xFF402000.
  197. //KThread* Previous ? (virtual address)
  198. //KThread* Next ? (virtual address)
  199. u32_le native_size;
  200. char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
  201. // Threading stuff
  202. u32_le status;
  203. u32_le entry_point;
  204. u32_le initial_stack;
  205. u32_le stack_top;
  206. u32_le stack_size;
  207. u32_le arg;
  208. u32_le processor_id;
  209. s32_le initial_priority;
  210. s32_le current_priority;
  211. };
  212. struct ThreadWaitInfo {
  213. u32 wait_value;
  214. u32 timeout_ptr;
  215. };
  216. class Thread : public KernelObject {
  217. public:
  218. /*const char *GetName() { return nt.name; }*/
  219. const char *GetTypeName() { return "Thread"; }
  220. //void GetQuickInfo(char *ptr, int size)
  221. //{
  222. // sprintf(ptr, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )",
  223. // context.pc, context.r[13], // 13 is stack pointer
  224. // (nt.status & THREADSTATUS_RUNNING) ? "RUN" : "",
  225. // (nt.status & THREADSTATUS_READY) ? "READY" : "",
  226. // (nt.status & THREADSTATUS_WAIT) ? "WAIT" : "",
  227. // (nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "",
  228. // (nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "",
  229. // (nt.status & THREADSTATUS_DEAD) ? "DEAD" : "",
  230. // nt.waitType,
  231. // nt.waitID,
  232. // waitInfo.waitValue);
  233. //}
  234. //static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; }
  235. static KernelIDType GetStaticIDType() { return KERNEL_ID_TYPE_THREAD; }
  236. KernelIDType GetIDType() const { return KERNEL_ID_TYPE_THREAD; }
  237. bool SetupStack(u32 stack_top, int stack_size) {
  238. current_stack.start = stack_top;
  239. nt.initial_stack = current_stack.start;
  240. nt.stack_size = stack_size;
  241. return true;
  242. }
  243. //bool FillStack() {
  244. // // Fill the stack.
  245. // if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) {
  246. // Memory::Memset(current_stack.start, 0xFF, nt.stack_size);
  247. // }
  248. // context.r[MIPS_REG_SP] = current_stack.start + nt.stack_size;
  249. // current_stack.end = context.r[MIPS_REG_SP];
  250. // // The k0 section is 256 bytes at the top of the stack.
  251. // context.r[MIPS_REG_SP] -= 256;
  252. // context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP];
  253. // u32 k0 = context.r[MIPS_REG_K0];
  254. // Memory::Memset(k0, 0, 0x100);
  255. // Memory::Write_U32(GetUID(), k0 + 0xc0);
  256. // Memory::Write_U32(nt.initialStack, k0 + 0xc8);
  257. // Memory::Write_U32(0xffffffff, k0 + 0xf8);
  258. // Memory::Write_U32(0xffffffff, k0 + 0xfc);
  259. // // After k0 comes the arguments, which is done by sceKernelStartThread().
  260. // Memory::Write_U32(GetUID(), nt.initialStack);
  261. // return true;
  262. //}
  263. //void FreeStack() {
  264. // if (current_stack.start != 0) {
  265. // DEBUG_LOG(KERNEL, "Freeing thread stack %s", nt.name);
  266. // if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) {
  267. // Memory::Memset(nt.initialStack, 0, nt.stack_size);
  268. // }
  269. // if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
  270. // kernelMemory.Free(current_stack.start);
  271. // }
  272. // else {
  273. // userMemory.Free(current_stack.start);
  274. // }
  275. // current_stack.start = 0;
  276. // }
  277. //}
  278. //bool PushExtendedStack(u32 size) {
  279. // u32 stack = userMemory.Alloc(size, true, (std::string("extended/") + nt.name).c_str());
  280. // if (stack == (u32)-1)
  281. // return false;
  282. // pushed_stacks.push_back(current_stack);
  283. // current_stack.start = stack;
  284. // current_stack.end = stack + size;
  285. // nt.initialStack = current_stack.start;
  286. // nt.stack_size = current_stack.end - current_stack.start;
  287. // // We still drop the thread_id at the bottom and fill it, but there's no k0.
  288. // Memory::Memset(current_stack.start, 0xFF, nt.stack_size);
  289. // Memory::Write_U32(GetUID(), nt.initialStack);
  290. // return true;
  291. //}
  292. //bool PopExtendedStack() {
  293. // if (pushed_stacks.size() == 0) {
  294. // return false;
  295. // }
  296. // userMemory.Free(current_stack.start);
  297. // current_stack = pushed_stacks.back();
  298. // pushed_stacks.pop_back();
  299. // nt.initialStack = current_stack.start;
  300. // nt.stack_size = current_stack.end - current_stack.start;
  301. // return true;
  302. //}
  303. Thread() {
  304. current_stack.start = 0;
  305. }
  306. // Can't use a destructor since savestates will call that too.
  307. //void Cleanup() {
  308. // // Callbacks are automatically deleted when their owning thread is deleted.
  309. // for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it)
  310. // kernelObjects.Destroy<Callback>(*it);
  311. // if (pushed_stacks.size() != 0)
  312. // {
  313. // WARN_LOG(KERNEL, "Thread ended within an extended stack");
  314. // for (size_t i = 0; i < pushed_stacks.size(); ++i)
  315. // userMemory.Free(pushed_stacks[i].start);
  316. // }
  317. // FreeStack();
  318. //}
  319. void setReturnValue(u32 retval);
  320. void setReturnValue(u64 retval);
  321. void resumeFromWait();
  322. //bool isWaitingFor(WaitType type, int id);
  323. //int getWaitID(WaitType type);
  324. ThreadWaitInfo getWaitInfo();
  325. // Utils
  326. inline bool IsRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
  327. inline bool IsStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
  328. inline bool IsReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
  329. inline bool IsWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
  330. inline bool IsSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
  331. NativeThread nt;
  332. ThreadWaitInfo waitInfo;
  333. UID moduleId;
  334. //bool isProcessingCallbacks;
  335. //u32 currentMipscallId;
  336. //UID currentCallbackId;
  337. ThreadContext context;
  338. std::vector<UID> callbacks;
  339. std::list<u32> pending_calls;
  340. struct StackInfo {
  341. u32 start;
  342. u32 end;
  343. };
  344. // This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse.
  345. // These are stacks that aren't "active" right now, but will pop off once the func returns.
  346. std::vector<StackInfo> pushed_stacks;
  347. StackInfo current_stack;
  348. // For thread end.
  349. std::vector<UID> waiting_threads;
  350. // Key is the callback id it was for, or if no callback, the thread id.
  351. std::map<UID, u64> paused_waits;
  352. };
  353. void ThreadContext::reset() {
  354. for (int i = 0; i < 16; i++) {
  355. reg[i] = 0;
  356. }
  357. reg[13] = Memory::SCRATCHPAD_VADDR_END;
  358. cpsr = 0;
  359. }
  360. // Lists all thread ids that aren't deleted/etc.
  361. std::vector<UID> g_thread_queue;
  362. // Lists only ready thread ids
  363. ThreadQueueList g_thread_ready_queue;
  364. UID g_current_thread = 0;
  365. Thread* g_current_thread_ptr = NULL;
  366. const char* g_hle_current_thread_name = NULL;
  367. /// Creates a new thread
  368. Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority,
  369. u32 entrypoint, u32 arg, u32 stack_top, u32 processor_id, int stack_size) {
  370. Thread *t = new Thread;
  371. id = g_kernel_objects.Create(t);
  372. g_thread_queue.push_back(id);
  373. g_thread_ready_queue.prepare(priority);
  374. memset(&t->nt, 0xCD, sizeof(t->nt));
  375. t->nt.entry_point = entrypoint;
  376. t->nt.native_size = sizeof(t->nt);
  377. t->nt.initial_priority = t->nt.current_priority = priority;
  378. t->nt.status = THREADSTATUS_DORMANT;
  379. t->nt.initial_stack = t->nt.stack_top = stack_top;
  380. t->nt.stack_size = stack_size;
  381. t->nt.processor_id = processor_id;
  382. strncpy(t->nt.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
  383. t->nt.name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
  384. t->nt.stack_size = stack_size;
  385. t->SetupStack(stack_top, stack_size);
  386. return t;
  387. }
  388. /// Resets the specified thread back to initial calling state
  389. void __KernelResetThread(Thread *t, int lowest_priority) {
  390. t->context.reset();
  391. t->context.pc = t->nt.entry_point;
  392. // If the thread would be better than lowestPriority, reset to its initial. Yes, kinda odd...
  393. if (t->nt.current_priority < lowest_priority) {
  394. t->nt.current_priority = t->nt.initial_priority;
  395. }
  396. memset(&t->waitInfo, 0, sizeof(t->waitInfo));
  397. }
  398. /// Returns the current executing thread
  399. inline Thread *__GetCurrentThread() {
  400. return g_current_thread_ptr;
  401. }
  402. /// Sets the current executing thread
  403. inline void __SetCurrentThread(Thread *thread, UID thread_id, const char *name) {
  404. g_current_thread = thread_id;
  405. g_current_thread_ptr = thread;
  406. g_hle_current_thread_name = name;
  407. }
  408. // TODO: Use __KernelChangeThreadState instead? It has other affects...
  409. void __KernelChangeReadyState(Thread *thread, UID thread_id, bool ready) {
  410. // Passing the id as a parameter is just an optimization, if it's wrong it will cause havoc.
  411. _dbg_assert_msg_(KERNEL, thread->GetUID() == thread_id, "Incorrect thread_id");
  412. int prio = thread->nt.current_priority;
  413. if (thread->IsReady()) {
  414. if (!ready)
  415. g_thread_ready_queue.remove(prio, thread_id);
  416. } else if (ready) {
  417. if (thread->IsRunning()) {
  418. g_thread_ready_queue.push_front(prio, thread_id);
  419. } else {
  420. g_thread_ready_queue.push_back(prio, thread_id);
  421. }
  422. thread->nt.status = THREADSTATUS_READY;
  423. }
  424. }
  425. void __KernelChangeReadyState(UID thread_id, bool ready) {
  426. u32 error;
  427. Thread *thread = g_kernel_objects.Get<Thread>(thread_id, error);
  428. if (thread) {
  429. __KernelChangeReadyState(thread, thread_id, ready);
  430. } else {
  431. WARN_LOG(KERNEL, "Trying to change the ready state of an unknown thread?");
  432. }
  433. }
  434. /// Returns NULL if the current thread is fine.
  435. Thread* __KernelNextThread() {
  436. UID best_thread;
  437. // If the current thread is running, it's a valid candidate.
  438. Thread *cur = __GetCurrentThread();
  439. if (cur && cur->IsRunning()) {
  440. best_thread = g_thread_ready_queue.pop_first_better(cur->nt.current_priority);
  441. if (best_thread != 0) {
  442. __KernelChangeReadyState(cur, g_current_thread, true);
  443. }
  444. } else {
  445. best_thread = g_thread_ready_queue.pop_first();
  446. }
  447. // Assume g_thread_ready_queue has not become corrupt.
  448. if (best_thread != 0) {
  449. return g_kernel_objects.GetFast<Thread>(best_thread);
  450. } else {
  451. return NULL;
  452. }
  453. }
  454. /// Saves the current CPU context
  455. void __KernelSaveContext(ThreadContext *ctx) {
  456. ctx->reg[0] = Core::g_app_core->GetReg(0);
  457. ctx->reg[1] = Core::g_app_core->GetReg(1);
  458. ctx->reg[2] = Core::g_app_core->GetReg(2);
  459. ctx->reg[3] = Core::g_app_core->GetReg(3);
  460. ctx->reg[4] = Core::g_app_core->GetReg(4);
  461. ctx->reg[5] = Core::g_app_core->GetReg(5);
  462. ctx->reg[6] = Core::g_app_core->GetReg(6);
  463. ctx->reg[7] = Core::g_app_core->GetReg(7);
  464. ctx->reg[8] = Core::g_app_core->GetReg(8);
  465. ctx->reg[9] = Core::g_app_core->GetReg(9);
  466. ctx->reg[10] = Core::g_app_core->GetReg(10);
  467. ctx->reg[11] = Core::g_app_core->GetReg(11);
  468. ctx->reg[12] = Core::g_app_core->GetReg(12);
  469. ctx->reg[13] = Core::g_app_core->GetReg(13);
  470. ctx->reg[14] = Core::g_app_core->GetReg(14);
  471. ctx->reg[15] = Core::g_app_core->GetReg(15);
  472. ctx->pc = Core::g_app_core->GetPC();
  473. ctx->cpsr = Core::g_app_core->GetCPSR();
  474. }
  475. /// Loads a CPU context
  476. void __KernelLoadContext(ThreadContext *ctx) {
  477. Core::g_app_core->SetReg(0, ctx->reg[0]);
  478. Core::g_app_core->SetReg(1, ctx->reg[1]);
  479. Core::g_app_core->SetReg(2, ctx->reg[2]);
  480. Core::g_app_core->SetReg(3, ctx->reg[3]);
  481. Core::g_app_core->SetReg(4, ctx->reg[4]);
  482. Core::g_app_core->SetReg(5, ctx->reg[5]);
  483. Core::g_app_core->SetReg(6, ctx->reg[6]);
  484. Core::g_app_core->SetReg(7, ctx->reg[7]);
  485. Core::g_app_core->SetReg(8, ctx->reg[8]);
  486. Core::g_app_core->SetReg(9, ctx->reg[9]);
  487. Core::g_app_core->SetReg(10, ctx->reg[10]);
  488. Core::g_app_core->SetReg(11, ctx->reg[11]);
  489. Core::g_app_core->SetReg(12, ctx->reg[12]);
  490. Core::g_app_core->SetReg(13, ctx->reg[13]);
  491. Core::g_app_core->SetReg(14, ctx->reg[14]);
  492. Core::g_app_core->SetReg(15, ctx->reg[15]);
  493. Core::g_app_core->SetPC(ctx->pc);
  494. Core::g_app_core->SetCPSR(ctx->cpsr);
  495. }
  496. /// Switches thread context
  497. void __KernelSwitchContext(Thread *target, const char *reason) {
  498. u32 old_pc = 0;
  499. UID old_uid = 0;
  500. const char *old_name = g_hle_current_thread_name != NULL ? g_hle_current_thread_name : "(none)";
  501. Thread *cur = __GetCurrentThread();
  502. if (cur) { // It might just have been deleted.
  503. __KernelSaveContext(&cur->context);
  504. old_pc = Core::g_app_core->GetPC();
  505. old_uid = cur->GetUID();
  506. // Normally this is taken care of in __KernelNextThread().
  507. if (cur->IsRunning())
  508. __KernelChangeReadyState(cur, old_uid, true);
  509. }
  510. if (target) {
  511. __SetCurrentThread(target, target->GetUID(), target->nt.name);
  512. __KernelChangeReadyState(target, g_current_thread, false);
  513. target->nt.status = (target->nt.status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
  514. __KernelLoadContext(&target->context);
  515. } else {
  516. __SetCurrentThread(NULL, 0, NULL);
  517. }
  518. }
  519. /// Sets up the root (primary) thread of execution
  520. UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size) {
  521. UID id;
  522. Thread *thread = __KernelCreateThread(id, module_id, "root", prio, Core::g_app_core->GetPC(),
  523. arg, Memory::SCRATCHPAD_VADDR_END, 0xFFFFFFFE, stack_size=stack_size);
  524. if (thread->current_stack.start == 0) {
  525. ERROR_LOG(KERNEL, "Unable to allocate stack for root thread.");
  526. }
  527. __KernelResetThread(thread, 0);
  528. Thread *prev_thread = __GetCurrentThread();
  529. if (prev_thread && prev_thread->IsRunning())
  530. __KernelChangeReadyState(g_current_thread, true);
  531. __SetCurrentThread(thread, id, "root");
  532. thread->nt.status = THREADSTATUS_RUNNING; // do not schedule
  533. strcpy(thread->nt.name, "root");
  534. __KernelLoadContext(&thread->context);
  535. // NOTE(bunnei): Not sure this is really correct, ignore args for now...
  536. //Core::g_app_core->SetReg(0, args);
  537. //Core::g_app_core->SetReg(13, (args + 0xf) & ~0xf); // Setup SP - probably not correct
  538. //u32 location = Core::g_app_core->GetReg(13); // SP
  539. //Core::g_app_core->SetReg(1, location);
  540. //if (argp)
  541. // Memory::Memcpy(location, argp, args);
  542. //// Let's assume same as starting a new thread, 64 bytes for safety/kernel.
  543. //Core::g_app_core->SetReg(13, Core::g_app_core->GetReg(13) - 64);
  544. return id;
  545. }
  546. void __KernelThreadingInit() {
  547. }
  548. void __KernelThreadingShutdown() {
  549. }