cellSysmodule HLE implementation (#18962)

Fully implements cellSysmodule and sets it to HLE by default.

There is an undocumented function that decrypts the OpenPSID. There
doesn't seem to be any information about this on the PS3 dev wiki or
anywhere else, so I thought I mention this separately.
This commit is contained in:
capriots 2026-07-01 08:42:17 +02:00 committed by GitHub
parent 67ee6c1ab9
commit 71e5d87a07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 1467 additions and 347 deletions

View File

@ -958,7 +958,7 @@ void padding(const unsigned char *lastb, unsigned char *pad, size_t length)
}
}
void aes_cmac(aes_context *ctx, size_t length, unsigned char *input, unsigned char *output)
void aes_cmac(aes_context *ctx, size_t length, const unsigned char *input, unsigned char *output)
{
unsigned char X[16], Y[16], M_last[16], padded[16];
unsigned char K1[16], K2[16];

View File

@ -172,7 +172,7 @@ int aes_crypt_ctr( aes_context *ctx,
const unsigned char *input,
unsigned char *output );
void aes_cmac(aes_context *ctx, size_t length, unsigned char *input, unsigned char *output);
void aes_cmac(aes_context *ctx, size_t length, const unsigned char *input, unsigned char *output);
#ifdef __cplusplus
}

View File

@ -77,7 +77,7 @@ void hex_to_bytes(unsigned char* data, std::string_view hex_str, usz str_length,
}
// Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC).
void aescbc128_decrypt(unsigned char *key, unsigned char *iv, unsigned char *in, unsigned char *out, usz len)
void aescbc128_decrypt(const unsigned char *key, unsigned char *iv, const unsigned char *in, unsigned char *out, usz len)
{
aes_context ctx;
aes_setkey_dec(&ctx, key, 128);
@ -87,7 +87,7 @@ void aescbc128_decrypt(unsigned char *key, unsigned char *iv, unsigned char *in,
memset(iv, 0, 0x10);
}
void aescbc128_encrypt(unsigned char *key, unsigned char *iv, unsigned char *in, unsigned char *out, usz len)
void aescbc128_encrypt(const unsigned char *key, unsigned char *iv, const unsigned char *in, unsigned char *out, usz len)
{
aes_context ctx;
aes_setkey_enc(&ctx, key, 128);
@ -97,14 +97,14 @@ void aescbc128_encrypt(unsigned char *key, unsigned char *iv, unsigned char *in,
memset(iv, 0, 0x10);
}
void aesecb128_encrypt(unsigned char *key, unsigned char *in, unsigned char *out)
void aesecb128_encrypt(const unsigned char *key, const unsigned char *in, unsigned char *out)
{
aes_context ctx;
aes_setkey_enc(&ctx, key, 128);
aes_crypt_ecb(&ctx, AES_ENCRYPT, in, out);
}
bool hmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, usz in_len, unsigned char *hash, usz hash_len)
bool hmac_hash_compare(const unsigned char *key, int key_len, const unsigned char *in, usz in_len, const unsigned char *hash, usz hash_len)
{
const std::unique_ptr<u8[]> out(new u8[key_len]);
@ -113,12 +113,12 @@ bool hmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, usz i
return std::memcmp(out.get(), hash, hash_len) == 0;
}
void hmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, usz in_len, unsigned char *hash)
void hmac_hash_forge(const unsigned char *key, int key_len, const unsigned char *in, usz in_len, unsigned char *hash)
{
sha1_hmac(key, key_len, in, in_len, hash);
}
bool cmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, usz in_len, unsigned char *hash, usz hash_len)
bool cmac_hash_compare(const unsigned char *key, int key_len, const unsigned char *in, usz in_len, const unsigned char *hash, usz hash_len)
{
const std::unique_ptr<u8[]> out(new u8[key_len]);
@ -129,7 +129,7 @@ bool cmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, usz i
return std::memcmp(out.get(), hash, hash_len) == 0;
}
void cmac_hash_forge(unsigned char *key, int /*key_len*/, unsigned char *in, usz in_len, unsigned char *hash)
void cmac_hash_forge(const unsigned char *key, int /*key_len*/, const unsigned char *in, usz in_len, unsigned char *hash)
{
aes_context ctx;
aes_setkey_enc(&ctx, key, 128);
@ -214,7 +214,7 @@ std::array<u8, PASSPHRASE_KEY_LEN> vtrm_portability_laid_paid()
return sc_combine_laid_paid(0x0000000000000000L, 0x0000000000000000L);
}
int sc_decrypt(const u8* sc_key, const std::array<u8, PASSPHRASE_KEY_LEN>& laid_paid, u8* iv, u8* input, u8* output)
int sc_decrypt(const u8* sc_key, const std::array<u8, PASSPHRASE_KEY_LEN>& laid_paid, u8* iv, const u8* input, u8* output)
{
aes_context ctx;
u8 key[PASSPHRASE_KEY_LEN];
@ -223,12 +223,12 @@ int sc_decrypt(const u8* sc_key, const std::array<u8, PASSPHRASE_KEY_LEN>& laid_
return aes_crypt_cbc(&ctx, AES_DECRYPT, PASSPHRASE_OUT_LEN, iv, input, output);
}
int vtrm_decrypt(int type, u8* iv, u8* input, u8* output)
int vtrm_decrypt(int type, u8* iv, const u8* input, u8* output)
{
return sc_decrypt(SC_ISO_SERIES_KEY_2, vtrm_get_laid_paid_from_type(type), iv, input, output);
}
int vtrm_decrypt_master(s64 laid, s64 paid, u8* iv, u8* input, u8* output)
int vtrm_decrypt_master(s64 laid, s64 paid, u8* iv, const u8* input, u8* output)
{
return sc_decrypt(SC_ISO_SERIES_INTERNAL_KEY_3, sc_combine_laid_paid(laid, paid), iv, input, output);
}
@ -247,7 +247,7 @@ const u8* vtrm_portability_type_mapper(int type)
}
}
int vtrm_decrypt_with_portability(int type, u8* iv, u8* input, u8* output)
int vtrm_decrypt_with_portability(int type, u8* iv, const u8* input, u8* output)
{
return sc_decrypt(vtrm_portability_type_mapper(type), vtrm_portability_laid_paid(), iv, input, output);
}

View File

@ -22,17 +22,17 @@ void bytes_to_hex(std::string& hex_str, const unsigned char* data, usz data_leng
void hex_to_bytes(unsigned char* data, std::string_view hex_str, usz str_length, std::string* error = nullptr);
// Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC).
void aescbc128_decrypt(unsigned char *key, unsigned char *iv, unsigned char *in, unsigned char *out, usz len);
void aescbc128_encrypt(unsigned char *key, unsigned char *iv, unsigned char *in, unsigned char *out, usz len);
void aesecb128_encrypt(unsigned char *key, unsigned char *in, unsigned char *out);
bool hmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, usz in_len, unsigned char *hash, usz hash_len);
void hmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, usz in_len, unsigned char *hash);
bool cmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, usz in_len, unsigned char *hash, usz hash_len);
void cmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, usz in_len, unsigned char *hash);
void aescbc128_decrypt(const unsigned char *key, unsigned char *iv, const unsigned char *in, unsigned char *out, usz len);
void aescbc128_encrypt(const unsigned char *key, unsigned char *iv, const unsigned char *in, unsigned char *out, usz len);
void aesecb128_encrypt(const unsigned char *key, const unsigned char *in, unsigned char *out);
bool hmac_hash_compare(const unsigned char *key, int key_len, const unsigned char *in, usz in_len, const unsigned char *hash, usz hash_len);
void hmac_hash_forge(const unsigned char *key, int key_len, const unsigned char *in, usz in_len, unsigned char *hash);
bool cmac_hash_compare(const unsigned char *key, int key_len, const unsigned char *in, usz in_len, const unsigned char *hash, usz hash_len);
void cmac_hash_forge(const unsigned char *key, int key_len, const unsigned char *in, usz in_len, const unsigned char *hash);
void mbedtls_zeroize(void *v, size_t n);
// SC passphrase crypto
int vtrm_decrypt(int type, u8* iv, u8* input, u8* output);
int vtrm_decrypt_master(s64 laid, s64 paid, u8* iv, u8* input, u8* output);
int vtrm_decrypt_with_portability(int type, u8* iv, u8* input, u8* output);
int vtrm_decrypt(int type, u8* iv, const u8* input, u8* output);
int vtrm_decrypt_master(s64 laid, s64 paid, u8* iv, const u8* input, u8* output);
int vtrm_decrypt_with_portability(int type, u8* iv, const u8* input, u8* output);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,144 @@
#pragma once
// Error codes
enum CellSysmoduleError
{
CELL_SYSMODULE_ERROR_DUPLICATED = 0x80012001,
CELL_SYSMODULE_ERROR_UNKNOWN = 0x80012002,
CELL_SYSMODULE_ERROR_UNLOADED = 0x80012003,
CELL_SYSMODULE_ERROR_INVALID_MEMCONTAINER = 0x80012004,
CELL_SYSMODULE_ERROR_FATAL = 0x800120ff,
};
enum CellSysmoduleModuleID : u16
{
CELL_SYSMODULE_NET = 0x00,
CELL_SYSMODULE_HTTP = 0x01,
CELL_SYSMODULE_HTTP_UTIL = 0x02,
CELL_SYSMODULE_SSL = 0x03,
CELL_SYSMODULE_HTTPS = 0x04,
CELL_SYSMODULE_VDEC = 0x05,
CELL_SYSMODULE_ADEC = 0x06,
CELL_SYSMODULE_DMUX = 0x07,
CELL_SYSMODULE_VPOST = 0x08,
CELL_SYSMODULE_RTC = 0x09,
CELL_SYSMODULE_SPURS = 0x0a,
CELL_SYSMODULE_OVIS = 0x0b,
CELL_SYSMODULE_SHEAP = 0x0c,
CELL_SYSMODULE_SYNC = 0x0d,
CELL_SYSMODULE_FS = 0x0e,
CELL_SYSMODULE_JPGDEC = 0x0f,
CELL_SYSMODULE_GCM_SYS = 0x10,
CELL_SYSMODULE_AUDIO = 0x11,
CELL_SYSMODULE_PAMF = 0x12,
CELL_SYSMODULE_ATRAC3PLUS = 0x13,
CELL_SYSMODULE_NETCTL = 0x14,
CELL_SYSMODULE_SYSUTIL = 0x15,
CELL_SYSMODULE_SYSUTIL_NP = 0x16,
CELL_SYSMODULE_IO = 0x17,
CELL_SYSMODULE_PNGDEC = 0x18,
CELL_SYSMODULE_FONT = 0x19,
CELL_SYSMODULE_FONTFT = 0x1a,
CELL_SYSMODULE_FREETYPE = 0x1b,
CELL_SYSMODULE_USBD = 0x1c,
CELL_SYSMODULE_SAIL = 0x1d,
CELL_SYSMODULE_L10N = 0x1e,
CELL_SYSMODULE_RESC = 0x1f,
CELL_SYSMODULE_DAISY = 0x20,
CELL_SYSMODULE_KEY2CHAR = 0x21,
CELL_SYSMODULE_MIC = 0x22,
CELL_SYSMODULE_CAMERA = 0x23,
CELL_SYSMODULE_VDEC_MPEG2 = 0x24,
CELL_SYSMODULE_VDEC_AVC = 0x25,
CELL_SYSMODULE_ADEC_LPCM = 0x26,
CELL_SYSMODULE_ADEC_AC3 = 0x27,
CELL_SYSMODULE_ADEC_ATX = 0x28,
CELL_SYSMODULE_ADEC_AT3 = 0x29,
CELL_SYSMODULE_DMUX_PAMF = 0x2a,
CELL_SYSMODULE_VDEC_AL = 0x2b,
CELL_SYSMODULE_ADEC_AL = 0x2c,
CELL_SYSMODULE_DMUX_AL = 0x2d,
CELL_SYSMODULE_LV2DBG = 0x2e,
// 0x2f
CELL_SYSMODULE_USBPSPCM = 0x30,
CELL_SYSMODULE_AVCONF_EXT = 0x31,
CELL_SYSMODULE_SYSUTIL_USERINFO = 0x32,
CELL_SYSMODULE_SYSUTIL_SAVEDATA = 0x33,
CELL_SYSMODULE_SUBDISPLAY = 0x34,
CELL_SYSMODULE_SYSUTIL_REC = 0x35,
CELL_SYSMODULE_VIDEO_EXPORT = 0x36,
CELL_SYSMODULE_SYSUTIL_GAME_EXEC = 0x37,
CELL_SYSMODULE_SYSUTIL_NP2 = 0x38,
CELL_SYSMODULE_SYSUTIL_AP = 0x39,
CELL_SYSMODULE_SYSUTIL_NP_CLANS = 0x3a,
CELL_SYSMODULE_SYSUTIL_OSK_EXT = 0x3b,
CELL_SYSMODULE_VDEC_DIVX = 0x3c,
CELL_SYSMODULE_JPGENC = 0x3d,
CELL_SYSMODULE_SYSUTIL_GAME = 0x3e,
CELL_SYSMODULE_BGDL = 0x3f,
CELL_SYSMODULE_FREETYPE_TT = 0x40,
CELL_SYSMODULE_SYSUTIL_VIDEO_UPLOAD = 0x41,
CELL_SYSMODULE_SYSUTIL_SYSCONF_EXT = 0x42,
CELL_SYSMODULE_FIBER = 0x43,
CELL_SYSMODULE_SYSUTIL_NP_COMMERCE2 = 0x44,
CELL_SYSMODULE_SYSUTIL_NP_TUS = 0x45,
CELL_SYSMODULE_VOICE = 0x46,
CELL_SYSMODULE_ADEC_CELP8 = 0x47,
CELL_SYSMODULE_CELP8ENC = 0x48,
CELL_SYSMODULE_SYSUTIL_LICENSEAREA = 0x49,
CELL_SYSMODULE_SYSUTIL_MUSIC2 = 0x4a,
// 0x4b
// 0x4c
// 0x4d
CELL_SYSMODULE_SYSUTIL_SCREENSHOT = 0x4e,
CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE = 0x4f,
CELL_SYSMODULE_SPURS_JQ = 0x50,
// 0x51
CELL_SYSMODULE_PNGENC = 0x52,
CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE2 = 0x53,
// 0x54
CELL_SYSMODULE_SYNC2 = 0x55,
CELL_SYSMODULE_SYSUTIL_NP_UTIL = 0x56,
CELL_SYSMODULE_RUDP = 0x57,
// 0x58 = Invalid
CELL_SYSMODULE_SYSUTIL_NP_SNS = 0x59,
CELL_SYSMODULE_GEM = 0x5a,
CELL_SYSMODULE_SYSUTIL_CROSS_CONTROLLER = 0x5c,
// Internal modules
CELL_SYSMODULE_CELPENC = 0xf00a,
CELL_SYSMODULE_GIFDEC = 0xf010,
CELL_SYSMODULE_ADEC_CELP = 0xf019,
CELL_SYSMODULE_ADEC_M2BC = 0xf01b,
CELL_SYSMODULE_ADEC_M4AAC = 0xf01d,
CELL_SYSMODULE_ADEC_MP3 = 0xf01e,
CELL_SYSMODULE_IMEJP = 0xf023,
CELL_SYSMODULE_SYSUTIL_MUSIC = 0xf028,
CELL_SYSMODULE_PHOTO_EXPORT = 0xf029,
CELL_SYSMODULE_PRINT = 0xf02a,
CELL_SYSMODULE_PHOTO_IMPORT = 0xf02b,
CELL_SYSMODULE_MUSIC_EXPORT = 0xf02c,
CELL_SYSMODULE_PHOTO_DECODE = 0xf02e,
CELL_SYSMODULE_SYSUTIL_SEARCH = 0xf02f,
CELL_SYSMODULE_SYSUTIL_AVCHAT2 = 0xf030,
CELL_SYSMODULE_SAIL_REC = 0xf034,
CELL_SYSMODULE_SYSUTIL_NP_TROPHY = 0xf035,
CELL_SYSMODULE_LIBATRAC3MULTI = 0xf054,
CELL_SYSMODULE_INVALID = 0xffff
};
struct SysmoduleUnk
{
be_t<s32> prx_id;
be_t<s32> unk;
};
CHECK_SIZE_ALIGN(SysmoduleUnk, 8, 4);
error_code cellSysmoduleLoadModule(ppu_thread& ppu, u16 id);
error_code cellSysmoduleLoadModuleInternal(ppu_thread& ppu, u16 id);
error_code cellSysmoduleUnloadModule(ppu_thread& ppu, u16 id);
error_code cellSysmoduleUnloadModuleInternal(ppu_thread& ppu, u16 id);
error_code cellSysmoduleIsLoadedEx(ppu_thread& ppu, u16 id);
error_code cellSysmoduleSetDebugmode(u32 debug_mode);

