mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-21 10:26:14 +08:00
Astro Bot shader type 4, pthread_cond_timedwait, and HLE/memory/cpu bug fixes (#40)
* [agc] Add shader type 4 (GS) and register defaults v13 support Astro Bot (#11) crashes on boot due to two missing GPU features: 1. Shader type 4 (Geometry Shader) — SPI_SHADER_PGM_LO/HI register offsets 0x8A/0x8B were missing. Added constants and switch cases for shader type 4 in GetExpectedSpiShaderPgmLo/Hi. Also added type 4 to IsEsGeometryShaderType (2 or 4 or 6). 2. Register defaults version 13 — was not recognized as supported. Added RegisterDefaultsVersion13 constant and included it in IsSupportedRegisterDefaultsVersion. * [kernel] Add POSIX pthread_cond_timedwait export SILENT HILL (#4) and Poppy Playtime (#3) crash on boot due to missing POSIX pthread_cond_timedwait (NID 27bAgiJmOh0). The Sony wrapper scePthreadCondTimedwait (NID BmMjYxmew1w) was already implemented, but the raw POSIX symbol was not exported. Added [SysAbiExport] for pthread_cond_timedwait delegating to existing PthreadCondWaitCore with timed: true. * [memory] Fix FlushInstructionCache null process handle PhysicalVirtualMemory.cs called FlushInstructionCache with null as the process handle in two places (SetProtection and TryWriteExclusive). On Windows, a null handle does not reliably resolve to the current process — the correct call is GetCurrentProcess() (pseudo-handle -1). Also corrected the P/Invoke signature: - Changed return type from void to bool with [return: MarshalAs(Bool)] - Added SetLastError = true - Added GetCurrentProcess() P/Invoke import This matches the pattern already used in DirectExecutionBackend.cs which correctly passes GetCurrentProcess() to all FlushInstructionCache calls. * [hle] Distinguish NOT_FOUND from NOT_IMPLEMENTED and log duplicate NIDs Three diagnostic improvements to the HLE dispatch path: 1. ModuleManager.RegisterFromAssembly — duplicate NID registration was silently skipped (dispatchTable first-wins, exportTable last-wins, causing metadata divergence). Now logs a warning with the NID and export name so conflicts are visible. 2. ModuleManager.TryDispatch — generation mismatch returned ORBIS_GEN2_ERROR_NOT_FOUND, conflating 'function does not exist' with 'function exists but not for this generation'. Now returns ORBIS_GEN2_ERROR_NOT_IMPLEMENTED for generation mismatch, matching the existing convention in CpuDispatcher. Also adds debug logging for both NOT_FOUND and NOT_IMPLEMENTED paths. 3. DirectExecutionBackend.Imports.cs — the import dispatch else-branch (the actual hot path that bypasses ModuleManager.TyDispatch via cached export) had the same conflation. Split into: - else if (export exists but generation mismatch) → NOT_IMPLEMENTED - else (no export at all) → NOT_FOUND This makes runtime diagnostics correctly distinguish missing exports from generation-unsupported exports. * [cpu] Check VirtualProtect return values in all stub creation paths 9 VirtualProtect calls in DirectExecutionBackend.cs had unchecked return values. If VirtualProtect silently fails, memory protection remains incorrect — stubs allocated with PAGE_EXECUTE_READWRITE (0x40) never get downgraded to PAGE_EXECUTE_READ (0x20), or guest thread entry stubs never get upgraded to writable. This causes access violations on next execution or silent data corruption. Fixed all 9 sites with proper error handling: - 6 stub creation methods (return 0 on failure + log error) - 2 guest thread entry methods (set reason + return Exception) - 1 guest entry method (set LastError + return MEMORY_FAULT) Stub creation sites fixed: - CreateImportDispatchStub (line ~1683) - EnsureTlsHandler (void, log + return) - CreateUnresolvedReturnStub (return 0) - CreateGuestReturnStub (return 0) - CreateExceptionHandlerTrampoline (return 0) - CreateTlsStoreHelperStub (return 0) Guest thread entry sites fixed: - StartGuestThreadNativeCall (return Exception) - StartGuestContinuationNativeCall (return Exception) - RunGuestEntryPoint (return MEMORY_FAULT) * [kernel] Remove unused duplicate _nextFileDescriptor field KernelExports.cs declared _nextFileDescriptor but never used it. The actual field used for file descriptor allocation lives in KernelMemoryCompatExports.cs (lines 1314, 1337). This was a dead duplicate causing CS0414 warning. Build is now 0 errors, 0 warnings. --------- Co-authored-by: Hermes Atlas <hermesatlas@example.com>
This commit is contained in:
@@ -358,12 +358,21 @@ public sealed partial class DirectExecutionBackend
|
|||||||
}
|
}
|
||||||
orbisGen2Result = (OrbisGen2Result)returnValue;
|
orbisGen2Result = (OrbisGen2Result)returnValue;
|
||||||
}
|
}
|
||||||
else
|
else if (importStubEntry.Export is { } mismatchedExport)
|
||||||
{
|
{
|
||||||
dispatchResolved = false;
|
dispatchResolved = true;
|
||||||
orbisGen2Result = OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
|
orbisGen2Result = OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_IMPLEMENTED;
|
||||||
cpuContext[CpuRegister.Rax] = unchecked((ulong)(int)orbisGen2Result);
|
cpuContext[CpuRegister.Rax] = unchecked((ulong)(int)orbisGen2Result);
|
||||||
}
|
Console.Error.WriteLine(
|
||||||
|
$"[LOADER][WARN] Import#{num} not implemented for generation {cpuContext.TargetGeneration}: " +
|
||||||
|
$"nid={importStubEntry.Nid} targets={mismatchedExport.Target} ret=0x{num7:X16}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dispatchResolved = false;
|
||||||
|
orbisGen2Result = OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
|
||||||
|
cpuContext[CpuRegister.Rax] = unchecked((ulong)(int)orbisGen2Result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1679,10 +1679,14 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
ptr2[num++] = 65;
|
ptr2[num++] = 65;
|
||||||
ptr2[num++] = 95;
|
ptr2[num++] = 95;
|
||||||
ptr2[num++] = 195;
|
ptr2[num++] = 195;
|
||||||
uint num2 = default(uint);
|
uint num2 = default(uint);
|
||||||
VirtualProtect(ptr, 192u, 32u, &num2);
|
if (!VirtualProtect(ptr, 192u, 32u, &num2))
|
||||||
FlushInstructionCache(GetCurrentProcess(), ptr, 192u);
|
{
|
||||||
return (nint)ptr;
|
Console.Error.WriteLine($"[LOADER][ERROR] VirtualProtect failed for import dispatch stub at 0x{(nint)ptr:X16}");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), ptr, 192u);
|
||||||
|
return (nint)ptr;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -1763,7 +1767,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
tlsHandlerAddress[num++] = 195;
|
tlsHandlerAddress[num++] = 195;
|
||||||
_tlsPatchStubOffset = (num + 15) & ~15;
|
_tlsPatchStubOffset = (num + 15) & ~15;
|
||||||
uint num2 = default(uint);
|
uint num2 = default(uint);
|
||||||
VirtualProtect((void*)_tlsHandlerAddress, TlsHandlerRegionSize, 32u, &num2);
|
if (!VirtualProtect((void*)_tlsHandlerAddress, TlsHandlerRegionSize, 32u, &num2))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"[LOADER][ERROR] VirtualProtect failed for TLS handler at 0x{_tlsHandlerAddress:X16}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
FlushInstructionCache(GetCurrentProcess(), (void*)_tlsHandlerAddress, TlsHandlerRegionSize);
|
FlushInstructionCache(GetCurrentProcess(), (void*)_tlsHandlerAddress, TlsHandlerRegionSize);
|
||||||
Console.Error.WriteLine($"[LOADER][INFO] TLS handler at 0x{_tlsHandlerAddress:X16}");
|
Console.Error.WriteLine($"[LOADER][INFO] TLS handler at 0x{_tlsHandlerAddress:X16}");
|
||||||
}
|
}
|
||||||
@@ -1784,7 +1792,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
ptr2[i] = 144;
|
ptr2[i] = 144;
|
||||||
}
|
}
|
||||||
uint num = default(uint);
|
uint num = default(uint);
|
||||||
VirtualProtect(ptr, 4096u, 32u, &num);
|
if (!VirtualProtect(ptr, 4096u, 32u, &num))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"[LOADER][ERROR] VirtualProtect failed for unresolved return stub at 0x{(nint)ptr:X16}");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
FlushInstructionCache(GetCurrentProcess(), ptr, 16u);
|
FlushInstructionCache(GetCurrentProcess(), ptr, 16u);
|
||||||
return (nint)ptr;
|
return (nint)ptr;
|
||||||
}
|
}
|
||||||
@@ -1831,7 +1843,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
EmitByte(code, ref offset, 0xC3);
|
EmitByte(code, ref offset, 0xC3);
|
||||||
|
|
||||||
uint oldProtect = default;
|
uint oldProtect = default;
|
||||||
VirtualProtect(ptr, stubSize, 32u, &oldProtect);
|
if (!VirtualProtect(ptr, stubSize, 32u, &oldProtect))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"[LOADER][ERROR] VirtualProtect failed for guest return stub at 0x{(nint)ptr:X16}");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
FlushInstructionCache(GetCurrentProcess(), ptr, (nuint)offset);
|
FlushInstructionCache(GetCurrentProcess(), ptr, (nuint)offset);
|
||||||
return (nint)ptr;
|
return (nint)ptr;
|
||||||
}
|
}
|
||||||
@@ -1923,7 +1939,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
*(int*)(code + guestRestoreJump) = restoreOffset - (guestRestoreJump + sizeof(int));
|
*(int*)(code + guestRestoreJump) = restoreOffset - (guestRestoreJump + sizeof(int));
|
||||||
|
|
||||||
uint oldProtect = default;
|
uint oldProtect = default;
|
||||||
VirtualProtect(ptr, stubSize, 32u, &oldProtect);
|
if (!VirtualProtect(ptr, stubSize, 32u, &oldProtect))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"[LOADER][ERROR] VirtualProtect failed for exception handler trampoline at 0x{(nint)ptr:X16}");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
FlushInstructionCache(GetCurrentProcess(), ptr, (nuint)offset);
|
FlushInstructionCache(GetCurrentProcess(), ptr, (nuint)offset);
|
||||||
return (nint)ptr;
|
return (nint)ptr;
|
||||||
}
|
}
|
||||||
@@ -2254,7 +2274,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
ptr[num2++] = 144;
|
ptr[num2++] = 144;
|
||||||
}
|
}
|
||||||
uint flNewProtect = default(uint);
|
uint flNewProtect = default(uint);
|
||||||
VirtualProtect((void*)num, 32u, 32u, &flNewProtect);
|
if (!VirtualProtect((void*)num, 32u, 32u, &flNewProtect))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"[LOADER][ERROR] VirtualProtect failed for TLS store helper at 0x{num:X16}");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
FlushInstructionCache(GetCurrentProcess(), (void*)num, 32u);
|
FlushInstructionCache(GetCurrentProcess(), (void*)num, 32u);
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
@@ -3591,7 +3615,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
return GuestNativeCallExitReason.Exception;
|
return GuestNativeCallExitReason.Exception;
|
||||||
}
|
}
|
||||||
uint oldProtect = default(uint);
|
uint oldProtect = default(uint);
|
||||||
VirtualProtect(ptr, stubSize, 64u, &oldProtect);
|
if (!VirtualProtect(ptr, stubSize, 64u, &oldProtect))
|
||||||
|
{
|
||||||
|
reason = $"VirtualProtect failed for guest thread entry stub at 0x{(nint)ptr:X16}";
|
||||||
|
return GuestNativeCallExitReason.Exception;
|
||||||
|
}
|
||||||
FlushInstructionCache(GetCurrentProcess(), ptr, stubSize);
|
FlushInstructionCache(GetCurrentProcess(), ptr, stubSize);
|
||||||
TlsSetValue(_hostRspSlotTlsIndex, (nint)hostRspSlot);
|
TlsSetValue(_hostRspSlotTlsIndex, (nint)hostRspSlot);
|
||||||
ActiveGuestThreadYieldRequested = false;
|
ActiveGuestThreadYieldRequested = false;
|
||||||
@@ -3728,7 +3756,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
return GuestNativeCallExitReason.Exception;
|
return GuestNativeCallExitReason.Exception;
|
||||||
}
|
}
|
||||||
uint oldProtect = default(uint);
|
uint oldProtect = default(uint);
|
||||||
VirtualProtect(ptr, stubSize, 64u, &oldProtect);
|
if (!VirtualProtect(ptr, stubSize, 64u, &oldProtect))
|
||||||
|
{
|
||||||
|
reason = $"VirtualProtect failed for guest continuation stub at 0x{(nint)ptr:X16}";
|
||||||
|
return GuestNativeCallExitReason.Exception;
|
||||||
|
}
|
||||||
FlushInstructionCache(GetCurrentProcess(), ptr, stubSize);
|
FlushInstructionCache(GetCurrentProcess(), ptr, stubSize);
|
||||||
TlsSetValue(_hostRspSlotTlsIndex, (nint)hostRspSlot);
|
TlsSetValue(_hostRspSlotTlsIndex, (nint)hostRspSlot);
|
||||||
ActiveGuestThreadYieldRequested = false;
|
ActiveGuestThreadYieldRequested = false;
|
||||||
@@ -3988,7 +4020,12 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint num5 = default(uint);
|
uint num5 = default(uint);
|
||||||
VirtualProtect(ptr, stubSize, 64u, &num5);
|
if (!VirtualProtect(ptr, stubSize, 64u, &num5))
|
||||||
|
{
|
||||||
|
LastError = $"VirtualProtect failed for guest entry stub at 0x{(nint)ptr:X16}";
|
||||||
|
result = OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
FlushInstructionCache(GetCurrentProcess(), ptr, stubSize);
|
FlushInstructionCache(GetCurrentProcess(), ptr, stubSize);
|
||||||
if (_hostRspSlotStorage != 0)
|
if (_hostRspSlotStorage != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -55,7 +55,11 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA
|
|||||||
private static extern nuint VirtualQuery(void* lpAddress, out MemoryBasicInformation64 lpBuffer, nuint dwLength);
|
private static extern nuint VirtualQuery(void* lpAddress, out MemoryBasicInformation64 lpBuffer, nuint dwLength);
|
||||||
|
|
||||||
[DllImport("kernel32.dll")]
|
[DllImport("kernel32.dll")]
|
||||||
private static extern void FlushInstructionCache(void* hProcess, void* lpBaseAddress, nuint dwSize);
|
private static extern void* GetCurrentProcess();
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
private static extern bool FlushInstructionCache(void* hProcess, void* lpBaseAddress, nuint dwSize);
|
||||||
|
|
||||||
public bool TryAllocateAtExact(ulong desiredAddress, ulong size, bool executable, out ulong actualAddress)
|
public bool TryAllocateAtExact(ulong desiredAddress, ulong size, bool executable, out ulong actualAddress)
|
||||||
{
|
{
|
||||||
@@ -451,7 +455,7 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA
|
|||||||
|
|
||||||
if ((flags & ProgramHeaderFlags.Execute) != 0)
|
if ((flags & ProgramHeaderFlags.Execute) != 0)
|
||||||
{
|
{
|
||||||
FlushInstructionCache(null, (void*)address, (nuint)size);
|
FlushInstructionCache(GetCurrentProcess(), (void*)address, (nuint)size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -699,7 +703,7 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IGuestMemoryA
|
|||||||
VirtualProtect(destPtr, (nuint)source.Length, oldProtect, out _);
|
VirtualProtect(destPtr, (nuint)source.Length, oldProtect, out _);
|
||||||
if (IsExecutableProtection(oldProtect))
|
if (IsExecutableProtection(oldProtect))
|
||||||
{
|
{
|
||||||
FlushInstructionCache(null, destPtr, (nuint)source.Length);
|
FlushInstructionCache(GetCurrentProcess(), destPtr, (nuint)source.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ public sealed class ModuleManager : IModuleManager
|
|||||||
var handler = CreateHandler(type, method, instances);
|
var handler = CreateHandler(type, method, instances);
|
||||||
if (!_dispatchTable.TryAdd(exportInfo.Value.Nid, handler))
|
if (!_dispatchTable.TryAdd(exportInfo.Value.Nid, handler))
|
||||||
{
|
{
|
||||||
|
Console.Error.WriteLine($"[HLE] Duplicate NID '{exportInfo.Value.Nid}' ({exportInfo.Value.ExportName}) — already registered, skipping.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +106,7 @@ public sealed class ModuleManager : IModuleManager
|
|||||||
|
|
||||||
if (!_dispatchTable.TryGetValue(nid, out var function) || !_exportTable.TryGetValue(nid, out var export))
|
if (!_dispatchTable.TryGetValue(nid, out var function) || !_exportTable.TryGetValue(nid, out var export))
|
||||||
{
|
{
|
||||||
|
Console.Error.WriteLine($"[HLE] NID '{nid}' not found in dispatch table.");
|
||||||
context[CpuRegister.Rax] = unchecked((ulong)(int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND);
|
context[CpuRegister.Rax] = unchecked((ulong)(int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND);
|
||||||
result = OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
|
result = OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
|
||||||
return false;
|
return false;
|
||||||
@@ -112,11 +114,13 @@ public sealed class ModuleManager : IModuleManager
|
|||||||
|
|
||||||
if ((export.Target & context.TargetGeneration) == 0)
|
if ((export.Target & context.TargetGeneration) == 0)
|
||||||
{
|
{
|
||||||
context[CpuRegister.Rax] = unchecked((ulong)(int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND);
|
Console.Error.WriteLine($"[HLE] NID '{nid}' ({export.Name}) found but not implemented for generation {context.TargetGeneration} (targets: {export.Target}).");
|
||||||
result = OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
|
context[CpuRegister.Rax] = unchecked((ulong)(int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_IMPLEMENTED);
|
||||||
|
result = OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_IMPLEMENTED;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
context.ClearRaxWriteFlag();
|
context.ClearRaxWriteFlag();
|
||||||
int ret = ((SysAbiFunction)function).Invoke(context);
|
int ret = ((SysAbiFunction)function).Invoke(context);
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ public static class AgcExports
|
|||||||
private const uint SpiShaderPgmHiEs = 0xC9;
|
private const uint SpiShaderPgmHiEs = 0xC9;
|
||||||
private const uint SpiShaderPgmLoLs = 0x148;
|
private const uint SpiShaderPgmLoLs = 0x148;
|
||||||
private const uint SpiShaderPgmHiLs = 0x149;
|
private const uint SpiShaderPgmHiLs = 0x149;
|
||||||
|
private const uint SpiShaderPgmLoGs = 0x8A;
|
||||||
|
private const uint SpiShaderPgmHiGs = 0x8B;
|
||||||
private const uint SpiPsInputEna = 0x1B3;
|
private const uint SpiPsInputEna = 0x1B3;
|
||||||
private const uint SpiPsInputAddr = 0x1B4;
|
private const uint SpiPsInputAddr = 0x1B4;
|
||||||
private const uint ComputePgmLo = 0x20C;
|
private const uint ComputePgmLo = 0x20C;
|
||||||
@@ -115,6 +117,7 @@ public static class AgcExports
|
|||||||
private const uint RegisterDefaultsVersion7 = 7;
|
private const uint RegisterDefaultsVersion7 = 7;
|
||||||
private const uint RegisterDefaultsVersion8 = 8;
|
private const uint RegisterDefaultsVersion8 = 8;
|
||||||
private const uint RegisterDefaultsVersion10 = 10;
|
private const uint RegisterDefaultsVersion10 = 10;
|
||||||
|
private const uint RegisterDefaultsVersion13 = 13;
|
||||||
private const int RegisterDefaultsSize = 0x40;
|
private const int RegisterDefaultsSize = 0x40;
|
||||||
private const int RegisterDefaultBlockSize = 16 * 8;
|
private const int RegisterDefaultBlockSize = 16 * 8;
|
||||||
|
|
||||||
@@ -5081,6 +5084,7 @@ public static class AgcExports
|
|||||||
0 => ComputePgmLo,
|
0 => ComputePgmLo,
|
||||||
1 => SpiShaderPgmLoPs,
|
1 => SpiShaderPgmLoPs,
|
||||||
2 or 6 => SpiShaderPgmLoEs,
|
2 or 6 => SpiShaderPgmLoEs,
|
||||||
|
4 => SpiShaderPgmLoGs,
|
||||||
7 => SpiShaderPgmLoLs,
|
7 => SpiShaderPgmLoLs,
|
||||||
_ => 0u,
|
_ => 0u,
|
||||||
};
|
};
|
||||||
@@ -5089,6 +5093,7 @@ public static class AgcExports
|
|||||||
0 => ComputePgmHi,
|
0 => ComputePgmHi,
|
||||||
1 => SpiShaderPgmHiPs,
|
1 => SpiShaderPgmHiPs,
|
||||||
2 or 6 => SpiShaderPgmHiEs,
|
2 or 6 => SpiShaderPgmHiEs,
|
||||||
|
4 => SpiShaderPgmHiGs,
|
||||||
7 => SpiShaderPgmHiLs,
|
7 => SpiShaderPgmHiLs,
|
||||||
_ => 0u,
|
_ => 0u,
|
||||||
};
|
};
|
||||||
@@ -5105,7 +5110,7 @@ public static class AgcExports
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsEsGeometryShaderType(byte shaderType) =>
|
private static bool IsEsGeometryShaderType(byte shaderType) =>
|
||||||
shaderType is 2 or 6;
|
shaderType is 2 or 4 or 6;
|
||||||
|
|
||||||
private static int SetIndirectPatchAddress(CpuContext ctx, string registerSpace)
|
private static int SetIndirectPatchAddress(CpuContext ctx, string registerSpace)
|
||||||
{
|
{
|
||||||
@@ -5252,7 +5257,8 @@ public static class AgcExports
|
|||||||
return version is
|
return version is
|
||||||
RegisterDefaultsVersion7 or
|
RegisterDefaultsVersion7 or
|
||||||
RegisterDefaultsVersion8 or
|
RegisterDefaultsVersion8 or
|
||||||
RegisterDefaultsVersion10;
|
RegisterDefaultsVersion10 or
|
||||||
|
RegisterDefaultsVersion13;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryGetRegisterDefaultsAllocation(
|
private static bool TryGetRegisterDefaultsAllocation(
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ namespace SharpEmu.Libs.Kernel;
|
|||||||
|
|
||||||
public static class KernelExports
|
public static class KernelExports
|
||||||
{
|
{
|
||||||
private static int _nextFileDescriptor = 2;
|
|
||||||
private static readonly object _cxaGate = new();
|
private static readonly object _cxaGate = new();
|
||||||
private static readonly List<CxaDestructorEntry> _cxaDestructors = new();
|
private static readonly List<CxaDestructorEntry> _cxaDestructors = new();
|
||||||
private static readonly object _coredumpGate = new();
|
private static readonly object _coredumpGate = new();
|
||||||
|
|||||||
@@ -329,6 +329,12 @@ public static class KernelPthreadCompatExports
|
|||||||
Target = Generation.Gen4 | Generation.Gen5,
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
LibraryName = "libKernel")]
|
LibraryName = "libKernel")]
|
||||||
public static int PosixPthreadCondSignal(CpuContext ctx) => PthreadCondSignalCore(ctx, ctx[CpuRegister.Rdi], broadcast: false);
|
public static int PosixPthreadCondSignal(CpuContext ctx) => PthreadCondSignalCore(ctx, ctx[CpuRegister.Rdi], broadcast: false);
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "27bAgiJmOh0",
|
||||||
|
ExportName = "pthread_cond_timedwait",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libKernel")]
|
||||||
|
public static int PosixPthreadCondTimedwait(CpuContext ctx) => PthreadCondWaitCore(ctx, ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi], timed: true, timeoutUsec: unchecked((uint)ctx[CpuRegister.Rdx]));
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "m5-2bsNfv7s",
|
Nid = "m5-2bsNfv7s",
|
||||||
|
|||||||
Reference in New Issue
Block a user