diff --git a/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs index 4835376..f884a59 100644 --- a/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs @@ -67,6 +67,13 @@ public static class KernelMemoryCompatExports private const int Einval = 22; private const int Erange = 34; private const int Struncate = 80; + private const int ClockRealtime = 0; + private const int ClockVirtual = 1; + private const int ClockProf = 2; + private const int ClockMonotonic = 4; + private const int ClockUptime = 5; + private const int ClockRealtimeFast = 10; + private const int ClockMonotonicFast = 12; private const nuint DefaultLibcHeapAlignment = 16; private const ushort KernelStatModeDirectory = 0x41FF; private const ushort KernelStatModeRegular = 0x81FF; @@ -1993,23 +2000,55 @@ public static class KernelMemoryCompatExports LibraryName = "libKernel")] public static int ClockGettime(CpuContext ctx) { + var clockId = unchecked((int)ctx[CpuRegister.Rdi]); var timespecAddress = ctx[CpuRegister.Rsi]; if (timespecAddress == 0) { - return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT; + KernelRuntimeCompatExports.TrySetErrno(ctx, Einval); + ctx[CpuRegister.Rax] = unchecked((ulong)-1); + return -1; } - var now = DateTimeOffset.UtcNow; - var seconds = now.ToUnixTimeSeconds(); - var nanoseconds = (now.Ticks % TimeSpan.TicksPerSecond) * 100; - if (!ctx.TryWriteUInt64(timespecAddress, unchecked((ulong)seconds)) || - !ctx.TryWriteUInt64(timespecAddress + sizeof(long), unchecked((ulong)nanoseconds))) + long seconds; + long nanoseconds; + switch (clockId) { - return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; + case ClockRealtime: + case ClockRealtimeFast: + case ClockVirtual: + case ClockProf: + { + var now = DateTimeOffset.UtcNow; + seconds = now.ToUnixTimeSeconds(); + nanoseconds = (now.Ticks % TimeSpan.TicksPerSecond) * 100; + break; + } + + case ClockMonotonic: + case ClockMonotonicFast: + case ClockUptime: + KernelRuntimeCompatExports.GetProcessMonotonicTime(out seconds, out nanoseconds); + break; + + default: + KernelRuntimeCompatExports.TrySetErrno(ctx, Einval); + ctx[CpuRegister.Rax] = unchecked((ulong)-1); + return -1; + } + + Span timespecBuffer = stackalloc byte[16]; + BinaryPrimitives.WriteInt64LittleEndian(timespecBuffer, seconds); + BinaryPrimitives.WriteInt64LittleEndian(timespecBuffer[sizeof(long)..], nanoseconds); + + if (!ctx.Memory.TryWrite(timespecAddress, timespecBuffer)) + { + KernelRuntimeCompatExports.TrySetErrno(ctx, Efault); + ctx[CpuRegister.Rax] = unchecked((ulong)-1); + return -1; } ctx[CpuRegister.Rax] = 0; - return (int)OrbisGen2Result.ORBIS_GEN2_OK; + return 0; } [SysAbiExport( diff --git a/src/SharpEmu.Libs/Kernel/KernelRuntimeCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelRuntimeCompatExports.cs index 0b6efaa..54ea069 100644 --- a/src/SharpEmu.Libs/Kernel/KernelRuntimeCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelRuntimeCompatExports.cs @@ -194,13 +194,14 @@ public static class KernelRuntimeCompatExports } else { - var elapsedTicks = Stopwatch.GetTimestamp() - _processStartCounter; - seconds = elapsedTicks / Stopwatch.Frequency; - nanoseconds = (elapsedTicks % Stopwatch.Frequency) * 1_000_000_000L / Stopwatch.Frequency; + GetProcessMonotonicTime(out seconds, out nanoseconds); } - if (!ctx.TryWriteUInt64(timeAddress, unchecked((ulong)seconds)) || - !ctx.TryWriteUInt64(timeAddress + sizeof(long), unchecked((ulong)nanoseconds))) + Span timespecBuffer = stackalloc byte[16]; + BinaryPrimitives.WriteInt64LittleEndian(timespecBuffer, seconds); + BinaryPrimitives.WriteInt64LittleEndian(timespecBuffer[sizeof(long)..], nanoseconds); + + if (!ctx.Memory.TryWrite(timeAddress, timespecBuffer)) { return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; } @@ -617,6 +618,13 @@ public static class KernelRuntimeCompatExports return address != 0 && ctx.TryWriteInt32(address, value); } + internal static void GetProcessMonotonicTime(out long seconds, out long nanoseconds) + { + var elapsedTicks = Stopwatch.GetTimestamp() - _processStartCounter; + seconds = elapsedTicks / Stopwatch.Frequency; + nanoseconds = (elapsedTicks % Stopwatch.Frequency) * 1_000_000_000L / Stopwatch.Frequency; + } + [SysAbiExport( Nid = "bnZxYgAFeA0", ExportName = "sceKernelGetSanitizerNewReplaceExternal", @@ -1713,7 +1721,7 @@ public static class KernelRuntimeCompatExports return null; } - Span stub = stackalloc byte[] + ReadOnlySpan stub = stackalloc byte[] { 0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, @@ -1721,7 +1729,14 @@ public static class KernelRuntimeCompatExports 0xC3, }; - Marshal.Copy(stub.ToArray(), 0, stubAddress, stub.Length); + unsafe + { + fixed (byte* src = stub) + { + Buffer.MemoryCopy(src, (void*)stubAddress, stub.Length, stub.Length); + } + } + return Marshal.GetDelegateForFunctionPointer(stubAddress); } catch