2012-11-01 16:19:01 +01:00
|
|
|
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
2012-11-04 23:01:49 +01:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 16:19:01 +01:00
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
2020-08-10 06:38:45 +00:00
|
|
|
#include <list>
|
2020-08-10 00:12:51 -07:00
|
|
|
#include "Common/Serialize/Serializer.h"
|
|
|
|
#include "Common/Serialize/SerializeFuncs.h"
|
|
|
|
#include "Common/Serialize/SerializeList.h"
|
2014-03-15 11:22:19 -07:00
|
|
|
#include "Core/HLE/sceKernel.h"
|
|
|
|
#include "Core/HLE/sceKernelAlarm.h"
|
|
|
|
#include "Core/HLE/sceKernelInterrupt.h"
|
|
|
|
#include "Core/HLE/HLE.h"
|
2013-02-03 22:10:06 -08:00
|
|
|
#include "Core/CoreTiming.h"
|
2014-03-15 11:22:19 -07:00
|
|
|
#include "Core/MemMap.h"
|
2012-11-01 16:19:01 +01:00
|
|
|
|
2012-12-21 11:58:32 -08:00
|
|
|
const int NATIVEALARM_SIZE = 20;
|
|
|
|
|
2013-02-04 00:41:16 +01:00
|
|
|
std::list<SceUID> triggeredAlarm;
|
|
|
|
|
2012-12-18 23:47:57 -08:00
|
|
|
struct NativeAlarm
|
2012-11-01 16:19:01 +01:00
|
|
|
{
|
2013-07-24 23:58:45 -07:00
|
|
|
SceSize_le size;
|
2014-01-28 00:37:59 -08:00
|
|
|
u32_le pad;
|
2013-07-24 23:58:45 -07:00
|
|
|
u64_le schedule;
|
|
|
|
u32_le handlerPtr;
|
|
|
|
u32_le commonPtr;
|
2012-12-18 23:47:57 -08:00
|
|
|
};
|
|
|
|
|
2020-03-15 08:33:40 -07:00
|
|
|
struct PSPAlarm : public KernelObject {
|
2015-10-17 02:55:10 -04:00
|
|
|
const char *GetName() override {return "[Alarm]";}
|
2020-07-20 11:01:52 +02:00
|
|
|
const char *GetTypeName() override { return GetStaticTypeName(); }
|
|
|
|
static const char *GetStaticTypeName() { return "Alarm"; }
|
2012-12-18 23:47:57 -08:00
|
|
|
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_ALMID; }
|
2013-06-18 23:54:29 -07:00
|
|
|
static int GetStaticIDType() { return SCE_KERNEL_TMID_Alarm; }
|
2015-10-17 02:55:10 -04:00
|
|
|
int GetIDType() const override { return SCE_KERNEL_TMID_Alarm; }
|
2012-12-26 20:34:10 -08:00
|
|
|
|
2020-03-15 08:33:40 -07:00
|
|
|
void DoState(PointerWrap &p) override {
|
2013-09-14 20:23:03 -07:00
|
|
|
auto s = p.Section("Alarm", 1);
|
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
|
2020-08-09 21:20:42 -07:00
|
|
|
Do(p, alm);
|
2012-12-26 20:34:10 -08:00
|
|
|
}
|
|
|
|
|
2012-12-18 23:47:57 -08:00
|
|
|
NativeAlarm alm;
|
|
|
|
};
|
|
|
|
|
2020-03-15 08:33:40 -07:00
|
|
|
void __KernelScheduleAlarm(PSPAlarm *alarm, u64 micro);
|
2012-12-19 08:17:09 -08:00
|
|
|
|
2013-02-04 00:41:16 +01:00
|
|
|
class AlarmIntrHandler : public IntrHandler
|
2012-12-19 08:17:09 -08:00
|
|
|
{
|
|
|
|
public:
|
2013-02-04 00:41:16 +01:00
|
|
|
AlarmIntrHandler() : IntrHandler(PSP_SYSTIMER0_INTR) {}
|
2012-12-27 15:56:46 -08:00
|
|
|
|
2014-12-08 15:14:35 -05:00
|
|
|
bool run(PendingInterrupt& pend) override
|
2012-12-19 08:17:09 -08:00
|
|
|
{
|
2012-12-26 20:34:10 -08:00
|
|
|
u32 error;
|
2013-02-04 00:41:16 +01:00
|
|
|
int alarmID = triggeredAlarm.front();
|
|
|
|
|
2020-03-15 08:33:40 -07:00
|
|
|
PSPAlarm *alarm = kernelObjects.Get<PSPAlarm>(alarmID, error);
|
2013-03-31 16:56:02 -07:00
|
|
|
if (error)
|
|
|
|
{
|
2013-09-07 22:02:55 +02:00
|
|
|
WARN_LOG(SCEKERNEL, "Ignoring deleted alarm %08x", alarmID);
|
2013-02-04 00:41:16 +01:00
|
|
|
return false;
|
2013-03-31 16:56:02 -07:00
|
|
|
}
|
2013-02-04 00:41:16 +01:00
|
|
|
|
|
|
|
currentMIPS->pc = alarm->alm.handlerPtr;
|
|
|
|
currentMIPS->r[MIPS_REG_A0] = alarm->alm.commonPtr;
|
2013-09-07 22:02:55 +02:00
|
|
|
DEBUG_LOG(SCEKERNEL, "Entering alarm %08x handler: %08x", alarmID, currentMIPS->pc);
|
2013-02-04 00:41:16 +01:00
|
|
|
|
|
|
|
return true;
|
2012-12-19 08:17:09 -08:00
|
|
|
}
|
|
|
|
|
2014-12-08 15:14:35 -05:00
|
|
|
void handleResult(PendingInterrupt& pend) override
|
2012-12-19 08:17:09 -08:00
|
|
|
{
|
2013-02-04 00:41:16 +01:00
|
|
|
int result = currentMIPS->r[MIPS_REG_V0];
|
|
|
|
|
|
|
|
int alarmID = triggeredAlarm.front();
|
|
|
|
triggeredAlarm.pop_front();
|
|
|
|
|
2012-12-19 08:17:09 -08:00
|
|
|
// A non-zero result means to reschedule.
|
|
|
|
if (result > 0)
|
2012-12-26 20:34:10 -08:00
|
|
|
{
|
2013-09-07 22:02:55 +02:00
|
|
|
DEBUG_LOG(SCEKERNEL, "Rescheduling alarm %08x for +%dms", alarmID, result);
|
2012-12-26 20:34:10 -08:00
|
|
|
u32 error;
|
2020-03-15 08:33:40 -07:00
|
|
|
PSPAlarm *alarm = kernelObjects.Get<PSPAlarm>(alarmID, error);
|
2014-09-01 16:56:26 -07:00
|
|
|
__KernelScheduleAlarm(alarm, result);
|
2012-12-26 20:34:10 -08:00
|
|
|
}
|
2012-12-21 12:28:28 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (result < 0)
|
2013-09-07 22:02:55 +02:00
|
|
|
WARN_LOG(SCEKERNEL, "Alarm requested reschedule for negative value %u, ignoring", (unsigned) result);
|
2012-12-21 12:28:28 -08:00
|
|
|
|
2013-09-07 22:02:55 +02:00
|
|
|
DEBUG_LOG(SCEKERNEL, "Finished alarm %08x", alarmID);
|
2013-03-31 16:56:02 -07:00
|
|
|
|
2012-12-21 12:28:28 -08:00
|
|
|
// Delete the alarm if it's not rescheduled.
|
2020-03-15 08:33:40 -07:00
|
|
|
kernelObjects.Destroy<PSPAlarm>(alarmID);
|
2012-12-21 12:28:28 -08:00
|
|
|
}
|
2012-12-19 08:17:09 -08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-01-17 22:04:52 -08:00
|
|
|
static int alarmTimer = -1;
|
2012-12-18 23:47:57 -08:00
|
|
|
|
2020-03-15 08:33:40 -07:00
|
|
|
static void __KernelTriggerAlarm(u64 userdata, int cyclesLate) {
|
2012-12-18 23:47:57 -08:00
|
|
|
int uid = (int) userdata;
|
|
|
|
|
|
|
|
u32 error;
|
2020-03-15 08:33:40 -07:00
|
|
|
PSPAlarm *alarm = kernelObjects.Get<PSPAlarm>(uid, error);
|
|
|
|
if (alarm) {
|
2013-02-04 00:41:16 +01:00
|
|
|
triggeredAlarm.push_back(uid);
|
|
|
|
__TriggerInterrupt(PSP_INTR_IMMEDIATE, PSP_SYSTIMER0_INTR);
|
|
|
|
}
|
2012-12-19 08:17:09 -08:00
|
|
|
}
|
|
|
|
|
2012-12-23 21:27:26 -08:00
|
|
|
void __KernelAlarmInit()
|
|
|
|
{
|
2013-02-04 00:41:16 +01:00
|
|
|
triggeredAlarm.clear();
|
|
|
|
__RegisterIntrHandler(PSP_SYSTIMER0_INTR, new AlarmIntrHandler());
|
2012-12-23 21:27:26 -08:00
|
|
|
alarmTimer = CoreTiming::RegisterEvent("Alarm", __KernelTriggerAlarm);
|
|
|
|
}
|
|
|
|
|
2012-12-27 14:21:39 -08:00
|
|
|
void __KernelAlarmDoState(PointerWrap &p)
|
|
|
|
{
|
2013-09-14 20:23:03 -07:00
|
|
|
auto s = p.Section("sceKernelAlarm", 1);
|
|
|
|
if (!s)
|
|
|
|
return;
|
|
|
|
|
2020-08-09 21:20:42 -07:00
|
|
|
Do(p, alarmTimer);
|
|
|
|
Do(p, triggeredAlarm);
|
2012-12-27 14:21:39 -08:00
|
|
|
CoreTiming::RestoreRegisterEvent(alarmTimer, "Alarm", __KernelTriggerAlarm);
|
|
|
|
}
|
|
|
|
|
2020-03-15 08:33:40 -07:00
|
|
|
KernelObject *__KernelAlarmObject() {
|
2012-12-26 22:45:19 -08:00
|
|
|
// Default object to load from state.
|
2020-03-15 08:33:40 -07:00
|
|
|
return new PSPAlarm;
|
2012-12-26 22:45:19 -08:00
|
|
|
}
|
|
|
|
|
2020-03-15 08:33:40 -07:00
|
|
|
void __KernelScheduleAlarm(PSPAlarm *alarm, u64 micro) {
|
2014-09-01 16:56:26 -07:00
|
|
|
alarm->alm.schedule = CoreTiming::GetGlobalTimeUs() + micro;
|
|
|
|
CoreTiming::ScheduleEvent(usToCycles(micro), alarmTimer, alarm->GetUID());
|
2012-12-18 23:47:57 -08:00
|
|
|
}
|
|
|
|
|
2014-12-08 04:40:08 -05:00
|
|
|
static SceUID __KernelSetAlarm(u64 micro, u32 handlerPtr, u32 commonPtr)
|
2012-12-18 23:47:57 -08:00
|
|
|
{
|
2012-12-21 12:04:02 -08:00
|
|
|
if (!Memory::IsValidAddress(handlerPtr))
|
|
|
|
return SCE_KERNEL_ERROR_ILLEGAL_ADDR;
|
|
|
|
|
2020-03-15 08:33:40 -07:00
|
|
|
PSPAlarm *alarm = new PSPAlarm();
|
2012-12-18 23:47:57 -08:00
|
|
|
SceUID uid = kernelObjects.Create(alarm);
|
|
|
|
|
2012-12-21 11:58:32 -08:00
|
|
|
alarm->alm.size = NATIVEALARM_SIZE;
|
2012-12-18 23:47:57 -08:00
|
|
|
alarm->alm.handlerPtr = handlerPtr;
|
|
|
|
alarm->alm.commonPtr = commonPtr;
|
|
|
|
|
2014-09-01 16:56:26 -07:00
|
|
|
__KernelScheduleAlarm(alarm, micro);
|
2012-12-18 23:47:57 -08:00
|
|
|
return uid;
|
2012-11-01 16:19:01 +01:00
|
|
|
}
|
|
|
|
|
2012-12-18 23:47:57 -08:00
|
|
|
SceUID sceKernelSetAlarm(SceUInt micro, u32 handlerPtr, u32 commonPtr)
|
2012-11-01 16:19:01 +01:00
|
|
|
{
|
2013-09-07 22:02:55 +02:00
|
|
|
DEBUG_LOG(SCEKERNEL, "sceKernelSetAlarm(%d, %08x, %08x)", micro, handlerPtr, commonPtr);
|
2014-09-01 16:56:26 -07:00
|
|
|
return __KernelSetAlarm((u64) micro, handlerPtr, commonPtr);
|
2012-11-01 16:19:01 +01:00
|
|
|
}
|
|
|
|
|
2012-12-21 11:58:32 -08:00
|
|
|
SceUID sceKernelSetSysClockAlarm(u32 microPtr, u32 handlerPtr, u32 commonPtr)
|
2012-11-01 16:19:01 +01:00
|
|
|
{
|
2012-12-21 11:58:32 -08:00
|
|
|
u64 micro;
|
2012-12-18 23:47:57 -08:00
|
|
|
|
2012-12-21 11:58:32 -08:00
|
|
|
if (Memory::IsValidAddress(microPtr))
|
|
|
|
micro = Memory::Read_U64(microPtr);
|
2012-12-18 23:47:57 -08:00
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
|
2013-09-07 22:02:55 +02:00
|
|
|
DEBUG_LOG(SCEKERNEL, "sceKernelSetSysClockAlarm(%lld, %08x, %08x)", micro, handlerPtr, commonPtr);
|
2014-09-01 16:56:26 -07:00
|
|
|
return __KernelSetAlarm(micro, handlerPtr, commonPtr);
|
2012-12-18 23:47:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int sceKernelCancelAlarm(SceUID uid)
|
|
|
|
{
|
2013-09-07 22:02:55 +02:00
|
|
|
DEBUG_LOG(SCEKERNEL, "sceKernelCancelAlarm(%08x)", uid);
|
2012-12-18 23:47:57 -08:00
|
|
|
|
|
|
|
CoreTiming::UnscheduleEvent(alarmTimer, uid);
|
|
|
|
|
2020-03-15 08:33:40 -07:00
|
|
|
return kernelObjects.Destroy<PSPAlarm>(uid);
|
2012-11-01 16:19:01 +01:00
|
|
|
}
|
|
|
|
|
2012-12-18 23:47:57 -08:00
|
|
|
int sceKernelReferAlarmStatus(SceUID uid, u32 infoPtr)
|
2012-11-01 16:19:01 +01:00
|
|
|
{
|
2012-12-21 11:58:32 -08:00
|
|
|
u32 error;
|
2020-03-15 08:33:40 -07:00
|
|
|
PSPAlarm *alarm = kernelObjects.Get<PSPAlarm>(uid, error);
|
2012-12-21 11:58:32 -08:00
|
|
|
if (!alarm)
|
|
|
|
{
|
2013-09-07 22:02:55 +02:00
|
|
|
ERROR_LOG(SCEKERNEL, "sceKernelReferAlarmStatus(%08x, %08x): invalid alarm", uid, infoPtr);
|
2012-12-21 11:58:32 -08:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2013-09-07 22:02:55 +02:00
|
|
|
DEBUG_LOG(SCEKERNEL, "sceKernelReferAlarmStatus(%08x, %08x)", uid, infoPtr);
|
2012-12-21 12:38:12 -08:00
|
|
|
|
2012-12-21 11:58:32 -08:00
|
|
|
if (!Memory::IsValidAddress(infoPtr))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
u32 size = Memory::Read_U32(infoPtr);
|
|
|
|
|
|
|
|
// Alarms actually respect size and write (kinda) what it can hold.
|
2012-12-21 12:28:28 -08:00
|
|
|
if (size > 0)
|
2012-12-21 11:58:32 -08:00
|
|
|
Memory::Write_U32(alarm->alm.size, infoPtr);
|
2012-12-21 12:28:28 -08:00
|
|
|
if (size > 4)
|
2012-12-21 11:58:32 -08:00
|
|
|
Memory::Write_U64(alarm->alm.schedule, infoPtr + 4);
|
2012-12-21 12:28:28 -08:00
|
|
|
if (size > 12)
|
2012-12-21 11:58:32 -08:00
|
|
|
Memory::Write_U32(alarm->alm.handlerPtr, infoPtr + 12);
|
2012-12-21 12:28:28 -08:00
|
|
|
if (size > 16)
|
2012-12-21 11:58:32 -08:00
|
|
|
Memory::Write_U32(alarm->alm.commonPtr, infoPtr + 16);
|
|
|
|
|
|
|
|
return 0;
|
2020-03-15 08:33:40 -07:00
|
|
|
}
|