View File

@ -61,7 +61,7 @@ s32 sys_process_is_stack(u32 p)
return (p >> 28) == 0xD;
}
error_code sys_process_get_paramsfo(vm::ptr<char> buffer)
error_code sys_process_get_paramsfo([[maybe_unused]] ppu_thread& ppu, vm::ptr<char> buffer)
{
sysPrxForUser.warning("sys_process_get_paramsfo(buffer=*0x%x)", buffer);

View File

@ -63,5 +63,18 @@ error_code sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, u32 en
error_code sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih);
void sys_ppu_thread_exit(ppu_thread& CPU, u64 val);
error_code sys_process_get_paramsfo(ppu_thread& ppu, vm::ptr<char> buffer);
void sys_game_process_exitspawn(ppu_thread& ppu, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags);
void sys_game_process_exitspawn2(ppu_thread& ppu, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags);
struct sys_prx_load_module_option_t;
struct sys_prx_unload_module_option_t;
struct sys_prx_module_info_t;
error_code sys_prx_load_module(ppu_thread& ppu, vm::cptr<char> path, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt);
error_code sys_prx_load_module_on_memcontainer(ppu_thread& ppu, vm::cptr<char> path, u32 mem_ct, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt);
error_code sys_prx_load_module_list(ppu_thread& ppu, s32 count, vm::cpptr<char> path_list, u64 flags, vm::ptr<sys_prx_load_module_option_t> pOpt, vm::ptr<u32> id_list);
error_code sys_prx_start_module(ppu_thread& ppu, u32 id, u32 args, vm::ptr<void> argp, vm::ptr<s32> result, u64 flags, vm::ptr<void> pOpt);
error_code sys_prx_stop_module(ppu_thread& ppu, u32 id, u32 args, vm::ptr<void> argp, vm::ptr<s32> result, u64 flags, vm::ptr<void> pOpt);
error_code sys_prx_unload_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_prx_unload_module_option_t> pOpt);
error_code sys_prx_get_module_info(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_prx_module_info_t> info);

