1 #include "StdStream.h"
2 #include "PspBios.h"
3 #include "ElfFile.h"
4 #include "lexical_cast_ex.h"
5 #include "Log.h"
6 #include "COP_SCU.h"
7 #include "Psp_ThreadManForUser.h"
8 #include "Psp_StdioForUser.h"
9 #include "Psp_SysMemUserForUser.h"
10 #include "Psp_KernelLibrary.h"
11
12 using namespace Psp;
13
14 #define LOGNAME ("PspBios")
15
16 #define RELOC_SECTION_ID (0x700000A0)
17
18 #define BIOS_THREAD_LINK_HEAD_BASE (Psp::CBios::CONTROL_BLOCK_START + 0x0000)
19 #define BIOS_CURRENT_THREAD_ID_BASE (Psp::CBios::CONTROL_BLOCK_START + 0x0008)
20 #define BIOS_CURRENT_TIME_BASE (Psp::CBios::CONTROL_BLOCK_START + 0x0010)
21 #define BIOS_HANDLERS_BASE (Psp::CBios::CONTROL_BLOCK_START + 0x0080)
22 #define BIOS_HANDLERS_END (BIOS_HEAPBLOCK_BASE - 1)
23 #define BIOS_HEAPBLOCK_BASE (Psp::CBios::CONTROL_BLOCK_START + 0x0100)
24 #define BIOS_HEAPBLOCK_SIZE (sizeof(Psp::CBios::HEAPBLOCK) * Psp::CBios::MAX_HEAPBLOCKS)
25 #define BIOS_MODULE_TRAMPOLINE_BASE (BIOS_HEAPBLOCK_BASE + BIOS_HEAPBLOCK_SIZE)
26 #define BIOS_MODULE_TRAMPOLINE_END (sizeof(Psp::CBios::MODULETRAMPOLINE) * Psp::CBios::MAX_MODULETRAMPOLINES)
27 #define BIOS_THREAD_BASE (BIOS_MODULE_TRAMPOLINE_BASE + BIOS_MODULE_TRAMPOLINE_END)
28 #define BIOS_THREAD_END (sizeof(Psp::CBios::THREAD) * Psp::CBios::MAX_THREADS)
29 #define BIOS_MESSAGEBOX_BASE (BIOS_THREAD_BASE + BIOS_THREAD_END)
30 #define BIOS_MESSAGEBOX_END (sizeof(Psp::CBios::MESSAGEBOX) * Psp::CBios::MAX_MESSAGEBOXES)
31 #define BIOS_MESSAGE_BASE (BIOS_MESSAGEBOX_BASE + BIOS_MESSAGEBOX_END)
32 #define BIOS_MESSAGE_END (sizeof(Psp::CBios::MESSAGE) * Psp::CBios::MAX_MESSAGES)
33 #define BIOS_CALCULATED_END (BIOS_MESSAGE_BASE + BIOS_MESSAGE_END)
34
35 CBios::MODULEFUNCTION CBios::g_IoFileMgrForUserFunctions[] =
36 {
37 {0x27EB27B8, "sceIoLseek"},
38 {0x109F50BC, "sceIoOpen"},
39 {0x42EC03AC, "sceIoWrite"},
40 {0x6A638D83, "sceIoRead"},
41 {0x810C4BC3, "sceIoClose"},
42 {0xA0B5A7C2, "sceIoReadAsync"},
43 {NULL, NULL},
44 };
45
46 CBios::MODULEFUNCTION CBios::g_SysMemUserForUserFunctions[] =
47 {
48 {0x91DE343C, "sceKernelSetCompiledSdkVersion"},
49 {0xF77D77CB, "sceKernelSetCompilerVersion"},
50 {0x237DBD4F, "sceKernelAllocPartitionMemory"},
51 {0x9D9A5BA1, "sceKernelGetBlockHeadAddr"},
52 {0xFE707FDF, "sceKernelAllocMemoryBlock"},
53 {0xDB83A952, "sceKernelGetMemoryBlockAddr"},
54 {0x50F61D8A, "sceKernelFreeMemoryBlock"},
55 };
56
57 CBios::MODULEFUNCTION CBios::g_ThreadManForUserFunctions[] =
58 {
59 {0x446D8DE6, "sceKernelCreateThread"},
60 {0xF475845D, "sceKernelStartThread"},
61 {0x278C0DF5, "sceKernelWaitThreadEnd"},
62 {0x9FA03CD3, "sceKernelDeleteThread"},
63 {0xCEADEB47, "sceKernelDelayThread"},
64 {0xAA73C935, "sceKernelExitThread"},
65 {0xE81CAF8F, "sceKernelCreateCallback"},
66 {0xD6DA4BA1, "sceKernelCreateSema"},
67 {0x4E3A1105, "sceKernelWaitSema"},
68 {0x3F53E640, "sceKernelSignalSema"},
69 {0x28B6489C, "sceKernelDeleteSema"},
70 {0x8125221D, "sceKernelCreateMbx"},
71 {0xE9B3061E, "sceKernelSendMbx"},
72 {0x0D81716A, "sceKernelPollMbx"},
73 {NULL, NULL},
74 };
75
76 CBios::MODULEFUNCTION CBios::g_StdioForUserFunctions[] =
77 {
78 {0xA6BAB2E9, "sceKernelStdout"},
79 {NULL, NULL},
80 };
81
82 CBios::MODULEFUNCTION CBios::g_LoadExecForUserFunctions[] =
83 {
84 {0x4AC57943, "sceKernelRegisterExitCallback"},
85 {NULL, NULL},
86 };
87
88 CBios::MODULEFUNCTION CBios::g_UtilsForUserFunctions[] =
89 {
90 {0xB435DEC5, "sceKernelDcacheWritebackInvalidateAll"},
91 {NULL, NULL},
92 };
93
94 CBios::MODULEFUNCTION CBios::g_SasCoreFunctions[] =
95 {
96 {0x76F01ACA, "sasSetKeyOn"},
97 {0xA0CF2FA4, "sasSetKeyOff"},
98 {0x019B25EB, "sasSetADSR"},
99 {0xCBCD4F79, "sasSetSimpleADSR"},
100 {0xAD84D37F, "sasSetPitch"},
101 {0x99944089, "sasSetVoice"},
102 {0xE1CD9561, "sasSetVoicePCM"},
103 {0x440CA7D8, "sasSetVolume"},
104 {0x2C8E6AB3, "sasGetPauseFlag"},
105 {0x68A46B95, "sasGetEndFlag"},
106 {0x07F58C24, "sasGetAllEnvelope"},
107 {0xA3589D81, "sasCore"},
108 {0x42778A9F, "sasInit"},
109 {0x33D4AB37, "sasSetEffectType"},
110 {0x267A6DD2, "sasSetEffectParam"},
111 {0xD5A229C9, "sasSetEffectVolume"},
112 {0xF983B186, "sasSetEffect"},
113 {NULL, NULL},
114 };
115
116 CBios::MODULEFUNCTION CBios::g_WaveFunctions[] =
117 {
118 {0xE2D56B2D, "sceAudioOutputPanned"},
119 {0x13F592BC, "sceAudioOutputPannedBlocking"},
120 {0xB011922F, "WaveAudioGetRestSample"},
121 {0x5EC81C55, "sceAudioChReserve"},
122 {0xCB2E439E, "sceAudioSetChannelDataLen"},
123 {NULL, NULL},
124 };
125
126 CBios::MODULEFUNCTION CBios::g_UmdUserFunctions[] =
127 {
128 {0xC6183D47, "sceUmdActivate"},
129 {0x6B4A146C, "sceUmdGetDriveStat"},
130 {0x8EF08FCE, "sceUmdWaitDriveStat"},
131 {0x6AF9B50A, "sceUmdCancelWaitDriveStat"},
132 {NULL, NULL},
133 };
134
135 CBios::MODULEFUNCTION CBios::g_UtilityFunctions[] =
136 {
137 {0x2A2B3DE0, "sceUtilityLoadModule"},
138 {0xE49BFE92, "sceUtilityUnloadModule"},
139 {NULL, NULL},
140 };
141
142 CBios::MODULEFUNCTION CBios::g_KernelLibraryFunctions[] =
143 {
144 {0x092968F4, "sceKernelCpuSuspendIntr"},
145 {0x5F10D406, "sceKernelCpuResumeIntr"},
146 };
147
148 CBios::MODULEFUNCTION CBios::g_ModuleMgrForUserFunctions[] =
149 {
150 {0xD8B73127, "sceKernelGetModuleIdByAddress"},
151 };
152
153 CBios::MODULE CBios::g_modules[] =
154 {
155 {"IoFileMgrForUser", g_IoFileMgrForUserFunctions},
156 {"SysMemUserForUser", g_SysMemUserForUserFunctions},
157 {"ThreadManForUser", g_ThreadManForUserFunctions},
158 {"LoadExecForUser", g_LoadExecForUserFunctions},
159 {"UtilsForUser", g_UtilsForUserFunctions},
160 {"ModuleMgrForUser", g_ModuleMgrForUserFunctions},
161 {"StdioForUser", g_StdioForUserFunctions},
162 {"sceSasCore", g_SasCoreFunctions},
163 {"sceAudio", g_WaveFunctions},
164 {"sceUmdUser", g_UmdUserFunctions},
165 {"sceUtility", g_UtilityFunctions},
166 {"Kernel_Library", g_KernelLibraryFunctions},
167 {NULL, NULL},
168 };
169
CBios(CMIPS & cpu,uint8 * ram,uint32 ramSize)170 CBios::CBios(CMIPS& cpu, uint8* ram, uint32 ramSize)
171 : m_module(NULL)
172 , m_ram(ram)
173 , m_ramSize(ramSize)
174 , m_cpu(cpu)
175 , m_heapBlocks(reinterpret_cast<HEAPBLOCK*>(&ram[BIOS_HEAPBLOCK_BASE]), 1, MAX_HEAPBLOCKS)
176 , m_moduleTrampolines(reinterpret_cast<MODULETRAMPOLINE*>(&ram[BIOS_MODULE_TRAMPOLINE_BASE]), 1, MAX_MODULETRAMPOLINES)
177 , m_threads(reinterpret_cast<THREAD*>(&ram[BIOS_THREAD_BASE]), 1, MAX_THREADS)
178 , m_messageBoxes(reinterpret_cast<MESSAGEBOX*>(&m_ram[BIOS_MESSAGEBOX_BASE]), 1, MAX_MESSAGEBOXES)
179 , m_messages(reinterpret_cast<MESSAGE*>(&m_ram[BIOS_MESSAGE_BASE]), 1, MAX_MESSAGES)
180 , m_rescheduleNeeded(false)
181 , m_threadFinishAddress(0)
182 , m_idleFunctionAddress(0)
183 {
184 static_assert(BIOS_CALCULATED_END <= CBios::CONTROL_BLOCK_END, "Error");
185 Reset();
186 }
187
~CBios()188 CBios::~CBios()
189 {
190 if(m_module != NULL)
191 {
192 delete m_module;
193 m_module = NULL;
194 }
195 }
196
Reset()197 void CBios::Reset()
198 {
199 //Assemble handlers
200 {
201 CMIPSAssembler assembler(reinterpret_cast<uint32*>(&m_ram[BIOS_HANDLERS_BASE]));
202 m_threadFinishAddress = AssembleThreadFinish(assembler);
203 // m_returnFromExceptionAddress = AssembleReturnFromException(assembler);
204 m_idleFunctionAddress = AssembleIdleFunction(assembler);
205 assert(BIOS_HANDLERS_END > ((assembler.GetProgramSize() * 4) + BIOS_HANDLERS_BASE));
206 }
207
208 if(m_module != NULL)
209 {
210 delete m_module;
211 m_module = NULL;
212 }
213
214 Heap_Init();
215
216 m_moduleTrampolines.FreeAll();
217 m_threads.FreeAll();
218
219 ThreadLinkHead() = 0;
220 CurrentThreadId() = -1;
221
222 //Initialize modules
223 m_modules.clear();
224
225 m_ioFileMgrForUserModule = IoFileMgrForUserModulePtr(new CIoFileMgrForUser(m_ram));
226 m_sasCoreModule = SasCoreModulePtr(new CSasCore(m_ram));
227 m_audioModule = AudioModulePtr(new CAudio(m_ram));
228
229 InsertModule(ModulePtr(new CThreadManForUser(*this, m_ram)));
230 InsertModule(m_ioFileMgrForUserModule);
231 InsertModule(ModulePtr(new CStdioForUser()));
232 InsertModule(ModulePtr(new CSysMemUserForUser(*this, m_ram)));
233 InsertModule(ModulePtr(new CKernelLibrary()));
234 InsertModule(m_sasCoreModule);
235 InsertModule(m_audioModule);
236 }
237
AssembleThreadFinish(CMIPSAssembler & assembler)238 uint32 CBios::AssembleThreadFinish(CMIPSAssembler& assembler)
239 {
240 uint32 address = BIOS_HANDLERS_BASE + assembler.GetProgramSize() * 4;
241 assembler.ADDIU(CMIPS::V0, CMIPS::R0, 0x0667);
242 assembler.SYSCALL();
243 return address;
244 }
245
AssembleReturnFromException(CMIPSAssembler & assembler)246 uint32 CBios::AssembleReturnFromException(CMIPSAssembler& assembler)
247 {
248 uint32 address = BIOS_HANDLERS_BASE + assembler.GetProgramSize() * 4;
249 assembler.ADDIU(CMIPS::V0, CMIPS::R0, 0x0668);
250 assembler.SYSCALL();
251 return address;
252 }
253
AssembleIdleFunction(CMIPSAssembler & assembler)254 uint32 CBios::AssembleIdleFunction(CMIPSAssembler& assembler)
255 {
256 uint32 address = BIOS_HANDLERS_BASE + assembler.GetProgramSize() * 4;
257 assembler.ADDIU(CMIPS::V0, CMIPS::R0, 0x0669);
258 assembler.SYSCALL();
259 return address;
260 }
261
InsertModule(const ModulePtr & module)262 void CBios::InsertModule(const ModulePtr& module)
263 {
264 m_modules[module->GetName()] = module;
265 }
266
GetIoFileMgr()267 CIoFileMgrForUser* CBios::GetIoFileMgr()
268 {
269 return m_ioFileMgrForUserModule.get();
270 }
271
GetSasCore()272 CSasCore* CBios::GetSasCore()
273 {
274 return m_sasCoreModule.get();
275 }
276
GetAudio()277 CAudio* CBios::GetAudio()
278 {
279 return m_audioModule.get();
280 }
281
HandleLinkedModuleCall()282 void CBios::HandleLinkedModuleCall()
283 {
284 uint32 searchAddress = m_cpu.m_State.nCOP0[CCOP_SCU::EPC];
285 uint32 libraryStubAddr = m_cpu.m_pMemoryMap->GetWord(searchAddress + 0x0C);
286
287 LIBRARYSTUB* libraryStub = reinterpret_cast<LIBRARYSTUB*>(m_ram + libraryStubAddr);
288
289 const char* moduleName = reinterpret_cast<char*>(m_ram + libraryStub->moduleStrAddr);
290
291 uint32 nidEntryAddr = libraryStub->stubNidTableAddr + (m_cpu.m_State.nGPR[CMIPS::V1].nV0 * 4);
292 uint32 nid = *reinterpret_cast<uint32*>(m_ram + nidEntryAddr);
293
294 ModuleMapType::const_iterator moduleIterator(m_modules.find(moduleName));
295 if(moduleIterator == m_modules.end())
296 {
297 #ifdef _DEBUG
298 CLog::GetInstance().Print(LOGNAME, "Module named '%s' wasn't found.\r\n", moduleName);
299 #endif
300 return;
301 }
302
303 const ModulePtr& module = moduleIterator->second;
304 module->Invoke(nid, m_cpu);
305 }
306
HandleException()307 void CBios::HandleException()
308 {
309 m_rescheduleNeeded = false;
310
311 uint32 searchAddress = m_cpu.m_State.nCOP0[CCOP_SCU::EPC];
312 uint32 callInstruction = m_cpu.m_pMemoryMap->GetWord(searchAddress);
313 if(callInstruction == 0x0000000C)
314 {
315 switch(m_cpu.m_State.nGPR[CMIPS::V0].nV0)
316 {
317 case 0x666:
318 HandleLinkedModuleCall();
319 break;
320 case 0x667:
321 ExitCurrentThread(0);
322 break;
323 default:
324 assert(0);
325 break;
326 }
327 }
328 else
329 {
330 #ifdef _DEBUG
331 CLog::GetInstance().Print(LOGNAME, "%0.8X: Unknown exception reason.\r\n", m_cpu.m_State.nCOP0[CCOP_SCU::EPC]);
332 #endif
333 assert(0);
334 }
335
336 if(m_rescheduleNeeded)
337 {
338 assert((m_cpu.m_State.nCOP0[CCOP_SCU::STATUS] & CMIPS::STATUS_EXL) == 0);
339 m_rescheduleNeeded = false;
340 Reschedule();
341 }
342
343 m_cpu.m_State.nHasException = 0;
344 }
345
346 #ifdef DEBUGGER_INCLUDED
347
GetModulesDebugInfo() const348 BiosDebugModuleInfoArray CBios::GetModulesDebugInfo() const
349 {
350 return m_moduleTags;
351 }
352
GetThreadsDebugInfo() const353 BiosDebugThreadInfoArray CBios::GetThreadsDebugInfo() const
354 {
355 return BiosDebugThreadInfoArray();
356 }
357
358 #endif
359
LoadModule(const char * path)360 void CBios::LoadModule(const char* path)
361 {
362 //Open module
363 {
364 uint32 handle = m_ioFileMgrForUserModule->Open(path, CIoFileMgrForUser::OPEN_READ, 0);
365 if(handle & 0x80000000)
366 {
367 throw std::runtime_error("Couldn't open executable for reading.");
368 }
369 Framework::CStream* stream = m_ioFileMgrForUserModule->GetFileStream(handle);
370 m_module = new CElfFile(*stream);
371 m_ioFileMgrForUserModule->IoClose(handle);
372 }
373
374 const ELFHEADER& moduleHeader(m_module->GetHeader());
375
376 uint32 moduleAllocSize = 0;
377 {
378 for(unsigned int i = 0; i < moduleHeader.nProgHeaderCount; i++)
379 {
380 ELFPROGRAMHEADER* programHeader = m_module->GetProgram(i);
381 if(programHeader->nType == RELOC_SECTION_ID) continue;
382 //Allocate a bit more for alignment computations later on
383 moduleAllocSize += programHeader->nFileSize + programHeader->nAlignment;
384 }
385 }
386
387 uint32 baseAddress = Heap_AllocateMemory(moduleAllocSize);
388 uint32 endAddress = 0;
389
390 {
391 uint32 currentAddress = baseAddress;
392 for(unsigned int i = 0; i < moduleHeader.nProgHeaderCount; i++)
393 {
394 ELFPROGRAMHEADER* programHeader = m_module->GetProgram(i);
395 if(programHeader->nType == RELOC_SECTION_ID) continue;
396
397 uint32 alignFixUp = (currentAddress & (programHeader->nAlignment - 1));
398 if(alignFixUp != 0)
399 {
400 currentAddress += programHeader->nAlignment - alignFixUp;
401 }
402
403 programHeader->nVAddress = currentAddress;
404
405 memcpy(
406 m_ram + currentAddress,
407 m_module->GetContent() + programHeader->nOffset,
408 programHeader->nFileSize);
409
410 endAddress = std::max<uint32>(endAddress, currentAddress + programHeader->nFileSize);
411 currentAddress += programHeader->nFileSize;
412 }
413 }
414
415 RelocateElf(*m_module);
416
417 {
418 BIOS_DEBUG_MODULE_INFO module;
419 module.name = "main";
420 module.begin = baseAddress;
421 module.end = endAddress;
422 module.param = m_module;
423 m_moduleTags.push_back(module);
424 }
425
426 ELFSECTIONHEADER* moduleInfoSectionHeader = m_module->FindSection(".rodata.sceModuleInfo");
427 MODULEINFO* moduleInfo = reinterpret_cast<MODULEINFO*>(m_ram + baseAddress + moduleInfoSectionHeader->nStart);
428
429 LIBRARYENTRY* libraryEntryBegin = reinterpret_cast<LIBRARYENTRY*>(m_ram + moduleInfo->libEntAddr);
430 LIBRARYENTRY* libraryEntryEnd = reinterpret_cast<LIBRARYENTRY*>(m_ram + moduleInfo->libEntBtmAddr);
431
432 LIBRARYSTUB* libraryStubBegin = reinterpret_cast<LIBRARYSTUB*>(m_ram + moduleInfo->libStubAddr);
433 LIBRARYSTUB* libraryStubEnd = reinterpret_cast<LIBRARYSTUB*>(m_ram + moduleInfo->libStubBtmAddr);
434
435 for(LIBRARYSTUB* libraryStub(libraryStubBegin); libraryStub != libraryStubEnd; libraryStub++)
436 {
437 const char* moduleName = reinterpret_cast<char*>(m_ram + libraryStub->moduleStrAddr);
438 uint32 stubAddr = libraryStub->stubAddress;
439 uint32 stubCount = libraryStub->stubSize;
440 uint32 nidAddr = libraryStub->stubNidTableAddr;
441
442 uint32 moduleTrampolineId = m_moduleTrampolines.Allocate();
443 assert(moduleTrampolineId != -1);
444
445 MODULETRAMPOLINE* trampoline(m_moduleTrampolines[moduleTrampolineId]);
446
447 //ADDIU V0, R0, 0x666
448 //SYSCALL
449 //JR RA
450 //NOP
451
452 trampoline->code0 = ((0x09) << 26) | (CMIPS::R0 << 21) | (CMIPS::V0 << 16) | 0x666;
453 trampoline->code1 = 0xC;
454 trampoline->code2 = 0x03E00008;
455 trampoline->code3 = 0;
456 trampoline->libStubAddr = reinterpret_cast<uint8*>(libraryStub) - m_ram;
457
458 uint32 trampolineAddr = (reinterpret_cast<uint8*>(trampoline) - m_ram) + 4;
459
460 MODULE* moduleDef = FindModule(moduleName);
461 for(unsigned int j = 0; j < stubCount; j++)
462 {
463 uint32* stubPtr = reinterpret_cast<uint32*>(m_ram + stubAddr + (j * 8));
464 uint32 nid = *reinterpret_cast<uint32*>(m_ram + nidAddr + (j * 4));
465 MODULEFUNCTION* moduleFunctionDef = FindModuleFunction(moduleDef, nid);
466 std::string name;
467 if(moduleFunctionDef != NULL)
468 {
469 name = moduleFunctionDef->name;
470 }
471 else
472 {
473 name = std::string(moduleName) + std::string("_") + lexical_cast_hex<std::string>(nid, 8);
474 }
475 m_cpu.m_Functions.InsertTag(stubAddr + (j * 8), name.c_str());
476
477 //J $trampoline
478 //ADDIU V1, R0, j
479
480 *(stubPtr + 0) = ((0x02) << 26) | ((trampolineAddr >> 2) & 0x03FFFFFF);
481 *(stubPtr + 1) = ((0x09) << 26) | (CMIPS::R0 << 21) | (CMIPS::V1 << 16) | j;
482 }
483 }
484
485 m_cpu.m_State.nGPR[CMIPS::GP].nV0 = moduleInfo->gp;
486
487 uint32 threadId = CreateThread("start_thread", baseAddress + moduleHeader.nEntryPoint, 0x20, DEFAULT_STACKSIZE, 0, 0);
488 assert(threadId != -1);
489
490 StartThread(threadId, 0, NULL);
491 if(CurrentThreadId() == -1)
492 {
493 Reschedule();
494 }
495
496 #if 0
497 //Search string
498 // const char* stringToSearch = "xa_MYROOM.adx";
499 const char* stringToSearch = "fname:%s";
500 size_t length = strlen(stringToSearch);
501 for(unsigned int i = baseAddress; i < endAddress; i++)
502 {
503 if(!strncmp(stringToSearch, reinterpret_cast<const char*>(m_ram + i), length))
504 {
505 printf("Found string at %0x%0.8X.\r\n", i);
506 }
507 }
508 #endif
509 #if 0
510 //0x003fe11c
511 //0x003fe9f0
512 //0x004428e4
513 //0x00442954
514 //0x00457988
515 //0x1D96A0
516 //0x3fdf4c
517 //0x003fe9f0
518 //1f5164
519 //0x4bcd38
520 //0x0040feac
521 //0x0044dad0
522 //0x004b9674
523 for(unsigned int i = baseAddress; i < endAddress; i += 4)
524 {
525 uint32 opcode = *reinterpret_cast<uint32*>(m_ram + i);
526 //if((opcode & 0xFFFF) == (0x8a50))
527 //if(opcode == 0x004579e0)
528 if(((opcode & 0xFFFF) == 0x4942))
529 {
530 printf("Found instruction at %0.8X.\r\n", i);
531 }
532 }
533 #endif
534 }
535
CreateThread(const char * name,uint32 threadProc,uint32 initPriority,uint32 stackSize,uint32 creationFlags,uint32 optParam)536 uint32 CBios::CreateThread(const char* name, uint32 threadProc, uint32 initPriority, uint32 stackSize, uint32 creationFlags, uint32 optParam)
537 {
538 uint32 threadId = m_threads.Allocate();
539 assert(threadId != -1);
540 if(threadId == -1)
541 {
542 return -1;
543 }
544
545 assert(stackSize >= 512);
546 uint32 stackBase = Heap_AllocateMemory(stackSize);
547
548 THREAD* thread(m_threads[threadId]);
549 strncpy(thread->name, name, 0x1F);
550 thread->name[0x1F] = 0;
551
552 thread->stackBase = stackBase;
553 thread->stackSize = stackSize;
554 thread->id = threadId;
555 thread->priority = initPriority;
556 thread->status = THREAD_STATUS_CREATED;
557 thread->nextActivateTime = 0;
558 thread->waitSemaphore = -1;
559
560 memset(&thread->context, 0, sizeof(THREADCONTEXT));
561 memset(m_ram + thread->stackBase, 0, thread->stackSize);
562
563 thread->context.epc = threadProc;
564 thread->context.delayJump = 1;
565 thread->context.gpr[CMIPS::RA] = m_threadFinishAddress;
566 thread->context.gpr[CMIPS::SP] = thread->stackBase + thread->stackSize;
567 thread->context.gpr[CMIPS::GP] = m_cpu.m_State.nGPR[CMIPS::GP].nV0;
568
569 LinkThread(thread->id);
570 return thread->id;
571 }
572
StartThread(uint32 threadId,uint32 argsSize,uint8 * argsPtr)573 void CBios::StartThread(uint32 threadId, uint32 argsSize, uint8* argsPtr)
574 {
575 THREAD& thread = GetThread(threadId);
576 if(thread.status != THREAD_STATUS_CREATED)
577 {
578 throw std::runtime_error("Invalid thread state.");
579 }
580 thread.status = THREAD_STATUS_RUNNING;
581 if(argsPtr != NULL)
582 {
583 //Copy params in stack
584 assert(argsSize <= thread.stackSize);
585 uint32 sp = thread.context.gpr[CMIPS::SP];
586 sp -= argsSize;
587 memcpy(m_ram + sp, argsPtr, argsSize);
588 thread.context.gpr[CMIPS::SP] = sp;
589 thread.context.gpr[CMIPS::A0] = sp;
590 }
591 m_rescheduleNeeded = true;
592 }
593
ExitCurrentThread(uint32 exitCode)594 void CBios::ExitCurrentThread(uint32 exitCode)
595 {
596 THREAD& thread = GetThread(CurrentThreadId());
597 if(thread.status != THREAD_STATUS_RUNNING)
598 {
599 throw std::runtime_error("Invalid thread state.");
600 }
601 thread.status = THREAD_STATUS_ZOMBIE;
602 m_rescheduleNeeded = true;
603 }
604
LinkThread(uint32 threadId)605 void CBios::LinkThread(uint32 threadId)
606 {
607 THREAD* thread = m_threads[threadId];
608 uint32* nextThreadId = &ThreadLinkHead();
609 while(1)
610 {
611 if((*nextThreadId) == 0)
612 {
613 (*nextThreadId) = threadId;
614 thread->nextThreadId = 0;
615 break;
616 }
617 THREAD* currentThread = m_threads[(*nextThreadId)];
618 if(currentThread->priority < thread->priority)
619 {
620 thread->nextThreadId = (*nextThreadId);
621 (*nextThreadId) = threadId;
622 break;
623 }
624 nextThreadId = ¤tThread->nextThreadId;
625 }
626 }
627
UnlinkThread(uint32 threadId)628 void CBios::UnlinkThread(uint32 threadId)
629 {
630 THREAD* thread = m_threads[threadId];
631 uint32* nextThreadId = &ThreadLinkHead();
632 while(1)
633 {
634 if((*nextThreadId) == 0)
635 {
636 break;
637 }
638 THREAD* currentThread = m_threads[(*nextThreadId)];
639 if((*nextThreadId) == threadId)
640 {
641 (*nextThreadId) = thread->nextThreadId;
642 thread->nextThreadId = 0;
643 break;
644 }
645 nextThreadId = ¤tThread->nextThreadId;
646 }
647 }
648
ThreadLinkHead() const649 uint32& CBios::ThreadLinkHead() const
650 {
651 return *reinterpret_cast<uint32*>(m_ram + BIOS_THREAD_LINK_HEAD_BASE);
652 }
653
CurrentThreadId() const654 uint32& CBios::CurrentThreadId() const
655 {
656 return *reinterpret_cast<uint32*>(m_ram + BIOS_CURRENT_THREAD_ID_BASE);
657 }
658
GetThread(uint32 threadId)659 CBios::THREAD& CBios::GetThread(uint32 threadId)
660 {
661 return *m_threads[threadId];
662 }
663
LoadThreadContext(uint32 threadId)664 void CBios::LoadThreadContext(uint32 threadId)
665 {
666 THREAD& thread = GetThread(threadId);
667 for(unsigned int i = 0; i < 32; i++)
668 {
669 if(i == CMIPS::R0) continue;
670 if(i == CMIPS::K0) continue;
671 if(i == CMIPS::K1) continue;
672 m_cpu.m_State.nGPR[i].nD0 = static_cast<int32>(thread.context.gpr[i]);
673 }
674 m_cpu.m_State.nPC = thread.context.epc;
675 m_cpu.m_State.nDelayedJumpAddr = thread.context.delayJump;
676 }
677
SaveThreadContext(uint32 threadId)678 void CBios::SaveThreadContext(uint32 threadId)
679 {
680 THREAD& thread = GetThread(threadId);
681 for(unsigned int i = 0; i < 32; i++)
682 {
683 if(i == CMIPS::R0) continue;
684 if(i == CMIPS::K0) continue;
685 if(i == CMIPS::K1) continue;
686 thread.context.gpr[i] = m_cpu.m_State.nGPR[i].nV0;
687 }
688 thread.context.epc = m_cpu.m_State.nPC;
689 thread.context.delayJump = m_cpu.m_State.nDelayedJumpAddr;
690 }
691
GetNextReadyThread()692 uint32 CBios::GetNextReadyThread()
693 {
694 uint32 nextThreadId = ThreadLinkHead();
695 while(nextThreadId != 0)
696 {
697 THREAD* nextThread = m_threads[nextThreadId];
698 nextThreadId = nextThread->nextThreadId;
699 // if(GetCurrentTime() <= nextThread->nextActivateTime) continue;
700 if(nextThread->status == THREAD_STATUS_RUNNING)
701 {
702 return nextThread->id;
703 }
704 }
705 return -1;
706 }
707
Reschedule()708 void CBios::Reschedule()
709 {
710 if(CurrentThreadId() != -1)
711 {
712 SaveThreadContext(CurrentThreadId());
713 UnlinkThread(CurrentThreadId());
714 LinkThread(CurrentThreadId());
715 }
716
717 uint32 nextThreadId = GetNextReadyThread();
718 if(nextThreadId == -1)
719 {
720 #ifdef _DEBUG
721 // printf("Warning, no thread available for running.\r\n");
722 #endif
723 m_cpu.m_State.nPC = m_idleFunctionAddress;
724 }
725 else
726 {
727 LoadThreadContext(nextThreadId);
728 }
729 #ifdef _DEBUG
730 if(nextThreadId != CurrentThreadId())
731 {
732 CLog::GetInstance().Print(LOGNAME, "Switched over to thread %i.\r\n", nextThreadId);
733 }
734 #endif
735 CurrentThreadId() = nextThreadId;
736 }
737
CreateMbx(const char * name,uint32 attr,uint32 optParam)738 uint32 CBios::CreateMbx(const char* name, uint32 attr, uint32 optParam)
739 {
740 uint32 mbxId = m_messageBoxes.Allocate();
741 assert(mbxId != -1);
742 if(mbxId == -1)
743 {
744 return -1;
745 }
746
747 MESSAGEBOX* mbx(m_messageBoxes[mbxId]);
748 strncpy(mbx->name, name, 0x1F);
749 mbx->name[0x1F] = 0;
750
751 mbx->attr = attr;
752
753 return mbxId;
754 }
755
SendMbx(uint32 mbxId,uint32 messagePtr)756 uint32 CBios::SendMbx(uint32 mbxId, uint32 messagePtr)
757 {
758 MESSAGEBOX* mbx(m_messageBoxes[mbxId]);
759 if(mbx == NULL) return -1;
760
761 uint32 messageId = m_messages.Allocate();
762 assert(messageId != -1);
763 if(messageId == -1)
764 {
765 return -1;
766 }
767
768 MESSAGE* message(m_messages[messageId]);
769 message->mbxId = mbxId;
770 message->value = messagePtr;
771 message->id = messageId;
772
773 return 0;
774 }
775
PollMbx(uint32 mbxId,uint32 messagePtr)776 uint32 CBios::PollMbx(uint32 mbxId, uint32 messagePtr)
777 {
778 MESSAGEBOX* mbx(m_messageBoxes[mbxId]);
779 if(mbx == NULL) return -1;
780
781 //Scan all messages to find one that is owned by this box. (gotta change that later on, totally not ordered)
782 MESSAGE* result(NULL);
783 for(unsigned int i = 0; i < MAX_MESSAGES; i++)
784 {
785 MESSAGE* message(m_messages.GetBase() + i);
786 if(!message->isValid) continue;
787 if(message->mbxId == mbxId)
788 {
789 result = message;
790 break;
791 }
792 }
793
794 if(result == NULL) return -1;
795
796 uint32* message = reinterpret_cast<uint32*>(m_ram + messagePtr);
797 (*message) = result->value;
798 m_messages.Free(result->id);
799
800 return 0;
801 }
802
Heap_Init()803 void CBios::Heap_Init()
804 {
805 m_heapBegin = CONTROL_BLOCK_END;
806 m_heapEnd = m_ramSize;
807 m_heapSize = m_heapEnd - m_heapBegin;
808
809 m_heapBlocks.FreeAll();
810
811 //Initialize block map
812 m_heapHeadBlockId = m_heapBlocks.Allocate();
813 HEAPBLOCK* block = m_heapBlocks[m_heapHeadBlockId];
814 block->address = m_heapSize;
815 block->size = 0;
816 block->nextBlock = 0;
817 }
818
Heap_AllocateMemory(uint32 size)819 uint32 CBios::Heap_AllocateMemory(uint32 size)
820 {
821 uint32 begin = 0;
822 const uint32 blockSize = MIN_HEAPBLOCK_SIZE;
823 size = ((size + (blockSize - 1)) / blockSize) * blockSize;
824
825 uint32* nextBlockId = &m_heapHeadBlockId;
826 HEAPBLOCK* nextBlock = m_heapBlocks[*nextBlockId];
827 while(nextBlock != NULL)
828 {
829 uint32 end = nextBlock->address;
830 if((end - begin) >= size)
831 {
832 break;
833 }
834 begin = nextBlock->address + nextBlock->size;
835 nextBlockId = &nextBlock->nextBlock;
836 nextBlock = m_heapBlocks[*nextBlockId];
837 }
838
839 if(nextBlock != NULL)
840 {
841 uint32 newBlockId = m_heapBlocks.Allocate();
842 assert(newBlockId != 0);
843 if(newBlockId == 0)
844 {
845 return 0;
846 }
847 HEAPBLOCK* newBlock = m_heapBlocks[newBlockId];
848 newBlock->address = begin;
849 newBlock->size = size;
850 newBlock->nextBlock = *nextBlockId;
851 *nextBlockId = newBlockId;
852 return begin + m_heapBegin;
853 }
854
855 assert(0);
856 return NULL;
857 }
858
Heap_FreeMemory(uint32 address)859 uint32 CBios::Heap_FreeMemory(uint32 address)
860 {
861 address -= m_heapBegin;
862 //Search for block pointing at the address
863 uint32* nextBlockId = &m_heapHeadBlockId;
864 HEAPBLOCK* nextBlock = m_heapBlocks[*nextBlockId];
865 while(nextBlock != NULL)
866 {
867 if(nextBlock->address == address)
868 {
869 break;
870 }
871 nextBlockId = &nextBlock->nextBlock;
872 nextBlock = m_heapBlocks[*nextBlockId];
873 }
874
875 if(nextBlock != NULL)
876 {
877 m_heapBlocks.Free(*nextBlockId);
878 *nextBlockId = nextBlock->nextBlock;
879 }
880 else
881 {
882 assert(0);
883 // CLog::GetInstance().Print(LOG_NAME, "%s: Trying to unallocate an unexisting memory block (0x%0.8X).\r\n", __FUNCTION__, address);
884 }
885 return 0;
886 }
887
Heap_GetBlockId(uint32 address)888 uint32 CBios::Heap_GetBlockId(uint32 address)
889 {
890 address -= m_heapBegin;
891
892 //Search for block pointing at the address
893 uint32* nextBlockId = &m_heapHeadBlockId;
894 HEAPBLOCK* nextBlock = m_heapBlocks[*nextBlockId];
895 while(nextBlock != NULL)
896 {
897 if(nextBlock->address == address)
898 {
899 break;
900 }
901 nextBlockId = &nextBlock->nextBlock;
902 nextBlock = m_heapBlocks[*nextBlockId];
903 }
904
905 if(nextBlock != NULL)
906 {
907 return *nextBlockId;
908 }
909 else
910 {
911 return -1;
912 }
913 }
914
Heap_GetBlockAddress(uint32 blockId)915 uint32 CBios::Heap_GetBlockAddress(uint32 blockId)
916 {
917 HEAPBLOCK* block = m_heapBlocks[blockId];
918 assert(block != NULL);
919 if(block == NULL)
920 {
921 return 0;
922 }
923 return block->address + m_heapBegin;
924 }
925
FindModule(const char * name)926 CBios::MODULE* CBios::FindModule(const char* name)
927 {
928 MODULE* currentModule = g_modules;
929 while(currentModule->name != NULL)
930 {
931 if(!strcmp(currentModule->name, name))
932 {
933 return currentModule;
934 }
935 currentModule++;
936 }
937 return NULL;
938 }
939
FindModuleFunction(MODULE * module,uint32 id)940 CBios::MODULEFUNCTION* CBios::FindModuleFunction(MODULE* module, uint32 id)
941 {
942 if(module == NULL) return NULL;
943 MODULEFUNCTION* currentFunction = module->functions;
944 while(currentFunction->name != NULL)
945 {
946 if(currentFunction->id == id)
947 {
948 return currentFunction;
949 }
950 currentFunction++;
951 }
952 return NULL;
953 }
954
RelocateElf(CELF & elf)955 void CBios::RelocateElf(CELF& elf)
956 {
957 const ELFHEADER& header = elf.GetHeader();
958 for(unsigned int i = 0; i < header.nSectHeaderCount; i++)
959 {
960 ELFSECTIONHEADER* sectionHeader = elf.GetSection(i);
961 if(sectionHeader != NULL &&
962 (/*sectionHeader->nType == CELF::SHT_REL || */ sectionHeader->nType == RELOC_SECTION_ID))
963 {
964 unsigned int linkedSection = sectionHeader->nInfo;
965 unsigned int recordCount = sectionHeader->nSize / 8;
966 const uint32* relocationRecord = reinterpret_cast<const uint32*>(elf.GetSectionData(i));
967 if(relocationRecord == NULL) continue;
968 for(unsigned int record = 0; record < recordCount; record++)
969 {
970 uint32 relocationType = relocationRecord[1] & 0xFF;
971 uint32 ofsBase = (relocationRecord[1] >> 8) & 0xFF;
972 uint32 addrBase = (relocationRecord[1] >> 16) & 0xFF;
973
974 ELFPROGRAMHEADER* progOfsBase = elf.GetProgram(ofsBase);
975 ELFPROGRAMHEADER* progAddrBase = elf.GetProgram(addrBase);
976 assert(progOfsBase != NULL);
977 assert(progAddrBase != NULL);
978 assert(progOfsBase->nType != RELOC_SECTION_ID);
979 assert(progAddrBase->nType != RELOC_SECTION_ID);
980
981 uint32 baseAddress = progAddrBase->nVAddress;
982 uint32 relocationAddress = relocationRecord[0] + progOfsBase->nVAddress;
983
984 assert(relocationAddress < m_ramSize);
985 if(relocationAddress < m_ramSize)
986 {
987 uint32& instruction = *reinterpret_cast<uint32*>(m_ram + relocationAddress);
988 switch(relocationType)
989 {
990 case CELF::R_MIPS_32:
991 {
992 instruction += baseAddress;
993 }
994 break;
995 case CELF::R_MIPS_26:
996 {
997 uint32 offset = (instruction & 0x03FFFFFF) + (baseAddress >> 2);
998 instruction &= ~0x03FFFFFF;
999 instruction |= offset;
1000 }
1001 break;
1002 case CELF::R_MIPS_HI16:
1003 {
1004 //Find the next LO16 reloc
1005 uint32 nextRelocAddress = FindNextRelocationTarget(elf, relocationRecord + 2, relocationRecord + (recordCount - record) * 2);
1006 assert(nextRelocAddress != -1);
1007 if(nextRelocAddress != -1)
1008 {
1009 uint32 nextInstruction = *reinterpret_cast<uint32*>(m_ram + nextRelocAddress);
1010 uint32 offset = static_cast<int16>(nextInstruction) + (instruction << 16);
1011 offset += baseAddress;
1012 instruction &= ~0xFFFF;
1013 if(offset & 0x8000) offset += 0x10000;
1014 instruction |= offset >> 16;
1015 }
1016 }
1017 break;
1018 case CELF::R_MIPS_LO16:
1019 {
1020 uint32 offset = static_cast<int16>(instruction);
1021 offset += baseAddress;
1022 instruction &= ~0xFFFF;
1023 instruction |= offset & 0xFFFF;
1024 }
1025 break;
1026 default:
1027 throw std::runtime_error("Unknown relocation type.");
1028 break;
1029 }
1030 }
1031 relocationRecord += 2;
1032 }
1033 }
1034 }
1035 }
1036
FindNextRelocationTarget(CELF & elf,const uint32 * begin,const uint32 * end)1037 uint32 CBios::FindNextRelocationTarget(CELF& elf, const uint32* begin, const uint32* end)
1038 {
1039 for(const uint32* relocationRecord(begin); relocationRecord != end; relocationRecord += 2)
1040 {
1041 uint32 relocationType = relocationRecord[1] & 0xFF;
1042 uint32 ofsBase = (relocationRecord[1] >> 8) & 0xFF;
1043 uint32 addrBase = (relocationRecord[1] >> 16) & 0xFF;
1044
1045 ELFPROGRAMHEADER* progOfsBase = elf.GetProgram(ofsBase);
1046
1047 assert(progOfsBase != NULL);
1048 assert(progOfsBase->nType != RELOC_SECTION_ID);
1049
1050 if(relocationType == CELF::R_MIPS_LO16)
1051 {
1052 return relocationRecord[0] + progOfsBase->nVAddress;
1053 }
1054 }
1055 return -1;
1056 }
1057
1058 #ifdef _DEBUG
1059
FindRelocationAt(CELF & elf,uint32 address,uint32 programSection)1060 uint32 CBios::FindRelocationAt(CELF& elf, uint32 address, uint32 programSection)
1061 {
1062 const ELFHEADER& header = elf.GetHeader();
1063 for(unsigned int i = 0; i < header.nSectHeaderCount; i++)
1064 {
1065 ELFSECTIONHEADER* sectionHeader = elf.GetSection(i);
1066 if(sectionHeader != NULL &&
1067 (/*sectionHeader->nType == CELF::SHT_REL || */ sectionHeader->nType == RELOC_SECTION_ID))
1068 {
1069 unsigned int linkedSection = sectionHeader->nInfo;
1070 unsigned int recordCount = sectionHeader->nSize / 8;
1071 const uint32* relocationRecord = reinterpret_cast<const uint32*>(elf.GetSectionData(i));
1072 if(relocationRecord == NULL) continue;
1073 for(unsigned int record = 0; record < recordCount; record++)
1074 {
1075 uint32 relocationType = relocationRecord[1] & 0xFF;
1076 uint32 ofsBase = (relocationRecord[1] >> 8) & 0xFF;
1077 uint32 addrBase = (relocationRecord[1] >> 16) & 0xFF;
1078
1079 if(ofsBase != programSection) continue;
1080
1081 // ELFPROGRAMHEADER* progOfsBase = elf.GetProgram(ofsBase);
1082 // ELFPROGRAMHEADER* progAddrBase = elf.GetProgram(addrBase);
1083 // assert(progOfsBase != NULL);
1084 // assert(progAddrBase != NULL);
1085 // assert(progOfsBase->nType != RELOC_SECTION_ID);
1086 // assert(progAddrBase->nType != RELOC_SECTION_ID);
1087 //
1088 // uint32 baseAddress = progAddrBase->nVAddress;
1089 uint32 relocationAddress = relocationRecord[0];
1090
1091 if(relocationAddress == address)
1092 {
1093 return reinterpret_cast<const uint8*>(relocationRecord) - elf.GetContent();
1094 }
1095
1096 relocationRecord += 2;
1097 }
1098 }
1099 }
1100
1101 return -1;
1102 }
1103
1104 #endif
1105