Merge pull request #90 from gizmo98/patch-2
[libretro-ppsspp.git] / Core / HLE / sceKernelInterrupt.cpp
blob19f118d72f8dc49e52982ac20497de97e9e24910
1 // Copyright (c) 2012- PPSSPP Project.
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.
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.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
18 #include <string>
19 #include <list>
20 #include <map>
22 #include "Core/MemMapHelpers.h"
23 #include "Core/Reporting.h"
24 #include "Core/HLE/HLE.h"
25 #include "Core/HLE/FunctionWrappers.h"
26 #include "Core/MIPS/MIPS.h"
27 #include "Common/ChunkFile.h"
29 #include "Core/Debugger/Breakpoints.h"
30 #include "Core/HLE/sceKernel.h"
31 #include "Core/HLE/sceKernelThread.h"
32 #include "Core/HLE/sceKernelInterrupt.h"
33 #include "Core/HLE/sceKernelMemory.h"
34 #include "Core/HLE/sceKernelMutex.h"
36 #include "GPU/GPUCommon.h"
37 #include "GPU/GPUState.h"
39 void __DisableInterrupts();
40 void __EnableInterrupts();
41 bool __InterruptsEnabled();
43 // Seems like some > 16 are taken but not available. Probably kernel only?
44 static const u32 PSP_NUMBER_SUBINTERRUPTS = 32;
46 // InterruptsManager
47 //////////////////////////////////////////////////////////////////////////
48 // INTERRUPT MANAGEMENT
49 //////////////////////////////////////////////////////////////////////////
51 class InterruptState
53 public:
54 void save();
55 void restore();
56 void clear();
58 void DoState(PointerWrap &p)
60 auto s = p.Section("InterruptState", 1);
61 if (!s)
62 return;
64 p.Do(savedCpu);
67 ThreadContext savedCpu;
70 // STATE
72 InterruptState intState;
73 IntrHandler* intrHandlers[PSP_NUMBER_INTERRUPTS];
74 std::list<PendingInterrupt> pendingInterrupts;
76 // Yeah, this bit is a bit silly.
77 static int interruptsEnabled = 1;
78 static bool inInterrupt;
79 static SceUID threadBeforeInterrupt;
82 static int sceKernelCpuSuspendIntr()
84 VERBOSE_LOG(SCEINTC, "sceKernelCpuSuspendIntr");
85 int returnValue;
86 if (__InterruptsEnabled())
88 returnValue = 1;
89 __DisableInterrupts();
91 else
93 returnValue = 0;
95 hleEatCycles(15);
96 return returnValue;
99 static void sceKernelCpuResumeIntr(u32 enable)
101 VERBOSE_LOG(SCEINTC, "sceKernelCpuResumeIntr(%i)", enable);
102 if (enable)
104 __EnableInterrupts();
105 hleRunInterrupts();
106 hleReSchedule("interrupts resumed");
108 else
110 __DisableInterrupts();
112 hleEatCycles(15);
115 static int sceKernelIsCpuIntrEnable()
117 u32 retVal = __InterruptsEnabled();
118 DEBUG_LOG(SCEINTC, "%i=sceKernelIsCpuIntrEnable()", retVal);
119 return retVal;
122 static int sceKernelIsCpuIntrSuspended(int flag)
124 int retVal = flag == 0 ? 1 : 0;
125 DEBUG_LOG(SCEINTC, "%i=sceKernelIsCpuIntrSuspended(%d)", retVal, flag);
126 return retVal;
129 static void sceKernelCpuResumeIntrWithSync(u32 enable)
131 sceKernelCpuResumeIntr(enable);
134 bool IntrHandler::run(PendingInterrupt& pend)
136 SubIntrHandler *handler = get(pend.subintr);
137 if (handler == NULL)
139 WARN_LOG(SCEINTC, "Ignoring interrupt, already been released.");
140 return false;
143 copyArgsToCPU(pend);
145 return true;
148 void IntrHandler::copyArgsToCPU(PendingInterrupt& pend)
150 SubIntrHandler* handler = get(pend.subintr);
151 DEBUG_LOG(CPU, "Entering interrupt handler %08x", handler->handlerAddress);
152 currentMIPS->pc = handler->handlerAddress;
153 currentMIPS->r[MIPS_REG_A0] = handler->subIntrNumber;
154 currentMIPS->r[MIPS_REG_A1] = handler->handlerArg;
155 // RA is already taken care of
158 void IntrHandler::handleResult(PendingInterrupt& pend)
160 //u32 result = currentMIPS->r[MIPS_REG_V0];
163 SubIntrHandler* IntrHandler::add(int subIntrNum)
165 return &subIntrHandlers[subIntrNum];
167 void IntrHandler::remove(int subIntrNum)
169 if (has(subIntrNum))
171 subIntrHandlers.erase(subIntrNum);
174 bool IntrHandler::has(int subIntrNum) const
176 return subIntrHandlers.find(subIntrNum) != subIntrHandlers.end();
178 void IntrHandler::enable(int subIntrNum)
180 subIntrHandlers[subIntrNum].enabled = true;
182 void IntrHandler::disable(int subIntrNum)
184 subIntrHandlers[subIntrNum].enabled = false;
186 SubIntrHandler* IntrHandler::get(int subIntrNum)
188 if (has(subIntrNum))
189 return &subIntrHandlers[subIntrNum];
190 else
191 return NULL;
193 void IntrHandler::clear()
195 subIntrHandlers.clear();
198 void IntrHandler::queueUp(int subintr) {
199 if (subintr == PSP_INTR_SUB_NONE) {
200 pendingInterrupts.push_back(PendingInterrupt(intrNumber, subintr));
201 } else {
202 // Just call execute on all the subintr handlers for this interrupt.
203 // They will get queued up.
204 for (auto iter = subIntrHandlers.begin(); iter != subIntrHandlers.end(); ++iter) {
205 if ((subintr == PSP_INTR_SUB_ALL || iter->first == subintr) && iter->second.enabled && iter->second.handlerAddress != 0) {
206 pendingInterrupts.push_back(PendingInterrupt(intrNumber, iter->first));
212 void IntrHandler::DoState(PointerWrap &p)
214 auto s = p.Section("IntrHandler", 1);
215 if (!s)
216 return;
218 p.Do(intrNumber);
219 p.Do<int, SubIntrHandler>(subIntrHandlers);
222 void PendingInterrupt::DoState(PointerWrap &p)
224 auto s = p.Section("PendingInterrupt", 1);
225 if (!s)
226 return;
228 p.Do(intr);
229 p.Do(subintr);
232 void __InterruptsInit()
234 interruptsEnabled = 1;
235 inInterrupt = false;
236 for (int i = 0; i < (int)ARRAY_SIZE(intrHandlers); ++i)
237 intrHandlers[i] = new IntrHandler(i);
238 intState.clear();
239 threadBeforeInterrupt = 0;
242 void __InterruptsDoState(PointerWrap &p)
244 auto s = p.Section("sceKernelInterrupt", 1);
245 if (!s)
246 return;
248 int numInterrupts = PSP_NUMBER_INTERRUPTS;
249 p.Do(numInterrupts);
250 if (numInterrupts != PSP_NUMBER_INTERRUPTS)
252 p.SetError(p.ERROR_FAILURE);
253 ERROR_LOG(SCEINTC, "Savestate failure: wrong number of interrupts, can't load.");
254 return;
257 intState.DoState(p);
258 PendingInterrupt pi(0, 0);
259 p.Do(pendingInterrupts, pi);
260 p.Do(interruptsEnabled);
261 p.Do(inInterrupt);
262 p.Do(threadBeforeInterrupt);
265 void __InterruptsDoStateLate(PointerWrap &p)
267 // We do these later to ensure the handlers have been registered.
268 for (int i = 0; i < PSP_NUMBER_INTERRUPTS; ++i)
269 intrHandlers[i]->DoState(p);
270 p.DoMarker("sceKernelInterrupt Late");
273 void __InterruptsShutdown()
275 for (size_t i = 0; i < ARRAY_SIZE(intrHandlers); ++i)
276 intrHandlers[i]->clear();
277 for (size_t i = 0; i < ARRAY_SIZE(intrHandlers); ++i)
279 if (intrHandlers[i])
281 delete intrHandlers[i];
282 intrHandlers[i] = 0;
285 pendingInterrupts.clear();
288 void __DisableInterrupts()
290 interruptsEnabled = 0;
293 void __EnableInterrupts()
295 interruptsEnabled = 1;
298 bool __InterruptsEnabled()
300 return interruptsEnabled != 0;
303 bool __IsInInterrupt()
305 return inInterrupt;
308 void InterruptState::save()
310 __KernelSaveContext(&savedCpu, true);
313 void InterruptState::restore()
315 __KernelLoadContext(&savedCpu, true);
318 void InterruptState::clear()
322 // http://forums.ps2dev.org/viewtopic.php?t=5687
324 // 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
327 // Returns true if anything was executed.
328 bool __RunOnePendingInterrupt()
330 bool needsThreadReturn = false;
332 if (inInterrupt || !interruptsEnabled) {
333 // Already in an interrupt! We'll keep going when it's done.
334 return false;
336 // Can easily prioritize between different kinds of interrupts if necessary.
337 retry:
338 if (!pendingInterrupts.empty()) {
339 PendingInterrupt pend = pendingInterrupts.front();
341 IntrHandler* handler = intrHandlers[pend.intr];
342 if (handler == NULL) {
343 WARN_LOG(SCEINTC, "Ignoring interrupt");
344 pendingInterrupts.pop_front();
345 goto retry;
348 // If we came from CoreTiming::Advance(), we might've come from a waiting thread's callback.
349 // To avoid "injecting" return values into our saved state, we context switch here.
350 SceUID savedThread = __KernelGetCurThread();
351 if (__KernelSwitchOffThread("interrupt")) {
352 threadBeforeInterrupt = savedThread;
353 needsThreadReturn = true;
356 intState.save();
357 inInterrupt = true;
359 if (!handler->run(pend)) {
360 pendingInterrupts.pop_front();
361 inInterrupt = false;
362 goto retry;
365 currentMIPS->r[MIPS_REG_RA] = __KernelInterruptReturnAddress();
366 return true;
367 } else {
368 if (needsThreadReturn)
369 __KernelSwitchToThread(threadBeforeInterrupt, "left interrupt");
370 // DEBUG_LOG(SCEINTC, "No more interrupts!");
371 return false;
375 static void __TriggerRunInterrupts(int type)
377 // If interrupts aren't enabled, we run them later.
378 if (interruptsEnabled && !inInterrupt)
380 if ((type & PSP_INTR_HLE) != 0)
381 hleRunInterrupts();
382 else if ((type & PSP_INTR_ALWAYS_RESCHED) != 0)
384 // "Always" only means if dispatch is enabled.
385 if (!__RunOnePendingInterrupt() && __KernelIsDispatchEnabled())
387 SceUID savedThread = __KernelGetCurThread();
388 if (__KernelSwitchOffThread("interrupt"))
389 threadBeforeInterrupt = savedThread;
392 else
393 __RunOnePendingInterrupt();
397 void __TriggerInterrupt(int type, PSPInterrupt intno, int subintr)
399 if (interruptsEnabled || (type & PSP_INTR_ONLY_IF_ENABLED) == 0)
401 intrHandlers[intno]->queueUp(subintr);
402 VERBOSE_LOG(SCEINTC, "Triggering subinterrupts for interrupt %i sub %i (%i in queue)", intno, subintr, (u32)pendingInterrupts.size());
403 __TriggerRunInterrupts(type);
407 void __KernelReturnFromInterrupt()
409 VERBOSE_LOG(SCEINTC, "Left interrupt handler at %08x", currentMIPS->pc);
411 hleSkipDeadbeef();
413 // This is what we just ran.
414 PendingInterrupt pend = pendingInterrupts.front();
415 pendingInterrupts.pop_front();
417 intrHandlers[pend.intr]->handleResult(pend);
418 inInterrupt = false;
420 // Restore context after running the interrupt.
421 intState.restore();
422 // All should now be back to normal, including PC.
424 // Alright, let's see if there's any more interrupts queued...
425 if (!__RunOnePendingInterrupt())
427 // Otherwise, we reschedule when dispatch was enabled, or switch back otherwise.
428 if (__KernelIsDispatchEnabled())
429 __KernelReSchedule("left interrupt");
430 else
431 __KernelSwitchToThread(threadBeforeInterrupt, "left interrupt");
435 void __RegisterIntrHandler(u32 intrNumber, IntrHandler* handler)
437 if(intrHandlers[intrNumber])
438 delete intrHandlers[intrNumber];
439 intrHandlers[intrNumber] = handler;
442 SubIntrHandler *__RegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 handler, u32 handlerArg, u32 &error) {
443 if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
444 error = SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
445 return NULL;
447 IntrHandler *intr = intrHandlers[intrNumber];
448 if (intr->has(subIntrNumber)) {
449 if (intr->get(subIntrNumber)->handlerAddress != 0) {
450 error = SCE_KERNEL_ERROR_FOUND_HANDLER;
451 return NULL;
452 } else {
453 SubIntrHandler *subIntrHandler = intr->get(subIntrNumber);
454 subIntrHandler->handlerAddress = handler;
455 subIntrHandler->handlerArg = handlerArg;
457 error = SCE_KERNEL_ERROR_OK;
458 return subIntrHandler;
462 SubIntrHandler *subIntrHandler = intr->add(subIntrNumber);
463 subIntrHandler->subIntrNumber = subIntrNumber;
464 subIntrHandler->intrNumber = intrNumber;
465 subIntrHandler->handlerAddress = handler;
466 subIntrHandler->handlerArg = handlerArg;
467 subIntrHandler->enabled = false;
469 error = SCE_KERNEL_ERROR_OK;
470 return subIntrHandler;
473 int __ReleaseSubIntrHandler(int intrNumber, int subIntrNumber) {
474 if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
475 return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
477 IntrHandler *intr = intrHandlers[intrNumber];
478 if (!intr->has(subIntrNumber) || intr->get(subIntrNumber)->handlerAddress == 0) {
479 return SCE_KERNEL_ERROR_NOTFOUND_HANDLER;
482 for (auto it = pendingInterrupts.begin(); it != pendingInterrupts.end(); ) {
483 if (it->intr == intrNumber && it->subintr == subIntrNumber) {
484 pendingInterrupts.erase(it++);
485 } else {
486 ++it;
490 // This also implicitly disables it, which is correct.
491 intrHandlers[intrNumber]->remove(subIntrNumber);
492 return 0;
495 u32 sceKernelRegisterSubIntrHandler(u32 intrNumber, u32 subIntrNumber, u32 handler, u32 handlerArg) {
496 if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
497 ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): invalid interrupt", intrNumber, subIntrNumber, handler, handlerArg);
498 return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
500 if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) {
501 ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): invalid subinterrupt", intrNumber, subIntrNumber, handler, handlerArg);
502 return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
505 u32 error;
506 SubIntrHandler *subIntrHandler = __RegisterSubIntrHandler(intrNumber, subIntrNumber, handler, handlerArg, error);
507 if (subIntrHandler) {
508 if (handler == 0) {
509 WARN_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): ignored NULL handler", intrNumber, subIntrNumber, handler, handlerArg);
510 } else {
511 DEBUG_LOG(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x)", intrNumber, subIntrNumber, handler, handlerArg);
513 } else if (error == SCE_KERNEL_ERROR_FOUND_HANDLER) {
514 ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): duplicate handler", intrNumber, subIntrNumber, handler, handlerArg);
515 } else {
516 ERROR_LOG_REPORT(SCEINTC, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): error %08x", intrNumber, subIntrNumber, handler, handlerArg, error);
518 return error;
521 u32 sceKernelReleaseSubIntrHandler(u32 intrNumber, u32 subIntrNumber) {
522 if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
523 ERROR_LOG_REPORT(SCEINTC, "sceKernelReleaseSubIntrHandler(%i, %i): invalid interrupt", intrNumber, subIntrNumber);
524 return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
526 if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) {
527 ERROR_LOG_REPORT(SCEINTC, "sceKernelReleaseSubIntrHandler(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber);
528 return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
531 u32 error = __ReleaseSubIntrHandler(intrNumber, subIntrNumber);
532 if (error != SCE_KERNEL_ERROR_OK) {
533 ERROR_LOG(SCEINTC, "sceKernelReleaseSubIntrHandler(%i, %i): error %08x", intrNumber, subIntrNumber, error);
535 return error;
538 u32 sceKernelEnableSubIntr(u32 intrNumber, u32 subIntrNumber) {
539 if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
540 ERROR_LOG_REPORT(SCEINTC, "sceKernelEnableSubIntr(%i, %i): invalid interrupt", intrNumber, subIntrNumber);
541 return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
543 if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) {
544 ERROR_LOG_REPORT(SCEINTC, "sceKernelEnableSubIntr(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber);
545 return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
548 DEBUG_LOG(SCEINTC, "sceKernelEnableSubIntr(%i, %i)", intrNumber, subIntrNumber);
549 u32 error;
550 if (!intrHandlers[intrNumber]->has(subIntrNumber)) {
551 // Enableing a handler before registering it works fine.
552 __RegisterSubIntrHandler(intrNumber, subIntrNumber, 0, 0, error);
555 intrHandlers[intrNumber]->enable(subIntrNumber);
556 return 0;
559 static u32 sceKernelDisableSubIntr(u32 intrNumber, u32 subIntrNumber) {
560 if (intrNumber >= PSP_NUMBER_INTERRUPTS) {
561 ERROR_LOG_REPORT(SCEINTC, "sceKernelDisableSubIntr(%i, %i): invalid interrupt", intrNumber, subIntrNumber);
562 return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
564 if (subIntrNumber >= PSP_NUMBER_SUBINTERRUPTS) {
565 ERROR_LOG_REPORT(SCEINTC, "sceKernelDisableSubIntr(%i, %i): invalid subinterrupt", intrNumber, subIntrNumber);
566 return SCE_KERNEL_ERROR_ILLEGAL_INTRCODE;
569 DEBUG_LOG(SCEINTC, "sceKernelDisableSubIntr(%i, %i)", intrNumber, subIntrNumber);
571 if (!intrHandlers[intrNumber]->has(subIntrNumber)) {
572 // Disabling when not registered is not an error.
573 return 0;
576 intrHandlers[intrNumber]->disable(subIntrNumber);
577 return 0;
581 struct PspIntrHandlerOptionParam {
582 int size; //+00
583 u32 entry; //+04
584 u32 common; //+08
585 u32 gp; //+0C
586 u16 intr_code; //+10
587 u16 sub_count; //+12
588 u16 intr_level; //+14
589 u16 enabled; //+16
590 u32 calls; //+18
591 u32 field_1C; //+1C
592 u32 total_clock_lo; //+20
593 u32 total_clock_hi; //+24
594 u32 min_clock_lo; //+28
595 u32 min_clock_hi; //+2C
596 u32 max_clock_lo; //+30
597 u32 max_clock_hi; //+34
598 }; //=38
600 static int QueryIntrHandlerInfo()
602 ERROR_LOG_REPORT(SCEINTC, "QueryIntrHandlerInfo()");
603 return 0;
606 static u32 sceKernelMemset(u32 addr, u32 fillc, u32 n)
608 u8 c = fillc & 0xff;
609 DEBUG_LOG(SCEINTC, "sceKernelMemset(ptr = %08x, c = %02x, n = %08x)", addr, c, n);
610 bool skip = false;
611 if (n != 0) {
612 if (Memory::IsVRAMAddress(addr)) {
613 skip = gpu->PerformMemorySet(addr, fillc, n);
615 if (!skip) {
616 Memory::Memset(addr, c, n);
619 return addr;
622 static u32 sceKernelMemcpy(u32 dst, u32 src, u32 size)
624 DEBUG_LOG(SCEKERNEL, "sceKernelMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size);
626 // Some games copy from executable code. We need to flush emuhack ops.
627 currentMIPS->InvalidateICache(src, size);
629 bool skip = false;
630 if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) {
631 skip = gpu->PerformMemoryCopy(dst, src, size);
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))
637 u8 *dstp = Memory::GetPointerUnchecked(dst);
638 u8 *srcp = Memory::GetPointerUnchecked(src);
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
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)
649 memmove(dstp, srcp, 8);
650 dstp += 8;
651 srcp += 8;
653 for (u32 size8 = size % 8; size8 > 0; --size8)
654 *dstp++ = *srcp++;
657 #ifndef MOBILE_DEVICE
658 CBreakPoints::ExecMemCheck(src, false, size, currentMIPS->pc);
659 CBreakPoints::ExecMemCheck(dst, true, size, currentMIPS->pc);
660 #endif
661 return dst;
664 const HLEFunction Kernel_Library[] =
666 {0x092968F4, &WrapI_V<sceKernelCpuSuspendIntr>, "sceKernelCpuSuspendIntr", 'i', "" },
667 {0X5F10D406, &WrapV_U<sceKernelCpuResumeIntr>, "sceKernelCpuResumeIntr", 'v', "x" },
668 {0X3B84732D, &WrapV_U<sceKernelCpuResumeIntrWithSync>, "sceKernelCpuResumeIntrWithSync", 'v', "x" },
669 {0X47A0B729, &WrapI_I<sceKernelIsCpuIntrSuspended>, "sceKernelIsCpuIntrSuspended", 'i', "i" },
670 {0xb55249d2, &WrapI_V<sceKernelIsCpuIntrEnable>, "sceKernelIsCpuIntrEnable", 'i', "", },
671 {0XA089ECA4, &WrapU_UUU<sceKernelMemset>, "sceKernelMemset", 'x', "xxx" },
672 {0XDC692EE3, &WrapI_UI<sceKernelTryLockLwMutex>, "sceKernelTryLockLwMutex", 'i', "xi" },
673 {0X37431849, &WrapI_UI<sceKernelTryLockLwMutex_600>, "sceKernelTryLockLwMutex_600", 'i', "xi" },
674 {0XBEA46419, &WrapI_UIU<sceKernelLockLwMutex>, "sceKernelLockLwMutex", 'i', "xix", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED },
675 {0X1FC64E09, &WrapI_UIU<sceKernelLockLwMutexCB>, "sceKernelLockLwMutexCB", 'i', "xix", HLE_NOT_IN_INTERRUPT | HLE_NOT_DISPATCH_SUSPENDED },
676 {0X15B6446B, &WrapI_UI<sceKernelUnlockLwMutex>, "sceKernelUnlockLwMutex", 'i', "xi" },
677 {0XC1734599, &WrapI_UU<sceKernelReferLwMutexStatus>, "sceKernelReferLwMutexStatus", 'i', "xx" },
678 {0X293B45B8, &WrapI_V<sceKernelGetThreadId>, "sceKernelGetThreadId", 'i', "" },
679 {0XD13BDE95, &WrapI_V<sceKernelCheckThreadStack>, "sceKernelCheckThreadStack", 'i', "" },
680 {0X1839852A, &WrapU_UUU<sceKernelMemcpy>, "sceKernelMemcpy", 'x', "xxx" },
681 {0XFA835CDE, &WrapI_I<sceKernelGetTlsAddr>, "sceKernelGetTlsAddr", 'i', "i" },
684 static u32 sysclib_memcpy(u32 dst, u32 src, u32 size) {
685 ERROR_LOG(SCEKERNEL, "Untested sysclib_memcpy(dest=%08x, src=%08x, size=%i)", dst, src, size);
686 memcpy(Memory::GetPointer(dst), Memory::GetPointer(src), size);
687 return dst;
690 static u32 sysclib_strcat(u32 dst, u32 src) {
691 ERROR_LOG(SCEKERNEL, "Untested sysclib_strcat(dest=%08x, src=%08x)", dst, src);
692 strcat((char *)Memory::GetPointer(dst), (char *)Memory::GetPointer(src));
693 return dst;
696 static int sysclib_strcmp(u32 dst, u32 src) {
697 ERROR_LOG(SCEKERNEL, "Untested sysclib_strcmp(dest=%08x, src=%08x)", dst, src);
698 return strcmp((char *)Memory::GetPointer(dst), (char *)Memory::GetPointer(src));
701 static u32 sysclib_strcpy(u32 dst, u32 src) {
702 ERROR_LOG(SCEKERNEL, "Untested sysclib_strcpy(dest=%08x, src=%08x)", dst, src);
703 strcpy((char *)Memory::GetPointer(dst), (char *)Memory::GetPointer(src));
704 return dst;
707 static u32 sysclib_strlen(u32 src) {
708 ERROR_LOG(SCEKERNEL, "Untested sysclib_strlen(src=%08x)", src);
709 return (u32)strlen(Memory::GetCharPointer(src));
712 static int sysclib_memcmp(u32 dst, u32 src, u32 size) {
713 ERROR_LOG(SCEKERNEL, "Untested sysclib_memcmp(dest=%08x, src=%08x, size=%i)", dst, src, size);
714 return memcmp(Memory::GetCharPointer(dst), Memory::GetCharPointer(src), size);
717 static int sysclib_sprintf(u32 dst, u32 fmt) {
718 ERROR_LOG(SCEKERNEL, "Unimpl sysclib_sprintf(dest=%08x, src=%08x)", dst, fmt);
719 // TODO
720 return sprintf((char *)Memory::GetPointer(dst), "%s", Memory::GetCharPointer(fmt));
723 static u32 sysclib_memset(u32 destAddr, int data, int size) {
724 ERROR_LOG(SCEKERNEL, "Untested sysclib_memset(dest=%08x, data=%d ,size=%d)", destAddr, data, size);
725 if (Memory::IsValidAddress(destAddr))
726 memset(Memory::GetPointer(destAddr), data, size);
727 return 0;
730 const HLEFunction SysclibForKernel[] =
732 {0XAB7592FF, &WrapU_UUU<sysclib_memcpy>, "memcpy", 'x', "xxx" },
733 {0X476FD94A, &WrapU_UU<sysclib_strcat>, "strcat", 'x', "xx" },
734 {0XC0AB8932, &WrapI_UU<sysclib_strcmp>, "strcmp", 'i', "xx" },
735 {0XEC6F1CF2, &WrapU_UU<sysclib_strcpy>, "strcpy", 'x', "xx" },
736 {0X52DF196C, &WrapU_U<sysclib_strlen>, "strlen", 'x', "x" },
737 {0X81D0D1F7, &WrapI_UUU<sysclib_memcmp>, "memcmp", 'i', "xxx" },
738 {0X7661E728, &WrapI_UU<sysclib_sprintf>, "sprintf", 'i', "xx" },
739 {0X10F3BB61, &WrapU_UII<sysclib_memset>, "memset", 'x', "xii" },
742 void Register_Kernel_Library()
744 RegisterModule("Kernel_Library", ARRAY_SIZE(Kernel_Library), Kernel_Library);
747 void Register_SysclibForKernel()
749 RegisterModule("SysclibForKernel", ARRAY_SIZE(SysclibForKernel), SysclibForKernel);
752 const HLEFunction InterruptManager[] =
754 {0XCA04A2B9, &WrapU_UUUU<sceKernelRegisterSubIntrHandler>, "sceKernelRegisterSubIntrHandler", 'x', "xxxx" },
755 {0XD61E6961, &WrapU_UU<sceKernelReleaseSubIntrHandler>, "sceKernelReleaseSubIntrHandler", 'x', "xx" },
756 {0XFB8E22EC, &WrapU_UU<sceKernelEnableSubIntr>, "sceKernelEnableSubIntr", 'x', "xx" },
757 {0X8A389411, &WrapU_UU<sceKernelDisableSubIntr>, "sceKernelDisableSubIntr", 'x', "xx" },
758 {0X5CB5A78B, nullptr, "sceKernelSuspendSubIntr", '?', "" },
759 {0X7860E0DC, nullptr, "sceKernelResumeSubIntr", '?', "" },
760 {0XFC4374B8, nullptr, "sceKernelIsSubInterruptOccurred", '?', "" },
761 {0xD2E8363F, &WrapI_V<QueryIntrHandlerInfo>, "QueryIntrHandlerInfo", 'i', "" }, // No sce prefix for some reason
762 {0XEEE43F47, nullptr, "sceKernelRegisterUserSpaceIntrStack", '?', "" },
766 void Register_InterruptManager()
768 RegisterModule("InterruptManager", ARRAY_SIZE(InterruptManager), InterruptManager);