mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-02 07:59:44 +08:00
more HLE's and fix cpu execution some titles
This commit is contained in:
@@ -166,11 +166,18 @@ public static class KernelEventQueueCompatExports
|
||||
public static int KernelWaitEqueue(CpuContext ctx)
|
||||
{
|
||||
var outCountAddress = ctx[CpuRegister.Rcx];
|
||||
var timeoutAddress = ctx[CpuRegister.R8];
|
||||
if (outCountAddress != 0 && !TryWriteUInt32(ctx, outCountAddress, 0))
|
||||
{
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||
}
|
||||
|
||||
if (timeoutAddress == 0 && GuestThreadExecution.RequestCurrentThreadBlock("sceKernelWaitEqueue"))
|
||||
{
|
||||
TraceEventQueue(ctx, "wait-block", ctx[CpuRegister.Rdi]);
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
}
|
||||
|
||||
TraceEventQueue(ctx, "wait", ctx[CpuRegister.Rdi]);
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,10 @@ public static class KernelExports
|
||||
LibraryName = "libKernel")]
|
||||
public static int Exit(CpuContext ctx)
|
||||
{
|
||||
_ = ctx;
|
||||
var status = unchecked((int)ctx[CpuRegister.Rdi]);
|
||||
Console.Error.WriteLine($"[LOADER][INFO] exit(status={status})");
|
||||
GuestThreadExecution.RequestCurrentEntryExit("exit", status);
|
||||
ctx[CpuRegister.Rax] = unchecked((ulong)status);
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
}
|
||||
|
||||
@@ -68,7 +71,8 @@ public static class KernelExports
|
||||
{
|
||||
var status = unchecked((int)ctx[CpuRegister.Rdi]);
|
||||
Console.Error.WriteLine($"[LOADER][INFO] catchReturnFromMain(status={status})");
|
||||
ctx[CpuRegister.Rax] = 0;
|
||||
GuestThreadExecution.RequestCurrentEntryExit("catchReturnFromMain", status);
|
||||
ctx[CpuRegister.Rax] = unchecked((ulong)status);
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
}
|
||||
|
||||
@@ -211,6 +215,19 @@ public static class KernelExports
|
||||
$"[LOADER][TRACE] pthread_create: out=0x{threadIdAddress:X16} attr=0x{attrAddress:X16} entry=0x{entryAddress:X16} arg=0x{argument:X16} name_ptr=0x{nameAddress:X16} name='{name}' -> thread=0x{threadHandle:X16}");
|
||||
}
|
||||
|
||||
var scheduler = GuestThreadExecution.Scheduler;
|
||||
if (scheduler is not null && entryAddress != 0)
|
||||
{
|
||||
var request = new GuestThreadStartRequest(threadHandle, entryAddress, argument, attrAddress, name);
|
||||
if (!scheduler.TryStartThread(ctx, request, out var error))
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][ERROR] pthread_create: failed to schedule guest thread '{name}' entry=0x{entryAddress:X16}: {error}");
|
||||
ctx[CpuRegister.Rax] = unchecked((ulong)(int)OrbisGen2Result.ORBIS_GEN2_ERROR_TRY_AGAIN);
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_TRY_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
ctx[CpuRegister.Rax] = 0;
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
}
|
||||
@@ -225,6 +242,16 @@ public static class KernelExports
|
||||
return PthreadCreate(ctx);
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "Jmi+9w9u0E4",
|
||||
ExportName = "pthread_create_name_np",
|
||||
Target = Generation.Gen4 | Generation.Gen5,
|
||||
LibraryName = "libKernel")]
|
||||
public static int PosixPthreadCreateNameNp(CpuContext ctx)
|
||||
{
|
||||
return PthreadCreate(ctx);
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "onNY9Byn-W8",
|
||||
ExportName = "scePthreadJoin",
|
||||
|
||||
@@ -42,6 +42,7 @@ public static class KernelMemoryCompatExports
|
||||
private const int SeekCur = 1;
|
||||
private const int SeekEnd = 2;
|
||||
private const ulong DirectMemorySizeBytes = 16384UL * 1024 * 1024;
|
||||
private const ulong UnsetMainDirectMemoryPoolBase = ulong.MaxValue;
|
||||
private const ulong FlexibleMemorySizeBytes = 448UL * 1024 * 1024;
|
||||
private const int OrbisVirtualQueryInfoSize = 72;
|
||||
private const int OrbisKernelMaximumNameLength = 32;
|
||||
@@ -93,6 +94,7 @@ public static class KernelMemoryCompatExports
|
||||
private static long _nextFileDescriptor = 2;
|
||||
private static ulong _nextPhysicalAddress;
|
||||
private static ulong _nextVirtualAddress;
|
||||
private static ulong _mainDirectMemoryPoolBase = UnsetMainDirectMemoryPoolBase;
|
||||
private static ulong _allocatedFlexibleBytes;
|
||||
private static ulong _threadAtexitCountCallback;
|
||||
private static ulong _threadAtexitReportCallback;
|
||||
@@ -1298,10 +1300,12 @@ public static class KernelMemoryCompatExports
|
||||
var hostPath = ResolveGuestPath(guestPath);
|
||||
if (!TryGetAprFileSize(hostPath, out var fileSize))
|
||||
{
|
||||
LogIoTrace("apr_resolve", guestPath, $"host='{hostPath}' index={i} count={count} result=not_found");
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
var fileId = AmprFileRegistry.Register(guestPath, hostPath);
|
||||
LogIoTrace("apr_resolve", guestPath, $"host='{hostPath}' index={i} count={count} id=0x{fileId:X8} size={fileSize}");
|
||||
|
||||
if (idsAddress != 0 &&
|
||||
!TryWriteUInt32Compat(ctx, idsAddress + (i * sizeof(uint)), fileId))
|
||||
@@ -1309,7 +1313,7 @@ public static class KernelMemoryCompatExports
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||
}
|
||||
|
||||
if (!TryWriteUInt32Compat(ctx, sizesAddress + (i * sizeof(uint)), fileSize))
|
||||
if (!TryWriteUInt64Compat(ctx, sizesAddress + (i * sizeof(ulong)), fileSize))
|
||||
{
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||
}
|
||||
@@ -1835,7 +1839,7 @@ public static class KernelMemoryCompatExports
|
||||
ulong selectedAddress;
|
||||
lock (_memoryGate)
|
||||
{
|
||||
if (!TryAllocateDirectMemoryLocked(searchStart, searchEnd, length, align, memoryType, out selectedAddress))
|
||||
if (!TryAllocateDirectMemoryLocked(searchStart, searchEnd, length, align, memoryType, DirectMemorySizeBytes, out selectedAddress))
|
||||
{
|
||||
TraceDirectMemoryCall(
|
||||
ctx,
|
||||
@@ -1904,17 +1908,42 @@ public static class KernelMemoryCompatExports
|
||||
ulong aligned;
|
||||
lock (_memoryGate)
|
||||
{
|
||||
if (!TryAllocateDirectMemoryLocked(0, DirectMemorySizeBytes, length, effectiveAlignment, memoryType, out aligned))
|
||||
var allocationLimit = DirectMemorySizeBytes;
|
||||
if (_mainDirectMemoryPoolBase != UnsetMainDirectMemoryPoolBase &&
|
||||
!TryAddU64(_mainDirectMemoryPoolBase, DirectMemorySizeBytes, out allocationLimit))
|
||||
{
|
||||
TraceDirectMemoryCall(
|
||||
ctx,
|
||||
"allocate_main_direct",
|
||||
length,
|
||||
effectiveAlignment,
|
||||
memoryType,
|
||||
outAddress,
|
||||
result: OrbisGen2Result.ORBIS_GEN2_ERROR_TRY_AGAIN);
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_TRY_AGAIN;
|
||||
allocationLimit = ulong.MaxValue;
|
||||
}
|
||||
|
||||
if (!TryAllocateDirectMemoryLocked(0, allocationLimit, length, effectiveAlignment, memoryType, allocationLimit, out aligned))
|
||||
{
|
||||
var poolBase = _mainDirectMemoryPoolBase == UnsetMainDirectMemoryPoolBase
|
||||
? AlignUp(GetDirectMemoryHighWaterMarkLocked(), effectiveAlignment)
|
||||
: _mainDirectMemoryPoolBase;
|
||||
|
||||
if (_mainDirectMemoryPoolBase == UnsetMainDirectMemoryPoolBase &&
|
||||
TryAddU64(poolBase, DirectMemorySizeBytes, out var shiftedLimit) &&
|
||||
TryAllocateDirectMemoryLocked(0, shiftedLimit, length, effectiveAlignment, memoryType, shiftedLimit, out aligned))
|
||||
{
|
||||
_mainDirectMemoryPoolBase = poolBase;
|
||||
if (ShouldTraceDirectMemory())
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] main_direct_pool: base=0x{poolBase:X16} limit=0x{shiftedLimit:X16}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TraceDirectMemoryCall(
|
||||
ctx,
|
||||
"allocate_main_direct",
|
||||
length,
|
||||
effectiveAlignment,
|
||||
memoryType,
|
||||
outAddress,
|
||||
result: OrbisGen2Result.ORBIS_GEN2_ERROR_TRY_AGAIN);
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_TRY_AGAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1986,8 +2015,11 @@ public static class KernelMemoryCompatExports
|
||||
var flags = ctx[CpuRegister.Rcx];
|
||||
var directMemoryStart = ctx[CpuRegister.R8];
|
||||
var alignment = ctx[CpuRegister.R9];
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] map_direct: inout=0x{inOutAddressPointer:X16} len=0x{length:X16} prot=0x{protection:X8} flags=0x{flags:X16} direct=0x{directMemoryStart:X16} align=0x{alignment:X16}");
|
||||
if (ShouldTraceDirectMemory())
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] map_direct: inout=0x{inOutAddressPointer:X16} len=0x{length:X16} prot=0x{protection:X8} flags=0x{flags:X16} direct=0x{directMemoryStart:X16} align=0x{alignment:X16}");
|
||||
}
|
||||
if (inOutAddressPointer == 0 || length == 0)
|
||||
{
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||
@@ -2018,8 +2050,11 @@ public static class KernelMemoryCompatExports
|
||||
{
|
||||
reserved = TryReserveGuestVirtualRange(ctx, desiredAddress, length, protection, out mappedAddress);
|
||||
}
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] map_direct reserve: requested=0x{requestedAddress:X16} desired=0x{desiredAddress:X16} reserved={reserved} mapped=0x{mappedAddress:X16}");
|
||||
if (ShouldTraceDirectMemory())
|
||||
{
|
||||
Console.Error.WriteLine(
|
||||
$"[LOADER][TRACE] map_direct reserve: requested=0x{requestedAddress:X16} desired=0x{desiredAddress:X16} reserved={reserved} mapped=0x{mappedAddress:X16}");
|
||||
}
|
||||
if (!reserved)
|
||||
{
|
||||
if (mappedAddress == 0)
|
||||
@@ -2027,7 +2062,10 @@ public static class KernelMemoryCompatExports
|
||||
mappedAddress = requestedAddress != 0
|
||||
? requestedAddress
|
||||
: AllocateMappedGuestAddress(ctx, length, effectiveAlignment);
|
||||
Console.Error.WriteLine($"[LOADER][TRACE] map_direct fallback mapped=0x{mappedAddress:X16}");
|
||||
if (ShouldTraceDirectMemory())
|
||||
{
|
||||
Console.Error.WriteLine($"[LOADER][TRACE] map_direct fallback mapped=0x{mappedAddress:X16}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3560,6 +3598,12 @@ public static class KernelMemoryCompatExports
|
||||
var app0Root = Environment.GetEnvironmentVariable("SHARPEMU_APP0_DIR");
|
||||
if (!string.IsNullOrWhiteSpace(app0Root))
|
||||
{
|
||||
if (string.Equals(guestPath, "/app0", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(guestPath, "app0", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return app0Root;
|
||||
}
|
||||
|
||||
if (guestPath.StartsWith("/app0/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var relative = guestPath["/app0/".Length..].Replace('/', Path.DirectorySeparatorChar);
|
||||
@@ -3571,6 +3615,14 @@ public static class KernelMemoryCompatExports
|
||||
var relative = guestPath["app0/".Length..].Replace('/', Path.DirectorySeparatorChar);
|
||||
return Path.Combine(app0Root, relative);
|
||||
}
|
||||
|
||||
if (!Path.IsPathFullyQualified(guestPath) &&
|
||||
!guestPath.StartsWith("/", StringComparison.Ordinal) &&
|
||||
!guestPath.StartsWith("\\", StringComparison.Ordinal))
|
||||
{
|
||||
var relative = guestPath.Replace('/', Path.DirectorySeparatorChar);
|
||||
return Path.Combine(app0Root, relative);
|
||||
}
|
||||
}
|
||||
|
||||
return guestPath;
|
||||
@@ -4235,7 +4287,7 @@ public static class KernelMemoryCompatExports
|
||||
ulong selectedAddress = 0,
|
||||
OrbisGen2Result? result = null)
|
||||
{
|
||||
if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_DIRECT_MEMORY"), "1", StringComparison.Ordinal))
|
||||
if (!ShouldTraceDirectMemory())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -4251,12 +4303,18 @@ public static class KernelMemoryCompatExports
|
||||
$"[LOADER][TRACE] {operation}: ret=0x{returnRip:X16} len=0x{length:X16} align=0x{alignment:X16} type=0x{memoryType:X8} out=0x{outAddress:X16} selected=0x{selectedAddress:X16} result={result?.ToString() ?? "<pending>"}");
|
||||
}
|
||||
|
||||
private static bool ShouldTraceDirectMemory()
|
||||
{
|
||||
return string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_DIRECT_MEMORY"), "1", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static bool TryAllocateDirectMemoryLocked(
|
||||
ulong searchStart,
|
||||
ulong searchEnd,
|
||||
ulong length,
|
||||
ulong alignment,
|
||||
int memoryType,
|
||||
ulong allocationLimit,
|
||||
out ulong selectedAddress)
|
||||
{
|
||||
selectedAddress = 0;
|
||||
@@ -4266,7 +4324,7 @@ public static class KernelMemoryCompatExports
|
||||
}
|
||||
|
||||
var effectiveAlignment = alignment == 0 ? 0x1000UL : alignment;
|
||||
if (!TryFindAllocatableDirectMemoryRangeLocked(searchStart, searchEnd, length, effectiveAlignment, out var freePosition) ||
|
||||
if (!TryFindAllocatableDirectMemoryRangeLocked(searchStart, searchEnd, length, effectiveAlignment, allocationLimit, out var freePosition) ||
|
||||
!TryAddU64(freePosition, length, out var endAddress))
|
||||
{
|
||||
return false;
|
||||
@@ -4283,6 +4341,7 @@ public static class KernelMemoryCompatExports
|
||||
ulong searchEnd,
|
||||
ulong length,
|
||||
ulong alignment,
|
||||
ulong allocationLimit,
|
||||
out ulong selectedAddress)
|
||||
{
|
||||
selectedAddress = 0;
|
||||
@@ -4291,7 +4350,7 @@ public static class KernelMemoryCompatExports
|
||||
return false;
|
||||
}
|
||||
|
||||
var effectiveEnd = Math.Min(searchEnd, DirectMemorySizeBytes);
|
||||
var effectiveEnd = Math.Min(searchEnd, allocationLimit);
|
||||
var candidate = AlignUp(searchStart, alignment);
|
||||
if (candidate >= effectiveEnd)
|
||||
{
|
||||
@@ -4411,7 +4470,7 @@ public static class KernelMemoryCompatExports
|
||||
{
|
||||
if (!TryAddU64(allocation.Start, allocation.Length, out var endAddress))
|
||||
{
|
||||
return DirectMemorySizeBytes;
|
||||
return ulong.MaxValue;
|
||||
}
|
||||
|
||||
if (endAddress > highWaterMark)
|
||||
@@ -4420,7 +4479,7 @@ public static class KernelMemoryCompatExports
|
||||
}
|
||||
}
|
||||
|
||||
return Math.Min(highWaterMark, DirectMemorySizeBytes);
|
||||
return highWaterMark;
|
||||
}
|
||||
|
||||
private static bool TryReadHostMemory(ulong address, Span<byte> destination)
|
||||
@@ -4817,7 +4876,7 @@ public static class KernelMemoryCompatExports
|
||||
return TryWriteHostPathStat(ctx, statAddress, hostPath, isDirectory);
|
||||
}
|
||||
|
||||
private static bool TryGetAprFileSize(string hostPath, out uint size)
|
||||
private static bool TryGetAprFileSize(string hostPath, out ulong size)
|
||||
{
|
||||
size = 0;
|
||||
try
|
||||
@@ -4834,7 +4893,7 @@ public static class KernelMemoryCompatExports
|
||||
}
|
||||
|
||||
var length = new FileInfo(hostPath).Length;
|
||||
size = length >= uint.MaxValue ? uint.MaxValue : (uint)length;
|
||||
size = length < 0 ? 0UL : unchecked((ulong)length);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
|
||||
@@ -18,6 +18,7 @@ public static class KernelPthreadCompatExports
|
||||
private const ulong SyntheticMutexHandleBase = 0x00006000_0000_0000;
|
||||
private const ulong SyntheticMutexAttrHandleBase = 0x00006001_0000_0000;
|
||||
private const ulong SyntheticCondHandleBase = 0x00006002_0000_0000;
|
||||
private const int DefaultSpuriousCondWakeMilliseconds = 1;
|
||||
|
||||
private static readonly object _stateGate = new();
|
||||
private static readonly Dictionary<ulong, PthreadMutexState> _mutexStates = new();
|
||||
@@ -887,6 +888,7 @@ public static class KernelPthreadCompatExports
|
||||
}
|
||||
|
||||
var waitResult = (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
var spuriousWake = false;
|
||||
lock (state.SyncRoot)
|
||||
{
|
||||
state.Waiters++;
|
||||
@@ -901,11 +903,36 @@ public static class KernelPthreadCompatExports
|
||||
return unlockResult;
|
||||
}
|
||||
|
||||
var scheduler = GuestThreadExecution.Scheduler;
|
||||
if (!timed && GuestThreadExecution.RequestCurrentThreadBlock("pthread_cond_wait"))
|
||||
{
|
||||
TracePthreadCond("wait-block", condAddress, mutexAddress, state, timed, waitResult);
|
||||
return waitResult;
|
||||
}
|
||||
|
||||
if (scheduler is not null)
|
||||
{
|
||||
Monitor.Exit(state.SyncRoot);
|
||||
try
|
||||
{
|
||||
scheduler.Pump(ctx, "pthread_cond_wait");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Enter(state.SyncRoot);
|
||||
}
|
||||
}
|
||||
|
||||
while (state.SignalEpoch == observedEpoch)
|
||||
{
|
||||
if (!timed)
|
||||
{
|
||||
Monitor.Wait(state.SyncRoot);
|
||||
if (!Monitor.Wait(state.SyncRoot, GetCondSpuriousWakeTimeout()))
|
||||
{
|
||||
spuriousWake = true;
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -917,7 +944,15 @@ public static class KernelPthreadCompatExports
|
||||
}
|
||||
|
||||
state.Waiters = Math.Max(0, state.Waiters - 1);
|
||||
TracePthreadCond(waitResult == (int)OrbisGen2Result.ORBIS_GEN2_OK ? "wait-wake" : "wait-timeout", condAddress, mutexAddress, state, timed, waitResult);
|
||||
TracePthreadCond(
|
||||
spuriousWake
|
||||
? "wait-spurious"
|
||||
: (waitResult == (int)OrbisGen2Result.ORBIS_GEN2_OK ? "wait-wake" : "wait-timeout"),
|
||||
condAddress,
|
||||
mutexAddress,
|
||||
state,
|
||||
timed,
|
||||
waitResult);
|
||||
}
|
||||
|
||||
var lockResult = PthreadMutexLockCore(ctx, mutexAddress, tryOnly: false);
|
||||
@@ -927,7 +962,15 @@ public static class KernelPthreadCompatExports
|
||||
return lockResult;
|
||||
}
|
||||
|
||||
TracePthreadCond(waitResult == (int)OrbisGen2Result.ORBIS_GEN2_OK ? "wait-exit" : "wait-exit-timeout", condAddress, mutexAddress, state, timed, waitResult);
|
||||
TracePthreadCond(
|
||||
spuriousWake
|
||||
? "wait-exit-spurious"
|
||||
: (waitResult == (int)OrbisGen2Result.ORBIS_GEN2_OK ? "wait-exit" : "wait-exit-timeout"),
|
||||
condAddress,
|
||||
mutexAddress,
|
||||
state,
|
||||
timed,
|
||||
waitResult);
|
||||
return waitResult;
|
||||
}
|
||||
|
||||
@@ -974,6 +1017,16 @@ public static class KernelPthreadCompatExports
|
||||
return TimeSpan.FromTicks((long)timeoutUsec * 10L);
|
||||
}
|
||||
|
||||
private static TimeSpan GetCondSpuriousWakeTimeout()
|
||||
{
|
||||
if (int.TryParse(Environment.GetEnvironmentVariable("SHARPEMU_PTHREAD_COND_SPURIOUS_WAKE_MS"), out var milliseconds))
|
||||
{
|
||||
return TimeSpan.FromMilliseconds(Math.Max(1, milliseconds));
|
||||
}
|
||||
|
||||
return TimeSpan.FromMilliseconds(DefaultSpuriousCondWakeMilliseconds);
|
||||
}
|
||||
|
||||
private static int NormalizeMutexType(int type)
|
||||
{
|
||||
return type switch
|
||||
|
||||
@@ -20,6 +20,7 @@ public static class KernelPthreadExtendedCompatExports
|
||||
private const int DefaultSchedPolicy = 0;
|
||||
private const int DefaultSchedPriority = 0;
|
||||
private const ulong SyntheticRwlockHandleBase = 0x00006003_0000_0000;
|
||||
private const ulong SyntheticPthreadAttrHandleBase = 0x00006004_0000_0000;
|
||||
|
||||
private static readonly object _stateGate = new();
|
||||
private static readonly Dictionary<ulong, ThreadState> _threadStates = new();
|
||||
@@ -28,6 +29,7 @@ public static class KernelPthreadExtendedCompatExports
|
||||
private static readonly Dictionary<int, TlsKeyState> _tlsKeys = new();
|
||||
private static int _nextTlsKey = 1;
|
||||
private static long _nextSyntheticRwlockHandleId = 1;
|
||||
private static long _nextSyntheticPthreadAttrHandleId = 1;
|
||||
|
||||
private static readonly Dictionary<ulong, Dictionary<int, ulong>> _threadLocalSpecific = new();
|
||||
|
||||
@@ -235,6 +237,41 @@ public static class KernelPthreadExtendedCompatExports
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "Xs9hdiD7sAA",
|
||||
ExportName = "pthread_setschedparam",
|
||||
Target = Generation.Gen4 | Generation.Gen5,
|
||||
LibraryName = "libKernel")]
|
||||
public static int PosixPthreadSetschedparam(CpuContext ctx)
|
||||
{
|
||||
var thread = ctx[CpuRegister.Rdi];
|
||||
var policy = unchecked((int)ctx[CpuRegister.Rsi]);
|
||||
var schedParamAddress = ctx[CpuRegister.Rdx];
|
||||
if (thread == 0 || schedParamAddress == 0)
|
||||
{
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!TryReadInt32(ctx, schedParamAddress, out var schedPriority))
|
||||
{
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||
}
|
||||
|
||||
lock (_stateGate)
|
||||
{
|
||||
var state = GetOrCreateThreadStateLocked(thread);
|
||||
state.Priority = schedPriority;
|
||||
state.Attributes = state.Attributes with
|
||||
{
|
||||
SchedPolicy = policy,
|
||||
SchedPriority = schedPriority,
|
||||
};
|
||||
}
|
||||
|
||||
ctx[CpuRegister.Rax] = 0;
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "nsYoNRywwNg",
|
||||
ExportName = "scePthreadAttrInit",
|
||||
@@ -248,15 +285,32 @@ public static class KernelPthreadExtendedCompatExports
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
var syntheticHandle = AllocateSyntheticHandle(SyntheticPthreadAttrHandleBase, ref _nextSyntheticPthreadAttrHandleId);
|
||||
if (!ctx.TryWriteUInt64(attrAddress, syntheticHandle))
|
||||
{
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||
}
|
||||
|
||||
lock (_stateGate)
|
||||
{
|
||||
_attrStates[attrAddress] = PthreadAttrState.Default;
|
||||
_attrStates[syntheticHandle] = PthreadAttrState.Default;
|
||||
}
|
||||
|
||||
ctx[CpuRegister.Rax] = 0;
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "wtkt-teR1so",
|
||||
ExportName = "pthread_attr_init",
|
||||
Target = Generation.Gen4 | Generation.Gen5,
|
||||
LibraryName = "libKernel")]
|
||||
public static int PosixPthreadAttrInit(CpuContext ctx)
|
||||
{
|
||||
return PthreadAttrInit(ctx);
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "62KCwEMmzcM",
|
||||
ExportName = "scePthreadAttrDestroy",
|
||||
@@ -270,15 +324,31 @@ public static class KernelPthreadExtendedCompatExports
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
var resolvedAddress = ResolvePthreadAttrHandle(ctx, attrAddress);
|
||||
lock (_stateGate)
|
||||
{
|
||||
_attrStates.Remove(attrAddress);
|
||||
if (resolvedAddress != attrAddress)
|
||||
{
|
||||
_attrStates.Remove(resolvedAddress);
|
||||
}
|
||||
}
|
||||
|
||||
_ = ctx.TryWriteUInt64(attrAddress, 0);
|
||||
ctx[CpuRegister.Rax] = 0;
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "zHchY8ft5pk",
|
||||
ExportName = "pthread_attr_destroy",
|
||||
Target = Generation.Gen4 | Generation.Gen5,
|
||||
LibraryName = "libKernel")]
|
||||
public static int PosixPthreadAttrDestroy(CpuContext ctx)
|
||||
{
|
||||
return PthreadAttrDestroy(ctx);
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "x1X76arYMxU",
|
||||
ExportName = "scePthreadAttrGet",
|
||||
@@ -611,16 +681,32 @@ public static class KernelPthreadExtendedCompatExports
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
var resolvedAddress = ResolvePthreadAttrHandle(ctx, attrAddress);
|
||||
lock (_stateGate)
|
||||
{
|
||||
var state = GetOrCreateAttrStateLocked(attrAddress);
|
||||
_attrStates[attrAddress] = state with { StackSize = stackSize };
|
||||
var state = GetOrCreateAttrStateLocked(resolvedAddress);
|
||||
var updated = state with { StackSize = stackSize };
|
||||
_attrStates[resolvedAddress] = updated;
|
||||
if (resolvedAddress != attrAddress)
|
||||
{
|
||||
_attrStates[attrAddress] = updated;
|
||||
}
|
||||
}
|
||||
|
||||
ctx[CpuRegister.Rax] = 0;
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "2Q0z6rnBrTE",
|
||||
ExportName = "pthread_attr_setstacksize",
|
||||
Target = Generation.Gen4 | Generation.Gen5,
|
||||
LibraryName = "libKernel")]
|
||||
public static int PosixPthreadAttrSetstacksize(CpuContext ctx)
|
||||
{
|
||||
return PthreadAttrSetstacksize(ctx);
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "6ULAa0fq4jA",
|
||||
ExportName = "scePthreadRwlockInit",
|
||||
@@ -1131,6 +1217,35 @@ public static class KernelPthreadExtendedCompatExports
|
||||
return state;
|
||||
}
|
||||
|
||||
private static ulong ResolvePthreadAttrHandle(CpuContext ctx, ulong attrAddress)
|
||||
{
|
||||
if (attrAddress == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock (_stateGate)
|
||||
{
|
||||
if (_attrStates.ContainsKey(attrAddress))
|
||||
{
|
||||
return attrAddress;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.TryReadUInt64(attrAddress, out var pointedHandle) && pointedHandle != 0)
|
||||
{
|
||||
lock (_stateGate)
|
||||
{
|
||||
if (_attrStates.ContainsKey(pointedHandle))
|
||||
{
|
||||
return pointedHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attrAddress;
|
||||
}
|
||||
|
||||
private static bool TryWriteFixedUtf8CString(CpuContext ctx, ulong address, string value, int maxBytes)
|
||||
{
|
||||
if (maxBytes <= 0)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using SharpEmu.HLE;
|
||||
|
||||
namespace SharpEmu.Libs.Kernel;
|
||||
|
||||
@@ -25,12 +26,24 @@ internal static class KernelPthreadState
|
||||
|
||||
internal static ulong GetCurrentThreadHandle()
|
||||
{
|
||||
var guestThreadHandle = GuestThreadExecution.CurrentGuestThreadHandle;
|
||||
if (guestThreadHandle != 0 && TryGetThreadIdentity(guestThreadHandle, out _))
|
||||
{
|
||||
return guestThreadHandle;
|
||||
}
|
||||
|
||||
EnsureCurrentThreadRegistered();
|
||||
return _currentThreadHandle;
|
||||
}
|
||||
|
||||
internal static ulong GetCurrentThreadUniqueId()
|
||||
{
|
||||
var guestThreadHandle = GuestThreadExecution.CurrentGuestThreadHandle;
|
||||
if (guestThreadHandle != 0 && TryGetThreadIdentity(guestThreadHandle, out var identity))
|
||||
{
|
||||
return identity.UniqueId;
|
||||
}
|
||||
|
||||
EnsureCurrentThreadRegistered();
|
||||
return _currentThreadUniqueId;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user