View File

@ -8,6 +8,7 @@
#include "Crypto/unself.h"
#include "Loader/ELF.h"
#include "Emu/Cell/PPUFunction.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Crypto/unedat.h"
@ -115,7 +116,7 @@ extern const std::map<std::string_view, int> g_prx_list
{ "libssl.sprx", 0 },
{ "libsvc1d.sprx", 0 },
{ "libsync2.sprx", 0 },
{ "libsysmodule.sprx", 0 },
{ "libsysmodule.sprx", 1 },
{ "libsysutil.sprx", 1 },
{ "libsysutil_ap.sprx", 1 },
{ "libsysutil_authdialog.sprx", 1 },
@ -177,6 +178,9 @@ extern const std::map<std::string_view, int> g_prx_list
bool ppu_register_library_lock(std::string_view libname, bool lock_lib);
extern error_code sysmoduleModuleStart(ppu_thread& ppu, u32 args, vm::ptr<void> argp);
extern error_code sysmoduleModuleStop(ppu_thread& ppu);
static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<sys_prx_load_module_option_t> /*pOpt*/, fs::file src = {}, s64 file_offset = 0)
{
if (flags != 0)
@ -232,6 +236,12 @@ static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr<s
{
const auto prx = idm::make_ptr<lv2_obj, lv2_prx>();
if (name == "libsysmodule.sprx")
{
prx->start = vm::cast(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(sysmoduleModuleStart)));
prx->stop = vm::cast(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(sysmoduleModuleStop)));
}
prx->name = std::move(name);
prx->path = std::move(path);

