diff --git a/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs index 2e45594..d82b7ed 100644 --- a/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs @@ -2327,6 +2327,37 @@ public static partial class KernelMemoryCompatExports return (int)OrbisGen2Result.ORBIS_GEN2_OK; } + [SysAbiExport( + Nid = "smIj7eqzZE8", + ExportName = "clock_getres", + Target = Generation.Gen4 | Generation.Gen5, + LibraryName = "libKernel")] + public static int ClockGetres(CpuContext ctx) + { + var timespecAddress = ctx[CpuRegister.Rsi]; + + // POSIX allows a null resolution pointer: the call then only validates + // the clock id, which every id a title passes here does. + if (timespecAddress == 0) + { + ctx[CpuRegister.Rax] = 0; + return (int)OrbisGen2Result.ORBIS_GEN2_OK; + } + + // clock_gettime above is backed by DateTimeOffset.UtcNow, whose tick is + // 100 ns, so that is the honest resolution to report rather than the 1 ns + // a caller might otherwise assume it can rely on. + const ulong ResolutionNanoseconds = 100; + if (!ctx.TryWriteUInt64(timespecAddress, 0) || + !ctx.TryWriteUInt64(timespecAddress + sizeof(long), ResolutionNanoseconds)) + { + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; + } + + ctx[CpuRegister.Rax] = 0; + return (int)OrbisGen2Result.ORBIS_GEN2_OK; + } + [SysAbiExport( Nid = "vNe1w4diLCs", ExportName = "__tls_get_addr", diff --git a/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs index cd2c92c..5b4e43c 100644 --- a/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs @@ -578,6 +578,19 @@ public static class KernelPthreadCompatExports return SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_OK); } + /// + /// The POSIX-named alias of . libKernel exports the + /// same routine under two NIDs, and shipped middleware links the plain name: + /// DOOM's libcohtml, PlayFab and party modules all import this one rather + /// than scePthreadOnce. + /// + [SysAbiExport( + Nid = "Z4QosVuAsA0", + ExportName = "pthread_once", + Target = Generation.Gen4 | Generation.Gen5, + LibraryName = "libKernel")] + public static int PthreadOncePOSIX(CpuContext ctx) => PthreadOnce(ctx); + private static int PthreadMutexInitCore(CpuContext ctx, ulong mutexAddress, ulong attrAddress) { if (mutexAddress == 0)