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