1 // Copyright (c) 2012- PPSSPP Project.
2 
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6 
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 // GNU General Public License 2.0 for more details.
11 
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14 
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17 
18 #include <algorithm>
19 #include <list>
20 #include <map>
21 #include <string>
22 
23 #include "Common/Serialize/Serializer.h"
24 #include "Common/Serialize/SerializeFuncs.h"
25 #include "Common/Serialize/SerializeList.h"
26 #include "Common/Serialize/SerializeMap.h"
27 #include "Core/MemMapHelpers.h"
28 #include "Core/Reporting.h"
29 #include "Core/HLE/HLE.h"
30 #include "Core/HLE/FunctionWrappers.h"
31 #include "Core/MIPS/MIPS.h"
32 
33 #include "Core/Debugger/MemBlockInfo.h"
34 #include "Core/HLE/sceKernel.h"
35 #include "Core/HLE/sceKernelThread.h"
36 #include "Core/HLE/sceKernelInterrupt.h"
37 #include "Core/HLE/sceKernelMemory.h"
38 #include "Core/HLE/sceKernelMutex.h"
39 
40 #include "GPU/GPUCommon.h"
41 #include "GPU/GPUState.h"
42 
43 // Seems like some > 16 are taken but not available.  Probably kernel only?
44 static const u32 PSP_NUMBER_SUBINTERRUPTS = 32;
45 
46 // InterruptsManager
47 //////////////////////////////////////////////////////////////////////////
48 // INTERRUPT MANAGEMENT
49 //////////////////////////////////////////////////////////////////////////
50 
51 class InterruptState {
52 public:
53 	void save();
54 	void restore();
55 	void clear();
56 
DoState(PointerWrap & p)57 	void DoState(PointerWrap &p) {
58 		auto s = p.Section("InterruptState", 1);
59 		if (!s)
60 			return;
61 
62 		Do(p, savedCpu);
63 	}
64 
65 	PSPThreadContext savedCpu;
66 };
67 
68 // STATE
69 
70 InterruptState intState;
71 IntrHandler* intrHandlers[PSP_NUMBER_INTERRUPTS];
72 std::list<PendingInterrupt> pendingInterrupts;
73 
74 // Yeah, this bit is a bit silly.
75 static int interruptsEnabled = 1;
76 static bool inInterrupt;
77 static SceUID threadBeforeInterrupt;
78 
79 
sceKernelCpuSuspendIntr()80 static int sceKernelCpuSuspendIntr()
81 {
82 	VERBOSE_LOG(SCEINTC, "sceKernelCpuSuspendIntr");
83 	int returnValue;
84 	if (__InterruptsEnabled())
85 	{
86 		returnValue = 1;
87 		__DisableInterrupts();
88 	}
89 	else
90 	{
91 		returnValue = 0;
92 	}
93 	hleEatCycles(15);
94 	return returnValue;
95 }
96 
sceKernelCpuResumeIntr(u32 enable)97 static void sceKernelCpuResumeIntr(u32 enable)
98 {
99 	VERBOSE_LOG(SCEINTC, "sceKernelCpuResumeIntr(%i)", enable);
100 	if (enable)
101 	{
102 		__EnableInterrupts();
103 		hleRunInterrupts();
104 		hleReSchedule("interrupts resumed");
105 	}
106 	else
107 	{
108 		__DisableInterrupts();
109 	}
110 	hleEatCycles(15);
111 }
112 
sceKernelIsCpuIntrEnable()113 static int sceKernelIsCpuIntrEnable()
114 {
115 	u32 retVal = __InterruptsEnabled();
116 	DEBUG_LOG(SCEINTC, "%i=sceKernelIsCpuIntrEnable()", retVal);
117 	return retVal;
118 }
119 
sceKernelIsCpuIntrSuspended(int flag)120 static int sceKernelIsCpuIntrSuspended(int flag)
121 {
122 	int retVal = flag == 0 ? 1 : 0;
123 	DEBUG_LOG(SCEINTC, "%i=sceKernelIsCpuIntrSuspended(%d)", retVal, flag);
124 	return retVal;
125 }
126 
sceKernelCpuResumeIntrWithSync(u32 enable)127 static void sceKernelCpuResumeIntrWithSync(u32 enable)
128 {
129 	sceKernelCpuResumeIntr(enable);
130 }
131 
run(PendingInterrupt & pend)132 bool IntrHandler::run(PendingInterrupt& pend)
133 {
134 	SubIntrHandler *handler = get(pend.subintr);
135 	if (handler == NULL)
136 	{
137 		WARN_LOG(SCEINTC, "Ignoring interrupt, already been released.");
138 		return false;
139 	}
140 
141 	copyArgsToCPU(pend);
142 
143 	return true;
144 }
145 
copyArgsToCPU(PendingInterrupt & pend)146 void IntrHandler::copyArgsToCPU(PendingInterrupt& pend)
147 {
148 	SubIntrHandler* handler = get(pend.subintr);
149 	DEBUG_LOG(CPU, "Entering interrupt handler %08x", handler->handlerAddress);
150 	currentMIPS->pc = handler->handlerAddress;
151 	currentMIPS->r[MIPS_REG_A0] = handler->subIntrNumber;
152 	currentMIPS->r[MIPS_REG_A1] = handler->handlerArg;
153 	// RA is already taken care of
154 }
155 
handleResult(PendingInterrupt & pend)156 void IntrHandler::handleResult(PendingInterrupt& pend)
157 {
158 	//u32 result = currentMIPS->r[MIPS_REG_V0];
159 }
160 
add(int subIntrNum)161 SubIntrHandler* IntrHandler::add(int subIntrNum)
162 {
163 	return &subIntrHandlers[subIntrNum];
164 }
remove(int subIntrNum)165 void IntrHandler::remove(int subIntrNum)
166 {
167 	if (has(subIntrNum))
168 	{
169 		subIntrHandlers.erase(subIntrNum);
170 	}
171 }
has(int subIntrNum) const172 bool IntrHandler::has(int subIntrNum) const
173 {
174 	return subIntrHandlers.find(subIntrNum) != subIntrHandlers.end();
175 }
enable(int subIntrNum)176 void IntrHandler::enable(int subIntrNum)
177 {
178 	subIntrHandlers[subIntrNum].enabled = true;
179 }
disable(int subIntrNum)180 void IntrHandler::disable(int subIntrNum)
181 {
182 	subIntrHandlers[subIntrNum].enabled = false;
183 }
get(int subIntrNum)184 SubIntrHandler* IntrHandler::get(int subIntrNum)
185 {
186 	if (has(subIntrNum))
187 		return &subIntrHandlers[subIntrNum];
188 	else
189 		return NULL;
190 }
clear()191 void IntrHandler::clear()
192 {
193 	subIntrHandlers.clear();
194 }
195 
queueUp(int subintr)196 void IntrHandler::queueUp(int subintr) {
197 	if (subintr == PSP_INTR_SUB_NONE) {
198 		pendingInterrupts.push_back(PendingInterrupt(intrNumber, subintr));
199 	} else {
200 		// Just call execute on all the subintr handlers for this interrupt.
201 		// They will get queued up.
202 		for (auto iter = subIntrHandlers.begin(); iter != subIntrHandlers.end(); ++iter) {
203 			if ((subintr == PSP_INTR_SUB_ALL || iter->first == subintr) && iter->second.enabled && iter->second.handlerAddress != 0) {
204 				pendingInterrupts.push_back(PendingInterrupt(intrNumber, iter->first));
205 			}
206 		}
207 	}
208 }
209 
DoState(PointerWrap & p)210 void IntrHandler::DoState(PointerWrap &p)
211 {
212 	auto s = p.Section("IntrHandler", 1);
213 	if (!s)
214 		return;
215 
216 	Do(p, intrNumber);
217 	Do<int, SubIntrHandler>(p, subIntrHandlers);
218 }
219 
DoState(PointerWrap & p)220 void PendingInterrupt::DoState(PointerWrap &p)
221 {
222 	auto s = p.Section("PendingInterrupt", 1);
223 	if (!s)
224 		return;
225 
226 	Do(p, intr);
227 	Do(p, subintr);
228 }
229 
__InterruptsInit()230 void __InterruptsInit()
231 {
232 	interruptsEnabled = 1;
233 	inInterrupt = false;
234 	for (int i = 0; i < (int)ARRAY_SIZE(intrHandlers); ++i)
235 		intrHandlers[i] = new IntrHandler(i);
236 	intState.clear();
237 	threadBeforeInterrupt = 0;
238 }
239 
__InterruptsDoState(PointerWrap & p)240 void __InterruptsDoState(PointerWrap &p)
241 {
242 	auto s = p.Section("sceKernelInterrupt", 1);
243 	if (!s)
244 		return;
245 
246 	int numInterrupts = PSP_NUMBER_INTERRUPTS;
247 	Do(p, numInterrupts);
248 	if (numInterrupts != PSP_NUMBER_INTERRUPTS)
249 	{
250 		p.SetError(p.ERROR_FAILURE);
251 		ERROR_LOG(SCEINTC, "Savestate failure: wrong number of interrupts, can't load.");
252 		return;
253 	}
254 
255 	intState.DoState(p);
256 	PendingInterrupt pi(0, 0);
257 	Do(p, pendingInterrupts, pi);
258 	Do(p, interruptsEnabled);
259 	Do(p, inInterrupt);
260 	Do(p, threadBeforeInterrupt);
261 }
262 
__InterruptsDoStateLate(PointerWrap & p)263 void __InterruptsDoStateLate(PointerWrap &p)
264 {
265 	// We do these later to ensure the handlers have been registered.
266 	for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i)
267 		intrHandlers[i]->DoState(p);
268 	p.DoMarker("sceKernelInterrupt Late");
269 }
270 
__InterruptsShutdown()271 void __InterruptsShutdown()
272 {
273 	for (size_t i = 0; i < ARRAY_SIZE(intrHandlers); ++i)
274 		intrHandlers[i]->clear();
275 	for (size_t i = 0; i < ARRAY_SIZE(intrHandlers); ++i)
276 	{
277 		if (intrHandlers[i])
278 		{
279 			delete intrHandlers[i];
280 			intrHandlers[i] = 0;
281 		}
282 	}
283 	pendingInterrupts.clear();
284 }
285 
__DisableInterrupts()286 void __DisableInterrupts()
287 {
288 	interruptsEnabled = 0;
289 }
290 
__EnableInterrupts()291 void __EnableInterrupts()
292 {
293 	interruptsEnabled = 1;
294 }
295 
__InterruptsEnabled()296 bool __InterruptsEnabled()
297 {
298 	return interruptsEnabled != 0;
299 }
300 
__IsInInterrupt()301 bool __IsInInterrupt()
302 {
303 	return inInterrupt;
304 }
305 
save()306 void InterruptState::save()
307 {
308 	__KernelSaveContext(&savedCpu, true);
309 }
310 
restore()311 void InterruptState::restore()
312 {
313 	__KernelLoadContext(&savedCpu, true);
314 }
315 
clear()316 void InterruptState::clear()
317 {
318 	savedCpu.reset();
319 }
320 
321 // http://forums.ps2dev.org/viewtopic.php?t=5687
322 
323 // http://www.google.se/url?sa=t&rct=j&q=&esrc=s&source=web&cd=7&ved=0CFYQFjAG&url=http%3A%2F%2Fdev.psnpt.com%2Fredmine%2Fprojects%2Fuofw%2Frepository%2Frevisions%2F65%2Fraw%2Ftrunk%2Finclude%2Finterruptman.h&ei=J4pCUKvyK4nl4QSu-YC4Cg&usg=AFQjCNFxJcgzQnv6dK7aiQlht_BM9grfQQ&sig2=GGk5QUEWI6qouYDoyE07YQ
324 
325 
326 // Returns true if anything was executed.
__RunOnePendingInterrupt()327 bool __RunOnePendingInterrupt()
328 {
329 	bool needsThreadReturn = false;
330 
331 	if (inInterrupt || !interruptsEnabled) {
332 		// Already in an interrupt! We'll keep going when it's done.
333 		return false;
334 	}
335 	// Can easily prioritize between different kinds of interrupts if necessary.
336 retry:
337 	if (!pendingInterrupts.empty()) {
338 		PendingInterrupt pend = pendingInterrupts.front();
339 
340 		IntrHandler* handler = intrHandlers[pend.intr];
341 		if (handler == NULL) {
342 			WARN_LOG(SCEINTC, "Ignoring interrupt");
343 			pendingInterrupts.pop_front();
344 			goto retry;
345 		}
346 
347 		// If we came from CoreTiming::Advance(), we might've come from a waiting thread's callback.
348 		// To avoid "injecting" return values into our saved state, we context switch here.
349 		SceUID savedThread = __KernelGetCurThread();
350 		if (__KernelSwitchOffThread("interrupt")) {
351 			threadBeforeInterrupt = savedThread;
352 			needsThreadReturn = true;
353 		}
354 
355 		intState.save();
356 		inInterrupt = true;
357 
358 		if (!handler->run(pend)) {
359 			pendingInterrupts.pop_front();
360 			inInterrupt = false;
361 			goto retry;
362 		}
363 
364 		currentMIPS->r[MIPS_REG_RA] = __KernelInterruptReturnAddress();
365 		return true;
366 	} else {
367 		if (needsThreadReturn)
368 			__KernelSwitchToThread(threadBeforeInterrupt, "left interrupt");
369 		// DEBUG_LOG(SCEINTC, "No more interrupts!");
370 		return false;
371 	}
372 }
373 
__TriggerRunInterrupts(int type)374 static void __TriggerRunInterrupts(int type)
375 {
376 	// If interrupts aren't enabled, we run them later.
377 	if (interruptsEnabled && !inInterrupt)
378 	{
379 		if ((type & PSP_INTR_HLE) != 0)
380 			hleRunInterrupts();
381 		else if ((type & PSP_INTR_ALWAYS_RESCHED) != 0)
382 		{
383 			// "Always" only means if dispatch is enabled.
384 			if (!__RunOnePendingInterrupt() && __KernelIsDispatchEnabled())
385 			{
386 				SceUID savedThread = __KernelGetCurThread();
387 				if (__KernelSwitchOffThread("interrupt"))
388 					threadBeforeInterrupt = savedThread;
389 			}
390 		}
391 		else
392 			__RunOnePendingInterrupt();
393 	}
394 }
395 
__TriggerInterrupt(int type,PSPInterrupt intno,int subintr)396 void __TriggerInterrupt(int type, PSPInterrupt intno, int subintr)
397 {
398 	if (interruptsEnabled || (type & PSP_INTR_ONLY_IF_ENABLED) == 0)
399 	{
400 		intrHandlers[intno]->queueUp(subintr);
401 		VERBOSE_LOG(SCEINTC, "Triggering subinterrupts for interrupt %i sub %i (%i in queue)", intno, subintr, (u32)pendingInterrupts.size());
402 		__TriggerRunInterrupts(type);
403 	}
404 }
405 
__KernelReturnFromInterrupt()406 void __KernelReturnFromInterrupt()
407 {
408 	VERBOSE_LOG(SCEINTC, "Left interrupt handler at %08x", currentMIPS->pc);
409 
410 	hleSkipDeadbeef();
411 
412 	// This is what we just ran.
413 	PendingInterrupt pend = pendingInterrupts.front();
414 	pendingInterrupts.pop_front();
415 
416 	intrHandlers[pend.intr]->handleResult(pend);
417 	inInterrupt = false;
418 
419 	// Restore context after running the interrupt.
420 	intState.restore();
421 	// All should now be back to normal, including PC.
422 
423 	// Alright, let's see if there's any more interrupts queued...
424 	if (!__RunOnePendingInterrupt())
425 	{
426 		// Otherwise, we reschedule when dispatch was enabled, or switch back otherwise.
427 		if (__KernelIsDispatchEnabled())
428 			__KernelReSchedule("left interrupt");
429 		else
430 			__KernelSwitchToThread(threadBeforeInterrupt, "left interrupt");
431 	}
432 }
433 
__RegisterIntrHandler(u32 intrNumber,IntrHandler * handler)434 void __RegisterIntrHandler(u32 intrNumber, IntrHandler* handler)
435 {
436 	if(intrHandlers[intrNumber])
437 		delete intrHandlers[intrNumber];
438 	intrHandlers[intrNumber] = handler;
439 }
440 
__RegisterSubIntrHandler(u32 intrNumber,u32 subIntrNumber,u32 handler,u32 handlerArg,u32 & error)441 SubIntrHandler *__RegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 handler, u32 handlerArg, u32 &error) {
442 	if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
443 		error = SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
444 		return NULL;
445 	}
446 	IntrHandler *intr = intrHandlers[intrNumber];
447 	if (intr->has(subIntrNumber)) {
448 		if (intr->get(subIntrNumber)->handlerAddress != 0) {
449 			error = SCE_KERNEL_ERROR_FOUND_HANDLER;
450 			return NULL;
451 		} else {
452 			SubIntrHandler *subIntrHandler = intr->get(subIntrNumber);
453 			subIntrHandler->handlerAddress = handler;
454 			subIntrHandler->handlerArg = handlerArg;
455 
456 			error = SCE_KERNEL_ERROR_OK;
457 			return subIntrHandler;
458 		}
459 	}
460 
461 	SubIntrHandler *subIntrHandler = intr->add(subIntrNumber);
462 	subIntrHandler->subIntrNumber = subIntrNumber;
463 	subIntrHandler->intrNumber = intrNumber;
464 	subIntrHandler->handlerAddress = handler;
465 	subIntrHandler->handlerArg = handlerArg;
466 	subIntrHandler->enabled = false;
467 
468 	error = SCE_KERNEL_ERROR_OK;
469 	return subIntrHandler;
470 }
471 
__ReleaseSubIntrHandler(int intrNumber,int subIntrNumber)472 int __ReleaseSubIntrHandler(int intrNumber, int subIntrNumber) {
473 	if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
474 		return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
475 	}
476 	IntrHandler *intr = intrHandlers[intrNumber];
477 	if (!intr->has(subIntrNumber) || intr->get(subIntrNumber)->handlerAddress == 0) {
478 		return SCE_KERNEL_ERROR_NOTFOUND_HANDLER;
479 	}
480 
481 	for (auto it = pendingInterrupts.begin(); it != pendingInterrupts.end(); ) {
482 		if (it->intr == intrNumber && it->subintr == subIntrNumber) {
483 			pendingInterrupts.erase(it++);
484 		} else {
485 			++it;
486 		}
487 	}
488 
489 	// This also implicitly disables it, which is correct.
490 	intrHandlers[intrNumber]->remove(subIntrNumber);
491 	return 0;
492 }
493 
sceKernelRegisterSubIntrHandler(u32 intrNumber,u32 subIntrNumber,u32 handler,u32 handlerArg)494 u32 sceKernelRegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 handler, u32 handlerArg) {
495 	if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
496 		ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): invalid interrupt", intrNumber, subIntrNumber, handler, handlerArg);
497 		return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
498 	}
499 	if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) {
500 		ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): invalid subinterrupt", intrNumber, subIntrNumber, handler, handlerArg);
501 		return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
502 	}
503 
504 	u32 error;
505 	SubIntrHandler *subIntrHandler = __RegisterSubIntrHandler(intrNumber, subIntrNumber, handler, handlerArg, error);
506 	if (subIntrHandler) {
507 		if (handler == 0) {
508 			WARN_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): ignored NULL handler", intrNumber, subIntrNumber, handler, handlerArg);
509 		} else {
510 			DEBUG_LOG(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x)", intrNumber, subIntrNumber, handler, handlerArg);
511 		}
512 	} else if (error == SCE_KERNEL_ERROR_FOUND_HANDLER) {
513 		ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): duplicate handler", intrNumber, subIntrNumber, handler, handlerArg);
514 	} else {
515 		ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): error %08x", intrNumber, subIntrNumber, handler, handlerArg, error);
516 	}
517 	return error;
518 }
519 
sceKernelReleaseSubIntrHandler(u32 intrNumber,u32 subIntrNumber)520 u32 sceKernelReleaseSubIntrHandler(u32 intrNumber, u32 subIntrNumber) {
521 	if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
522 		ERROR_LOG_REPORT(SCEINTC, "sceKernelReleaseSubIntrHandler(%i, %i): invalid interrupt", intrNumber, subIntrNumber);
523 		return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
524 	}
525 	if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) {
526 		ERROR_LOG_REPORT(SCEINTC, "sceKernelReleaseSubIntrHandler(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber);
527 		return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
528 	}
529 
530 	u32 error = __ReleaseSubIntrHandler(intrNumber, subIntrNumber);
531 	if (error != SCE_KERNEL_ERROR_OK) {
532 		ERROR_LOG(SCEINTC, "sceKernelReleaseSubIntrHandler(%i, %i): error %08x", intrNumber, subIntrNumber, error);
533 	}
534 	return error;
535 }
536 
sceKernelEnableSubIntr(u32 intrNumber,u32 subIntrNumber)537 u32 sceKernelEnableSubIntr(u32 intrNumber, u32 subIntrNumber) {
538 	if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
539 		ERROR_LOG_REPORT(SCEINTC, "sceKernelEnableSubIntr(%i, %i): invalid interrupt", intrNumber, subIntrNumber);
540 		return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
541 	}
542 	if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) {
543 		ERROR_LOG_REPORT(SCEINTC, "sceKernelEnableSubIntr(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber);
544 		return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
545 	}
546 
547 	DEBUG_LOG(SCEINTC, "sceKernelEnableSubIntr(%i, %i)", intrNumber, subIntrNumber);
548 	u32 error;
549 	if (!intrHandlers[intrNumber]->has(subIntrNumber)) {
550 		// Enableing a handler before registering it works fine.
551 		__RegisterSubIntrHandler(intrNumber, subIntrNumber, 0, 0, error);
552 	}
553 
554 	intrHandlers[intrNumber]->enable(subIntrNumber);
555 	return 0;
556 }
557 
sceKernelDisableSubIntr(u32 intrNumber,u32 subIntrNumber)558 static u32 sceKernelDisableSubIntr(u32 intrNumber, u32 subIntrNumber) {
559 	if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
560 		ERROR_LOG_REPORT(SCEINTC, "sceKernelDisableSubIntr(%i, %i): invalid interrupt", intrNumber, subIntrNumber);
561 		return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
562 	}
563 	if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) {
564 		ERROR_LOG_REPORT(SCEINTC, "sceKernelDisableSubIntr(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber);
565 		return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
566 	}
567 
568 	DEBUG_LOG(SCEINTC, "sceKernelDisableSubIntr(%i, %i)", intrNumber, subIntrNumber);
569 
570 	if (!intrHandlers[intrNumber]->has(subIntrNumber)) {
571 		// Disabling when not registered is not an error.
572 		return 0;
573 	}
574 
575 	intrHandlers[intrNumber]->disable(subIntrNumber);
576 	return 0;
577 }
578 
579 
580 struct PspIntrHandlerOptionParam {
581 	int size;              //+00
582 	u32 entry;             //+04
583 	u32 common;            //+08
584 	u32 gp;                //+0C
585 	u16 intr_code;         //+10
586 	u16 sub_count;         //+12
587 	u16 intr_level;        //+14
588 	u16 enabled;           //+16
589 	u32 calls;             //+18
590 	u32 field_1C;          //+1C
591 	u32 total_clock_lo;    //+20
592 	u32 total_clock_hi;    //+24
593 	u32 min_clock_lo;      //+28
594 	u32 min_clock_hi;      //+2C
595 	u32 max_clock_lo;      //+30
596 	u32 max_clock_hi;      //+34
597 };  //=38
598 
QueryIntrHandlerInfo()599 static int QueryIntrHandlerInfo()
600 {
601 	ERROR_LOG_REPORT(SCEINTC, "QueryIntrHandlerInfo()");
602 	return 0;
603 }
604 
sceKernelMemset(u32 addr,u32 fillc,u32 n)605 static u32 sceKernelMemset(u32 addr, u32 fillc, u32 n)
606 {
607 	u8 c = fillc & 0xff;
608 	DEBUG_LOG(SCEINTC, "sceKernelMemset(ptr = %08x, c = %02x, n = %08x)", addr, c, n);
609 	bool skip = false;
610 	if (n != 0) {
611 		if (Memory::IsVRAMAddress(addr)) {
612 			skip = gpu->PerformMemorySet(addr, fillc, n);
613 		}
614 		if (!skip) {
615 			Memory::Memset(addr, c, n);
616 		}
617 	}
618 	NotifyMemInfo(MemBlockFlags::WRITE, addr, n, "KernelMemset");
619 	return addr;
620 }
621 
sceKernelMemcpy(u32 dst,u32 src,u32 size)622 static u32 sceKernelMemcpy(u32 dst, u32 src, u32 size)
623 {
624 	DEBUG_LOG(SCEKERNEL, "sceKernelMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size);
625 
626 	// Some games copy from executable code.  We need to flush emuhack ops.
627 	currentMIPS->InvalidateICache(src, size);
628 
629 	bool skip = false;
630 	if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) {
631 		skip = gpu->PerformMemoryCopy(dst, src, size);
632 	}
633 
634 	// Technically should crash if these are invalid and size > 0...
635 	if (!skip && Memory::IsValidAddress(dst) && Memory::IsValidAddress(src) && Memory::IsValidAddress(dst + size - 1) && Memory::IsValidAddress(src + size - 1))
636 	{
637 		u8 *dstp = Memory::GetPointerUnchecked(dst);
638 		u8 *srcp = Memory::GetPointerUnchecked(src);
639 
640 		// If it's non-overlapping, just do it in one go.
641 		if (dst + size < src || src + size < dst)
642 			memcpy(dstp, srcp, size);
643 		else
644 		{
645 			// Try to handle overlapped copies with similar properties to hardware, just in case.
646 			// Not that anyone ought to rely on it.
647 			for (u32 size64 = size / 8; size64 > 0; --size64)
648 			{
649 				memmove(dstp, srcp, 8);
650 				dstp += 8;
651 				srcp += 8;
652 			}
653 			for (u32 size8 = size % 8; size8 > 0; --size8)
654 				*dstp++ = *srcp++;
655 		}
656 	}
657 
658 	const std::string tag = "KernelMemcpy/" + GetMemWriteTagAt(src, size);
659 	NotifyMemInfo(MemBlockFlags::READ, src, size, tag.c_str(), tag.size());
660 	NotifyMemInfo(MemBlockFlags::WRITE, dst, size, tag.c_str(), tag.size());
661 
662 	return dst;
663 }
664 
665 const HLEFunction Kernel_Library[] =
666 {
667 	{0x092968F4, &WrapI_V<sceKernelCpuSuspendIntr>,            "sceKernelCpuSuspendIntr",             'i', ""     },
668 	{0X5F10D406, &WrapV_U<sceKernelCpuResumeIntr>,             "sceKernelCpuResumeIntr",              'v', "x"    },
669 	{0X3B84732D, &WrapV_U<sceKernelCpuResumeIntrWithSync>,     "sceKernelCpuResumeIntrWithSync",      'v', "x"    },
670 	{0X47A0B729, &WrapI_I<sceKernelIsCpuIntrSuspended>,        "sceKernelIsCpuIntrSuspended",         'i', "i"    },
671 	{0xb55249d2, &WrapI_V<sceKernelIsCpuIntrEnable>,           "sceKernelIsCpuIntrEnable",            'i', "",    },
672 	{0XA089ECA4, &WrapU_UUU<sceKernelMemset>,                  "sceKernelMemset",                     'x', "xxx"  },
673 	{0XDC692EE3, &WrapI_UI<sceKernelTryLockLwMutex>,           "sceKernelTryLockLwMutex",             'i', "xi"   },
674 	{0X37431849, &WrapI_UI<sceKernelTryLockLwMutex_600>,       "sceKernelTryLockLwMutex_600",         'i', "xi"   },
675 	{0XBEA46419, &WrapI_UIU<sceKernelLockLwMutex>,             "sceKernelLockLwMutex",                'i', "xix", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED },
676 	{0X1FC64E09, &WrapI_UIU<sceKernelLockLwMutexCB>,           "sceKernelLockLwMutexCB",              'i', "xix", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED },
677 	{0X15B6446B, &WrapI_UI<sceKernelUnlockLwMutex>,            "sceKernelUnlockLwMutex",              'i', "xi"   },
678 	{0XC1734599, &WrapI_UU<sceKernelReferLwMutexStatus>,       "sceKernelReferLwMutexStatus",         'i', "xx"   },
679 	{0X293B45B8, &WrapI_V<sceKernelGetThreadId>,               "sceKernelGetThreadId",                'i', ""     },
680 	{0XD13BDE95, &WrapI_V<sceKernelCheckThreadStack>,          "sceKernelCheckThreadStack",           'i', ""     },
681 	{0X1839852A, &WrapU_UUU<sceKernelMemcpy>,                  "sceKernelMemcpy",                     'x', "xxx"  },
682 	{0XFA835CDE, &WrapI_I<sceKernelGetTlsAddr>,                "sceKernelGetTlsAddr",                 'i', "i"    },
683 	{0X05572A5F, &WrapV_V<sceKernelExitGame>,                  "sceKernelExitGame",                   'v', ""     },
684 	{0X4AC57943, &WrapI_I<sceKernelRegisterExitCallback>,      "sceKernelRegisterExitCallback",       'i', "i"    },
685 };
686 
sysclib_memcpy(u32 dst,u32 src,u32 size)687 static u32 sysclib_memcpy(u32 dst, u32 src, u32 size) {
688 	if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) {
689 		memcpy(Memory::GetPointer(dst), Memory::GetPointer(src), size);
690 	}
691 	const std::string tag = "KernelMemcpy/" + GetMemWriteTagAt(src, size);
692 	NotifyMemInfo(MemBlockFlags::READ, src, size, tag.c_str(), tag.size());
693 	NotifyMemInfo(MemBlockFlags::WRITE, dst, size, tag.c_str(), tag.size());
694 	return dst;
695 }
696 
sysclib_strcat(u32 dst,u32 src)697 static u32 sysclib_strcat(u32 dst, u32 src) {
698 	ERROR_LOG(SCEKERNEL, "Untested sysclib_strcat(dest=%08x, src=%08x)", dst, src);
699 	if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src)) {
700 		strcat((char *)Memory::GetPointer(dst), (char *)Memory::GetPointer(src));
701 	}
702 	return dst;
703 }
704 
sysclib_strcmp(u32 dst,u32 src)705 static int sysclib_strcmp(u32 dst, u32 src) {
706 	ERROR_LOG(SCEKERNEL, "Untested sysclib_strcmp(dest=%08x, src=%08x)", dst, src);
707 	if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src)) {
708 		return strcmp((char *)Memory::GetPointer(dst), (char *)Memory::GetPointer(src));
709 	} else {
710 		// What to do? Crash, probably.
711 		return 0;
712 	}
713 }
714 
sysclib_strcpy(u32 dst,u32 src)715 static u32 sysclib_strcpy(u32 dst, u32 src) {
716 	ERROR_LOG(SCEKERNEL, "Untested sysclib_strcpy(dest=%08x, src=%08x)", dst, src);
717 	if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(src)) {
718 		strcpy((char *)Memory::GetPointer(dst), (char *)Memory::GetPointer(src));
719 	}
720 	return dst;
721 }
722 
sysclib_strlen(u32 src)723 static u32 sysclib_strlen(u32 src) {
724 	ERROR_LOG(SCEKERNEL, "Untested sysclib_strlen(src=%08x)", src);
725 	if (Memory::IsValidAddress(src)) {
726 		return (u32)strlen(Memory::GetCharPointer(src));
727 	} else {
728 		// What to do? Crash, probably.
729 		return 0;
730 	}
731 }
732 
sysclib_memcmp(u32 dst,u32 src,u32 size)733 static int sysclib_memcmp(u32 dst, u32 src, u32 size) {
734 	ERROR_LOG(SCEKERNEL, "Untested sysclib_memcmp(dest=%08x, src=%08x, size=%i)", dst, src, size);
735 	if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) {
736 		return memcmp(Memory::GetCharPointer(dst), Memory::GetCharPointer(src), size);
737 	} else {
738 		// What to do? Crash, probably.
739 		return 0;
740 	}
741 }
742 
sysclib_sprintf(u32 dst,u32 fmt)743 static int sysclib_sprintf(u32 dst, u32 fmt) {
744 	ERROR_LOG(SCEKERNEL, "Unimpl sysclib_sprintf(dest=%08x, src=%08x)", dst, fmt);
745 	if (Memory::IsValidAddress(dst) && Memory::IsValidAddress(fmt)) {
746 		// TODO: Properly use the format string with more parameters.
747 		return sprintf((char *)Memory::GetPointer(dst), "%s", Memory::GetCharPointer(fmt));
748 	} else {
749 		// What to do? Crash, probably.
750 		return 0;
751 	}
752 }
753 
sysclib_memset(u32 destAddr,int data,int size)754 static u32 sysclib_memset(u32 destAddr, int data, int size) {
755 	ERROR_LOG(SCEKERNEL, "Untested sysclib_memset(dest=%08x, data=%d ,size=%d)", destAddr, data, size);
756 	if (Memory::IsValidRange(destAddr, size)) {
757 		memset(Memory::GetPointer(destAddr), data, size);
758 	}
759 	NotifyMemInfo(MemBlockFlags::WRITE, destAddr, size, "KernelMemset");
760 	return 0;
761 }
762 
sysclib_strstr(u32 s1,u32 s2)763 static int sysclib_strstr(u32 s1, u32 s2) {
764 	ERROR_LOG(SCEKERNEL, "Untested sysclib_strstr(%08x, %08x)", s1, s2);
765 	if (Memory::IsValidAddress(s1) && Memory::IsValidAddress(s2)) {
766 		std::string str1 = Memory::GetCharPointer(s1);
767 		std::string str2 = Memory::GetCharPointer(s2);
768 		size_t index = str1.find(str2);
769 		if (index == str1.npos) {
770 			return 0;
771 		}
772 		return s1 + (uint32_t)index;
773 	}
774 	return 0;
775 }
776 
sysclib_strncmp(u32 s1,u32 s2,u32 size)777 static int sysclib_strncmp(u32 s1, u32 s2, u32 size) {
778 	ERROR_LOG(SCEKERNEL, "Untested sysclib_strncmp(%08x, %08x, %08x)", s1, s2, size);
779 	if (Memory::IsValidAddress(s1) && Memory::IsValidAddress(s2)) {
780 		const char * str1 = Memory::GetCharPointer(s1);
781 		const char * str2 = Memory::GetCharPointer(s2);
782 		return strncmp(str1, str2, size);
783 	}
784 	return 0;
785 }
786 
sysclib_memmove(u32 dst,u32 src,u32 size)787 static u32 sysclib_memmove(u32 dst, u32 src, u32 size) {
788 	ERROR_LOG(SCEKERNEL, "Untested sysclib_memmove(%08x, %08x, %08x)", dst, src, size);
789 	if (Memory::IsValidRange(dst, size) && Memory::IsValidRange(src, size)) {
790 		memmove(Memory::GetPointer(dst), Memory::GetPointer(src), size);
791 	}
792 	const std::string tag = "KernelMemmove/" + GetMemWriteTagAt(src, size);
793 	NotifyMemInfo(MemBlockFlags::READ, src, size, tag.c_str(), tag.size());
794 	NotifyMemInfo(MemBlockFlags::WRITE, dst, size, tag.c_str(), tag.size());
795 	return 0;
796 }
797 
sysclib_strncpy(u32 dest,u32 src,u32 size)798 static u32 sysclib_strncpy(u32 dest, u32 src, u32 size) {
799 	if (!Memory::IsValidAddress(dest) || Memory::IsValidAddress(src)) {
800 		return hleLogError(SCEKERNEL, 0, "invalid address");
801 	}
802 
803 	// This is just regular strncpy, but being explicit to avoid warnings/safety fixes on missing null.
804 	u32 i = 0;
805 	u32 srcSize = Memory::ValidSize(src, size);
806 	const u8 *srcp = Memory::GetPointer(src);
807 	u8 *destp = Memory::GetPointer(dest);
808 	for (i = 0; i < srcSize; ++i) {
809 		u8 c = *srcp++;
810 		if (c == 0)
811 			break;
812 		*destp++ = c;
813 	}
814 
815 	u32 destSize = Memory::ValidSize(dest, size);
816 	for (; i < destSize; ++i) {
817 		*destp++ = 0;
818 	}
819 
820 	return hleLogSuccessX(SCEKERNEL, dest);
821 }
822 
823 const HLEFunction SysclibForKernel[] =
824 {
825 	{0xAB7592FF, &WrapU_UUU<sysclib_memcpy>,                   "memcpy",                              'x', "xxx",    HLE_KERNEL_SYSCALL },
826 	{0x476FD94A, &WrapU_UU<sysclib_strcat>,                    "strcat",                              'x', "xx",     HLE_KERNEL_SYSCALL },
827 	{0xC0AB8932, &WrapI_UU<sysclib_strcmp>,                    "strcmp",                              'i', "xx",     HLE_KERNEL_SYSCALL },
828 	{0xEC6F1CF2, &WrapU_UU<sysclib_strcpy>,                    "strcpy",                              'x', "xx",     HLE_KERNEL_SYSCALL },
829 	{0x52DF196C, &WrapU_U<sysclib_strlen>,                     "strlen",                              'x', "x",      HLE_KERNEL_SYSCALL },
830 	{0x81D0D1F7, &WrapI_UUU<sysclib_memcmp>,                   "memcmp",                              'i', "xxx",    HLE_KERNEL_SYSCALL },
831 	{0x7661E728, &WrapI_UU<sysclib_sprintf>,                   "sprintf",                             'i', "xx",     HLE_KERNEL_SYSCALL },
832 	{0x10F3BB61, &WrapU_UII<sysclib_memset>,                   "memset",                              'x', "xii",    HLE_KERNEL_SYSCALL },
833 	{0x0D188658, &WrapI_UU<sysclib_strstr>,                    "strstr",                              'i', "xx",     HLE_KERNEL_SYSCALL },
834 	{0x7AB35214, &WrapI_UUU<sysclib_strncmp>,                  "strncmp",                             'i', "xxx",    HLE_KERNEL_SYSCALL },
835 	{0xA48D2592, &WrapU_UUU<sysclib_memmove>,                  "memmove",                             'x', "xxx",    HLE_KERNEL_SYSCALL },
836 	{0xB49A7697, &WrapU_UUU<sysclib_strncpy>,                  "strncpy",                             'x', "xxi",    HLE_KERNEL_SYSCALL },
837 };
838 
Register_Kernel_Library()839 void Register_Kernel_Library()
840 {
841 	RegisterModule("Kernel_Library", ARRAY_SIZE(Kernel_Library), Kernel_Library);
842 }
843 
Register_SysclibForKernel()844 void Register_SysclibForKernel()
845 {
846 	RegisterModule("SysclibForKernel", ARRAY_SIZE(SysclibForKernel), SysclibForKernel);
847 }
848 
849 const HLEFunction InterruptManager[] =
850 {
851 	{0XCA04A2B9, &WrapU_UUUU<sceKernelRegisterSubIntrHandler>, "sceKernelRegisterSubIntrHandler",     'x', "xxxx" },
852 	{0XD61E6961, &WrapU_UU<sceKernelReleaseSubIntrHandler>,    "sceKernelReleaseSubIntrHandler",      'x', "xx"   },
853 	{0XFB8E22EC, &WrapU_UU<sceKernelEnableSubIntr>,            "sceKernelEnableSubIntr",              'x', "xx"   },
854 	{0X8A389411, &WrapU_UU<sceKernelDisableSubIntr>,           "sceKernelDisableSubIntr",             'x', "xx"   },
855 	{0X5CB5A78B, nullptr,                                      "sceKernelSuspendSubIntr",             '?', ""     },
856 	{0X7860E0DC, nullptr,                                      "sceKernelResumeSubIntr",              '?', ""     },
857 	{0XFC4374B8, nullptr,                                      "sceKernelIsSubInterruptOccurred",     '?', ""     },
858 	{0xD2E8363F, &WrapI_V<QueryIntrHandlerInfo>,               "QueryIntrHandlerInfo",                'i', ""     },  // No sce prefix for some reason
859 	{0XEEE43F47, nullptr,                                      "sceKernelRegisterUserSpaceIntrStack", '?', ""     },
860 };
861 
862 
Register_InterruptManager()863 void Register_InterruptManager()
864 {
865 	RegisterModule("InterruptManager", ARRAY_SIZE(InterruptManager), InterruptManager);
866 }
867