diff --git a/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs index 5fc37f8..c549505 100644 --- a/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs @@ -2531,6 +2531,17 @@ public static class KernelMemoryCompatExports if (fixedMapping && requestedAddress != 0) { mappedAddress = requestedAddress; + reserved = IsGuestRangeBacked(ctx, requestedAddress, length); + if (!reserved) + { + TryReserveExactGuestVirtualRange(ctx, requestedAddress, length, protection); + reserved = IsGuestRangeBacked(ctx, requestedAddress, length); + } + + if (!reserved) + { + mappedAddress = 0; + } } else { @@ -2541,7 +2552,7 @@ public static class KernelMemoryCompatExports 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 (!reserved && !fixedMapping) { if (mappedAddress == 0) { @@ -2625,12 +2636,18 @@ public static class KernelMemoryCompatExports if (fixedMapping && requestedAddress != 0) { mappedAddress = requestedAddress; + if (!IsGuestRangeBacked(ctx, requestedAddress, length)) + { + TryReserveExactGuestVirtualRange(ctx, requestedAddress, length, protection); + if (!IsGuestRangeBacked(ctx, requestedAddress, length)) + { + mappedAddress = 0; + } + } } else if (!TryReserveGuestVirtualRange(ctx, desiredAddress, length, protection, OrbisPageSize, out mappedAddress)) { - mappedAddress = requestedAddress != 0 && fixedMapping - ? requestedAddress - : AllocateMappedGuestAddress(ctx, length, 0x1000UL); + mappedAddress = AllocateMappedGuestAddress(ctx, length, 0x1000UL); } if (ShouldTraceDirectMemory()) @@ -3995,6 +4012,37 @@ public static class KernelMemoryCompatExports out mappedAddress); } + private static bool TryReserveExactGuestVirtualRange( + CpuContext ctx, + ulong desiredAddress, + ulong length, + int protection) + { + var executable = (protection & OrbisProtCpuExec) != 0; + return KernelVirtualRangeAllocator.TryReserve( + ctx, + desiredAddress, + length, + executable, + alignment: 0, + allowSearch: false, + allowAllocateAtAlternative: false, + "reserve fixed range", + out _); + } + + private static bool IsGuestRangeBacked(CpuContext ctx, ulong address, ulong length) + { + if (address == 0 || length == 0 || ulong.MaxValue - address < length - 1) + { + return false; + } + + Span probe = stackalloc byte[1]; + return ctx.Memory.TryRead(address, probe) && + ctx.Memory.TryRead(address + length - 1, probe); + } + private static bool IsMappedGuestRangeAvailable( CpuContext ctx, ulong address, diff --git a/src/SharpEmu.Libs/Kernel/KernelPthreadExtendedCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelPthreadExtendedCompatExports.cs index a798599..d16e371 100644 --- a/src/SharpEmu.Libs/Kernel/KernelPthreadExtendedCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelPthreadExtendedCompatExports.cs @@ -22,6 +22,7 @@ public static class KernelPthreadExtendedCompatExports private const int DefaultSchedPriority = DefaultThreadPriority; private const ulong SyntheticRwlockHandleBase = 0x00006003_0000_0000; private const ulong SyntheticPthreadAttrHandleBase = 0x00006004_0000_0000; + private const ulong SyntheticRwlockAttrHandleBase = 0x00006005_0000_0000; private static readonly object _stateGate = new(); private static readonly Dictionary _threadStates = new(); @@ -31,6 +32,7 @@ public static class KernelPthreadExtendedCompatExports private static int _nextTlsKey = 1; private static long _nextSyntheticRwlockHandleId = 1; private static long _nextSyntheticPthreadAttrHandleId = 1; + private static long _nextSyntheticRwlockAttrHandleId = 1; private static readonly ConcurrentDictionary> _threadLocalSpecific = new(); @@ -839,6 +841,37 @@ public static class KernelPthreadExtendedCompatExports return PthreadAttrSetstacksize(ctx); } + [SysAbiExport( + Nid = "Bvn74vj6oLo", + ExportName = "scePthreadAttrSetstack", + Target = Generation.Gen4 | Generation.Gen5, + LibraryName = "libKernel")] + public static int PthreadAttrSetstack(CpuContext ctx) + { + var attrAddress = ctx[CpuRegister.Rdi]; + var stackAddress = ctx[CpuRegister.Rsi]; + var stackSize = ctx[CpuRegister.Rdx]; + if (attrAddress == 0 || stackAddress == 0 || stackSize == 0) + { + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT; + } + + var resolvedAddress = ResolvePthreadAttrHandle(ctx, attrAddress); + lock (_stateGate) + { + var state = GetOrCreateAttrStateLocked(resolvedAddress); + var updated = state with { StackAddress = stackAddress, StackSize = stackSize }; + _attrStates[resolvedAddress] = updated; + if (resolvedAddress != attrAddress) + { + _attrStates[attrAddress] = updated; + } + } + + ctx[CpuRegister.Rax] = 0; + return (int)OrbisGen2Result.ORBIS_GEN2_OK; + } + [SysAbiExport( Nid = "6ULAa0fq4jA", ExportName = "scePthreadRwlockInit", @@ -1016,6 +1049,47 @@ public static class KernelPthreadExtendedCompatExports LibraryName = "libKernel")] public static int PosixPthreadRwlockUnlock(CpuContext ctx) => PthreadRwlockUnlock(ctx); + [SysAbiExport( + Nid = "yOfGg-I1ZII", + ExportName = "scePthreadRwlockattrInit", + Target = Generation.Gen4 | Generation.Gen5, + LibraryName = "libKernel")] + public static int PthreadRwlockattrInit(CpuContext ctx) + { + var attrAddress = ctx[CpuRegister.Rdi]; + if (attrAddress == 0) + { + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT; + } + + var syntheticHandle = AllocateSyntheticHandle(SyntheticRwlockAttrHandleBase, ref _nextSyntheticRwlockAttrHandleId); + if (!KernelMemoryCompatExports.TryWriteUInt64Compat(ctx, attrAddress, syntheticHandle)) + { + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; + } + + ctx[CpuRegister.Rax] = 0; + return (int)OrbisGen2Result.ORBIS_GEN2_OK; + } + + [SysAbiExport( + Nid = "i2ifZ3fS2fo", + ExportName = "scePthreadRwlockattrDestroy", + Target = Generation.Gen4 | Generation.Gen5, + LibraryName = "libKernel")] + public static int PthreadRwlockattrDestroy(CpuContext ctx) + { + var attrAddress = ctx[CpuRegister.Rdi]; + if (attrAddress == 0) + { + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT; + } + + _ = KernelMemoryCompatExports.TryWriteUInt64Compat(ctx, attrAddress, 0); + ctx[CpuRegister.Rax] = 0; + return (int)OrbisGen2Result.ORBIS_GEN2_OK; + } + [SysAbiExport( Nid = "mqULNdimTn0", ExportName = "pthread_key_create", @@ -1045,7 +1119,7 @@ public static class KernelPthreadExtendedCompatExports return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; } - ctx[CpuRegister.Rax] = unchecked((uint)key); + ctx[CpuRegister.Rax] = 0; return (int)OrbisGen2Result.ORBIS_GEN2_OK; }