mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-25 20:28:48 +08:00
cdee77521e
* [agc] WAIT_REG_MEM suspend/resume, draw packet fixes, new HLE exports, debug cleanup
Rebased onto upstream 79a7437 (par274/sharpemu, rewritten history).
- GpuWaitRegistry: DCBs suspended on unsatisfied WAIT_REG_MEM are re-polled
against guest memory on every submit; fixed 64-bit and standard packet parse
offsets, apply the mask, treat PM4 compare function 0 as "always".
- TryReadSubmittedDrawCount: accept the 5-dword ItDrawIndex2 form emitted by
DcbDrawIndex (count at +4); menu draws were silently discarded before.
- sceAgcDriverSubmitMultiDcbs: reversed ABI (rdi=address array, rsi=dword
sizes, rdx=count).
- VideoOut: vblank events, sceVideoOutGetFlipStatus, buffers registered via
sceVideoOutRegisterBuffers are valid flip targets.
- New HLE: libc stdio (fopen/fread/fseek/ftell/fclose/fgets), Dinkumware
_Getpctype ctype table, NpTrophy2 stubs, AMPR PAK sequential-read tracker,
MsgDialog lifecycle, NGS2 alt NIDs + dummy vtable for handle objects,
guarded memset intrinsic, abort()/strcasecmp null-arg recovery.
- Removed investigation-only code (INT3 breakpoints, qfont/mcpp dumps,
error-candidate printf traces, unconditional debug logs).
First rendered frame: Quake (PPSA01880) presents a 1920x1080 guest frame.
* Implemented a guarded native intrinsic (rep movsb) in DirectExecutionBackend to bypass HLE dispatch overhead, while preserving memory safety checks.
* [hle] clock_gettime clock ids, AudioOut2 canary fix, NID rebinds, new offline stubs
- clock_gettime (lLMT9vJAck0): support CLOCK_SECOND and the *_PRECISE/*_FAST
variants instead of returning EINVAL, which games treated as fatal and
retried in a tight loop.
- AudioOut2: context param writes shrunk to the guest-observed layout (the
old 0x80-byte reset smashed the stack canary at +0x60 and killed audio
init); ContextQueryMemory writes the single u64 the caller expects.
- NGS2: dropped wrong alt-NID aliases (they hash to sceImeUpdate,
sceMouseRead, sceSystemGestureUpdateAllTouchRecognizer - now bound in
their real libraries); added sceNgs2PanInit; fixed VoiceGetState NIDs.
- New verified stubs: sceUltInitialize, sceNpUniversalDataSystemDestroyHandle,
sceNpGetOnlineId, sceNpGetNpReachabilityState, sceImeKeyboardOpen,
sceImeKeyboardGetResourceId, sceMouseOpen, sceKernelAprGetFileSize.
- Import gateway: unwind guest workers at dispatch during backend teardown;
env-gated SHARPEMU_LOG_THREAD_MODE tracing.
* [cpu] Isolate guest execution on native worker threads
Guest entry stubs no longer run above CLR-managed frames: each run is handed
to a pooled raw OS thread whose loop is emitted native code. While guest code
executes there is not a single managed frame on the thread and it stays in
preemptive GC mode, so the GC never walks a frame chain interleaved with
guest stubs that carry no CLR unwind info (the ReversePInvokeBadTransition /
UnmanagedCallersOnly FailFast class of crashes on pumped guest threads).
- NativeGuestExecutor: CreateThread + emitted run loop (WaitForSingleObject,
UnmanagedCallersOnly prologue/epilogue, entry stub call, SetEvent). The
prologue rebinds guest TLS, the host-RSP slot, thread affinity and the
Active* ambient per run, so workers carry no guest identity and pool
freely; the orchestrating managed thread parks in a preemptive wait.
- All three entry sites route through RunGuestEntryStub: guest thread
entries, blocked-continuation resumes, and the main ExecuteEntry.
- Teardown stops workers before any executable stub or TLS index they
reference is freed; a worker that will not stop leaks its loop instead of
freeing running code.
- Kill switch: SHARPEMU_DISABLE_NATIVE_GUEST_WORKERS=1 restores the inline
calli path.
90 lines
3.2 KiB
C#
90 lines
3.2 KiB
C#
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
using SharpEmu.HLE;
|
|
using System.Buffers.Binary;
|
|
|
|
namespace SharpEmu.Libs.Np;
|
|
|
|
public static class NpUniversalDataSystemExports
|
|
{
|
|
private const int NpUniversalDataSystemErrorInvalidArgument = unchecked((int)0x80553102);
|
|
private static int _nextHandle = 1;
|
|
|
|
[SysAbiExport(
|
|
Nid = "sjaobBgqeB4",
|
|
ExportName = "sceNpUniversalDataSystemInitialize",
|
|
Target = Generation.Gen4 | Generation.Gen5,
|
|
LibraryName = "libSceNpUniversalDataSystem")]
|
|
public static int NpUniversalDataSystemInitialize(CpuContext ctx)
|
|
{
|
|
var parameterAddress = ctx[CpuRegister.Rdi];
|
|
if (parameterAddress == 0)
|
|
{
|
|
return ctx.SetReturn(NpUniversalDataSystemErrorInvalidArgument, typeof(long));
|
|
}
|
|
|
|
Span<byte> parameters = stackalloc byte[16];
|
|
return ctx.Memory.TryRead(parameterAddress, parameters)
|
|
? ctx.SetReturn(0, typeof(long))
|
|
: ctx.SetReturn((int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT, typeof(long));
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "5zBnau1uIEo",
|
|
ExportName = "sceNpUniversalDataSystemCreateContext",
|
|
Target = Generation.Gen4 | Generation.Gen5,
|
|
LibraryName = "libSceNpUniversalDataSystem")]
|
|
public static int NpUniversalDataSystemCreateContext(CpuContext ctx)
|
|
{
|
|
var contextAddress = ctx[CpuRegister.Rdi];
|
|
if (contextAddress == 0)
|
|
{
|
|
return ctx.SetReturn(0, typeof(long));
|
|
}
|
|
|
|
Span<byte> context = stackalloc byte[sizeof(int)];
|
|
BinaryPrimitives.WriteInt32LittleEndian(context, 1);
|
|
return ctx.Memory.TryWrite(contextAddress, context)
|
|
? ctx.SetReturn(0, typeof(long))
|
|
: ctx.SetReturn((int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT, typeof(long));
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "hT0IAEvN+M0",
|
|
ExportName = "sceNpUniversalDataSystemCreateHandle",
|
|
Target = Generation.Gen4 | Generation.Gen5,
|
|
LibraryName = "libSceNpUniversalDataSystem")]
|
|
public static int NpUniversalDataSystemCreateHandle(CpuContext ctx)
|
|
{
|
|
var handle = Interlocked.Increment(ref _nextHandle);
|
|
if (ctx.TryWriteInt32(ctx[CpuRegister.Rdi], handle, checkNil: true) ||
|
|
ctx.TryWriteInt32(ctx[CpuRegister.Rsi], handle, checkNil: true))
|
|
{
|
|
return ctx.SetReturn(0, typeof(long));
|
|
}
|
|
|
|
return ctx.SetReturn((int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT, typeof(long));
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "tpFJ8LIKvPw",
|
|
ExportName = "sceNpUniversalDataSystemRegisterContext",
|
|
Target = Generation.Gen4 | Generation.Gen5,
|
|
LibraryName = "libSceNpUniversalDataSystem")]
|
|
public static int NpUniversalDataSystemRegisterContext(CpuContext ctx)
|
|
{
|
|
return ctx.SetReturn(0, typeof(long));
|
|
}
|
|
|
|
[SysAbiExport(
|
|
Nid = "AUIHb7jUX3I",
|
|
ExportName = "sceNpUniversalDataSystemDestroyHandle",
|
|
Target = Generation.Gen4 | Generation.Gen5,
|
|
LibraryName = "libSceNpUniversalDataSystem")]
|
|
public static int NpUniversalDataSystemDestroyHandle(CpuContext ctx)
|
|
{
|
|
return ctx.SetReturn(0, typeof(long));
|
|
}
|
|
}
|