mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-12 12:45:56 +00:00
Merge branch 'main' into fontlib
This commit is contained in:
commit
9569c29644
24 changed files with 727 additions and 327 deletions
|
@ -179,7 +179,7 @@ s32 PS4_SYSV_ABI sceGnmComputeWaitOnAddress(u32* cmdbuf, u32 size, uintptr_t add
|
|||
auto* wait_reg_mem = reinterpret_cast<PM4CmdWaitRegMem*>(cmdbuf);
|
||||
wait_reg_mem->header = PM4Type3Header{PM4ItOpcode::WaitRegMem, 5};
|
||||
wait_reg_mem->raw = (is_mem << 4u) | (cmp_func & 7u);
|
||||
wait_reg_mem->poll_addr_lo = u32(addr & addr_mask);
|
||||
wait_reg_mem->poll_addr_lo_raw = u32(addr & addr_mask);
|
||||
wait_reg_mem->poll_addr_hi = u32(addr >> 32u);
|
||||
wait_reg_mem->ref = ref;
|
||||
wait_reg_mem->mask = mask;
|
||||
|
|
|
@ -12,12 +12,25 @@
|
|||
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
extern boost::asio::io_context io_context;
|
||||
extern void KernelSignalRequest();
|
||||
|
||||
static constexpr auto HrTimerSpinlockThresholdUs = 1200u;
|
||||
|
||||
// Events are uniquely identified by id and filter.
|
||||
|
||||
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
event.time_added = std::chrono::steady_clock::now();
|
||||
if (event.event.filter == SceKernelEvent::Filter::Timer ||
|
||||
event.event.filter == SceKernelEvent::Filter::HrTimer) {
|
||||
// HrTimer events are offset by the threshold of time at the end that we spinlock for
|
||||
// greater accuracy.
|
||||
const auto offset =
|
||||
event.event.filter == SceKernelEvent::Filter::HrTimer ? HrTimerSpinlockThresholdUs : 0u;
|
||||
event.timer_interval = std::chrono::microseconds(event.event.data - offset);
|
||||
}
|
||||
|
||||
const auto& it = std::ranges::find(m_events, event);
|
||||
if (it != m_events.cend()) {
|
||||
|
@ -29,6 +42,47 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EqueueInternal::ScheduleEvent(u64 id, s16 filter,
|
||||
void (*callback)(SceKernelEqueue, const SceKernelEvent&)) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
||||
return ev.event.ident == id && ev.event.filter == filter;
|
||||
});
|
||||
if (it == m_events.cend()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& event = *it;
|
||||
ASSERT(event.event.filter == SceKernelEvent::Filter::Timer ||
|
||||
event.event.filter == SceKernelEvent::Filter::HrTimer);
|
||||
|
||||
if (!it->timer) {
|
||||
it->timer = std::make_unique<boost::asio::steady_timer>(io_context, event.timer_interval);
|
||||
} else {
|
||||
// If the timer already exists we are scheduling a reoccurrence after the next period.
|
||||
// Set the expiration time to the previous occurrence plus the period.
|
||||
it->timer->expires_at(it->timer->expiry() + event.timer_interval);
|
||||
}
|
||||
|
||||
it->timer->async_wait(
|
||||
[this, event_data = event.event, callback](const boost::system::error_code& ec) {
|
||||
if (ec) {
|
||||
if (ec != boost::system::errc::operation_canceled) {
|
||||
LOG_ERROR(Kernel_Event, "Timer callback error: {}", ec.message());
|
||||
} else {
|
||||
// Timer was cancelled (removed) before it triggered
|
||||
LOG_DEBUG(Kernel_Event, "Timer cancelled");
|
||||
}
|
||||
return;
|
||||
}
|
||||
callback(this, event_data);
|
||||
});
|
||||
KernelSignalRequest();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EqueueInternal::RemoveEvent(u64 id, s16 filter) {
|
||||
bool has_found = false;
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
@ -152,18 +206,14 @@ int EqueueInternal::WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros) {
|
|||
return count;
|
||||
}
|
||||
|
||||
extern boost::asio::io_context io_context;
|
||||
extern void KernelSignalRequest();
|
||||
bool EqueueInternal::EventExists(u64 id, s16 filter) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
static constexpr auto HrTimerSpinlockThresholdUs = 1200u;
|
||||
const auto& it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
||||
return ev.event.ident == id && ev.event.filter == filter;
|
||||
});
|
||||
|
||||
static void SmallTimerCallback(const boost::system::error_code& error, SceKernelEqueue eq,
|
||||
SceKernelEvent kevent) {
|
||||
static EqueueEvent event;
|
||||
event.event = kevent;
|
||||
event.event.data = HrTimerSpinlockThresholdUs;
|
||||
eq->AddSmallTimer(event);
|
||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
|
||||
return it != m_events.cend();
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelCreateEqueue(SceKernelEqueue* eq, const char* name) {
|
||||
|
@ -243,6 +293,14 @@ int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
static void HrTimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
|
||||
static EqueueEvent event;
|
||||
event.event = kevent;
|
||||
event.event.data = HrTimerSpinlockThresholdUs;
|
||||
eq->AddSmallTimer(event);
|
||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::HrTimer, kevent.udata);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
|
@ -273,17 +331,10 @@ s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec*
|
|||
return eq->AddSmallTimer(event) ? ORBIS_OK : ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
event.timer = std::make_unique<boost::asio::steady_timer>(
|
||||
io_context, std::chrono::microseconds(total_us - HrTimerSpinlockThresholdUs));
|
||||
|
||||
event.timer->async_wait(std::bind(SmallTimerCallback, std::placeholders::_1, eq, event.event));
|
||||
|
||||
if (!eq->AddEvent(event)) {
|
||||
if (!eq->AddEvent(event) ||
|
||||
!eq->ScheduleEvent(id, SceKernelEvent::Filter::HrTimer, HrTimerCallback)) {
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
|
||||
KernelSignalRequest();
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -300,6 +351,57 @@ int PS4_SYSV_ABI sceKernelDeleteHRTimerEvent(SceKernelEqueue eq, int id) {
|
|||
}
|
||||
}
|
||||
|
||||
static void TimerCallback(SceKernelEqueue eq, const SceKernelEvent& kevent) {
|
||||
if (eq->EventExists(kevent.ident, kevent.filter)) {
|
||||
eq->TriggerEvent(kevent.ident, SceKernelEvent::Filter::Timer, kevent.udata);
|
||||
|
||||
if (!(kevent.flags & SceKernelEvent::Flags::OneShot)) {
|
||||
// Reschedule the event for its next period.
|
||||
eq->ScheduleEvent(kevent.ident, kevent.filter, TimerCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelAddTimerEvent(SceKernelEqueue eq, int id, SceKernelUseconds usec,
|
||||
void* udata) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
EqueueEvent event{};
|
||||
event.event.ident = static_cast<u64>(id);
|
||||
event.event.filter = SceKernelEvent::Filter::Timer;
|
||||
event.event.flags = SceKernelEvent::Flags::Add;
|
||||
event.event.fflags = 0;
|
||||
event.event.data = usec;
|
||||
event.event.udata = udata;
|
||||
|
||||
if (eq->EventExists(event.event.ident, event.event.filter)) {
|
||||
eq->RemoveEvent(id, SceKernelEvent::Filter::Timer);
|
||||
LOG_DEBUG(Kernel_Event,
|
||||
"Timer event already exists, removing it: queue name={}, queue id={}",
|
||||
eq->GetName(), event.event.ident);
|
||||
}
|
||||
|
||||
LOG_DEBUG(Kernel_Event, "Added timing event: queue name={}, queue id={}, usec={}, pointer={:x}",
|
||||
eq->GetName(), event.event.ident, usec, reinterpret_cast<uintptr_t>(udata));
|
||||
|
||||
if (!eq->AddEvent(event) ||
|
||||
!eq->ScheduleEvent(id, SceKernelEvent::Filter::Timer, TimerCallback)) {
|
||||
return ORBIS_KERNEL_ERROR_ENOMEM;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelDeleteTimerEvent(SceKernelEqueue eq, int id) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
return eq->RemoveEvent(id, SceKernelEvent::Filter::Timer) ? ORBIS_OK
|
||||
: ORBIS_KERNEL_ERROR_ENOENT;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
|
@ -380,6 +482,8 @@ void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
|
||||
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);
|
||||
LIB_FUNCTION("J+LF6LwObXU", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteHRTimerEvent);
|
||||
LIB_FUNCTION("57ZK+ODEXWY", "libkernel", 1, "libkernel", 1, 1, sceKernelAddTimerEvent);
|
||||
LIB_FUNCTION("YWQFUyXIVdU", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteTimerEvent);
|
||||
LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
|
||||
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
|
||||
LIB_FUNCTION("mJ7aghmgvfc", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventId);
|
||||
|
|
|
@ -21,6 +21,9 @@ namespace Libraries::Kernel {
|
|||
class EqueueInternal;
|
||||
struct EqueueEvent;
|
||||
|
||||
using SceKernelUseconds = u32;
|
||||
using SceKernelEqueue = EqueueInternal*;
|
||||
|
||||
struct SceKernelEvent {
|
||||
enum Filter : s16 {
|
||||
None = 0,
|
||||
|
@ -77,6 +80,7 @@ struct EqueueEvent {
|
|||
SceKernelEvent event;
|
||||
void* data = nullptr;
|
||||
std::chrono::steady_clock::time_point time_added;
|
||||
std::chrono::microseconds timer_interval;
|
||||
std::unique_ptr<boost::asio::steady_timer> timer;
|
||||
|
||||
void ResetTriggerState() {
|
||||
|
@ -133,6 +137,8 @@ public:
|
|||
}
|
||||
|
||||
bool AddEvent(EqueueEvent& event);
|
||||
bool ScheduleEvent(u64 id, s16 filter,
|
||||
void (*callback)(SceKernelEqueue, const SceKernelEvent&));
|
||||
bool RemoveEvent(u64 id, s16 filter);
|
||||
int WaitForEvents(SceKernelEvent* ev, int num, u32 micros);
|
||||
bool TriggerEvent(u64 ident, s16 filter, void* trigger_data);
|
||||
|
@ -152,6 +158,8 @@ public:
|
|||
|
||||
int WaitForSmallTimer(SceKernelEvent* ev, int num, u32 micros);
|
||||
|
||||
bool EventExists(u64 id, s16 filter);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::mutex m_mutex;
|
||||
|
@ -160,9 +168,6 @@ private:
|
|||
std::condition_variable m_cond;
|
||||
};
|
||||
|
||||
using SceKernelUseconds = u32;
|
||||
using SceKernelEqueue = EqueueInternal*;
|
||||
|
||||
u64 PS4_SYSV_ABI sceKernelGetEventData(const SceKernelEvent* ev);
|
||||
|
||||
void RegisterEventQueue(Core::Loader::SymbolsResolver* sym);
|
||||
|
|
|
@ -108,6 +108,9 @@ void SetPosixErrno(int e) {
|
|||
case EACCES:
|
||||
g_posix_errno = POSIX_EACCES;
|
||||
break;
|
||||
case EFAULT:
|
||||
g_posix_errno = POSIX_EFAULT;
|
||||
break;
|
||||
case EINVAL:
|
||||
g_posix_errno = POSIX_EINVAL;
|
||||
break;
|
||||
|
|
|
@ -290,6 +290,12 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut
|
|||
directMemoryEndOut);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end) {
|
||||
LOG_DEBUG(Kernel_Vmm, "called, addr = {}", fmt::ptr(addr));
|
||||
auto* memory = Core::Memory::Instance();
|
||||
return memory->IsStack(std::bit_cast<VAddr>(addr), start, end);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
|
||||
int* numEntriesOut) {
|
||||
return sceKernelBatchMap2(entries, numEntries, numEntriesOut,
|
||||
|
@ -636,6 +642,7 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("7oxv3PPCumo", "libkernel", 1, "libkernel", 1, 1, sceKernelReserveVirtualRange);
|
||||
LIB_FUNCTION("BC+OG5m9+bw", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemoryType);
|
||||
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize);
|
||||
LIB_FUNCTION("yDBwVAolDgg", "libkernel", 1, "libkernel", 1, 1, sceKernelIsStack);
|
||||
LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory);
|
||||
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
|
||||
LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection);
|
||||
|
|
|
@ -158,6 +158,7 @@ void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func[]);
|
|||
int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut,
|
||||
void** directMemoryStartOut,
|
||||
void** directMemoryEndOut);
|
||||
int PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end);
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
|
||||
int* numEntriesOut);
|
||||
|
|
|
@ -315,7 +315,7 @@ int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
|
|||
auto result = ef->Poll(bitPattern, wait, clear, pResultPat);
|
||||
|
||||
if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_EBUSY) {
|
||||
LOG_ERROR(Kernel_Event, "returned {}", result);
|
||||
LOG_DEBUG(Kernel_Event, "returned {:#x}", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -361,7 +361,7 @@ int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern,
|
|||
u32 result = ef->Wait(bitPattern, wait, clear, pResultPat, pTimeout);
|
||||
|
||||
if (result != ORBIS_OK && result != ORBIS_KERNEL_ERROR_ETIMEDOUT) {
|
||||
LOG_ERROR(Kernel_Event, "returned {:#x}", result);
|
||||
LOG_DEBUG(Kernel_Event, "returned {:#x}", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -5,24 +5,23 @@
|
|||
|
||||
#include "common/assert.h"
|
||||
#include "common/native_clock.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/libraries/kernel/kernel.h"
|
||||
#include "core/libraries/kernel/orbis_error.h"
|
||||
#include "core/libraries/kernel/posix_error.h"
|
||||
#include "core/libraries/kernel/time.h"
|
||||
#include "core/libraries/libs.h"
|
||||
|
||||
#ifdef _WIN64
|
||||
#include <pthread_time.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "common/ntapi.h"
|
||||
|
||||
#else
|
||||
#if __APPLE__
|
||||
#include <date/tz.h>
|
||||
#endif
|
||||
#include <ctime>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
@ -52,88 +51,116 @@ u64 PS4_SYSV_ABI sceKernelReadTsc() {
|
|||
return clock->GetUptime();
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) {
|
||||
#ifdef _WIN64
|
||||
const auto start_time = std::chrono::high_resolution_clock::now();
|
||||
auto total_wait_time = std::chrono::microseconds(microseconds);
|
||||
static s32 posix_nanosleep_impl(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp,
|
||||
const bool interruptible) {
|
||||
if (!rqtp || rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1'000'000'000) {
|
||||
SetPosixErrno(EINVAL);
|
||||
return -1;
|
||||
}
|
||||
const auto duration = std::chrono::nanoseconds(rqtp->tv_sec * 1'000'000'000 + rqtp->tv_nsec);
|
||||
std::chrono::nanoseconds remain;
|
||||
const auto uninterrupted = Common::AccurateSleep(duration, &remain, interruptible);
|
||||
if (rmtp) {
|
||||
rmtp->tv_sec = remain.count() / 1'000'000'000;
|
||||
rmtp->tv_nsec = remain.count() % 1'000'000'000;
|
||||
}
|
||||
if (!uninterrupted) {
|
||||
SetPosixErrno(EINTR);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (total_wait_time.count() > 0) {
|
||||
auto wait_time = std::chrono::ceil<std::chrono::milliseconds>(total_wait_time).count();
|
||||
u64 res = SleepEx(static_cast<u64>(wait_time), true);
|
||||
if (res == WAIT_IO_COMPLETION) {
|
||||
auto elapsedTime = std::chrono::high_resolution_clock::now() - start_time;
|
||||
auto elapsedMicroseconds =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(elapsedTime).count();
|
||||
total_wait_time = std::chrono::microseconds(microseconds - elapsedMicroseconds);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
s32 PS4_SYSV_ABI posix_nanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
|
||||
return posix_nanosleep_impl(rqtp, rmtp, true);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelNanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
|
||||
if (const auto ret = posix_nanosleep_impl(rqtp, rmtp, false); ret < 0) {
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_usleep(u32 microseconds) {
|
||||
const OrbisKernelTimespec ts = {
|
||||
.tv_sec = microseconds / 1'000'000,
|
||||
.tv_nsec = (microseconds % 1'000'000) * 1'000,
|
||||
};
|
||||
return posix_nanosleep(&ts, nullptr);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) {
|
||||
const OrbisKernelTimespec ts = {
|
||||
.tv_sec = microseconds / 1'000'000,
|
||||
.tv_nsec = (microseconds % 1'000'000) * 1'000,
|
||||
};
|
||||
return sceKernelNanosleep(&ts, nullptr);
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI posix_sleep(u32 seconds) {
|
||||
const OrbisKernelTimespec ts = {
|
||||
.tv_sec = seconds,
|
||||
.tv_nsec = 0,
|
||||
};
|
||||
OrbisKernelTimespec rm;
|
||||
if (const auto ret = posix_nanosleep(&ts, &rm); ret < 0) {
|
||||
return *__Error() == POSIX_EINTR ? rm.tv_sec + (rm.tv_nsec == 0 ? 0 : 1) : seconds;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) {
|
||||
return sceKernelUsleep(seconds * 1'000'000);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_clock_gettime(u32 clock_id, OrbisKernelTimespec* ts) {
|
||||
if (ts == nullptr) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
timespec start;
|
||||
timespec remain;
|
||||
start.tv_sec = microseconds / 1000000;
|
||||
start.tv_nsec = (microseconds % 1000000) * 1000;
|
||||
timespec* requested = &start;
|
||||
int ret = 0;
|
||||
do {
|
||||
ret = nanosleep(requested, &remain);
|
||||
requested = &remain;
|
||||
} while (ret != 0);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
if (clock_id == ORBIS_CLOCK_PROCTIME) {
|
||||
const auto us = sceKernelGetProcessTime();
|
||||
ts->tv_sec = static_cast<s64>(us / 1'000'000);
|
||||
ts->tv_nsec = static_cast<s64>((us % 1'000'000) * 1000);
|
||||
return 0;
|
||||
}
|
||||
if (clock_id == ORBIS_CLOCK_EXT_NETWORK || clock_id == ORBIS_CLOCK_EXT_DEBUG_NETWORK ||
|
||||
clock_id == ORBIS_CLOCK_EXT_AD_NETWORK || clock_id == ORBIS_CLOCK_EXT_RAW_NETWORK) {
|
||||
LOG_ERROR(Lib_Kernel, "Unsupported clock type {}, using CLOCK_MONOTONIC", clock_id);
|
||||
clock_id = ORBIS_CLOCK_MONOTONIC;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_usleep(u32 microseconds) {
|
||||
return sceKernelUsleep(microseconds);
|
||||
}
|
||||
|
||||
u32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(seconds));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
#ifndef CLOCK_REALTIME
|
||||
#define CLOCK_REALTIME 0
|
||||
#endif
|
||||
#ifndef CLOCK_MONOTONIC
|
||||
#define CLOCK_MONOTONIC 1
|
||||
#endif
|
||||
#ifndef CLOCK_PROCESS_CPUTIME_ID
|
||||
#define CLOCK_PROCESS_CPUTIME_ID 2
|
||||
#endif
|
||||
#ifndef CLOCK_THREAD_CPUTIME_ID
|
||||
#define CLOCK_THREAD_CPUTIME_ID 3
|
||||
#endif
|
||||
#ifndef CLOCK_REALTIME_COARSE
|
||||
#define CLOCK_REALTIME_COARSE 5
|
||||
#endif
|
||||
#ifndef CLOCK_MONOTONIC_COARSE
|
||||
#define CLOCK_MONOTONIC_COARSE 6
|
||||
#endif
|
||||
|
||||
#define DELTA_EPOCH_IN_100NS 116444736000000000ULL
|
||||
|
||||
static u64 FileTimeTo100Ns(FILETIME& ft) {
|
||||
return *reinterpret_cast<u64*>(&ft);
|
||||
}
|
||||
|
||||
static s32 clock_gettime(u32 clock_id, struct timespec* ts) {
|
||||
#ifdef _WIN32
|
||||
static const auto FileTimeTo100Ns = [](FILETIME& ft) { return *reinterpret_cast<u64*>(&ft); };
|
||||
switch (clock_id) {
|
||||
case CLOCK_REALTIME:
|
||||
case CLOCK_REALTIME_COARSE: {
|
||||
case ORBIS_CLOCK_REALTIME:
|
||||
case ORBIS_CLOCK_REALTIME_PRECISE: {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
const u64 ns = FileTimeTo100Ns(ft) - DELTA_EPOCH_IN_100NS;
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
static constexpr u64 DeltaEpochIn100ns = 116444736000000000ULL;
|
||||
const u64 ns = FileTimeTo100Ns(ft) - DeltaEpochIn100ns;
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
return 0;
|
||||
}
|
||||
case CLOCK_MONOTONIC:
|
||||
case CLOCK_MONOTONIC_COARSE: {
|
||||
case ORBIS_CLOCK_SECOND:
|
||||
case ORBIS_CLOCK_REALTIME_FAST: {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
static constexpr u64 DeltaEpochIn100ns = 116444736000000000ULL;
|
||||
const u64 ns = FileTimeTo100Ns(ft) - DeltaEpochIn100ns;
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_UPTIME:
|
||||
case ORBIS_CLOCK_UPTIME_PRECISE:
|
||||
case ORBIS_CLOCK_MONOTONIC:
|
||||
case ORBIS_CLOCK_MONOTONIC_PRECISE:
|
||||
case ORBIS_CLOCK_UPTIME_FAST:
|
||||
case ORBIS_CLOCK_MONOTONIC_FAST: {
|
||||
static LARGE_INTEGER pf = [] {
|
||||
LARGE_INTEGER res{};
|
||||
QueryPerformanceFrequency(&pf);
|
||||
|
@ -141,43 +168,53 @@ static s32 clock_gettime(u32 clock_id, struct timespec* ts) {
|
|||
}();
|
||||
|
||||
LARGE_INTEGER pc{};
|
||||
QueryPerformanceCounter(&pc);
|
||||
if (!QueryPerformanceCounter(&pc)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
ts->tv_sec = pc.QuadPart / pf.QuadPart;
|
||||
ts->tv_nsec = ((pc.QuadPart % pf.QuadPart) * 1000'000'000) / pf.QuadPart;
|
||||
return 0;
|
||||
}
|
||||
case CLOCK_PROCESS_CPUTIME_ID: {
|
||||
case ORBIS_CLOCK_THREAD_CPUTIME_ID: {
|
||||
FILETIME ct, et, kt, ut;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
return EFAULT;
|
||||
if (!GetThreadTimes(GetCurrentThread(), &ct, &et, &kt, &ut)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
const u64 ns = FileTimeTo100Ns(ut) + FileTimeTo100Ns(kt);
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
return 0;
|
||||
}
|
||||
case CLOCK_THREAD_CPUTIME_ID: {
|
||||
case ORBIS_CLOCK_VIRTUAL: {
|
||||
FILETIME ct, et, kt, ut;
|
||||
if (!GetThreadTimes(GetCurrentThread(), &ct, &et, &kt, &ut)) {
|
||||
return EFAULT;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
const u64 ns = FileTimeTo100Ns(ut) + FileTimeTo100Ns(kt);
|
||||
const u64 ns = FileTimeTo100Ns(ut);
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_PROF: {
|
||||
FILETIME ct, et, kt, ut;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
const u64 ns = FileTimeTo100Ns(kt);
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return EINVAL;
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* ts) {
|
||||
if (ts == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
|
||||
clockid_t pclock_id = CLOCK_MONOTONIC;
|
||||
#else
|
||||
clockid_t pclock_id;
|
||||
switch (clock_id) {
|
||||
case ORBIS_CLOCK_REALTIME:
|
||||
case ORBIS_CLOCK_REALTIME_PRECISE:
|
||||
|
@ -185,7 +222,7 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
|
|||
break;
|
||||
case ORBIS_CLOCK_SECOND:
|
||||
case ORBIS_CLOCK_REALTIME_FAST:
|
||||
#ifndef __APPLE__
|
||||
#ifdef CLOCK_REALTIME_COARSE
|
||||
pclock_id = CLOCK_REALTIME_COARSE;
|
||||
#else
|
||||
pclock_id = CLOCK_REALTIME;
|
||||
|
@ -199,7 +236,7 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
|
|||
break;
|
||||
case ORBIS_CLOCK_UPTIME_FAST:
|
||||
case ORBIS_CLOCK_MONOTONIC_FAST:
|
||||
#ifndef __APPLE__
|
||||
#ifdef CLOCK_MONOTONIC_COARSE
|
||||
pclock_id = CLOCK_MONOTONIC_COARSE;
|
||||
#else
|
||||
pclock_id = CLOCK_MONOTONIC;
|
||||
|
@ -208,196 +245,226 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* t
|
|||
case ORBIS_CLOCK_THREAD_CPUTIME_ID:
|
||||
pclock_id = CLOCK_THREAD_CPUTIME_ID;
|
||||
break;
|
||||
case ORBIS_CLOCK_PROCTIME: {
|
||||
const auto us = sceKernelGetProcessTime();
|
||||
ts->tv_sec = us / 1'000'000;
|
||||
ts->tv_nsec = (us % 1'000'000) * 1000;
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_VIRTUAL: {
|
||||
#ifdef _WIN64
|
||||
FILETIME ct, et, kt, ut;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
return EFAULT;
|
||||
}
|
||||
const u64 ns = FileTimeTo100Ns(ut);
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
#else
|
||||
struct rusage ru;
|
||||
rusage ru;
|
||||
const auto res = getrusage(RUSAGE_SELF, &ru);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
ts->tv_sec = ru.ru_utime.tv_sec;
|
||||
ts->tv_nsec = ru.ru_utime.tv_usec * 1000;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_PROF: {
|
||||
#ifdef _WIN64
|
||||
FILETIME ct, et, kt, ut;
|
||||
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
|
||||
return EFAULT;
|
||||
}
|
||||
const u64 ns = FileTimeTo100Ns(kt);
|
||||
ts->tv_sec = ns / 10'000'000;
|
||||
ts->tv_nsec = (ns % 10'000'000) * 100;
|
||||
#else
|
||||
struct rusage ru;
|
||||
rusage ru;
|
||||
const auto res = getrusage(RUSAGE_SELF, &ru);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
ts->tv_sec = ru.ru_stime.tv_sec;
|
||||
ts->tv_nsec = ru.ru_stime.tv_usec * 1000;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_EXT_NETWORK:
|
||||
case ORBIS_CLOCK_EXT_DEBUG_NETWORK:
|
||||
case ORBIS_CLOCK_EXT_AD_NETWORK:
|
||||
case ORBIS_CLOCK_EXT_RAW_NETWORK:
|
||||
pclock_id = CLOCK_MONOTONIC;
|
||||
LOG_ERROR(Lib_Kernel, "unsupported = {} using CLOCK_MONOTONIC", clock_id);
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
timespec t{};
|
||||
int result = clock_gettime(pclock_id, &t);
|
||||
const auto result = clock_gettime(pclock_id, &t);
|
||||
ts->tv_sec = t.tv_sec;
|
||||
ts->tv_nsec = t.tv_nsec;
|
||||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp) {
|
||||
const auto res = orbis_clock_gettime(clock_id, tp);
|
||||
if (res < 0) {
|
||||
return ErrnoToSceKernelError(res);
|
||||
if (result < 0) {
|
||||
SetPosixErrno(errno);
|
||||
return -1;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_nanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
|
||||
const auto* request = reinterpret_cast<const timespec*>(rqtp);
|
||||
auto* remain = reinterpret_cast<timespec*>(rmtp);
|
||||
return nanosleep(request, remain);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelNanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
|
||||
if (!rqtp || !rmtp) {
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
|
||||
if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0) {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
return posix_nanosleep(rqtp, rmtp);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) {
|
||||
if (!tp) {
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
FILETIME filetime;
|
||||
GetSystemTimePreciseAsFileTime(&filetime);
|
||||
|
||||
constexpr u64 UNIX_TIME_START = 0x295E9648864000;
|
||||
constexpr u64 TICKS_PER_SECOND = 1000000;
|
||||
|
||||
u64 ticks = filetime.dwHighDateTime;
|
||||
ticks <<= 32;
|
||||
ticks |= filetime.dwLowDateTime;
|
||||
ticks /= 10;
|
||||
ticks -= UNIX_TIME_START;
|
||||
|
||||
tp->tv_sec = ticks / TICKS_PER_SECOND;
|
||||
tp->tv_usec = ticks % TICKS_PER_SECOND;
|
||||
#else
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
tp->tv_sec = tv.tv_sec;
|
||||
tp->tv_usec = tv.tv_usec;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelClockGettime(const u32 clock_id, OrbisKernelTimespec* ts) {
|
||||
if (const auto ret = posix_clock_gettime(clock_id, ts); ret < 0) {
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) {
|
||||
// FreeBSD docs mention that the kernel generally does not track these values
|
||||
// and they are usually returned as zero.
|
||||
if (tz) {
|
||||
tz->tz_minuteswest = 0;
|
||||
tz->tz_dsttime = 0;
|
||||
}
|
||||
return sceKernelGettimeofday(tp);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
|
||||
#ifdef _WIN64
|
||||
ASSERT(tz);
|
||||
static int tzflag = 0;
|
||||
if (!tzflag) {
|
||||
_tzset();
|
||||
tzflag++;
|
||||
}
|
||||
tz->tz_minuteswest = _timezone / 60;
|
||||
tz->tz_dsttime = _daylight;
|
||||
#else
|
||||
struct timezone tzz;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, &tzz);
|
||||
tz->tz_dsttime = tzz.tz_dsttime;
|
||||
tz->tz_minuteswest = tzz.tz_minuteswest;
|
||||
#endif
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_clock_getres(u32 clock_id, OrbisKernelTimespec* res) {
|
||||
s32 PS4_SYSV_ABI posix_clock_getres(u32 clock_id, OrbisKernelTimespec* res) {
|
||||
if (res == nullptr) {
|
||||
return ORBIS_KERNEL_ERROR_EFAULT;
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
clockid_t pclock_id = CLOCK_REALTIME;
|
||||
|
||||
if (clock_id == ORBIS_CLOCK_EXT_NETWORK || clock_id == ORBIS_CLOCK_EXT_DEBUG_NETWORK ||
|
||||
clock_id == ORBIS_CLOCK_EXT_AD_NETWORK || clock_id == ORBIS_CLOCK_EXT_RAW_NETWORK) {
|
||||
LOG_ERROR(Lib_Kernel, "Unsupported clock type {}, using CLOCK_MONOTONIC", clock_id);
|
||||
clock_id = ORBIS_CLOCK_MONOTONIC;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
switch (clock_id) {
|
||||
case ORBIS_CLOCK_SECOND:
|
||||
case ORBIS_CLOCK_REALTIME_FAST: {
|
||||
DWORD timeAdjustment;
|
||||
DWORD timeIncrement;
|
||||
BOOL isTimeAdjustmentDisabled;
|
||||
if (!GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
res->tv_sec = 0;
|
||||
res->tv_nsec = timeIncrement * 100;
|
||||
return 0;
|
||||
}
|
||||
case ORBIS_CLOCK_REALTIME:
|
||||
case ORBIS_CLOCK_REALTIME_PRECISE:
|
||||
case ORBIS_CLOCK_UPTIME:
|
||||
case ORBIS_CLOCK_UPTIME_PRECISE:
|
||||
case ORBIS_CLOCK_MONOTONIC:
|
||||
case ORBIS_CLOCK_MONOTONIC_PRECISE:
|
||||
case ORBIS_CLOCK_UPTIME_FAST:
|
||||
case ORBIS_CLOCK_MONOTONIC_FAST: {
|
||||
LARGE_INTEGER pf;
|
||||
if (!QueryPerformanceFrequency(&pf)) {
|
||||
SetPosixErrno(EFAULT);
|
||||
return -1;
|
||||
}
|
||||
res->tv_sec = 0;
|
||||
res->tv_nsec =
|
||||
std::max(static_cast<s32>((1000000000 + (pf.QuadPart >> 1)) / pf.QuadPart), 1);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#else
|
||||
clockid_t pclock_id;
|
||||
switch (clock_id) {
|
||||
case ORBIS_CLOCK_REALTIME:
|
||||
case ORBIS_CLOCK_REALTIME_PRECISE:
|
||||
case ORBIS_CLOCK_REALTIME_FAST:
|
||||
pclock_id = CLOCK_REALTIME;
|
||||
break;
|
||||
case ORBIS_CLOCK_SECOND:
|
||||
case ORBIS_CLOCK_REALTIME_FAST:
|
||||
#ifdef CLOCK_REALTIME_COARSE
|
||||
pclock_id = CLOCK_REALTIME_COARSE;
|
||||
#else
|
||||
pclock_id = CLOCK_REALTIME;
|
||||
#endif
|
||||
break;
|
||||
case ORBIS_CLOCK_UPTIME:
|
||||
case ORBIS_CLOCK_UPTIME_PRECISE:
|
||||
case ORBIS_CLOCK_MONOTONIC:
|
||||
case ORBIS_CLOCK_MONOTONIC_PRECISE:
|
||||
case ORBIS_CLOCK_MONOTONIC_FAST:
|
||||
pclock_id = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case ORBIS_CLOCK_UPTIME_FAST:
|
||||
case ORBIS_CLOCK_MONOTONIC_FAST:
|
||||
#ifdef CLOCK_MONOTONIC_COARSE
|
||||
pclock_id = CLOCK_MONOTONIC_COARSE;
|
||||
#else
|
||||
pclock_id = CLOCK_MONOTONIC;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
timespec t{};
|
||||
int result = clock_getres(pclock_id, &t);
|
||||
const auto result = clock_getres(pclock_id, &t);
|
||||
res->tv_sec = t.tv_sec;
|
||||
res->tv_nsec = t.tv_nsec;
|
||||
if (result == 0) {
|
||||
return ORBIS_OK;
|
||||
if (result < 0) {
|
||||
SetPosixErrno(errno);
|
||||
return -1;
|
||||
}
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
|
||||
OrbisKernelTimezone* timezone, int* dst_seconds) {
|
||||
s32 PS4_SYSV_ABI sceKernelClockGetres(const u32 clock_id, OrbisKernelTimespec* res) {
|
||||
if (const auto ret = posix_clock_getres(clock_id, res); ret < 0) {
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI posix_gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) {
|
||||
#ifdef _WIN64
|
||||
if (tp) {
|
||||
FILETIME filetime;
|
||||
GetSystemTimePreciseAsFileTime(&filetime);
|
||||
|
||||
constexpr u64 UNIX_TIME_START = 0x295E9648864000;
|
||||
constexpr u64 TICKS_PER_SECOND = 1000000;
|
||||
|
||||
u64 ticks = filetime.dwHighDateTime;
|
||||
ticks <<= 32;
|
||||
ticks |= filetime.dwLowDateTime;
|
||||
ticks /= 10;
|
||||
ticks -= UNIX_TIME_START;
|
||||
|
||||
tp->tv_sec = ticks / TICKS_PER_SECOND;
|
||||
tp->tv_usec = ticks % TICKS_PER_SECOND;
|
||||
}
|
||||
if (tz) {
|
||||
static int tzflag = 0;
|
||||
if (!tzflag) {
|
||||
_tzset();
|
||||
tzflag++;
|
||||
}
|
||||
tz->tz_minuteswest = _timezone / 60;
|
||||
tz->tz_dsttime = _daylight;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
struct timezone tzz;
|
||||
timeval tv;
|
||||
const auto ret = gettimeofday(&tv, &tzz);
|
||||
if (tp) {
|
||||
tp->tv_sec = tv.tv_sec;
|
||||
tp->tv_usec = tv.tv_usec;
|
||||
}
|
||||
if (tz) {
|
||||
tz->tz_dsttime = tzz.tz_dsttime;
|
||||
tz->tz_minuteswest = tzz.tz_minuteswest;
|
||||
}
|
||||
if (ret < 0) {
|
||||
SetPosixErrno(errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelGettimeofday(OrbisKernelTimeval* tp) {
|
||||
if (const auto ret = posix_gettimeofday(tp, nullptr); ret < 0) {
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
|
||||
if (const auto ret = posix_gettimeofday(nullptr, tz); ret < 0) {
|
||||
return ErrnoToSceKernelError(*__Error());
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
|
||||
OrbisKernelTimezone* timezone, s32* dst_seconds) {
|
||||
LOG_INFO(Kernel, "called");
|
||||
if (timezone) {
|
||||
sceKernelGettimezone(timezone);
|
||||
param_1 -= (timezone->tz_minuteswest + timezone->tz_dsttime) * 60;
|
||||
if (seconds)
|
||||
if (seconds) {
|
||||
*seconds = param_1;
|
||||
if (dst_seconds)
|
||||
}
|
||||
if (dst_seconds) {
|
||||
*dst_seconds = timezone->tz_dsttime * 60;
|
||||
}
|
||||
} else {
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
@ -415,7 +482,7 @@ Common::NativeClock* GetClock() {
|
|||
|
||||
} // namespace Dev
|
||||
|
||||
int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time,
|
||||
s32 PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time,
|
||||
struct OrbisTimesec* st, u64* dst_sec) {
|
||||
LOG_TRACE(Kernel, "Called");
|
||||
#ifdef __APPLE__
|
||||
|
@ -444,28 +511,35 @@ int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time,
|
|||
void RegisterTime(Core::Loader::SymbolsResolver* sym) {
|
||||
clock = std::make_unique<Common::NativeClock>();
|
||||
initial_ptc = clock->GetUptime();
|
||||
|
||||
// POSIX
|
||||
LIB_FUNCTION("yS8U2TGCe1A", "libkernel", 1, "libkernel", 1, 1, posix_nanosleep);
|
||||
LIB_FUNCTION("yS8U2TGCe1A", "libScePosix", 1, "libkernel", 1, 1, posix_nanosleep);
|
||||
LIB_FUNCTION("QcteRwbsnV0", "libkernel", 1, "libkernel", 1, 1, posix_usleep);
|
||||
LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep);
|
||||
LIB_FUNCTION("0wu33hunNdE", "libkernel", 1, "libkernel", 1, 1, posix_sleep);
|
||||
LIB_FUNCTION("0wu33hunNdE", "libScePosix", 1, "libkernel", 1, 1, posix_sleep);
|
||||
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, posix_clock_gettime);
|
||||
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, posix_clock_gettime);
|
||||
LIB_FUNCTION("smIj7eqzZE8", "libkernel", 1, "libkernel", 1, 1, posix_clock_getres);
|
||||
LIB_FUNCTION("smIj7eqzZE8", "libScePosix", 1, "libkernel", 1, 1, posix_clock_getres);
|
||||
LIB_FUNCTION("n88vx3C5nW8", "libkernel", 1, "libkernel", 1, 1, posix_gettimeofday);
|
||||
LIB_FUNCTION("n88vx3C5nW8", "libScePosix", 1, "libkernel", 1, 1, posix_gettimeofday);
|
||||
|
||||
// Orbis
|
||||
LIB_FUNCTION("4J2sUJmuHZQ", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTime);
|
||||
LIB_FUNCTION("fgxnMeTNUtY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTimeCounter);
|
||||
LIB_FUNCTION("BNowx2l588E", "libkernel", 1, "libkernel", 1, 1,
|
||||
sceKernelGetProcessTimeCounterFrequency);
|
||||
LIB_FUNCTION("-2IRUCO--PM", "libkernel", 1, "libkernel", 1, 1, sceKernelReadTsc);
|
||||
LIB_FUNCTION("1j3S3n-tTW4", "libkernel", 1, "libkernel", 1, 1, sceKernelGetTscFrequency);
|
||||
LIB_FUNCTION("ejekcaNQNq0", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimeofday);
|
||||
LIB_FUNCTION("n88vx3C5nW8", "libkernel", 1, "libkernel", 1, 1, gettimeofday);
|
||||
LIB_FUNCTION("n88vx3C5nW8", "libScePosix", 1, "libkernel", 1, 1, gettimeofday);
|
||||
LIB_FUNCTION("QvsZxomvUHs", "libkernel", 1, "libkernel", 1, 1, sceKernelNanosleep);
|
||||
LIB_FUNCTION("1jfXLRVzisc", "libkernel", 1, "libkernel", 1, 1, sceKernelUsleep);
|
||||
LIB_FUNCTION("QcteRwbsnV0", "libkernel", 1, "libkernel", 1, 1, posix_usleep);
|
||||
LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep);
|
||||
LIB_FUNCTION("-ZR+hG7aDHw", "libkernel", 1, "libkernel", 1, 1, sceKernelSleep);
|
||||
LIB_FUNCTION("0wu33hunNdE", "libScePosix", 1, "libkernel", 1, 1, sceKernelSleep);
|
||||
LIB_FUNCTION("yS8U2TGCe1A", "libkernel", 1, "libkernel", 1, 1, posix_nanosleep);
|
||||
LIB_FUNCTION("yS8U2TGCe1A", "libScePosix", 1, "libkernel", 1, 1, posix_nanosleep);
|
||||
LIB_FUNCTION("QBi7HCK03hw", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGettime);
|
||||
LIB_FUNCTION("wRYVA5Zolso", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGetres);
|
||||
LIB_FUNCTION("ejekcaNQNq0", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimeofday);
|
||||
LIB_FUNCTION("kOcnerypnQA", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimezone);
|
||||
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, orbis_clock_gettime);
|
||||
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, orbis_clock_gettime);
|
||||
LIB_FUNCTION("smIj7eqzZE8", "libScePosix", 1, "libkernel", 1, 1, posix_clock_getres);
|
||||
LIB_FUNCTION("0NTHN1NKONI", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertLocaltimeToUtc);
|
||||
LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime);
|
||||
}
|
||||
|
|
|
@ -75,14 +75,14 @@ u64 PS4_SYSV_ABI sceKernelGetProcessTime();
|
|||
u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounter();
|
||||
u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounterFrequency();
|
||||
u64 PS4_SYSV_ABI sceKernelReadTsc();
|
||||
int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp);
|
||||
s32 PS4_SYSV_ABI sceKernelClockGettime(u32 clock_id, OrbisKernelTimespec* tp);
|
||||
s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz);
|
||||
int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
|
||||
OrbisKernelTimezone* timezone, int* dst_seconds);
|
||||
s32 PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
|
||||
OrbisKernelTimezone* timezone, s32* dst_seconds);
|
||||
|
||||
int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, OrbisTimesec* st,
|
||||
s32 PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, OrbisTimesec* st,
|
||||
u64* dst_sec);
|
||||
int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds);
|
||||
s32 PS4_SYSV_ABI sceKernelUsleep(u32 microseconds);
|
||||
|
||||
void RegisterTime(Core::Loader::SymbolsResolver* sym);
|
||||
|
||||
|
|
|
@ -380,8 +380,7 @@ s32 PS4_SYSV_ABI sceNgs2GeomApply(const OrbisNgs2GeomListenerWork* listener,
|
|||
|
||||
s32 PS4_SYSV_ABI sceNgs2PanInit(OrbisNgs2PanWork* work, const float* aSpeakerAngle, float unitAngle,
|
||||
u32 numSpeakers) {
|
||||
LOG_ERROR(Lib_Ngs2, "aSpeakerAngle = {}, unitAngle = {}, numSpeakers = {}", *aSpeakerAngle,
|
||||
unitAngle, numSpeakers);
|
||||
LOG_ERROR(Lib_Ngs2, "unitAngle = {}, numSpeakers = {}", unitAngle, numSpeakers);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue