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 "Common/Serialize/Serializer.h"
21 #include "Common/Serialize/SerializeFuncs.h"
22 #include "Common/Serialize/SerializeList.h"
23 #include "Core/CoreTiming.h"
24 #include "Core/MemMapHelpers.h"
25 #include "Core/Reporting.h"
26 #include "Core/HLE/sceKernel.h"
27 #include "Core/HLE/sceKernelInterrupt.h"
28 #include "Core/HLE/sceKernelMemory.h"
29 #include "Core/HLE/sceKernelVTimer.h"
30 #include "Core/HLE/HLE.h"
31
32 static int vtimerTimer = -1;
33 static SceUID runningVTimer = 0;
34 static std::list<SceUID> vtimers;
35
36 struct NativeVTimer {
37 SceSize_le size;
38 char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
39 s32_le active;
40 u64_le base;
41 u64_le current;
42 u64_le schedule;
43 u32_le handlerAddr;
44 u32_le commonAddr;
45 };
46
47 struct VTimer : public KernelObject {
GetNameVTimer48 const char *GetName() override { return nvt.name; }
GetTypeNameVTimer49 const char *GetTypeName() override { return GetStaticTypeName(); }
GetStaticTypeNameVTimer50 static const char *GetStaticTypeName() { return "VTimer"; }
GetMissingErrorCodeVTimer51 static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_VTID; }
GetStaticIDTypeVTimer52 static int GetStaticIDType() { return SCE_KERNEL_TMID_VTimer; }
GetIDTypeVTimer53 int GetIDType() const override { return SCE_KERNEL_TMID_VTimer; }
54
DoStateVTimer55 void DoState(PointerWrap &p) override {
56 auto s = p.Section("VTimer", 1, 2);
57 if (!s)
58 return;
59
60 Do(p, nvt);
61 if (s < 2) {
62 u32 memoryPtr;
63 Do(p, memoryPtr);
64 }
65 }
66
67 NativeVTimer nvt;
68 };
69
__KernelVTimerObject()70 KernelObject *__KernelVTimerObject() {
71 return new VTimer;
72 }
73
__getVTimerRunningTime(VTimer * vt)74 static u64 __getVTimerRunningTime(VTimer *vt) {
75 if (vt->nvt.active == 0)
76 return 0;
77
78 return CoreTiming::GetGlobalTimeUs() - vt->nvt.base;
79 }
80
__getVTimerCurrentTime(VTimer * vt)81 static u64 __getVTimerCurrentTime(VTimer* vt) {
82 return vt->nvt.current + __getVTimerRunningTime(vt);
83 }
84
__KernelCancelVTimer(SceUID id)85 static int __KernelCancelVTimer(SceUID id) {
86 u32 error;
87 VTimer *vt = kernelObjects.Get<VTimer>(id, error);
88
89 if (!vt)
90 return error;
91
92 CoreTiming::UnscheduleEvent(vtimerTimer, id);
93 vt->nvt.handlerAddr = 0;
94 return 0;
95 }
96
__KernelScheduleVTimer(VTimer * vt,u64 schedule)97 static void __KernelScheduleVTimer(VTimer *vt, u64 schedule) {
98 CoreTiming::UnscheduleEvent(vtimerTimer, vt->GetUID());
99
100 vt->nvt.schedule = schedule;
101
102 if (vt->nvt.active == 1 && vt->nvt.handlerAddr != 0) {
103 // The "real" base is base + current. But when setting the time, base is important.
104 // The schedule is relative to those.
105 u64 cyclesIntoFuture;
106 if (schedule < 250) {
107 schedule = 250;
108 }
109 s64 goalUs = (u64)vt->nvt.base + schedule - (u64)vt->nvt.current;
110 s64 minGoalUs = CoreTiming::GetGlobalTimeUs() + 250;
111 if (goalUs < minGoalUs) {
112 cyclesIntoFuture = usToCycles(250);
113 } else {
114 cyclesIntoFuture = usToCycles(goalUs - CoreTiming::GetGlobalTimeUs());
115 }
116
117 CoreTiming::ScheduleEvent(cyclesIntoFuture, vtimerTimer, vt->GetUID());
118 }
119 }
120
__rescheduleVTimer(SceUID id,u32 delay)121 static void __rescheduleVTimer(SceUID id, u32 delay) {
122 u32 error;
123 VTimer *vt = kernelObjects.Get<VTimer>(id, error);
124
125 if (error)
126 return;
127
128 __KernelScheduleVTimer(vt, vt->nvt.schedule + delay);
129 }
130
131 class VTimerIntrHandler : public IntrHandler
132 {
133 static const int HANDLER_STACK_SPACE = 48;
134
135 public:
VTimerIntrHandler()136 VTimerIntrHandler() : IntrHandler(PSP_SYSTIMER1_INTR) {}
137
run(PendingInterrupt & pend)138 bool run(PendingInterrupt &pend) override {
139 u32 error;
140 SceUID vtimerID = vtimers.front();
141
142 VTimer *vtimer = kernelObjects.Get<VTimer>(vtimerID, error);
143
144 if (error)
145 return false;
146
147 // Reserve some stack space for arguments.
148 u32 argArea = currentMIPS->r[MIPS_REG_SP];
149 currentMIPS->r[MIPS_REG_SP] -= HANDLER_STACK_SPACE;
150
151 Memory::Write_U64(vtimer->nvt.schedule, argArea - 16);
152 Memory::Write_U64(__getVTimerCurrentTime(vtimer), argArea - 8);
153
154 currentMIPS->pc = vtimer->nvt.handlerAddr;
155 currentMIPS->r[MIPS_REG_A0] = vtimer->GetUID();
156 currentMIPS->r[MIPS_REG_A1] = argArea - 16;
157 currentMIPS->r[MIPS_REG_A2] = argArea - 8;
158 currentMIPS->r[MIPS_REG_A3] = vtimer->nvt.commonAddr;
159
160 runningVTimer = vtimerID;
161
162 return true;
163 }
164
handleResult(PendingInterrupt & pend)165 void handleResult(PendingInterrupt &pend) override {
166 u32 result = currentMIPS->r[MIPS_REG_V0];
167
168 currentMIPS->r[MIPS_REG_SP] += HANDLER_STACK_SPACE;
169
170 int vtimerID = vtimers.front();
171 vtimers.pop_front();
172
173 runningVTimer = 0;
174
175 if (result == 0)
176 __KernelCancelVTimer(vtimerID);
177 else
178 __rescheduleVTimer(vtimerID, result);
179 }
180 };
181
__KernelTriggerVTimer(u64 userdata,int cyclesLate)182 static void __KernelTriggerVTimer(u64 userdata, int cyclesLate) {
183 SceUID uid = (SceUID) userdata;
184
185 u32 error;
186 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
187 if (vt) {
188 vtimers.push_back(uid);
189 __TriggerInterrupt(PSP_INTR_IMMEDIATE, PSP_SYSTIMER1_INTR);
190 }
191 }
192
__KernelVTimerDoState(PointerWrap & p)193 void __KernelVTimerDoState(PointerWrap &p) {
194 auto s = p.Section("sceKernelVTimer", 1, 2);
195 if (!s)
196 return;
197
198 Do(p, vtimerTimer);
199 Do(p, vtimers);
200 CoreTiming::RestoreRegisterEvent(vtimerTimer, "VTimer", __KernelTriggerVTimer);
201
202 if (s >= 2)
203 Do(p, runningVTimer);
204 else
205 runningVTimer = 0;
206 }
207
__KernelVTimerInit()208 void __KernelVTimerInit() {
209 vtimers.clear();
210 __RegisterIntrHandler(PSP_SYSTIMER1_INTR, new VTimerIntrHandler());
211 vtimerTimer = CoreTiming::RegisterEvent("VTimer", __KernelTriggerVTimer);
212
213 // Intentionally starts at 0. This explains the behavior where 0 is treated differently outside a timer.
214 runningVTimer = 0;
215 }
216
sceKernelCreateVTimer(const char * name,u32 optParamAddr)217 u32 sceKernelCreateVTimer(const char *name, u32 optParamAddr) {
218 if (!name) {
219 WARN_LOG_REPORT(SCEKERNEL, "%08x=sceKernelCreateVTimer(): invalid name", SCE_KERNEL_ERROR_ERROR);
220 return SCE_KERNEL_ERROR_ERROR;
221 }
222 DEBUG_LOG(SCEKERNEL, "sceKernelCreateVTimer(%s, %08x)", name, optParamAddr);
223
224 VTimer *vtimer = new VTimer;
225 SceUID id = kernelObjects.Create(vtimer);
226
227 memset(&vtimer->nvt, 0, sizeof(NativeVTimer));
228 vtimer->nvt.size = sizeof(NativeVTimer);
229 strncpy(vtimer->nvt.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
230 vtimer->nvt.name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
231
232 if (optParamAddr != 0) {
233 u32 size = Memory::Read_U32(optParamAddr);
234 if (size > 4)
235 WARN_LOG_REPORT(SCEKERNEL, "sceKernelCreateVTimer(%s) unsupported options parameter, size = %d", name, size);
236 }
237
238 return id;
239 }
240
sceKernelDeleteVTimer(SceUID uid)241 u32 sceKernelDeleteVTimer(SceUID uid) {
242 DEBUG_LOG(SCEKERNEL, "sceKernelDeleteVTimer(%08x)", uid);
243
244 u32 error;
245 VTimer* vt = kernelObjects.Get<VTimer>(uid, error);
246
247 if (error) {
248 WARN_LOG(SCEKERNEL, "%08x=sceKernelDeleteVTimer(%08x)", error, uid);
249 return error;
250 }
251
252 for (std::list<SceUID>::iterator it = vtimers.begin(); it != vtimers.end(); ++it) {
253 if (*it == vt->GetUID()) {
254 vtimers.erase(it);
255 break;
256 }
257 }
258
259 return kernelObjects.Destroy<VTimer>(uid);
260 }
261
sceKernelGetVTimerBase(SceUID uid,u32 baseClockAddr)262 u32 sceKernelGetVTimerBase(SceUID uid, u32 baseClockAddr) {
263 DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerBase(%08x, %08x)", uid, baseClockAddr);
264
265 u32 error;
266 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
267
268 if (error) {
269 WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerBase(%08x, %08x)", error, uid, baseClockAddr);
270 return error;
271 }
272
273 if (Memory::IsValidAddress(baseClockAddr))
274 Memory::Write_U64(vt->nvt.base, baseClockAddr);
275
276 return 0;
277 }
278
sceKernelGetVTimerBaseWide(SceUID uid)279 u64 sceKernelGetVTimerBaseWide(SceUID uid) {
280 DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerBaseWide(%08x)", uid);
281
282 u32 error;
283 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
284
285 if (error) {
286 WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerBaseWide(%08x)", error, uid);
287 return -1;
288 }
289
290 return vt->nvt.base;
291 }
292
sceKernelGetVTimerTime(SceUID uid,u32 timeClockAddr)293 u32 sceKernelGetVTimerTime(SceUID uid, u32 timeClockAddr) {
294 DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerTime(%08x, %08x)", uid, timeClockAddr);
295
296 u32 error;
297 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
298
299 if (error) {
300 WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerTime(%08x, %08x)", error, uid, timeClockAddr);
301 return error;
302 }
303
304 u64 time = __getVTimerCurrentTime(vt);
305 if (Memory::IsValidAddress(timeClockAddr))
306 Memory::Write_U64(time, timeClockAddr);
307
308 return 0;
309 }
310
sceKernelGetVTimerTimeWide(SceUID uid)311 u64 sceKernelGetVTimerTimeWide(SceUID uid) {
312 DEBUG_LOG(SCEKERNEL, "sceKernelGetVTimerTimeWide(%08x)", uid);
313
314 u32 error;
315 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
316
317 if (error) {
318 WARN_LOG(SCEKERNEL, "%08x=sceKernelGetVTimerTimeWide(%08x)", error, uid);
319 return -1;
320 }
321
322 u64 time = __getVTimerCurrentTime(vt);
323 return time;
324 }
325
__KernelSetVTimer(VTimer * vt,u64 time)326 static u64 __KernelSetVTimer(VTimer *vt, u64 time) {
327 u64 current = __getVTimerCurrentTime(vt);
328 vt->nvt.current = time - __getVTimerRunningTime(vt);
329
330 // Run if we're now passed the schedule.
331 __KernelScheduleVTimer(vt, vt->nvt.schedule);
332
333 return current;
334 }
335
sceKernelSetVTimerTime(SceUID uid,u32 timeClockAddr)336 u32 sceKernelSetVTimerTime(SceUID uid, u32 timeClockAddr) {
337 DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerTime(%08x, %08x)", uid, timeClockAddr);
338
339 u32 error;
340 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
341
342 if (error) {
343 WARN_LOG(SCEKERNEL, "%08x=sceKernelSetVTimerTime(%08x, %08x)", error, uid, timeClockAddr);
344 return error;
345 }
346
347 u64 time = Memory::Read_U64(timeClockAddr);
348 if (Memory::IsValidAddress(timeClockAddr))
349 Memory::Write_U64(__KernelSetVTimer(vt, time), timeClockAddr);
350
351 return 0;
352 }
353
sceKernelSetVTimerTimeWide(SceUID uid,u64 timeClock)354 u64 sceKernelSetVTimerTimeWide(SceUID uid, u64 timeClock) {
355 if (__IsInInterrupt()) {
356 WARN_LOG(SCEKERNEL, "sceKernelSetVTimerTimeWide(%08x, %llu): in interrupt", uid, timeClock);
357 return -1;
358 }
359 DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerTimeWide(%08x, %llu)", uid, timeClock);
360
361 u32 error;
362 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
363
364 if (error || vt == NULL) {
365 WARN_LOG(SCEKERNEL, "%08x=sceKernelSetVTimerTimeWide(%08x, %llu)", error, uid, timeClock);
366 return -1;
367 }
368
369 return __KernelSetVTimer(vt, timeClock);
370 }
371
__startVTimer(VTimer * vt)372 static void __startVTimer(VTimer *vt) {
373 vt->nvt.active = 1;
374 vt->nvt.base = CoreTiming::GetGlobalTimeUs();
375
376 if (vt->nvt.handlerAddr != 0)
377 __KernelScheduleVTimer(vt, vt->nvt.schedule);
378 }
379
sceKernelStartVTimer(SceUID uid)380 u32 sceKernelStartVTimer(SceUID uid) {
381 hleEatCycles(12200);
382
383 if (uid == runningVTimer) {
384 WARN_LOG(SCEKERNEL, "sceKernelStartVTimer(%08x): invalid vtimer", uid);
385 return SCE_KERNEL_ERROR_ILLEGAL_VTID;
386 }
387
388 DEBUG_LOG(SCEKERNEL, "sceKernelStartVTimer(%08x)", uid);
389
390 u32 error;
391 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
392
393 if (vt) {
394 if (vt->nvt.active != 0)
395 return 1;
396
397 __startVTimer(vt);
398 return 0;
399 }
400
401 return error;
402 }
403
__stopVTimer(VTimer * vt)404 static void __stopVTimer(VTimer *vt) {
405 // This increases (__getVTimerCurrentTime includes nvt.current.)
406 vt->nvt.current = __getVTimerCurrentTime(vt);
407 vt->nvt.active = 0;
408 vt->nvt.base = 0;
409 }
410
sceKernelStopVTimer(SceUID uid)411 u32 sceKernelStopVTimer(SceUID uid) {
412 if (uid == runningVTimer) {
413 WARN_LOG(SCEKERNEL, "sceKernelStopVTimer(%08x): invalid vtimer", uid);
414 return SCE_KERNEL_ERROR_ILLEGAL_VTID;
415 }
416 DEBUG_LOG(SCEKERNEL, "sceKernelStopVTimer(%08x)", uid);
417
418 u32 error;
419 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
420
421 if (vt) {
422 if (vt->nvt.active == 0)
423 return 0;
424
425 __stopVTimer(vt);
426 return 1;
427 }
428
429 return error;
430 }
431
sceKernelSetVTimerHandler(SceUID uid,u32 scheduleAddr,u32 handlerFuncAddr,u32 commonAddr)432 u32 sceKernelSetVTimerHandler(SceUID uid, u32 scheduleAddr, u32 handlerFuncAddr, u32 commonAddr) {
433 hleEatCycles(900);
434 if (uid == runningVTimer) {
435 WARN_LOG(SCEKERNEL, "sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x): invalid vtimer", uid, scheduleAddr, handlerFuncAddr, commonAddr);
436 return SCE_KERNEL_ERROR_ILLEGAL_VTID;
437 }
438
439 u32 error;
440 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
441
442 if (error) {
443 WARN_LOG(SCEKERNEL, "%08x=sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x)", error, uid, scheduleAddr, handlerFuncAddr, commonAddr);
444 return error;
445 }
446
447 DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerHandler(%08x, %08x, %08x, %08x)", uid, scheduleAddr, handlerFuncAddr, commonAddr);
448 hleEatCycles(2000);
449
450 u64 schedule = Memory::Read_U64(scheduleAddr);
451 vt->nvt.handlerAddr = handlerFuncAddr;
452 if (handlerFuncAddr) {
453 vt->nvt.commonAddr = commonAddr;
454 __KernelScheduleVTimer(vt, schedule);
455 } else {
456 __KernelScheduleVTimer(vt, vt->nvt.schedule);
457 }
458
459 return 0;
460 }
461
sceKernelSetVTimerHandlerWide(SceUID uid,u64 schedule,u32 handlerFuncAddr,u32 commonAddr)462 u32 sceKernelSetVTimerHandlerWide(SceUID uid, u64 schedule, u32 handlerFuncAddr, u32 commonAddr) {
463 hleEatCycles(900);
464 if (uid == runningVTimer) {
465 WARN_LOG(SCEKERNEL, "sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x): invalid vtimer", uid, schedule, handlerFuncAddr, commonAddr);
466 return SCE_KERNEL_ERROR_ILLEGAL_VTID;
467 }
468
469 u32 error;
470 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
471
472 if (error) {
473 WARN_LOG(SCEKERNEL, "%08x=sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x)", error, uid, schedule, handlerFuncAddr, commonAddr);
474 return error;
475 }
476
477 DEBUG_LOG(SCEKERNEL, "sceKernelSetVTimerHandlerWide(%08x, %llu, %08x, %08x)", uid, schedule, handlerFuncAddr, commonAddr);
478
479 vt->nvt.handlerAddr = handlerFuncAddr;
480 if (handlerFuncAddr) {
481 vt->nvt.commonAddr = commonAddr;
482 __KernelScheduleVTimer(vt, schedule);
483 } else {
484 __KernelScheduleVTimer(vt, vt->nvt.schedule);
485 }
486
487 return 0;
488 }
489
sceKernelCancelVTimerHandler(SceUID uid)490 u32 sceKernelCancelVTimerHandler(SceUID uid) {
491 if (uid == runningVTimer) {
492 WARN_LOG(SCEKERNEL, "sceKernelCancelVTimerHandler(%08x): invalid vtimer", uid);
493 return SCE_KERNEL_ERROR_ILLEGAL_VTID;
494 }
495
496 DEBUG_LOG(SCEKERNEL, "sceKernelCancelVTimerHandler(%08x)", uid);
497
498 //__cancelVTimer checks if uid is valid
499 return __KernelCancelVTimer(uid);
500 }
501
sceKernelReferVTimerStatus(SceUID uid,u32 statusAddr)502 u32 sceKernelReferVTimerStatus(SceUID uid, u32 statusAddr) {
503 DEBUG_LOG(SCEKERNEL, "sceKernelReferVTimerStatus(%08x, %08x)", uid, statusAddr);
504
505 u32 error;
506 VTimer *vt = kernelObjects.Get<VTimer>(uid, error);
507
508 if (error) {
509 WARN_LOG(SCEKERNEL, "%08x=sceKernelReferVTimerStatus(%08x, %08x)", error, uid, statusAddr);
510 return error;
511 }
512
513 if (Memory::IsValidAddress(statusAddr)) {
514 NativeVTimer status = vt->nvt;
515 u32 size = Memory::Read_U32(statusAddr);
516 status.current = __getVTimerCurrentTime(vt);
517 Memory::Memcpy(statusAddr, &status, std::min(size, (u32)sizeof(status)), "VTimerStatus");
518 }
519
520 return 0;
521 }
522
523 // Not sure why this is exposed...
_sceKernelReturnFromTimerHandler()524 void _sceKernelReturnFromTimerHandler() {
525 ERROR_LOG_REPORT(SCEKERNEL,"_sceKernelReturnFromTimerHandler - should not be called!");
526 }
527