[hle] Add missing service exports

This commit is contained in:
ParantezTech
2026-06-21 23:18:55 +03:00
parent 5512da9e12
commit 5afa5e1ffa
10 changed files with 591 additions and 0 deletions
@@ -0,0 +1,38 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System.Threading;
using SharpEmu.HLE;
namespace SharpEmu.Libs.CommonDialog;
public static class CommonDialogExports
{
private const int AlreadySystemInitialized = unchecked((int)0x80B80002);
private static int _initialized;
[SysAbiExport(
Nid = "uoUpLGNkygk",
ExportName = "sceCommonDialogInitialize",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceCommonDialog")]
public static int CommonDialogInitialize(CpuContext ctx)
{
var result = Interlocked.Exchange(ref _initialized, 1) == 0
? 0
: AlreadySystemInitialized;
ctx[CpuRegister.Rax] = unchecked((ulong)result);
return result;
}
[SysAbiExport(
Nid = "BQ3tey0JmQM",
ExportName = "sceCommonDialogIsUsed",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceCommonDialog")]
public static int CommonDialogIsUsed(CpuContext ctx)
{
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
}
@@ -0,0 +1,24 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System.Threading;
using SharpEmu.HLE;
namespace SharpEmu.Libs.GameUpdate;
public static class GameUpdateExports
{
private static int _initialized;
[SysAbiExport(
Nid = "YJtKLttI9fM",
ExportName = "sceGameUpdateInitialize",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceGameUpdate")]
public static int GameUpdateInitialize(CpuContext ctx)
{
Interlocked.Exchange(ref _initialized, 1);
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
}
+91
View File
@@ -0,0 +1,91 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System;
using SharpEmu.HLE;
namespace SharpEmu.Libs.Json;
public static class JsonExports
{
[SysAbiExport(
Nid = "-hJRce8wn1U",
ExportName = "_ZN3sce4Json12MemAllocatorC2Ev",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceJson")]
public static int MemAllocatorConstructor(CpuContext ctx)
{
var thisAddress = ctx[CpuRegister.Rdi];
TraceJson("MemAllocator.ctor", thisAddress, 0);
ctx[CpuRegister.Rax] = thisAddress;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "OcAgPxcq5Vk",
ExportName = "_ZN3sce4Json12MemAllocatorD2Ev",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceJson")]
public static int MemAllocatorDestructor(CpuContext ctx)
{
TraceJson("MemAllocator.dtor", ctx[CpuRegister.Rdi], 0);
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "cK6bYHf-Q5E",
ExportName = "_ZN3sce4Json11InitializerC1Ev",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceJson")]
public static int InitializerConstructor(CpuContext ctx)
{
var thisAddress = ctx[CpuRegister.Rdi];
TraceJson("Initializer.ctor", thisAddress, 0);
ctx[CpuRegister.Rax] = thisAddress;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "RujUxbr3haM",
ExportName = "_ZN3sce4Json11InitializerD1Ev",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceJson")]
public static int InitializerDestructor(CpuContext ctx)
{
TraceJson("Initializer.dtor", ctx[CpuRegister.Rdi], 0);
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "Cxwy7wHq4J0",
ExportName = "_ZN3sce4Json11Initializer10initializeEPKNS0_13InitParameterE",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceJson")]
public static int InitializerInitialize(CpuContext ctx)
{
var thisAddress = ctx[CpuRegister.Rdi];
var initParameterAddress = ctx[CpuRegister.Rsi];
if (thisAddress == 0)
{
ctx[CpuRegister.Rax] = unchecked((ulong)(int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
}
TraceJson("Initializer.initialize", thisAddress, initParameterAddress);
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
private static void TraceJson(string operation, ulong thisAddress, ulong argument)
{
if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_JSON"), "1", StringComparison.Ordinal))
{
return;
}
Console.Error.WriteLine(
$"[LOADER][TRACE] json.{operation} this=0x{thisAddress:X16} arg=0x{argument:X16}");
}
}
+79
View File
@@ -0,0 +1,79 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System;
using System.Collections.Concurrent;
using System.Threading;
using SharpEmu.HLE;
namespace SharpEmu.Libs.Network;
public static class Http2Exports
{
private const int Http2ErrorInvalidId = unchecked((int)0x80436004);
private const int Http2ErrorInvalidArgument = unchecked((int)0x80436016);
private static readonly ConcurrentDictionary<int, Http2Context> _contexts = new();
private static int _nextContextId;
private sealed record Http2Context(int NetId, int SslId, ulong PoolSize, int MaxRequests);
[SysAbiExport(
Nid = "3JCe3lCbQ8A",
ExportName = "sceHttp2Init",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceHttp2")]
public static int Http2Init(CpuContext ctx)
{
var netId = unchecked((int)ctx[CpuRegister.Rdi]);
var sslId = unchecked((int)ctx[CpuRegister.Rsi]);
var poolSize = ctx[CpuRegister.Rdx];
var maxRequests = unchecked((int)ctx[CpuRegister.Rcx]);
if (poolSize == 0 || maxRequests <= 0)
{
return SetReturn(ctx, Http2ErrorInvalidArgument);
}
var id = Interlocked.Increment(ref _nextContextId);
_contexts[id] = new Http2Context(netId, sslId, poolSize, maxRequests);
TraceHttp2("init", id, unchecked((ulong)netId), unchecked((ulong)sslId), poolSize, unchecked((ulong)maxRequests));
ctx[CpuRegister.Rax] = unchecked((ulong)id);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "YiBUtz-pGkc",
ExportName = "sceHttp2Term",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceHttp2")]
public static int Http2Term(CpuContext ctx)
{
var id = unchecked((int)ctx[CpuRegister.Rdi]);
if (!_contexts.TryRemove(id, out _))
{
return SetReturn(ctx, Http2ErrorInvalidId);
}
TraceHttp2("term", id, 0, 0, 0, 0);
return SetReturn(ctx, 0);
}
private static int SetReturn(CpuContext ctx, int result)
{
ctx[CpuRegister.Rax] = unchecked((ulong)result);
return result;
}
private static void TraceHttp2(string operation, int id, ulong arg0, ulong arg1, ulong arg2, ulong arg3)
{
if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_HTTP2"), "1", StringComparison.Ordinal))
{
return;
}
Console.Error.WriteLine(
$"[LOADER][TRACE] http2.{operation} id={id} arg0=0x{arg0:X16} arg1=0x{arg1:X16} arg2=0x{arg2:X16} arg3=0x{arg3:X16}");
}
}
@@ -0,0 +1,20 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using SharpEmu.HLE;
namespace SharpEmu.Libs.Network;
public static class NetCtlExports
{
[SysAbiExport(
Nid = "gky0+oaNM4k",
ExportName = "sceNetCtlInit",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceNetCtl")]
public static int NetCtlInit(CpuContext ctx)
{
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
}
+140
View File
@@ -0,0 +1,140 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System;
using System.Collections.Concurrent;
using System.Text;
using System.Threading;
using SharpEmu.HLE;
namespace SharpEmu.Libs.Network;
public static class NetExports
{
private const int NetErrorBadFileDescriptor = unchecked((int)0x80410109);
private const int NetErrorInvalidArgument = unchecked((int)0x80410116);
private const int MaxNameLength = 256;
private static readonly ConcurrentDictionary<int, NetPool> _pools = new();
private static int _nextPoolId;
private static bool _initialized;
private sealed record NetPool(string Name, int Size, int Flags);
[SysAbiExport(
Nid = "Nlev7Lg8k3A",
ExportName = "sceNetInit",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceNet")]
public static int NetInit(CpuContext ctx)
{
_initialized = true;
TraceNet("init", 0, 0, 0, 0);
return SetReturn(ctx, 0);
}
[SysAbiExport(
Nid = "cTGkc6-TBlI",
ExportName = "sceNetTerm",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceNet")]
public static int NetTerm(CpuContext ctx)
{
_initialized = false;
_pools.Clear();
TraceNet("term", 0, 0, 0, 0);
return SetReturn(ctx, 0);
}
[SysAbiExport(
Nid = "dgJBaeJnGpo",
ExportName = "sceNetPoolCreate",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceNet")]
public static int NetPoolCreate(CpuContext ctx)
{
var nameAddress = ctx[CpuRegister.Rdi];
var size = unchecked((int)ctx[CpuRegister.Rsi]);
var flags = unchecked((int)ctx[CpuRegister.Rdx]);
if (size <= 0)
{
return SetReturn(ctx, NetErrorInvalidArgument);
}
var name = TryReadUtf8Z(ctx, nameAddress, MaxNameLength, out var value)
? value
: string.Empty;
var id = Interlocked.Increment(ref _nextPoolId);
_pools[id] = new NetPool(name, size, flags);
TraceNet("pool.create", id, unchecked((ulong)size), unchecked((ulong)flags), _initialized ? 1UL : 0UL);
ctx[CpuRegister.Rax] = unchecked((ulong)id);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "K7RlrTkI-mw",
ExportName = "sceNetPoolDestroy",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceNet")]
public static int NetPoolDestroy(CpuContext ctx)
{
var id = unchecked((int)ctx[CpuRegister.Rdi]);
if (!_pools.TryRemove(id, out _))
{
return SetReturn(ctx, NetErrorBadFileDescriptor);
}
TraceNet("pool.destroy", id, 0, 0, _initialized ? 1UL : 0UL);
return SetReturn(ctx, 0);
}
private static int SetReturn(CpuContext ctx, int result)
{
ctx[CpuRegister.Rax] = unchecked((ulong)result);
return result;
}
private static bool TryReadUtf8Z(CpuContext ctx, ulong address, int maxLength, out string value)
{
value = string.Empty;
if (address == 0)
{
return true;
}
Span<byte> one = stackalloc byte[1];
var bytes = new byte[maxLength];
var count = 0;
for (; count < maxLength; count++)
{
if (!ctx.Memory.TryRead(address + (ulong)count, one))
{
return false;
}
if (one[0] == 0)
{
break;
}
bytes[count] = one[0];
}
value = Encoding.UTF8.GetString(bytes, 0, count);
return true;
}
private static void TraceNet(string operation, int id, ulong arg0, ulong arg1, ulong arg2)
{
if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_NET"), "1", StringComparison.Ordinal))
{
return;
}
Console.Error.WriteLine(
$"[LOADER][TRACE] net.{operation} id={id} arg0=0x{arg0:X16} arg1=0x{arg1:X16} arg2=0x{arg2:X16}");
}
}
+87
View File
@@ -0,0 +1,87 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System;
using System.Collections.Concurrent;
using System.Threading;
using SharpEmu.HLE;
namespace SharpEmu.Libs.Network;
public static class SslExports
{
private const int SslErrorInvalidId = unchecked((int)0x8095F006);
private const int SslErrorOutOfSize = unchecked((int)0x8095F008);
private static readonly ConcurrentDictionary<int, SslContext> _contexts = new();
private static int _nextContextId;
private sealed record SslContext(ulong PoolSize);
[SysAbiExport(
Nid = "hdpVEUDFW3s",
ExportName = "sceSslInit",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceSsl")]
public static int SslInit(CpuContext ctx)
{
var poolSize = ctx[CpuRegister.Rdi];
if (poolSize == 0)
{
return SetReturn(ctx, SslErrorOutOfSize);
}
var id = Interlocked.Increment(ref _nextContextId);
_contexts[id] = new SslContext(poolSize);
TraceSsl("init", id, poolSize);
ctx[CpuRegister.Rax] = unchecked((ulong)id);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "0K1yQ6Lv-Yc",
ExportName = "sceSslTerm",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceSsl")]
public static int SslTerm(CpuContext ctx)
{
var id = unchecked((int)ctx[CpuRegister.Rdi]);
if (!_contexts.TryRemove(id, out _))
{
return SetReturn(ctx, SslErrorInvalidId);
}
TraceSsl("term", id, 0);
return SetReturn(ctx, 0);
}
[SysAbiExport(
Nid = "viRXSHZYd0c",
ExportName = "sceSslClose",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceSsl")]
public static int SslClose(CpuContext ctx)
{
var id = unchecked((int)ctx[CpuRegister.Rdi]);
TraceSsl("close", id, 0);
return SetReturn(ctx, 0);
}
private static int SetReturn(CpuContext ctx, int result)
{
ctx[CpuRegister.Rax] = unchecked((ulong)result);
return result;
}
private static void TraceSsl(string operation, int id, ulong arg0)
{
if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_SSL"), "1", StringComparison.Ordinal))
{
return;
}
Console.Error.WriteLine(
$"[LOADER][TRACE] ssl.{operation} id={id} arg0=0x{arg0:X16}");
}
}
+65
View File
@@ -0,0 +1,65 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System;
using System.Threading;
using SharpEmu.HLE;
namespace SharpEmu.Libs.Np;
public static class NpWebApi2Exports
{
private const int NpWebApi2ErrorInvalidArgument = unchecked((int)0x80553402);
private static int _initialized;
[SysAbiExport(
Nid = "+o9816YQhqQ",
ExportName = "sceNpWebApi2Initialize",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceNpWebApi2")]
public static int NpWebApi2Initialize(CpuContext ctx)
{
var httpContextId = unchecked((int)ctx[CpuRegister.Rdi]);
var poolSize = ctx[CpuRegister.Rsi];
if (httpContextId <= 0 || poolSize == 0)
{
return SetReturn(ctx, NpWebApi2ErrorInvalidArgument);
}
Interlocked.Exchange(ref _initialized, 1);
TraceNpWebApi2("init", httpContextId, poolSize);
return SetReturn(ctx, 0);
}
[SysAbiExport(
Nid = "bEvXpcEk200",
ExportName = "sceNpWebApi2Terminate",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceNpWebApi2")]
public static int NpWebApi2Terminate(CpuContext ctx)
{
var libraryContextId = unchecked((int)ctx[CpuRegister.Rdi]);
Interlocked.Exchange(ref _initialized, 0);
TraceNpWebApi2("term", libraryContextId, 0);
return SetReturn(ctx, 0);
}
private static int SetReturn(CpuContext ctx, int result)
{
ctx[CpuRegister.Rax] = unchecked((ulong)result);
return result;
}
private static void TraceNpWebApi2(string operation, int id, ulong arg0)
{
if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_NP_WEB_API2"), "1", StringComparison.Ordinal))
{
return;
}
Console.Error.WriteLine(
$"[LOADER][TRACE] npwebapi2.{operation} id={id} arg0=0x{arg0:X16} initialized={Volatile.Read(ref _initialized)}");
}
}
@@ -0,0 +1,24 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System.Threading;
using SharpEmu.HLE;
namespace SharpEmu.Libs.NpGameIntent;
public static class NpGameIntentExports
{
private static int _initialized;
[SysAbiExport(
Nid = "m87BHxt-H60",
ExportName = "sceNpGameIntentInitialize",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceNpGameIntent")]
public static int NpGameIntentInitialize(CpuContext ctx)
{
Interlocked.Exchange(ref _initialized, 1);
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
}
@@ -10,6 +10,7 @@ public static class SystemServiceExports
{
private const int OrbisSystemServiceErrorParameter = unchecked((int)0x80A10003);
private const int SystemServiceStatusSize = 0x0C;
private const int DisplaySafeAreaInfoSize = sizeof(float) + 128;
[SysAbiExport(
Nid = "rPo6tV8D9bM",
@@ -34,6 +35,28 @@ public static class SystemServiceExports
: SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
}
[SysAbiExport(
Nid = "1n37q1Bvc5Y",
ExportName = "sceSystemServiceGetDisplaySafeAreaInfo",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceSystemService")]
public static int SystemServiceGetDisplaySafeAreaInfo(CpuContext ctx)
{
var infoAddress = ctx[CpuRegister.Rdi];
if (infoAddress == 0)
{
return SetReturn(ctx, OrbisSystemServiceErrorParameter);
}
Span<byte> info = stackalloc byte[DisplaySafeAreaInfoSize];
info.Clear();
BinaryPrimitives.WriteSingleLittleEndian(info, 1.0f);
return ctx.Memory.TryWrite(infoAddress, info)
? SetReturn(ctx, 0)
: SetReturn(ctx, (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
}
private static int SetReturn(CpuContext ctx, int result)
{
ctx[CpuRegister.Rax] = unchecked((ulong)result);