mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-18 17:06:12 +08:00
Add sceKernelNanosleep to libKernel (#72)
Implements the sceKernelNanosleep export (NID QvsZxomvUHs) for both Gen4 and Gen5 targets. Reads the requested timespec from guest memory, validates the pointer and tv_nsec range, sleeps for the requested duration, and zeroes the optional remaining-time struct on completion. Also fixes: reading rqtp as a guest pointer to a timespec (tv_sec/tv_nsec int64 pair) instead of raw register values, and keeps the optimized sceKernelUsleep short-sleep path untouched. Co-authored-by: par274 <par274@users.noreply.github.com>
This commit is contained in:
@@ -24,6 +24,7 @@ public static class KernelRuntimeCompatExports
|
|||||||
internal const int ClockRealtimeFast = 10;
|
internal const int ClockRealtimeFast = 10;
|
||||||
internal const int ClockMonotonicFast = 12;
|
internal const int ClockMonotonicFast = 12;
|
||||||
private const int Efault = 14;
|
private const int Efault = 14;
|
||||||
|
private const int Einval = 22;
|
||||||
private const ulong TlsErrnoOffset = 0x40;
|
private const ulong TlsErrnoOffset = 0x40;
|
||||||
private const ulong TlsStackChkGuardBaseOffset = 0x800;
|
private const ulong TlsStackChkGuardBaseOffset = 0x800;
|
||||||
private const ulong StackChkGuardFieldOffset = 0x10;
|
private const ulong StackChkGuardFieldOffset = 0x10;
|
||||||
@@ -74,6 +75,77 @@ public static class KernelRuntimeCompatExports
|
|||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
private delegate ulong RdtscDelegate();
|
private delegate ulong RdtscDelegate();
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "QvsZxomvUHs",
|
||||||
|
ExportName = "sceKernelNanosleep",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libKernel")]
|
||||||
|
public static int KernelNanosleep(CpuContext ctx)
|
||||||
|
{
|
||||||
|
var requestAddress = ctx[CpuRegister.Rdi];
|
||||||
|
var remainAddress = ctx[CpuRegister.Rsi];
|
||||||
|
|
||||||
|
if (requestAddress == 0)
|
||||||
|
{
|
||||||
|
ctx[CpuRegister.Rax] = Einval;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<byte> timespecBuffer = stackalloc byte[16];
|
||||||
|
if (!ctx.Memory.TryRead(requestAddress, timespecBuffer))
|
||||||
|
{
|
||||||
|
ctx[CpuRegister.Rax] = Efault;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tvSec = BinaryPrimitives.ReadInt64LittleEndian(timespecBuffer);
|
||||||
|
var tvNsec = BinaryPrimitives.ReadInt64LittleEndian(timespecBuffer[sizeof(long)..]);
|
||||||
|
|
||||||
|
if (tvSec < 0 || tvNsec < 0 || tvNsec >= 1_000_000_000L)
|
||||||
|
{
|
||||||
|
ctx[CpuRegister.Rax] = Einval;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tvSec == 0 && tvNsec == 0)
|
||||||
|
{
|
||||||
|
WriteRemainingTime(ctx, remainAddress, 0, 0);
|
||||||
|
ctx[CpuRegister.Rax] = 0;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
GuestThreadExecution.Scheduler?.Pump(ctx, "sceKernelNanosleep");
|
||||||
|
|
||||||
|
// TimeSpan resolution is 100 ns ticks, so sub-100 ns requests round up to
|
||||||
|
// a single tick rather than collapsing to a zero-length (no-op) sleep.
|
||||||
|
var totalTicks = tvSec * TimeSpan.TicksPerSecond + Math.Max(tvNsec / 100L, 1L);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.Sleep(TimeSpan.FromTicks(totalTicks));
|
||||||
|
}
|
||||||
|
catch (ArgumentOutOfRangeException)
|
||||||
|
{
|
||||||
|
Thread.Sleep(TimeSpan.FromMilliseconds(int.MaxValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteRemainingTime(ctx, remainAddress, 0, 0);
|
||||||
|
ctx[CpuRegister.Rax] = 0;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteRemainingTime(CpuContext ctx, ulong remainAddress, long seconds, long nanoseconds)
|
||||||
|
{
|
||||||
|
if (remainAddress == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<byte> remainBuffer = stackalloc byte[16];
|
||||||
|
BinaryPrimitives.WriteInt64LittleEndian(remainBuffer, seconds);
|
||||||
|
BinaryPrimitives.WriteInt64LittleEndian(remainBuffer[sizeof(long)..], nanoseconds);
|
||||||
|
ctx.Memory.TryWrite(remainAddress, remainBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "1jfXLRVzisc",
|
Nid = "1jfXLRVzisc",
|
||||||
ExportName = "sceKernelUsleep",
|
ExportName = "sceKernelUsleep",
|
||||||
|
|||||||
Reference in New Issue
Block a user