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/.
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;
47 //////////////////////////////////////////////////////////////////////////
48 // INTERRUPT MANAGEMENT
49 //////////////////////////////////////////////////////////////////////////
58 void DoState(PointerWrap
&p
)
60 auto s
= p
.Section("InterruptState", 1);
67 ThreadContext savedCpu
;
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");
86 if (__InterruptsEnabled())
89 __DisableInterrupts();
99 static void sceKernelCpuResumeIntr(u32 enable
)
101 VERBOSE_LOG(SCEINTC
, "sceKernelCpuResumeIntr(%i)", enable
);
104 __EnableInterrupts();
106 hleReSchedule("interrupts resumed");
110 __DisableInterrupts();
115 static int sceKernelIsCpuIntrEnable()
117 u32 retVal
= __InterruptsEnabled();
118 DEBUG_LOG(SCEINTC
, "%i=sceKernelIsCpuIntrEnable()", retVal
);
122 static int sceKernelIsCpuIntrSuspended(int flag
)
124 int retVal
= flag
== 0 ? 1 : 0;
125 DEBUG_LOG(SCEINTC
, "%i=sceKernelIsCpuIntrSuspended(%d)", retVal
, flag
);
129 static void sceKernelCpuResumeIntrWithSync(u32 enable
)
131 sceKernelCpuResumeIntr(enable
);
134 bool IntrHandler::run(PendingInterrupt
& pend
)
136 SubIntrHandler
*handler
= get(pend
.subintr
);
139 WARN_LOG(SCEINTC
, "Ignoring interrupt, already been released.");
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
)
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
)
189 return &subIntrHandlers
[subIntrNum
];
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
));
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);
219 p
.Do
<int, SubIntrHandler
>(subIntrHandlers
);
222 void PendingInterrupt::DoState(PointerWrap
&p
)
224 auto s
= p
.Section("PendingInterrupt", 1);
232 void __InterruptsInit()
234 interruptsEnabled
= 1;
236 for (int i
= 0; i
< (int)ARRAY_SIZE(intrHandlers
); ++i
)
237 intrHandlers
[i
] = new IntrHandler(i
);
239 threadBeforeInterrupt
= 0;
242 void __InterruptsDoState(PointerWrap
&p
)
244 auto s
= p
.Section("sceKernelInterrupt", 1);
248 int numInterrupts
= PSP_NUMBER_INTERRUPTS
;
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.");
258 PendingInterrupt
pi(0, 0);
259 p
.Do(pendingInterrupts
, pi
);
260 p
.Do(interruptsEnabled
);
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
)
281 delete intrHandlers
[i
];
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()
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.
336 // Can easily prioritize between different kinds of interrupts if necessary.
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();
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;
359 if (!handler
->run(pend
)) {
360 pendingInterrupts
.pop_front();
365 currentMIPS
->r
[MIPS_REG_RA
] = __KernelInterruptReturnAddress();
368 if (needsThreadReturn
)
369 __KernelSwitchToThread(threadBeforeInterrupt
, "left interrupt");
370 // DEBUG_LOG(SCEINTC, "No more interrupts!");
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)
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
;
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
);
413 // This is what we just ran.
414 PendingInterrupt pend
= pendingInterrupts
.front();
415 pendingInterrupts
.pop_front();
417 intrHandlers
[pend
.intr
]->handleResult(pend
);
420 // Restore context after running the interrupt.
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");
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
;
447 IntrHandler
*intr
= intrHandlers
[intrNumber
];
448 if (intr
->has(subIntrNumber
)) {
449 if (intr
->get(subIntrNumber
)->handlerAddress
!= 0) {
450 error
= SCE_KERNEL_ERROR_FOUND_HANDLER
;
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
++);
490 // This also implicitly disables it, which is correct.
491 intrHandlers
[intrNumber
]->remove(subIntrNumber
);
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
;
506 SubIntrHandler
*subIntrHandler
= __RegisterSubIntrHandler(intrNumber
, subIntrNumber
, handler
, handlerArg
, error
);
507 if (subIntrHandler
) {
509 WARN_LOG_REPORT(SCEINTC
, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): ignored NULL handler", intrNumber
, subIntrNumber
, handler
, handlerArg
);
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
);
516 ERROR_LOG_REPORT(SCEINTC
, "sceKernelRegisterSubIntrHandler(%i, %i, %08x, %08x): error %08x", intrNumber
, subIntrNumber
, handler
, handlerArg
, 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
);
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
);
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
);
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.
576 intrHandlers
[intrNumber
]->disable(subIntrNumber
);
581 struct PspIntrHandlerOptionParam
{
588 u16 intr_level
; //+14
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
600 static int QueryIntrHandlerInfo()
602 ERROR_LOG_REPORT(SCEINTC
, "QueryIntrHandlerInfo()");
606 static u32
sceKernelMemset(u32 addr
, u32 fillc
, u32 n
)
609 DEBUG_LOG(SCEINTC
, "sceKernelMemset(ptr = %08x, c = %02x, n = %08x)", addr
, c
, n
);
612 if (Memory::IsVRAMAddress(addr
)) {
613 skip
= gpu
->PerformMemorySet(addr
, fillc
, n
);
616 Memory::Memset(addr
, c
, n
);
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
);
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
);
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);
653 for (u32 size8
= size
% 8; size8
> 0; --size8
)
657 #ifndef MOBILE_DEVICE
658 CBreakPoints::ExecMemCheck(src
, false, size
, currentMIPS
->pc
);
659 CBreakPoints::ExecMemCheck(dst
, true, size
, currentMIPS
->pc
);
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
);
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
));
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
));
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
);
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
);
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
);