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 = &currentThread->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 = &currentThread->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