View File

@ -960,6 +960,7 @@
<ClInclude Include="Emu\Cell\Modules\cellSync.h" />
<ClInclude Include="Emu\Cell\Modules\cellSync2.h" />
<ClInclude Include="Emu\Cell\Modules\cellSysconf.h" />
<ClInclude Include="Emu\Cell\Modules\cellSysmodule.h" />
<ClInclude Include="Emu\Cell\Modules\cellSysutil.h" />
<ClInclude Include="Emu\Cell\Modules\cellSysutilAvc2.h" />
<ClInclude Include="Emu\Cell\Modules\cellUsbd.h" />

View File

@ -1914,6 +1914,9 @@
<ClInclude Include="Emu\Cell\Modules\cellSysconf.h">
<Filter>Emu\Cell\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\Modules\cellSysmodule.h">
<Filter>Emu\Cell\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\Modules\cellSysutil.h">
<Filter>Emu\Cell\Modules</Filter>
</ClInclude>

View File

@ -10,6 +10,7 @@ struct bit_set
public:
constexpr bit_set() noexcept : m_bitset() {}
constexpr bit_set(usz val) noexcept : m_bitset(val) {}
explicit constexpr bit_set(auto&&... args) noexcept requires std::is_constructible_v<std::bitset<Bits>, decltype(args)...> : m_bitset(std::forward<decltype(args)>(args)...) {}
[[nodiscard]] bool test(usz pos, std::source_location src_loc = std::source_location::current()) const
{