cellRtc: improvements

This commit is contained in:
capriots 2024-04-18 16:45:26 +02:00 committed by Megamouse
parent 56692e23f5
commit c8e624850b
2 changed files with 168 additions and 246 deletions

View file

@ -9,7 +9,6 @@
LOG_CHANNEL(cellRtc);
// clang-format off
template <>
void fmt_class_string<CellRtcError>::format(std::string& out, u64 arg)
{
@ -36,54 +35,6 @@ void fmt_class_string<CellRtcError>::format(std::string& out, u64 arg)
return unknown;
});
}
// clang-format on
// Grabbed from JPCSP
// This is the # of microseconds between January 1, 0001 and January 1, 1970.
constexpr u64 RTC_MAGIC_OFFSET = 62135596800000000ULL;
// This is the # of microseconds between January 1, 0001 and January 1, 1601 (for Win32 FILETIME.)
constexpr u64 RTC_FILETIME_OFFSET = 50491123200000000ULL;
constexpr u64 EPOCH_AS_FILETIME = 116444736000000000ULL;
// Also stores leap year
constexpr u8 DAYS_IN_MONTH[24] = {0x1F, 0x1C, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F, 0x1F, 0x1E, 0x1F, 0x1E, 0x1F};
s64 convertToUNIXTime(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years)
{
return s64{seconds} + s64{minutes} * 60 + s64{hours} * 3600 + s64{days} * 86400 + s64{s64{years} - 70} * 31536000 + s64{(years - 69) / 4} * 86400 - s64{(years - 1) / 100} * 86400 +
s64{(years + 299) / 400} * 86400;
}
u64 convertToWin32FILETIME(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years)
{
s64 unixtime = convertToUNIXTime(seconds, minutes, hours, days, years);
u64 win32time = static_cast<u64>(unixtime) * 10000000 + EPOCH_AS_FILETIME;
u64 win32filetime = win32time | win32time >> 32;
return win32filetime;
}
// TODO make all this use tick resolution and figure out the magic numbers
// TODO MULHDU instruction returns high 64 bit of the 128 bit result of two 64-bit regs multiplication
// need to be replaced with utils::mulh64, utils::umulh64, utils::div128, utils::udiv128 in needed places
// cellRtcSetTick / cellRtcSetWin32FileTime / cellRtcSetCurrentTick / cellRtcSetCurrentSecureTick
// TODO undo optimized division
// Internal helper functions in cellRtc
error_code set_secure_rtc_time(u64 time)
{
return sys_ss_secure_rtc(0x3003 /* SET_TIME */, time, 0, 0); // TODO
}
error_code get_secure_rtc_time(u64 unk1, u64 unk2, u64 unk3)
{
return sys_ss_secure_rtc(0x3002 /* GET_TIME */, unk1, unk2, unk3); // TODO
}
// End of internal helper functions
// Helper methods
static inline char ascii(u8 num)
{
@ -100,11 +51,9 @@ static bool is_leap_year(u32 year)
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
// End of helper methods
error_code cellRtcGetCurrentTick(vm::ptr<CellRtcTick> pTick)
{
cellRtc.todo("cellRtcGetCurrentTick(pTick=*0x%x)", pTick);
cellRtc.trace("cellRtcGetCurrentTick(pTick=*0x%x)", pTick);
if (!vm::check_addr(pTick.addr()))
{
@ -115,7 +64,7 @@ error_code cellRtcGetCurrentTick(vm::ptr<CellRtcTick> pTick)
vm::var<s64> nsec;
error_code ret = sys_time_get_current_time(sec, nsec);
if (ret != CELL_OK)
if (ret < CELL_OK)
{
return ret;
}
@ -127,7 +76,7 @@ error_code cellRtcGetCurrentTick(vm::ptr<CellRtcTick> pTick)
error_code cellRtcGetCurrentClock(vm::ptr<CellRtcDateTime> pClock, s32 iTimeZone)
{
cellRtc.todo("cellRtcGetCurrentClock(pClock=*0x%x, iTimeZone=%d)", pClock, iTimeZone);
cellRtc.notice("cellRtcGetCurrentClock(pClock=*0x%x, iTimeZone=%d)", pClock, iTimeZone);
if (!vm::check_addr(pClock.addr()))
{
@ -144,7 +93,7 @@ error_code cellRtcGetCurrentClock(vm::ptr<CellRtcDateTime> pClock, s32 iTimeZone
vm::var<s64> nsec;
error_code ret = sys_time_get_current_time(sec, nsec);
if (ret != CELL_OK)
if (ret < CELL_OK)
{
return ret;
}
@ -159,7 +108,7 @@ error_code cellRtcGetCurrentClock(vm::ptr<CellRtcDateTime> pClock, s32 iTimeZone
error_code cellRtcGetCurrentClockLocalTime(vm::ptr<CellRtcDateTime> pClock)
{
cellRtc.todo("cellRtcGetCurrentClockLocalTime(pClock=*0x%x)", pClock);
cellRtc.trace("cellRtcGetCurrentClockLocalTime(pClock=*0x%x)", pClock);
if (!vm::check_addr(pClock.addr()))
{
@ -170,7 +119,7 @@ error_code cellRtcGetCurrentClockLocalTime(vm::ptr<CellRtcDateTime> pClock)
vm::var<s32> summertime;
error_code ret = sys_time_get_timezone(timezone, summertime);
if (ret != CELL_OK)
if (ret < CELL_OK)
{
return ret;
}
@ -190,14 +139,14 @@ error_code cellRtcGetCurrentClockLocalTime(vm::ptr<CellRtcDateTime> pClock)
vm::var<s64> nsec;
ret = sys_time_get_current_time(sec, nsec);
if (ret != CELL_OK)
if (ret < CELL_OK)
{
return ret;
}
tick->tick = *nsec / 1000 + *sec * cellRtcGetTickResolution() + RTC_MAGIC_OFFSET;
cellRtcTickAddMinutes(tick, tick, s64{*timezone} + s64{*summertime});
cellRtcTickAddMinutes(tick, tick, *timezone + *summertime);
cellRtcSetTick(pClock, tick);
return CELL_OK;
@ -319,7 +268,7 @@ error_code cellRtcFormatRfc2822LocalTime(vm::ptr<char> pszDateTime, vm::cptr<Cel
vm::var<s32> summertime;
error_code ret = sys_time_get_timezone(timezone, summertime);
if (ret != CELL_OK)
if (ret < CELL_OK)
{
return ret;
}
@ -449,7 +398,7 @@ error_code cellRtcFormatRfc3339LocalTime(vm::ptr<char> pszDateTime, vm::cptr<Cel
vm::var<s32> summertime;
error_code ret = sys_time_get_timezone(timezone, summertime);
if (ret != CELL_OK)
if (ret < CELL_OK)
{
return ret;
}
@ -773,7 +722,7 @@ error_code cellRtcParseDateTime(vm::ptr<CellRtcTick> pUtc, vm::cptr<char> pszDat
cellRtc.warning("cellRtcParseDateTime(): ASCII value 0x%x at position %d is not a digit", pszDateTime[pos], pos);
}
day = digit(pszDateTime[pos]);
day = static_cast<u16>(pszDateTime[pos]) - '0'; // Needs to be sign extended first to match LLE for values from 0x80 to 0xb0
pos++;
}
@ -1006,7 +955,7 @@ error_code cellRtcParseRfc3339(vm::ptr<CellRtcTick> pUtc, vm::cptr<char> pszDate
error_code cellRtcGetTick(vm::cptr<CellRtcDateTime> pTime, vm::ptr<CellRtcTick> pTick)
{
cellRtc.notice("cellRtcGetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick);
cellRtc.trace("cellRtcGetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick);
if (!vm::check_addr(pTime.addr()))
{
@ -1110,7 +1059,7 @@ u64 date_time_to_tick(CellRtcDateTime date_time)
error_code cellRtcSetTick(vm::ptr<CellRtcDateTime> pTime, vm::cptr<CellRtcTick> pTick)
{
cellRtc.notice("cellRtcSetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick);
cellRtc.trace("cellRtcSetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick);
if (!vm::check_addr(pTime.addr()))
{
@ -1262,7 +1211,7 @@ error_code cellRtcTickAddWeeks(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick
error_code cellRtcTickAddMonths(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 iAdd)
{
cellRtc.trace("cellRtcTickAddMonths(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd);
cellRtc.notice("cellRtcTickAddMonths(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd);
if (!vm::check_addr(pTick0.addr()))
{
@ -1277,41 +1226,28 @@ error_code cellRtcTickAddMonths(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTic
vm::var<CellRtcDateTime> date_time;
cellRtcSetTick(date_time, pTick1);
// Not pretty, but works
const s32 total_months = date_time->year * 12 + date_time->month + iAdd - 1;
const u16 new_year = total_months / 12;
const u16 new_month = total_months - new_year * 12 + 1;
s64 total_months = (date_time->year * 12ULL) + date_time->month + iAdd + -1;
s32 total_months_s32 = ::narrow<s32>(total_months);
u32 unk_1 = total_months_s32 >> 0x1f;
u64 unk_2 = ((total_months_s32 / 6 + unk_1) >> 1) - unk_1;
u32 unk_3 = ::narrow<u32>(unk_2);
unk_1 = unk_3 & 0xffff;
u64 unk_4 = (total_months - ((u64{unk_3} << 4) - (unk_3 << 2))) + 1;
if (((unk_2 & 0xffff) == 0) || ((unk_3 = unk_4 & 0xffff, (unk_4 & 0xffff) == 0 || unk_3 > 12)))
u16 month_days;
if (new_year == 0u || new_month < 1u || new_month > 12u)
{
return CELL_RTC_ERROR_INVALID_ARG;
}
u32 uVar1 = ((s64{unk_1} * 0x51eb851f) >> 0x20);
// Leap year check
u32 month_idx;
if ((unk_1 == (uVar1 >> 7) * 400) || ((unk_1 != (uVar1 >> 5) * 100 && ((unk_2 & 3) == 0))))
{
month_idx = unk_3 + 11;
month_days = static_cast<u16>(CELL_RTC_ERROR_INVALID_ARG); // LLE writes the error to this variable
}
else
{
month_idx = unk_3 - 1;
month_days = is_leap_year(new_year) ? DAYS_IN_MONTH_LEAP[new_month - 1] : DAYS_IN_MONTH[new_month - 1];
}
u32 month_days = DAYS_IN_MONTH[month_idx];
if (month_days < date_time->day)
{
date_time->day = month_days;
}
date_time->month = ::narrow<u16>(unk_4);
date_time->year = ::narrow<u16>(unk_2);
date_time->month = new_month;
date_time->year = new_year;
cellRtcGetTick(date_time, pTick0);
return CELL_OK;
@ -1319,7 +1255,7 @@ error_code cellRtcTickAddMonths(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTic
error_code cellRtcTickAddYears(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 iAdd)
{
cellRtc.trace("cellRtcTickAddYears(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd);
cellRtc.notice("cellRtcTickAddYears(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd);
if (!vm::check_addr(pTick0.addr()))
{
@ -1334,33 +1270,26 @@ error_code cellRtcTickAddYears(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick
vm::var<CellRtcDateTime> date_time;
cellRtcSetTick(date_time, pTick1);
u64 total_years = iAdd + date_time->year;
u32 unk_1 = total_years & 0xffff;
if (unk_1 == 0 || date_time->month == 0 || date_time->month > 12)
{
return CELL_RTC_ERROR_INVALID_ARG;
}
const u16 month = date_time->month;
const u16 new_year = date_time->year + iAdd;
u32 uVar1 = ((s64{unk_1} * 0x51eb851f) >> 0x20);
u16 month_days;
// Leap year check
u32 month_idx;
if ((unk_1 == (uVar1 >> 7) * 400) || ((unk_1 != (uVar1 >> 5) * 100 && ((total_years & 3) == 0))))
if (new_year == 0u || month < 1u || month > 12u)
{
month_idx = date_time->month + 0xb;
month_days = static_cast<u16>(CELL_RTC_ERROR_INVALID_ARG); // LLE writes the error to this variable
}
else
{
month_idx = date_time->month - 1;
month_days = is_leap_year(new_year) ? DAYS_IN_MONTH_LEAP[month - 1] : DAYS_IN_MONTH[month - 1];
}
u32 month_days = DAYS_IN_MONTH[month_idx];
if (month_days < date_time->day)
{
date_time->day = month_days;
}
date_time->year = ::narrow<u16>(total_years);
date_time->year = new_year;
cellRtcGetTick(date_time, pTick0);
return CELL_OK;
@ -1368,7 +1297,7 @@ error_code cellRtcTickAddYears(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick
error_code cellRtcConvertUtcToLocalTime(vm::cptr<CellRtcTick> pUtc, vm::ptr<CellRtcTick> pLocalTime)
{
cellRtc.todo("cellRtcConvertUtcToLocalTime(pUtc=*0x%x, pLocalTime=*0x%x)", pUtc, pLocalTime);
cellRtc.trace("cellRtcConvertUtcToLocalTime(pUtc=*0x%x, pLocalTime=*0x%x)", pUtc, pLocalTime);
vm::var<s32> timezone;
vm::var<s32> summertime;
@ -1376,7 +1305,7 @@ error_code cellRtcConvertUtcToLocalTime(vm::cptr<CellRtcTick> pUtc, vm::ptr<Cell
error_code ret = sys_time_get_timezone(timezone, summertime);
if (-1 < ret)
{
ret = cellRtcTickAddMinutes(pLocalTime, pUtc, s64{*timezone} + s64{*summertime});
ret = cellRtcTickAddMinutes(pLocalTime, pUtc, *timezone + *summertime);
}
return ret;
@ -1384,7 +1313,7 @@ error_code cellRtcConvertUtcToLocalTime(vm::cptr<CellRtcTick> pUtc, vm::ptr<Cell
error_code cellRtcConvertLocalTimeToUtc(vm::cptr<CellRtcTick> pLocalTime, vm::ptr<CellRtcTick> pUtc)
{
cellRtc.todo("cellRtcConvertLocalTimeToUtc(pLocalTime=*0x%x, pUtc=*0x%x)", pLocalTime, pUtc);
cellRtc.notice("cellRtcConvertLocalTimeToUtc(pLocalTime=*0x%x, pUtc=*0x%x)", pLocalTime, pUtc);
vm::var<s32> timezone;
vm::var<s32> summertime;
@ -1392,7 +1321,7 @@ error_code cellRtcConvertLocalTimeToUtc(vm::cptr<CellRtcTick> pLocalTime, vm::pt
error_code ret = sys_time_get_timezone(timezone, summertime);
if (-1 < ret)
{
ret = cellRtcTickAddMinutes(pUtc, pLocalTime, -(s64{*timezone} + s64{*summertime}));
ret = cellRtcTickAddMinutes(pUtc, pLocalTime, -(*timezone + *summertime));
}
return ret;
@ -1400,23 +1329,41 @@ error_code cellRtcConvertLocalTimeToUtc(vm::cptr<CellRtcTick> pLocalTime, vm::pt
error_code cellRtcGetCurrentSecureTick(vm::ptr<CellRtcTick> tick)
{
cellRtc.todo("cellRtcGetCurrentSecureTick(*0x%x)", tick);
cellRtc.notice("cellRtcGetCurrentSecureTick(tick=*0x%x)", tick);
if (!vm::check_addr(tick.addr()))
{
return CELL_RTC_ERROR_INVALID_POINTER;
}
// TODO
tick->tick = RTC_SYSTEM_TIME_MIN;
tick->tick = 0xe01d003a63a000;
const vm::var<u64> time{0};
const vm::var<u64> status{0};
return CELL_OK;
error_code ret = sys_ss_secure_rtc(0x3002, 0, time.addr(), status.addr());
if (ret >= CELL_OK)
{
tick->tick += *time * cellRtcGetTickResolution();
}
else if (ret == static_cast<s32>(SYS_SS_RTC_ERROR_UNK))
{
switch (*status)
{
case 1: ret = CELL_RTC_ERROR_NO_CLOCK; break;
case 2: ret = CELL_RTC_ERROR_NOT_INITIALIZED; break;
case 4: ret = CELL_RTC_ERROR_INVALID_VALUE; break;
case 8: ret = CELL_RTC_ERROR_NO_CLOCK; break;
}
}
return ret;
}
error_code cellRtcGetDosTime(vm::cptr<CellRtcDateTime> pDateTime, vm::ptr<u32> puiDosTime)
{
cellRtc.todo("cellRtcGetDosTime(pDateTime=*0x%x, puiDosTime=*0x%x)", pDateTime, puiDosTime);
cellRtc.notice("cellRtcGetDosTime(pDateTime=*0x%x, puiDosTime=*0x%x)", pDateTime, puiDosTime);
if (!vm::check_addr(pDateTime.addr()))
{
@ -1430,27 +1377,26 @@ error_code cellRtcGetDosTime(vm::cptr<CellRtcDateTime> pDateTime, vm::ptr<u32> p
if (pDateTime->year < 1980)
{
if (puiDosTime)
if (puiDosTime) // Should always evaluate to true, nullptr was already checked above
{
*puiDosTime = 0;
return -1;
}
}
else if (pDateTime->year >= 2108)
{
if (puiDosTime)
{
*puiDosTime = 0xff9fbf7d; // kHighDosTime
return -1;
}
}
else
{
if (!puiDosTime)
{
return CELL_OK;
}
return -1;
}
if (pDateTime->year >= 2108)
{
if (puiDosTime) // Should always evaluate to true, nullptr was already checked above
{
*puiDosTime = 0xff9fbf7d; // kHighDosTime
}
return -1;
}
if (puiDosTime) // Should always evaluate to true, nullptr was already checked above
{
s32 year = ((pDateTime->year - 1980) & 0x7F) << 9;
s32 month = ((pDateTime->month) & 0xF) << 5;
s32 hour = ((pDateTime->hour) & 0x1F) << 11;
@ -1460,65 +1406,59 @@ error_code cellRtcGetDosTime(vm::cptr<CellRtcDateTime> pDateTime, vm::ptr<u32> p
s32 ymd = year | month | day;
s32 hms = hour | minute | second;
*puiDosTime = (ymd << 16) | hms;
return CELL_OK;
}
return -1;
return CELL_OK;
}
error_code cellRtcGetSystemTime(vm::cptr<CellRtcDateTime> pDateTime, vm::ptr<CellRtcTick> pTick)
error_code cellRtcGetSystemTime(vm::cptr<CellRtcDateTime> pDateTime, vm::ptr<s64> pTimeStamp)
{
cellRtc.todo("cellRtcGetSystemTime(pDateTime=*0x%x, pTick=*0x%x)", pDateTime, pTick);
cellRtc.notice("cellRtcGetSystemTime(pDateTime=*0x%x, pTimeStamp=*0x%x)", pDateTime, pTimeStamp);
if (!vm::check_addr(pDateTime.addr()))
{
return CELL_RTC_ERROR_INVALID_POINTER;
}
if (!vm::check_addr(pTick.addr()))
if (!vm::check_addr(pTimeStamp.addr()))
{
return CELL_RTC_ERROR_INVALID_POINTER;
}
error_code ret;
vm::var<CellRtcTick> tick;
cellRtcGetTick(pDateTime, tick);
if (tick->tick < 63082281600000000) // Max time
if (tick->tick < RTC_SYSTEM_TIME_MIN)
{
ret = CELL_RTC_ERROR_INVALID_VALUE;
if (pTick)
if (pTimeStamp) // Should always evaluate to true, nullptr was already checked above
{
pTick->tick = 0;
}
}
else
{
if (tick->tick < 0xeb5325dc3ec23f) // 66238041600999999
{
ret = CELL_OK;
if (pTick)
{
pTick->tick = (tick->tick + 0xff1fe2ffc59c6000) / cellRtcGetTickResolution();
}
}
else
{
ret = CELL_RTC_ERROR_INVALID_VALUE;
if (pTick)
{
pTick->tick = 0xbc19137f; // 1 day?
}
*pTimeStamp = 0;
}
return CELL_RTC_ERROR_INVALID_VALUE;
}
return ret;
if (tick->tick >= RTC_SYSTEM_TIME_MAX + cellRtcGetTickResolution())
{
if (pTimeStamp) // Should always evaluate to true, nullptr was already checked above
{
*pTimeStamp = (RTC_SYSTEM_TIME_MAX - RTC_SYSTEM_TIME_MIN) / cellRtcGetTickResolution();
}
return CELL_RTC_ERROR_INVALID_VALUE;
}
if (pTimeStamp) // Should always evaluate to true, nullptr was already checked above
{
*pTimeStamp = (tick->tick - RTC_SYSTEM_TIME_MIN) / cellRtcGetTickResolution();
}
return CELL_OK;
}
error_code cellRtcGetTime_t(vm::cptr<CellRtcDateTime> pDateTime, vm::ptr<s64> piTime)
{
cellRtc.todo("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime);
cellRtc.notice("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime);
if (!vm::check_addr(pDateTime.addr()))
{
@ -1533,30 +1473,27 @@ error_code cellRtcGetTime_t(vm::cptr<CellRtcDateTime> pDateTime, vm::ptr<s64> pi
vm::var<CellRtcTick> tick;
cellRtcGetTick(pDateTime, tick);
error_code ret;
if (tick->tick < RTC_MAGIC_OFFSET)
{
ret = CELL_RTC_ERROR_INVALID_VALUE;
if (piTime)
if (piTime) // Should always evaluate to true, nullptr was already checked above
{
*piTime = 0;
}
}
else
{
ret = CELL_OK;
if (piTime)
{
*piTime = (tick->tick + 0xff23400100d44000) / cellRtcGetTickResolution();
}
return CELL_RTC_ERROR_INVALID_VALUE;
}
return ret;
if (piTime) // Should always evaluate to true, nullptr was already checked above
{
*piTime = (tick->tick - RTC_MAGIC_OFFSET) / cellRtcGetTickResolution();
}
return CELL_OK;
}
error_code cellRtcGetWin32FileTime(vm::cptr<CellRtcDateTime> pDateTime, vm::ptr<u64> pulWin32FileTime)
{
cellRtc.todo("cellRtcGetWin32FileTime(pDateTime=*0x%x, pulWin32FileTime=*0x%x)", pDateTime, pulWin32FileTime);
cellRtc.notice("cellRtcGetWin32FileTime(pDateTime=*0x%x, pulWin32FileTime=*0x%x)", pDateTime, pulWin32FileTime);
if (!vm::check_addr(pDateTime.addr()))
{
@ -1571,83 +1508,73 @@ error_code cellRtcGetWin32FileTime(vm::cptr<CellRtcDateTime> pDateTime, vm::ptr<
vm::var<CellRtcTick> tick;
cellRtcGetTick(pDateTime, tick);
error_code ret;
if (tick->tick < RTC_FILETIME_OFFSET)
{
ret = CELL_RTC_ERROR_INVALID_VALUE;
if (pulWin32FileTime)
if (pulWin32FileTime) // Should always evaluate to true, nullptr was already checked above
{
*pulWin32FileTime = 0;
}
}
else
{
ret = CELL_OK;
if (pulWin32FileTime)
{
*pulWin32FileTime = tick->tick * 10 + 0xf8fe31e8dd890000;
}
return CELL_RTC_ERROR_INVALID_VALUE;
}
return ret;
if (pulWin32FileTime) // Should always evaluate to true, nullptr was already checked above
{
*pulWin32FileTime = (tick->tick - RTC_FILETIME_OFFSET) * 10;
}
return CELL_OK;
}
error_code cellRtcSetCurrentSecureTick(vm::ptr<CellRtcTick> pTick)
{
cellRtc.todo("cellRtcSetCurrentSecureTick(pTick=*0x%x)", pTick);
cellRtc.notice("cellRtcSetCurrentSecureTick(pTick=*0x%x)", pTick);
if (!pTick)
{
return CELL_RTC_ERROR_INVALID_POINTER;
}
u64 uVar1 = pTick->tick + 0xff1fe2ffc59c6000;
if (uVar1 >= 0xb3625a1cbe000) // 3155760000000000
if (pTick->tick > RTC_SYSTEM_TIME_MAX)
{
return CELL_RTC_ERROR_INVALID_VALUE;
}
return set_secure_rtc_time(uVar1 / cellRtcGetTickResolution());
return sys_ss_secure_rtc(0x3003, (pTick->tick - RTC_SYSTEM_TIME_MIN) / cellRtcGetTickResolution(), 0, 0);
}
error_code cellRtcSetCurrentTick(vm::cptr<CellRtcTick> pTick)
{
cellRtc.todo("cellRtcSetCurrentTick(pTick=*0x%x)", pTick);
cellRtc.notice("cellRtcSetCurrentTick(pTick=*0x%x)", pTick);
if (!pTick)
{
return CELL_RTC_ERROR_INVALID_POINTER;
}
//u64 tmp = pTick->tick + 0xff23400100d44000;
if (!(0xdcbffeff2bbfff < pTick->tick))
if (pTick->tick < RTC_MAGIC_OFFSET)
{
return CELL_RTC_ERROR_INVALID_ARG;
return CELL_RTC_ERROR_INVALID_VALUE;
}
// TODO syscall not implemented
/*
u64 tmp2 = sys_time_get_system_time(tmp / cellRtcGetTickResolution(), (tmp % cellRtcGetTickResolution()) * 1000);
const u64 unix_time = pTick->tick - RTC_MAGIC_OFFSET;
return (tmp2 & (tmp2 | tmp2 - 1) >> 0x1f);
*/
return CELL_OK;
const error_code ret = sys_time_set_current_time(unix_time / cellRtcGetTickResolution(), unix_time % cellRtcGetTickResolution() * 1000);
return ret >= CELL_OK ? CELL_OK : ret;
}
error_code cellRtcSetConf(s64 unk1, s64 unk2, u32 timezone, u32 summertime)
{
cellRtc.todo("cellRtcSetConf(unk1=0x%x, unk2=0x%x, timezone=%d, summertime=%d)", unk1, unk2, timezone, summertime);
cellRtc.notice("cellRtcSetConf(unk1=0x%x, unk2=0x%x, timezone=%d, summertime=%d)", unk1, unk2, timezone, summertime);
// Seems the first 2 args are ignored :|
// TODO Syscall not implemented
// return sys_time_set_timezone(timezone, summertime);
return CELL_OK;
return sys_time_set_timezone(timezone, summertime);
}
error_code cellRtcSetDosTime(vm::ptr<CellRtcDateTime> pDateTime, u32 uiDosTime)
{
cellRtc.todo("cellRtcSetDosTime(pDateTime=*0x%x, uiDosTime=0x%x)", pDateTime, uiDosTime);
cellRtc.notice("cellRtcSetDosTime(pDateTime=*0x%x, uiDosTime=0x%x)", pDateTime, uiDosTime);
if (!vm::check_addr(pDateTime.addr()))
{
@ -1668,7 +1595,7 @@ error_code cellRtcSetDosTime(vm::ptr<CellRtcDateTime> pDateTime, u32 uiDosTime)
return CELL_OK;
}
u32 cellRtcGetTickResolution()
constexpr u32 cellRtcGetTickResolution()
{
// Amount of ticks in a second
return 1000000;
@ -1676,7 +1603,7 @@ u32 cellRtcGetTickResolution()
error_code cellRtcSetTime_t(vm::ptr<CellRtcDateTime> pDateTime, u64 iTime)
{
cellRtc.todo("cellRtcSetTime_t(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime);
cellRtc.notice("cellRtcSetTime_t(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime);
if (!vm::check_addr(pDateTime.addr()))
{
@ -1693,7 +1620,7 @@ error_code cellRtcSetTime_t(vm::ptr<CellRtcDateTime> pDateTime, u64 iTime)
error_code cellRtcSetSystemTime(vm::ptr<CellRtcDateTime> pDateTime, u64 iTime)
{
cellRtc.todo("cellRtcSetSystemTime(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime);
cellRtc.notice("cellRtcSetSystemTime(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime);
if (!vm::check_addr(pDateTime.addr()))
{
@ -1701,14 +1628,16 @@ error_code cellRtcSetSystemTime(vm::ptr<CellRtcDateTime> pDateTime, u64 iTime)
}
vm::var<CellRtcTick> tick;
tick->tick = iTime * cellRtcGetTickResolution() + 0xe01d003a63a000;
tick->tick = iTime * cellRtcGetTickResolution() + RTC_SYSTEM_TIME_MIN;
return cellRtcSetTick(pDateTime, tick);
cellRtcSetTick(pDateTime, tick);
return CELL_OK;
}
error_code cellRtcSetWin32FileTime(vm::ptr<CellRtcDateTime> pDateTime, u64 ulWin32FileTime)
{
cellRtc.todo("cellRtcSetWin32FileTime(pDateTime=*0x%x, ulWin32FileTime=0x%llx)", pDateTime, ulWin32FileTime);
cellRtc.notice("cellRtcSetWin32FileTime(pDateTime=*0x%x, ulWin32FileTime=0x%llx)", pDateTime, ulWin32FileTime);
if (!vm::check_addr(pDateTime.addr()))
{
@ -1723,7 +1652,7 @@ error_code cellRtcSetWin32FileTime(vm::ptr<CellRtcDateTime> pDateTime, u64 ulWin
error_code cellRtcIsLeapYear(s32 year)
{
cellRtc.todo("cellRtcIsLeapYear(year=%d)", year);
cellRtc.notice("cellRtcIsLeapYear(year=%d)", year);
if (year < 1)
{
@ -1735,22 +1664,17 @@ error_code cellRtcIsLeapYear(s32 year)
error_code cellRtcGetDaysInMonth(s32 year, s32 month)
{
cellRtc.todo("cellRtcGetDaysInMonth(year=%d, month=%d)", year, month);
cellRtc.notice("cellRtcGetDaysInMonth(year=%d, month=%d)", year, month);
if ((year <= 0) || (month <= 0) || (month > 12))
{
return CELL_RTC_ERROR_INVALID_ARG;
}
if (is_leap_year(year))
{
return not_an_error(DAYS_IN_MONTH[month + 11]);
}
return not_an_error(DAYS_IN_MONTH[month - 1]);
return not_an_error(is_leap_year(year) ? DAYS_IN_MONTH_LEAP[month - 1] : DAYS_IN_MONTH[month - 1]);
}
error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day)
s32 cellRtcGetDayOfWeek(s32 year, s32 month, s32 day)
{
cellRtc.trace("cellRtcGetDayOfWeek(year=%d, month=%d, day=%d)", year, month, day);
@ -1760,13 +1684,16 @@ error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day)
month += 12;
}
return not_an_error(((month * 0xd + 8) / 5 + ((year + (year >> 2) + (year < 0 && (year & 3U) != 0)) - year / 100) + year / 400 + day) % 7);
return ((month * 13 + 8) / 5 + year + year / 4 - year / 100 + year / 400 + day) % 7;
}
error_code cellRtcCheckValid(vm::cptr<CellRtcDateTime> pTime)
{
cellRtc.todo("cellRtcCheckValid(pTime=*0x%x)", pTime);
cellRtc.todo("cellRtcCheckValid year: %d, month: %d, day: %d, hour: %d, minute: %d, second: %d, microsecond: %d\n", pTime->year, pTime->month, pTime->day, pTime->hour, pTime->minute, pTime->second, pTime->microsecond);
cellRtc.notice("cellRtcCheckValid(pTime=*0x%x)", pTime);
ensure(!!pTime); // Not checked on LLE
cellRtc.notice("cellRtcCheckValid year: %d, month: %d, day: %d, hour: %d, minute: %d, second: %d, microsecond: %d", pTime->year, pTime->month, pTime->day, pTime->hour, pTime->minute, pTime->second, pTime->microsecond);
if (pTime->year == 0 || pTime->year >= 10000)
{
@ -1778,19 +1705,9 @@ error_code cellRtcCheckValid(vm::cptr<CellRtcDateTime> pTime)
return CELL_RTC_ERROR_INVALID_MONTH;
}
s32 month_idx;
const auto& days_in_month = is_leap_year(pTime->year) ? DAYS_IN_MONTH_LEAP : DAYS_IN_MONTH;
if (is_leap_year(pTime->year))
{
// Leap year check
month_idx = pTime->month + 11;
}
else
{
month_idx = pTime->month - 1;
}
if (pTime->day == 0 || pTime->day > DAYS_IN_MONTH[month_idx])
if (pTime->day == 0 || pTime->day > days_in_month[pTime->month - 1])
{
return CELL_RTC_ERROR_INVALID_DAY;
}
@ -1818,9 +1735,11 @@ error_code cellRtcCheckValid(vm::cptr<CellRtcDateTime> pTime)
return CELL_OK;
}
error_code cellRtcCompareTick(vm::cptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1)
s32 cellRtcCompareTick(vm::cptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1)
{
cellRtc.todo("cellRtcCompareTick(pTick0=*0x%x, pTick1=*0x%x)", pTick0, pTick1);
cellRtc.notice("cellRtcCompareTick(pTick0=*0x%x, pTick1=*0x%x)", pTick0, pTick1);
ensure(!!pTick0 && !!pTick1); // Not checked on LLE
s32 ret = -1;
if (pTick1->tick <= pTick0->tick)
@ -1828,7 +1747,7 @@ error_code cellRtcCompareTick(vm::cptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick
ret = pTick1->tick < pTick0->tick;
}
return not_an_error(ret);
return ret;
}
DECLARE(ppu_module_manager::cellRtc)

View file

@ -38,10 +38,18 @@ struct CellRtcDateTime
be_t<u32> microsecond; // 0 to 999999
};
constexpr u64 RTC_MAGIC_OFFSET = 62135596800000000ull; // 1970-01-01 00:00:00.000000
constexpr u64 RTC_FILETIME_OFFSET = 50491123200000000ull; // 1601-01-01 00:00:00.000000
constexpr u64 RTC_SYSTEM_TIME_MIN = 63082281600000000ull; // 2000-01-01 00:00:00.000000
constexpr u64 RTC_SYSTEM_TIME_MAX = 66238041599999999ull; // 2099-12-31 23:59:59.999999
constexpr u32 DAYS_IN_400_YEARS = 365 * 400 + 97;
constexpr u16 DAYS_IN_100_YEARS = 365 * 100 + 24;
constexpr u16 DAYS_IN_4_YEARS = 365 * 4 + 1;
constexpr std::array<u8, 12> DAYS_IN_MONTH = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
constexpr std::array<u8, 12> DAYS_IN_MONTH_LEAP = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
constexpr std::array<u16, 13> MONTH_OFFSET = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, umax };
constexpr std::array<u16, 13> MONTH_OFFSET_LEAP = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, umax };
@ -50,17 +58,12 @@ constexpr std::array<std::string_view, 12> MONTH_NAMES = { "january", "febru
constexpr std::array<std::string_view, 70> TIME_ZONE_NAMES = { "gmt", "est", "edt", "cst", "cdt", "mst", "mdt", "pst", "pdt", "nzdt", "nzst", "idle", "nzt", "aesst", "acsst", "cadt", "sadt", "aest", "east", "gst", "ligt", "acst", "sast", "cast", "awsst", "jst", "kst", "wdt", "mt", "awst", "cct", "wadt", "wst", "jt", "wast", "it", "bt", "eetdst", "eet", "cetdst", "fwt", "ist", "mest", "metdst", "sst", "bst", "cet", "dnt", "fst", "met", "mewt", "mez", "nor", "set", "swt", "wetdst", "wet", "wat", "ndt", "adt", "nft", "nst", "ast", "ydt", "hdt", "yst", "ahst", "cat", "nt", "idlw" };
constexpr std::array<s8, 70> TIME_ZONE_VALUES = { 0, -10, -8, -12, -10, -14, -12, -16, -14, 26, 24, 24, 24, 22, 21, 21, 21, 20, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 16, 16, 16, 16, 15, 14, 7, 6, 6, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, -2, -3, -6, -5, -5, -8, -16, -18, -18, -20, -20, -22, -24 }; // In units of 30 minutes
error_code cellRtcTickAddYears(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 iAdd);
error_code cellRtcTickAddMonths(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 lAdd);
error_code cellRtcTickAddDays(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 lAdd);
error_code cellRtcTickAddHours(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s32 lAdd);
error_code cellRtcTickAddMinutes(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s64 lAdd);
error_code cellRtcTickAddSeconds(vm::ptr<CellRtcTick> pTick0, vm::cptr<CellRtcTick> pTick1, s64 lAdd);
error_code cellRtcSetTick(vm::ptr<CellRtcDateTime> pTime, vm::cptr<CellRtcTick> pTick);
u32 cellRtcGetTickResolution();
constexpr u32 cellRtcGetTickResolution();
error_code cellRtcCheckValid(vm::cptr<CellRtcDateTime> pTime);
error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day);
s32 cellRtcGetDayOfWeek(s32 year, s32 month, s32 day);
error_code cellRtcGetTick(vm::cptr<CellRtcDateTime> pTime, vm::ptr<CellRtcTick> pTick);
error_code cellRtcGetCurrentTick(vm::ptr<CellRtcTick> pTick);