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