diff --git a/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp b/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp index 41eae6bb82..d089667ca0 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp @@ -1,19 +1,21 @@ #include "stdafx.h" +#include "Crypto/utils.h" +#include "Emu/Cell/lv2/sys_fs.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_memory.h" +#include "Emu/Cell/lv2/sys_process.h" +#include "Emu/Cell/lv2/sys_prx.h" +#include "Emu/Cell/lv2/sys_ss.h" #include "Emu/Cell/PPUModule.h" +#include "Emu/savestate_utils.hpp" +#include "sysPrxForUser.h" +#include "util/bit_set.hpp" + +#include "cellSysmodule.h" +#include LOG_CHANNEL(cellSysmodule); -constexpr auto CELL_SYSMODULE_LOADED = CELL_OK; - -enum CellSysmoduleError : u32 -{ - 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, -}; - template<> void fmt_class_string::format(std::string& out, u64 arg) { @@ -32,406 +34,1346 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -static const char* get_module_name(u16 id) +namespace { - switch (id) - { - case 0x0000: return "sys_net"; - case 0x0001: return "cellHttp"; - case 0x0002: return "cellHttpUtil"; - case 0x0003: return "cellSsl"; - case 0x0004: return "cellHttps"; - case 0x0005: return "libvdec"; - case 0x0006: return "cellAdec"; - case 0x0007: return "cellDmux"; - case 0x0008: return "cellVpost"; - case 0x0009: return "cellRtc"; - case 0x000a: return "cellSpurs"; - case 0x000b: return "cellOvis"; - case 0x000c: return "cellSheap"; - case 0x000d: return "cellSync"; - case 0x000e: return "sys_fs"; - case 0x000f: return "cellJpgDec"; - case 0x0010: return "cellGcmSys"; - case 0x0011: return "cellAudio"; - case 0x0012: return "cellPamf"; - case 0x0013: return "cellAtrac"; - case 0x0014: return "cellNetCtl"; - case 0x0015: return "cellSysutil"; - case 0x0016: return "sceNp"; - case 0x0017: return "sys_io"; - case 0x0018: return "cellPngDec"; - case 0x0019: return "cellFont"; - case 0x001a: return "cellFontFT"; - case 0x001b: return "cell_FreeType2"; - case 0x001c: return "cellUsbd"; - case 0x001d: return "cellSail"; - case 0x001e: return "cellL10n"; - case 0x001f: return "cellResc"; - case 0x0020: return "cellDaisy"; - case 0x0021: return "cellKey2char"; - case 0x0022: return "cellMic"; - case 0x0023: return "cellCamera"; - case 0x0024: return "cellVdecMpeg2"; - case 0x0025: return "cellVdecAvc"; - case 0x0026: return "cellAdecLpcm"; - case 0x0027: return "cellAdecAc3"; - case 0x0028: return "cellAdecAtx"; - case 0x0029: return "cellAdecAt3"; - case 0x002a: return "cellDmuxPamf"; - case 0x002b: return nullptr; - case 0x002c: return nullptr; - case 0x002d: return nullptr; - case 0x002e: return "sys_lv2dbg"; - case 0x002f: return "cellSysutilAvcExt"; - case 0x0030: return "cellUsbPspcm"; - case 0x0031: return "cellSysutilAvconfExt"; - case 0x0032: return "cellUserInfo"; - case 0x0033: return "cellSaveData"; - case 0x0034: return "cellSubDisplay"; - case 0x0035: return "cellRec"; - case 0x0036: return "cellVideoExportUtility"; - case 0x0037: return "cellGameExec"; - case 0x0038: return "sceNp2"; - case 0x0039: return "cellSysutilAp"; - case 0x003a: return "sceNpClans"; - case 0x003b: return "cellOskExtUtility"; - case 0x003c: return "cellVdecDivx"; - case 0x003d: return "cellJpgEnc"; - case 0x003e: return "cellGame"; - case 0x003f: return "cellBGDLUtility"; - case 0x0040: return "cell_FreeType2"; - case 0x0041: return "cellVideoUpload"; - case 0x0042: return "cellSysconfExtUtility"; - case 0x0043: return "cellFiber"; - case 0x0044: return "sceNpCommerce2"; - case 0x0045: return "sceNpTus"; - case 0x0046: return "cellVoice"; - case 0x0047: return "cellAdecCelp8"; - case 0x0048: return "cellCelp8Enc"; - case 0x0049: return "cellSysutilMisc"; - case 0x004a: return "cellMusicUtility"; - // TODO: Check if those libad are correctly matched. - // They belong to those IDs but actual order is unknown. - case 0x004b: return "libad_core"; - case 0x004c: return "libad_async"; - case 0x004d: return "libad_billboard_util"; - case 0x004e: return "cellScreenShotUtility"; - case 0x004f: return "cellMusicDecodeUtility"; - case 0x0050: return "cellSpursJq"; - case 0x0052: return "cellPngEnc"; - case 0x0053: return "cellMusicDecodeUtility"; - case 0x0054: return "libmedi"; - case 0x0055: return "cellSync2"; - case 0x0056: return "sceNpUtil"; - case 0x0057: return "cellRudp"; - case 0x0059: return "sceNpSns"; - case 0x005a: return "libgem"; - case 0x005c: return "cellCrossController"; - case 0xf00a: return "cellCelpEnc"; - case 0xf010: return "cellGifDec"; - case 0xf019: return "cellAdecCelp"; - case 0xf01b: return "cellAdecM2bc"; - case 0xf01d: return "cellAdecM4aac"; - case 0xf01e: return "cellAdecMp3"; - case 0xf023: return "cellImeJpUtility"; - case 0xf028: return "cellMusicUtility"; - case 0xf029: return "cellPhotoUtility"; - case 0xf02a: return "cellPrintUtility"; - case 0xf02b: return "cellPhotoImportUtil"; - case 0xf02c: return "cellMusicExportUtility"; - case 0xf02e: return "cellPhotoDecodeUtil"; - case 0xf02f: return "cellSearchUtility"; - case 0xf030: return "cellSysutilAvc2"; - case 0xf034: return "cellSailRec"; - case 0xf035: return "sceNpTrophy"; - case 0xf044: return "cellSysutilNpEula"; - case 0xf053: return "cellAdecAt3multi"; - case 0xf054: return "cellAtracMulti"; - } + constexpr u16 INTERNAL_MODULE_ID_BASE = 0xf000; + constexpr u16 INTERNAL_MODULE_ID_MASK = 0x0fff; + constexpr u16 UNK_MODULE_ID_BASE = 0xff00; + constexpr u8 UNK_MODULE_ID_MASK = 0x00ff; - return nullptr; + constexpr std::array DEPENDENCIES_NET { CELL_SYSMODULE_NETCTL }; + constexpr std::array DEPENDENCIES_HTTP { CELL_SYSMODULE_NET, CELL_SYSMODULE_RTC }; + constexpr std::array DEPENDENCIES_HTTPUTIL{ CELL_SYSMODULE_HTTP }; + constexpr std::array DEPENDENCIES_HTTPS { CELL_SYSMODULE_SSL, CELL_SYSMODULE_HTTP }; + constexpr std::array DEPENDENCIES_SSL { CELL_SYSMODULE_NET, CELL_SYSMODULE_RTC, CELL_SYSMODULE_FS }; + constexpr std::array DEPENDENCIES_NP2 { CELL_SYSMODULE_SYSUTIL_NP }; + constexpr std::array DEPENDENCIES_CLANS { CELL_SYSMODULE_SYSUTIL_NP, CELL_SYSMODULE_HTTPS }; + constexpr std::array DEPENDENCIES_FS { CELL_SYSMODULE_FS }; + constexpr std::array DEPENDENCIES_AT3P { CELL_SYSMODULE_ADEC_AT3, CELL_SYSMODULE_ADEC_ATX }; + constexpr std::array DEPENDENCIES_AT3M { 0xf053 }; + constexpr std::array DEPENDENCIES_SPURS { CELL_SYSMODULE_SPURS }; + constexpr std::array DEPENDENCIES_VDEC_AL { CELL_SYSMODULE_VDEC_AL }; + constexpr std::array DEPENDENCIES_ADEC_AL { CELL_SYSMODULE_ADEC_AL }; + constexpr std::array DEPENDENCIES_ADEC2 { 0xf03f }; + constexpr std::array DEPENDENCIES_DMUX_AL { CELL_SYSMODULE_DMUX_AL }; + constexpr std::array DEPENDENCIES_VDEC { CELL_SYSMODULE_VDEC_MPEG2, CELL_SYSMODULE_VDEC_AVC, CELL_SYSMODULE_VDEC_AL }; + constexpr std::array DEPENDENCIES_ADEC { CELL_SYSMODULE_ADEC_LPCM, CELL_SYSMODULE_ADEC_AC3, CELL_SYSMODULE_ADEC_AT3, CELL_SYSMODULE_ADEC_ATX, CELL_SYSMODULE_ADEC_AL }; + constexpr std::array DEPENDENCIES_DMUX { CELL_SYSMODULE_DMUX_PAMF, CELL_SYSMODULE_DMUX_AL }; + constexpr std::array DEPENDENCIES_PSPCM { CELL_SYSMODULE_USBD }; + constexpr std::array DEPENDENCIES_COMM { CELL_SYSMODULE_SYSUTIL_NP2, CELL_SYSMODULE_HTTPS }; + constexpr std::array DEPENDENCIES_NP_TUS { CELL_SYSMODULE_SYSUTIL_NP2 }; + constexpr std::array DEPENDENCIES_AD_CORE { CELL_SYSMODULE_FS, CELL_SYSMODULE_NET, CELL_SYSMODULE_SYSUTIL_NP }; + constexpr std::array DEPENDENCIES_AD_ASYNC{ 0x4b }; + constexpr std::array DEPENDENCIES_SPURS_JQ{ CELL_SYSMODULE_FIBER }; + constexpr std::array DEPENDENCIES_MEDI { CELL_SYSMODULE_NET, CELL_SYSMODULE_SYSUTIL_NP }; + + struct module_info + { + std::string_view path; + std::span dependencies; + }; + + constexpr std::array MODULE_INFOS + { + // 93 external modules + module_info + { .path = "external/libnet.sprx", .dependencies = DEPENDENCIES_NET }, // CELL_SYSUTIL_NET + { .path = "external/libhttp.sprx", .dependencies = DEPENDENCIES_HTTP }, // CELL_SYSMODULE_HTTP + { .path = {}, .dependencies = DEPENDENCIES_HTTPUTIL }, // CELL_SYSMODULE_HTTP_UTIL + { .path = "external/libssl.sprx", .dependencies = DEPENDENCIES_SSL }, // CELL_SYSMODULE_SSL + { .path = {}, .dependencies = DEPENDENCIES_HTTPS }, // CELL_SYSMODULE_HTTPS + { .path = {}, .dependencies = DEPENDENCIES_VDEC }, // CELL_SYSMODULE_VDEC + { .path = {}, .dependencies = DEPENDENCIES_ADEC }, // CELL_SYSMODULE_ADEC + { .path = {}, .dependencies = DEPENDENCIES_DMUX }, // CELL_SYSMODULE_DMUX + { .path = "external/libvpost.sprx", .dependencies = {} }, // CELL_SYSMODULE_VPOST + { .path = "external/librtc.sprx", .dependencies = {} }, // CELL_SYSMODULE_RTC + { .path = "external/libsre.sprx", .dependencies = {} }, // CELL_SYSMODULE_SPURS + { .path = {}, .dependencies = DEPENDENCIES_SPURS }, // CELL_SYSMODULE_OVIS + { .path = {}, .dependencies = DEPENDENCIES_SPURS }, // CELL_SYSMODULE_SHEAP + { .path = {}, .dependencies = DEPENDENCIES_SPURS }, // CELL_SYSMODULE_SYNC + { .path = "external/libfs.sprx", .dependencies = {} }, // CELL_SYSMODULE_FS + { .path = "external/libjpgdec.sprx", .dependencies = DEPENDENCIES_FS }, // CELL_SYSMODULE_JPGDEC + { .path = "external/libgcm_sys.sprx", .dependencies = {} }, // CELL_SYSMODULE_GCM_SYS + { .path = "external/libaudio.sprx", .dependencies = {} }, // CELL_SYSMODULE_AUDIO + { .path = "external/libpamf.sprx", .dependencies = {} }, // CELL_SYSMODULE_PAMF + { .path = "external/libatrac3plus.sprx", .dependencies = DEPENDENCIES_AT3P }, // CELL_SYSMODULE_ATRAC3PLUS + { .path = "external/libnetctl.sprx", .dependencies = {} }, // CELL_SYSMODULE_NETCTL + { .path = "external/libsysutil.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL + { .path = "external/libsysutil_np.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_NP + { .path = "external/libio.sprx", .dependencies = {} }, // CELL_SYSMODULE_IO + { .path = "external/libpngdec.sprx", .dependencies = DEPENDENCIES_FS }, // CELL_SYSMODULE_PNGDEC + { .path = "external/libfont.sprx", .dependencies = DEPENDENCIES_FS }, // CELL_SYSMODULE_FONT + { .path = "external/libfontFT.sprx", .dependencies = {} }, // CELL_SYSMODULE_FONTFT + { .path = "external/libfreetype.sprx", .dependencies = DEPENDENCIES_FS }, // CELL_SYSMODULE_FREETYPE + { .path = "external/libusbd.sprx", .dependencies = {} }, // CELL_SYSMODULE_USBD + { .path = "external/libsail.sprx", .dependencies = {} }, // CELL_SYSMODULE_SAIL + { .path = "external/libl10n.sprx", .dependencies = {} }, // CELL_SYSMODULE_L10N + { .path = "external/libresc.sprx", .dependencies = {} }, // CELL_SYSMODULE_RESC + { .path = {}, .dependencies = DEPENDENCIES_SPURS }, // CELL_SYSMODULE_DAISY + { .path = "external/libkey2char.sprx", .dependencies = {} }, // CELL_SYSMODULE_KEY2CHAR + { .path = "external/libmic.sprx", .dependencies = {} }, // CELL_SYSMODULE_MIC + { .path = "external/libcamera.sprx", .dependencies = {} }, // CELL_SYSMODULE_CAMERA + { .path = "external/libsmvd2.sprx", .dependencies = DEPENDENCIES_VDEC_AL }, // CELL_SYSMODULE_VDEC_MPEG2 + { .path = "external/libavcdec.sprx", .dependencies = DEPENDENCIES_VDEC_AL }, // CELL_SYSMODULE_VDEC_AVC + { .path = {}, .dependencies = DEPENDENCIES_ADEC_AL }, // CELL_SYSMODULE_ADEC_LPCM + { .path = "external/libac3dec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // CELL_SYSMODULE_ADEC_AC3 + { .path = "external/libatxdec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // CELL_SYSMODULE_ADEC_ATX + { .path = "external/libat3dec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // CELL_SYSMODULE_ADEC_AT3 + { .path = "external/libdmuxpamf.sprx", .dependencies = DEPENDENCIES_DMUX_AL }, // CELL_SYSMODULE_DMUX_PAMF + { .path = "external/libvdec.sprx", .dependencies = {} }, // CELL_SYSMODULE_VDEC_AL + { .path = "external/libadec.sprx", .dependencies = {} }, // CELL_SYSMODULE_ADEC_AL + { .path = "external/libdmux.sprx", .dependencies = {} }, // CELL_SYSMODULE_DMUX_AL + { .path = "external/liblv2dbg_for_dex.sprx", .dependencies = {} }, // CELL_SYSMODULE_LV2DBG + { .path = "external/libsysutil_avc_ext.sprx", .dependencies = {} }, // 0x2f + { .path = "external/libusbpspcm.sprx", .dependencies = DEPENDENCIES_PSPCM }, // CELL_SYSMODULE_USBPSPCM + { .path = "external/libsysutil_avconf_ext.sprx", .dependencies = {} }, // CELL_SYSMODULE_AVCONF_EXT + { .path = "external/libsysutil_userinfo.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_USERINFO + { .path = "external/libsysutil_savedata.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_SAVEDATA + { .path = "external/libsysutil_subdisplay.sprx", .dependencies = {} }, // CELL_SYSMODULE_SUBDISPLAY + { .path = "external/libsysutil_rec.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_REC + { .path = "external/libsysutil_video_export.sprx", .dependencies = {} }, // CELL_SYSMODULE_VIDEO_EXPORT + { .path = "external/libsysutil_game_exec.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_GAME_EXEC + { .path = "external/libsysutil_np2.sprx", .dependencies = DEPENDENCIES_NP2 }, // CELL_SYSMODULE_SYSUTIL_NP2 + { .path = "external/libsysutil_ap.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_AP + { .path = "external/libsysutil_np_clans.sprx", .dependencies = DEPENDENCIES_CLANS }, // CELL_SYSMODULE_SYSUTIL_NP_CLANS + { .path = "external/libsysutil_oskdialog_ext.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_OSK_EXT + { .path = "external/libdivxdec.sprx", .dependencies = DEPENDENCIES_VDEC_AL }, // CELL_SYSMODULE_VDEC_DIVX + { .path = "external/libjpgenc.sprx", .dependencies = DEPENDENCIES_FS }, // CELL_SYSMODULE_JPGENC + { .path = "external/libsysutil_game.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_GAME + { .path = "external/libsysutil_bgdl.sprx", .dependencies = {} }, // CELL_SYSMODULE_BGDL + { .path = "external/libfreetypeTT.sprx", .dependencies = DEPENDENCIES_FS }, // CELL_SYSMODULE_FREETYPE_TT + { .path = "external/libsysutil_video_upload.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_VIDEO_UPLOAD + { .path = "external/libsysutil_sysconf_ext.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_SYSCONF_EXT + { .path = "external/libfiber.sprx", .dependencies = {} }, // CELL_SYSMODULE_FIBER + { .path = "external/libsysutil_np_commerce2.sprx", .dependencies = DEPENDENCIES_COMM }, // CELL_SYSMODULE_SYSUTIL_NP_COMMERCE2 + { .path = "external/libsysutil_np_tus.sprx", .dependencies = DEPENDENCIES_NP_TUS }, // CELL_SYSMODULE_SYSUTIL_NP_TUS + { .path = "external/libvoice.sprx", .dependencies = {} }, // CELL_SYSMODULE_VOICE + { .path = "external/libcelp8dec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // CELL_SYSMODULE_ADEC_CELP8 + { .path = "external/libcelp8enc.sprx", .dependencies = {} }, // CELL_SYSMODULE_CELP8ENC + { .path = "external/libsysutil_misc.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_LICENSEAREA + { .path = "external/libsysutil_music.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_MUSIC2 + { .path = "external/libad_core.sprx", .dependencies = DEPENDENCIES_AD_CORE }, // 0x4b + { .path = "external/libad_async.sprx", .dependencies = DEPENDENCIES_AD_ASYNC }, // 0x4c + { .path = "external/libad_billboard_util.sprx", .dependencies = DEPENDENCIES_AD_CORE }, // 0x4d + { .path = "external/libsysutil_screenshot.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_SCREENSHOT + { .path = "external/libsysutil_music_decode.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE + { .path = "external/libspurs_jq.sprx", .dependencies = DEPENDENCIES_SPURS_JQ }, // CELL_SYSMODULE_SPURS_JQ + { .path = "external/libsysutil_authdialog.sprx", .dependencies = {} }, // 0x51 + { .path = "external/libpngenc.sprx", .dependencies = DEPENDENCIES_FS }, // CELL_SYSMODULE_PNGENC + { .path = "external/libsysutil_music_decode.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE2 + { .path = "external/libmedi.sprx", .dependencies = DEPENDENCIES_MEDI }, // 0x54 + { .path = "external/libsync2.sprx", .dependencies = DEPENDENCIES_SPURS_JQ }, // CELL_SYSMODULE_SYNC2 + { .path = "external/libsysutil_np_util.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_NP_UTIL + { .path = "external/librudp.sprx", .dependencies = {} }, // CELL_SYSMODULE_RUDP + { .path = "external/libsysutil_syschat.sprx", .dependencies = {} }, // 0x58 + { .path = "external/libsysutil_np_sns.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_NP_SNS + { .path = "external/libgem.sprx", .dependencies = {} }, // CELL_SYSMODULE_GEM + { .path = "external/libsysutil_photo_network_sharing.sprx", .dependencies = {} }, // 0x5b + { .path = "external/libsysutil_cross_controller.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_CROSS_CONTROLLER + + // 87 internal modules + { .path = "internal/libat3enc.sprx", .dependencies = {} }, // 0xf000 + { .path = "internal/libatxenc.sprx", .dependencies = {} }, // 0xf001 + { .path = "external/libvdec.sprx", .dependencies = {} }, // 0xf002 + { .path = "internal/libvpost.sprx", .dependencies = {} }, // 0xf003 + { .path = "internal/libmp3enc.sprx", .dependencies = DEPENDENCIES_FS }, // 0xf004 + { .path = "external/libaacenc.sprx", .dependencies = {} }, // 0xf005 + { .path = "external/libadec_internal.sprx", .dependencies = {} }, // 0xf006 + { .path = "internal/libapostsrc.sprx", .dependencies = {} }, // 0xf007 + { .path = "internal/libaudio_internal.sprx", .dependencies = {} }, // 0xf008 + { .path = "external/libavchatjpgdec.sprx", .dependencies = {} }, // 0xf009 + { .path = "external/libcelpenc.sprx", .dependencies = {} }, // CELL_SYSMODULE_CELPENC + { .path = "internal/libddlenc.sprx", .dependencies = {} }, // 0xf00b + { .path = "external/libdmux.sprx", .dependencies = {} }, // 0xf00c + { .path = "internal/libexif.sprx", .dependencies = DEPENDENCIES_FS }, // 0xf00d + { .path = "internal/libft2d.sprx", .dependencies = {} }, // 0xf00e + { .path = "internal/libgcm_osd.sprx", .dependencies = {} }, // 0xf00f + { .path = "external/libgifdec.sprx", .dependencies = DEPENDENCIES_FS }, // CELL_SYSMODULE_GIFDEC + { .path = "external/libjpgdec.sprx", .dependencies = DEPENDENCIES_FS }, // 0xf011 + { .path = "external/libjpgenc.sprx", .dependencies = DEPENDENCIES_FS }, // 0xf012 + { .path = "external/libm4venc.sprx", .dependencies = {} }, // 0xf013 + { .path = "external/libpamf.sprx", .dependencies = {} }, // 0xf014 + { .path = "external/libpngdec.sprx", .dependencies = DEPENDENCIES_FS }, // 0xf015 + { .path = "external/libpngenc.sprx", .dependencies = DEPENDENCIES_FS }, // 0xf016 + { .path = "internal/libps2savedata.sprx", .dependencies = {} }, // 0xf017 + { .path = "internal/libtiffdec.sprx", .dependencies = DEPENDENCIES_FS }, // 0xf018 + { .path = "external/libcelpdec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // CELL_SYSMODULE_ADEC_CELP + { .path = "internal/libdtsdec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf01a + { .path = "external/libm2bcdec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // CELL_SYSMODULE_ADEC_M2BC + { .path = "internal/libm2aacdec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf01c + { .path = "external/libm4aacdec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // CELL_SYSMODULE_ADEC_M4AAC + { .path = "external/libmp3dec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // CELL_SYSMODULE_ADEC_MP3 + { .path = "internal/libtrhddec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf01f + { .path = "external/libsvc1d.sprx", .dependencies = DEPENDENCIES_VDEC_AL }, // 0xf020 + { .path = "external/libsmvd4.sprx", .dependencies = DEPENDENCIES_VDEC_AL }, // 0xf021 + { .path = "external/libsysutil_remoteplay.sprx", .dependencies = {} }, // 0xf022 + { .path = "external/libsysutil_imejp.sprx", .dependencies = {} }, // CELL_SYSMODULE_IMEJP + { .path = "external/libwmadec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf024 + { .path = "internal/libasfparser.sprx", .dependencies = {} }, // 0xf025 + { .path = "external/libddpdec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf026 + { .path = "internal/libdtslbrdec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf027 + { .path = "external/libsysutil_music.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_MUSIC + { .path = "external/libsysutil_photo_export.sprx", .dependencies = {} }, // CELL_SYSMODULE_PHOTO_EXPORT + { .path = "external/libsysutil_print.sprx", .dependencies = {} }, // CELL_SYSMODULE_PRINT + { .path = "external/libsysutil_photo_import.sprx", .dependencies = {} }, // CELL_SYSMODULE_PHOTO_IMPORT + { .path = "external/libsysutil_music_export.sprx", .dependencies = {} }, // CELL_SYSMODULE_MUSIC_EXPORT + { .path = "external/libavcenc_small.sprx", .dependencies = {} }, // 0xf02d + { .path = "external/libsysutil_photo_decode.sprx", .dependencies = {} }, // CELL_SYSMODULE_PHOTO_DECODE + { .path = "external/libsysutil_search.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_SEARCH + { .path = "external/libsysutil_avc2.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_AVCHAT2 + { .path = "external/libmp4.sprx", .dependencies = {} }, // 0xf031 + { .path = "external/libsysutil_rtcalarm.sprx", .dependencies = {} }, // 0xf032 + { .path = "external/libavcenc_small.sprx", .dependencies = {} }, // 0xf033 + { .path = "external/libsail_rec.sprx", .dependencies = {} }, // CELL_SYSMODULE_SAIL_REC + { .path = "external/libsysutil_np_trophy.sprx", .dependencies = {} }, // CELL_SYSMODULE_SYSUTIL_NP_TROPHY + { .path = "external/libsjvtd.sprx", .dependencies = DEPENDENCIES_VDEC_AL }, // 0xf036 + { .path = "internal/libdtshddec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf037 + { .path = "internal/libmp3sdec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf038 + { .path = "external/libsail_avi.sprx", .dependencies = {} }, // 0xf039 + { .path = "external/libavcenc.sprx", .dependencies = {} }, // 0xf03a + { .path = "external/libapostsrc_mini.sprx", .dependencies = {} }, // 0xf03b + { .path = "external/libvoice_internal.sprx", .dependencies = {} }, // 0xf03c + { .path = "external/libmpl1dec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf03d + { .path = "external/libasfparser2_astd.sprx", .dependencies = {} }, // 0xf03e + { .path = "external/libadec2.sprx", .dependencies = {} }, // 0xf03f + { .path = "external/libac3dec2.sprx", .dependencies = DEPENDENCIES_ADEC2 }, // 0xf040 + { .path = "external/libatxdec2.sprx", .dependencies = DEPENDENCIES_ADEC2 }, // 0xf041 + { .path = "internal/libdivx311dec.sprx", .dependencies = DEPENDENCIES_VDEC_AL }, // 0xf042 + { .path = "external/libvpost2.sprx", .dependencies = {} }, // 0xf043 + { .path = "external/libsysutil_np_eula.sprx", .dependencies = {} }, // 0xf044 + { .path = "external/libsysutil_storagedata.sprx", .dependencies = {} }, // 0xf045 + { .path = "external/libm4hdenc.sprx", .dependencies = {} }, // 0xf046 + { .path = "external/libsysutil_savedata_psp.sprx", .dependencies = {} }, // 0xf047 + { .path = "external/libsysutil_video_player.sprx", .dependencies = {} }, // 0xf048 + { .path = "external/libmvcdec.sprx", .dependencies = DEPENDENCIES_VDEC_AL }, // 0xf049 + { .path = "external/libaacenc_spurs.sprx", .dependencies = {} }, // 0xf04a + { .path = "internal/libdtshdcoredec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf04b + { .path = "internal/libpidvd.sprx", .dependencies = {} }, // 0xf04c + { .path = "external/libsysutil_dtcp_ip.sprx", .dependencies = {} }, // 0xf04d + { .path = "external/libsysutil_syschat.sprx", .dependencies = {} }, // 0xf04e + { .path = "external/libsysutil_np_installer.sprx", .dependencies = {} }, // 0xf04f + { .path = "external/libbemp2sys.sprx", .dependencies = {} }, // 0xf050 + { .path = "external/libbeisobmf.sprx", .dependencies = {} }, // 0xf051 + { .path = "external/libsysutil_photo_export2.sprx", .dependencies = {} }, // 0xf052 + { .path = "external/libat3multidec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf053 + { .path = "external/libatrac3multi.sprx", .dependencies = DEPENDENCIES_AT3M }, // CELL_SYSMODULE_LIBATRAC3MULTI + { .path = "external/libsysutil_dec_psnvideo.sprx", .dependencies = {} }, // 0xf055 + { .path = "external/libdtslbrdec.sprx", .dependencies = DEPENDENCIES_ADEC_AL }, // 0xf056 + + // Special modules + { .path = "external/liblv2dbg_for_dex.sprx", .dependencies = {} }, + { .path = "external/liblv2dbg_for_cex.sprx", .dependencies = {} }, + + { .path = "external/libgcm_sys_deh.sprx", .dependencies = {} }, + { .path = "external/libgcm_sys.sprx", .dependencies = {} }, + + { .path = "external/libfs.sprx", .dependencies = {} }, + { .path = "external/libfs_155.sprx", .dependencies = {} }, + + { .path = "external/libprof.sprx", .dependencies = {} }, + { .path = "external/liblv2coredump.sprx", .dependencies = {} }, + { .path = "external/libgpad.sprx", .dependencies = {} } + }; + + constexpr u8 INTERNAL_MODULES_OFFSET = 93; + constexpr u8 INTERNAL_MODULES_COUNT = 87; + constexpr u8 LV2_DBG_IDX = INTERNAL_MODULES_OFFSET + INTERNAL_MODULES_COUNT; + constexpr u8 GCM_SYS_DEH_IDX = LV2_DBG_IDX + 2; + constexpr u8 FS_IDX = LV2_DBG_IDX + 4; + constexpr u8 PROF_IDX = LV2_DBG_IDX + 6; + constexpr u8 LV2COREDUMP_IDX = LV2_DBG_IDX + 7; + constexpr u8 GPAD_IDX = LV2_DBG_IDX + 8; + + constexpr std::string_view MODULE_BASE_PATH = "/dev_flash/sys/"; + constexpr std::string_view MODULE_BASE_PATH_DEBUG = "/app_home/"; + constexpr u8 BASE_PATH_MAX_SIZE = 0x10; + constexpr u8 PATH_MAX_SIZE = 0x40; + static_assert(MODULE_BASE_PATH.size() < BASE_PATH_MAX_SIZE && MODULE_BASE_PATH_DEBUG.size() < BASE_PATH_MAX_SIZE); + static_assert(std::ranges::all_of(MODULE_INFOS, [](const auto& path) { return path.size() + BASE_PATH_MAX_SIZE < PATH_MAX_SIZE; }, &module_info::path)); + + constexpr std::array DEFAULT_MODULES + { + CELL_SYSMODULE_SYSUTIL, + CELL_SYSMODULE_GCM_SYS, + CELL_SYSMODULE_AUDIO, + CELL_SYSMODULE_IO, + CELL_SYSMODULE_SPURS, + CELL_SYSMODULE_FS, + CELL_SYSMODULE_SYSUTIL_NP_TROPHY + }; + + constexpr bit_set LOADABLE_INTERNAL_MODULES + { + "0010000" // 0xf054 + "0000000000010000" // 0xf044 + "0000000000110001" // 0xf030, 0xf034, 0xf035 + "1101111100001000" // 0xf023, 0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02e, 0xf02f + "0110101000000001" // 0xf010, 0xf019, 0xf01b, 0xf01d, 0xf01e + "0000010000000000" // 0xf00a + }; + + constexpr bit_set LOADABLE_INTERNAL_MODULES_EX + { + "1110111" // 0xf050, 0xf051, 0xf052, 0xf054, 0xf055, 0xf056 + "1110011111111011" // 0xf040, 0xf041, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047, 0xf048, 0xf049, 0xf04a, 0xf04d, 0xf04e, 0xf04f + "1110011001111101" // 0xf030, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf039, 0xf03a, 0xf03d, 0xf03e, 0xf03f + "1101111101011111" // 0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf026, 0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02e, 0xf02f + "0110101000001001" // 0xf010, 0xf013, 0xf019, 0xf01b, 0xf01d, 0xf01e + "0000010000100000" // 0xf005, 0xf00a + }; + + constexpr std::array KEY_UNK{ 'S', 'r', 'e', 'k', 'i', 'r', 't', 'S', 'a', 'h', 'o', 'n', 'a', 'N', 'l', 'a' }; + + struct module_state + { + s32 loaded_count; + s32 prx_id; + }; + + struct sysmodule_context + { + sys_lwmutex_t mutex; + + be_t unk_addr; + + std::optional mem_container_id; + + std::array module_states; + + std::array module_base_path; + u8 module_base_path_size; + }; + + vm::gvar s_sysmodule_context; } -static const char* get_module_id(u16 id) +template +[[nodiscard]] static bool check_special_handling(ppu_thread& ppu) { - static thread_local char tls_id_name[8]; // for test + // TODO replace with proper struct + const vm::var paramsfo(0x40); + std::memset(paramsfo.get_ptr(), 0, paramsfo.get_count()); - switch (id) + const error_code ret = ppu_execute<&sys_process_get_paramsfo>(ppu, +paramsfo); + + switch (module_id) { - case 0x0000: return "CELL_SYSMODULE_NET"; - case 0x0001: return "CELL_SYSMODULE_HTTP"; - case 0x0002: return "CELL_SYSMODULE_HTTP_UTIL"; - case 0x0003: return "CELL_SYSMODULE_SSL"; - case 0x0004: return "CELL_SYSMODULE_HTTPS"; - case 0x0005: return "CELL_SYSMODULE_VDEC"; - case 0x0006: return "CELL_SYSMODULE_ADEC"; - case 0x0007: return "CELL_SYSMODULE_DMUX"; - case 0x0008: return "CELL_SYSMODULE_VPOST"; - case 0x0009: return "CELL_SYSMODULE_RTC"; - case 0x000a: return "CELL_SYSMODULE_SPURS"; - case 0x000b: return "CELL_SYSMODULE_OVIS"; - case 0x000c: return "CELL_SYSMODULE_SHEAP"; - case 0x000d: return "CELL_SYSMODULE_SYNC"; - case 0x000e: return "CELL_SYSMODULE_FS"; - case 0x000f: return "CELL_SYSMODULE_JPGDEC"; - case 0x0010: return "CELL_SYSMODULE_GCM_SYS"; - case 0x0011: return "CELL_SYSMODULE_AUDIO"; - case 0x0012: return "CELL_SYSMODULE_PAMF"; - case 0x0013: return "CELL_SYSMODULE_ATRAC3PLUS"; - case 0x0014: return "CELL_SYSMODULE_NETCTL"; - case 0x0015: return "CELL_SYSMODULE_SYSUTIL"; - case 0x0016: return "CELL_SYSMODULE_SYSUTIL_NP"; - case 0x0017: return "CELL_SYSMODULE_IO"; - case 0x0018: return "CELL_SYSMODULE_PNGDEC"; - case 0x0019: return "CELL_SYSMODULE_FONT"; - case 0x001a: return "CELL_SYSMODULE_FONTFT"; - case 0x001b: return "CELL_SYSMODULE_FREETYPE"; - case 0x001c: return "CELL_SYSMODULE_USBD"; - case 0x001d: return "CELL_SYSMODULE_SAIL"; - case 0x001e: return "CELL_SYSMODULE_L10N"; - case 0x001f: return "CELL_SYSMODULE_RESC"; - case 0x0020: return "CELL_SYSMODULE_DAISY"; - case 0x0021: return "CELL_SYSMODULE_KEY2CHAR"; - case 0x0022: return "CELL_SYSMODULE_MIC"; - case 0x0023: return "CELL_SYSMODULE_CAMERA"; - case 0x0024: return "CELL_SYSMODULE_VDEC_MPEG2"; - case 0x0025: return "CELL_SYSMODULE_VDEC_AVC"; - case 0x0026: return "CELL_SYSMODULE_ADEC_LPCM"; - case 0x0027: return "CELL_SYSMODULE_ADEC_AC3"; - case 0x0028: return "CELL_SYSMODULE_ADEC_ATX"; - case 0x0029: return "CELL_SYSMODULE_ADEC_AT3"; - case 0x002a: return "CELL_SYSMODULE_DMUX_PAMF"; - case 0x002b: return "CELL_SYSMODULE_VDEC_AL"; - case 0x002c: return "CELL_SYSMODULE_ADEC_AL"; - case 0x002d: return "CELL_SYSMODULE_DMUX_AL"; - case 0x002e: return "CELL_SYSMODULE_LV2DBG"; - case 0x002f: return "CELL_SYSMODULE_SYSUTIL_AVCHAT"; - case 0x0030: return "CELL_SYSMODULE_USBPSPCM"; - case 0x0031: return "CELL_SYSMODULE_AVCONF_EXT"; - case 0x0032: return "CELL_SYSMODULE_SYSUTIL_USERINFO"; - case 0x0033: return "CELL_SYSMODULE_SYSUTIL_SAVEDATA"; - case 0x0034: return "CELL_SYSMODULE_SUBDISPLAY"; - case 0x0035: return "CELL_SYSMODULE_SYSUTIL_REC"; - case 0x0036: return "CELL_SYSMODULE_VIDEO_EXPORT"; - case 0x0037: return "CELL_SYSMODULE_SYSUTIL_GAME_EXEC"; - case 0x0038: return "CELL_SYSMODULE_SYSUTIL_NP2"; - case 0x0039: return "CELL_SYSMODULE_SYSUTIL_AP"; - case 0x003a: return "CELL_SYSMODULE_SYSUTIL_NP_CLANS"; - case 0x003b: return "CELL_SYSMODULE_SYSUTIL_OSK_EXT"; - case 0x003c: return "CELL_SYSMODULE_VDEC_DIVX"; - case 0x003d: return "CELL_SYSMODULE_JPGENC"; - case 0x003e: return "CELL_SYSMODULE_SYSUTIL_GAME"; - case 0x003f: return "CELL_SYSMODULE_BGDL"; - case 0x0040: return "CELL_SYSMODULE_FREETYPE_TT"; - case 0x0041: return "CELL_SYSMODULE_SYSUTIL_VIDEO_UPLOAD"; - case 0x0042: return "CELL_SYSMODULE_SYSUTIL_SYSCONF_EXT"; - case 0x0043: return "CELL_SYSMODULE_FIBER"; - case 0x0044: return "CELL_SYSMODULE_SYSUTIL_NP_COMMERCE2"; - case 0x0045: return "CELL_SYSMODULE_SYSUTIL_NP_TUS"; - case 0x0046: return "CELL_SYSMODULE_VOICE"; - case 0x0047: return "CELL_SYSMODULE_ADEC_CELP8"; - case 0x0048: return "CELL_SYSMODULE_CELP8ENC"; - case 0x0049: return "CELL_SYSMODULE_SYSUTIL_LICENSEAREA"; - case 0x004a: return "CELL_SYSMODULE_SYSUTIL_MUSIC2"; - // TODO: Check if those libad are correctly matched. - // They belong to those IDs but actual order is unknown. - case 0x004b: return "CELL_SYSMODULE_AD_CORE"; - case 0x004c: return "CELL_SYSMODULE_AD_ASYNC"; - case 0x004d: return "CELL_SYSMODULE_AD_BILLBOARD_UTIL"; - case 0x004e: return "CELL_SYSMODULE_SYSUTIL_SCREENSHOT"; - case 0x004f: return "CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE"; - case 0x0050: return "CELL_SYSMODULE_SPURS_JQ"; - case 0x0052: return "CELL_SYSMODULE_PNGENC"; - case 0x0053: return "CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE2"; - case 0x0054: return "CELL_SYSMODULE_MEDI"; - case 0x0055: return "CELL_SYSMODULE_SYNC2"; - case 0x0056: return "CELL_SYSMODULE_SYSUTIL_NP_UTIL"; - case 0x0057: return "CELL_SYSMODULE_RUDP"; - case 0x0059: return "CELL_SYSMODULE_SYSUTIL_NP_SNS"; - case 0x005a: return "CELL_SYSMODULE_GEM"; - case 0x005c: return "CELL_SYSMODULE_SYSUTIL_CROSS_CONTROLLER"; - case 0xf00a: return "CELL_SYSMODULE_CELPENC"; - case 0xf010: return "CELL_SYSMODULE_GIFDEC"; - case 0xf019: return "CELL_SYSMODULE_ADEC_CELP"; - case 0xf01b: return "CELL_SYSMODULE_ADEC_M2BC"; - case 0xf01d: return "CELL_SYSMODULE_ADEC_M4AAC"; - case 0xf01e: return "CELL_SYSMODULE_ADEC_MP3"; - case 0xf023: return "CELL_SYSMODULE_IMEJP"; - case 0xf028: return "CELL_SYSMODULE_SYSUTIL_MUSIC"; - case 0xf029: return "CELL_SYSMODULE_PHOTO_EXPORT"; - case 0xf02a: return "CELL_SYSMODULE_PRINT"; - case 0xf02b: return "CELL_SYSMODULE_PHOTO_IMPORT"; - case 0xf02c: return "CELL_SYSMODULE_MUSIC_EXPORT"; - case 0xf02e: return "CELL_SYSMODULE_PHOTO_DECODE"; - case 0xf02f: return "CELL_SYSMODULE_SYSUTIL_SEARCH"; - case 0xf030: return "CELL_SYSMODULE_SYSUTIL_AVCHAT2"; - case 0xf034: return "CELL_SYSMODULE_SAIL_REC"; - case 0xf035: return "CELL_SYSMODULE_SYSUTIL_NP_TROPHY"; - case 0xf044: return "CELL_SYSMODULE_SYSUTIL_NP_EULA"; - case 0xf053: return "CELL_SYSMODULE_ADEC_AT3MULTI"; - case 0xf054: return "CELL_SYSMODULE_LIBATRAC3MULTI"; - case 0xffff: return "CELL_SYSMODULE_INVALID"; + case CELL_SYSMODULE_LV2DBG: + { + // If the LSB of the u64 at offset 0x18 and the extra load flag "EnableLv2ExceptionHandler" is set, + // or a certain bit in bootflag.dat, loads liblv2dbg_for_dex.sprx instead of liblv2dbg_for_cex + const vm::var boot_flag(8); + std::memset(boot_flag.get_ptr(), 0, boot_flag.get_count()); + + if (ret != CELL_OK || !read_from_ptr>(paramsfo, 0x18)) + { + const vm::var file_descriptor; + + if (sys_fs_open(ppu, vm::make_str("/dev_hdd0/data/bootflag.dat"), 0, file_descriptor, 0, vm::null, 0) != CELL_OK) + { + return true; + } + + const vm::var nread; + ensure(sys_fs_read(ppu, *file_descriptor, boot_flag, 8, nread) == CELL_OK && *nread == 8ull); // Not checked on LLE + ensure(sys_fs_close(ppu, *file_descriptor) == CELL_OK); // Not checked on LLE + + return !!read_from_ptr>(boot_flag, 1); + } + + return !read_from_ptr>(paramsfo, 0x10); + } + case CELL_SYSMODULE_GCM_SYS: + { + // If the extra load flag "EnableGCMDebug" is set, loads libgcm_sys_deh.sprx instead of libgcm_sys.sprx + return ret != CELL_OK || !read_from_ptr>(paramsfo, 0x10); + } + case CELL_SYSMODULE_FS: + { + // "F.E.A.R. First Encounter Assault Recon" needs an older version of cellFs + return std::ranges::contains(std::array{ "BLUS30003", "BLES00035", "BLES00036" }, std::string_view{ paramsfo.get_ptr() + 1, 9 }); + } + case CELL_SYSMODULE_SAIL: + { + // "Armored Core 4" needs a frame buffer release delay of three frames + return std::ranges::contains(std::array{ "BLJM60012", "BLES00039", "BLUS30027", "BLKS20001" }, std::string_view{ paramsfo.get_ptr() + 1, 9 }); + } + default: + std::unreachable(); + } +} + +static error_code load_module(ppu_thread& ppu, u8 module_idx, u32 args, vm::ptr argp) +{ + cellSysmodule.notice("load_module(module_idx=%d, args=%d, argp=*0x%x)", module_idx, args, argp); + + ensure(module_idx < MODULE_INFOS.size()); + auto& [loaded_count, prx_id] = s_sysmodule_context->module_states[module_idx]; + const auto& [path, dependencies] = MODULE_INFOS[module_idx]; + + cellSysmodule.notice("load_module(): path=\"%s\", loaded_count=%d, prx_id=%d", path, loaded_count, prx_id); + + if (path.empty()) + { + return CELL_OK; } - std::snprintf(tls_id_name, sizeof(tls_id_name), "0x%04X", id); - return tls_id_name; + if (loaded_count == smax + || ppu_execute<&sys_lwmutex_lock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex), 0) != CELL_OK) + { + return CELL_SYSMODULE_ERROR_FATAL; + } + + if (loaded_count == 0) + { + const vm::var module_path(72); + std::memcpy(module_path.get_ptr(), s_sysmodule_context->module_base_path.data(), s_sysmodule_context->module_base_path_size); + std::memcpy(module_path.get_ptr() + s_sysmodule_context->module_base_path_size, path.data(), path.size() + 1); + + const error_code ret = s_sysmodule_context->mem_container_id + ? ppu_execute<&sys_prx_load_module_on_memcontainer>(ppu, +module_path, *s_sysmodule_context->mem_container_id, 0, vm::null) + : ppu_execute<&sys_prx_load_module>(ppu, +module_path, 0, vm::null); + + prx_id = ret; + + if (ret < 1) + { + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + return ret; + } + + if (const error_code ret = ppu_execute<&sys_prx_start_module>(ppu, prx_id, args, argp, +vm::make_var(0), 0, vm::null); ret != CELL_OK) + { + ensure(ppu_execute<&sys_prx_unload_module>(ppu, prx_id, 0, vm::null) == CELL_OK); // Not checked on LLE + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + return ret; + } + } + + loaded_count++; + + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + return CELL_OK; +} + +template +static error_code unload_module(ppu_thread& ppu, u8 module_idx) +{ + cellSysmodule.notice("unload_module(module_idx=%d)", module_idx); + + ensure(module_idx < MODULE_INFOS.size()); + auto& [loaded_count, prx_id] = s_sysmodule_context->module_states[module_idx]; + const std::string_view& path = MODULE_INFOS[module_idx].path; + + cellSysmodule.notice("unload_module(): path=\"%s\", loaded_count=%d, prx_id=%d", path, loaded_count, prx_id); + + if (path.empty()) + { + return CELL_OK; + } + + if (ppu_execute<&sys_lwmutex_lock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex), 0) != CELL_OK) + { + return CELL_SYSMODULE_ERROR_FATAL; + } + + if (loaded_count == 1 || force_unload) + { + ensure(ppu_execute<&sys_prx_stop_module>(ppu, prx_id, 0, vm::null, +vm::make_var(0), 0, vm::null) == CELL_OK); // Not checked on LLE + ensure(ppu_execute<&sys_prx_unload_module>(ppu, prx_id, 0, vm::null) == CELL_OK); // Not checked on LLE + loaded_count = 0; + } + else if (loaded_count > 1) + { + loaded_count--; + } + + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + return CELL_OK; +} + +extern error_code sysmoduleModuleStop(ppu_thread& ppu) +{ + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; + + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellSysmodule.notice("module_stop()"); + + if (s_sysmodule_context->unk_addr) + { + if (sys_memory_free(ppu, s_sysmodule_context->unk_addr) != CELL_OK) + { + return 1; // SYS_PRX_STOP_FAILED + } + + s_sysmodule_context->unk_addr = 0; + } + + if (ppu_execute<&sys_lwmutex_destroy>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) != CELL_OK) + { + return 1; // SYS_PRX_STOP_FAILED + } + + return CELL_OK; // SYS_PRX_STOP_OK +} + +extern error_code sysmoduleModuleStart(ppu_thread& ppu, u32 args, vm::ptr argp) +{ + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; + + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellSysmodule.notice("module_start(args=%d, argp=*0x%x)", args, argp); + + s_sysmodule_context->mem_container_id.reset(); + + if (const vm::var auth_id; sys_ss_access_control_engine(1, sys_process_getpid(), auth_id.addr()) == CELL_OK) + { + if ((*auth_id & 0x00ffffff) == 1 || (*auth_id & 0x00ffffff) == 2) + { + return 1; // SYS_PRX_NO_RESIDENT + } + } + else if (sys_ss_access_control_engine(2, auth_id.addr(), 0) != CELL_OK || *auth_id == PAID_44 || *auth_id == 0x1070000056000001ll) + { + return 1; // SYS_PRX_NO_RESIDENT + } + + const vm::var lwmutex_attr + {{ + .protocol = SYS_SYNC_PRIORITY, + .recursive = SYS_SYNC_NOT_RECURSIVE, + .name_u64 = "_smolwm"_u64 + }}; + + if (ppu_execute<&sys_lwmutex_create>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex), +lwmutex_attr) != CELL_OK) + { + return 1; // SYS_PRX_NO_RESIDENT + } + + // TODO replace with proper struct + const vm::var paramsfo(0x40); + std::memset(paramsfo.get_ptr(), 0, paramsfo.get_count()); + + error_code get_paramsfo_ret = ppu_execute<&sys_process_get_paramsfo>(ppu, +paramsfo); + const bool retail_gcm_sys = check_special_handling(ppu); + + // Load default modules + if (const vm::var sdk_version; + ensure(sys_process_get_sdk_version(sys_process_getpid(), sdk_version) == CELL_OK), // Not checked on LLE + *sdk_version < 0x330000) + { + for (const u16 module_id : DEFAULT_MODULES | std::views::take(5) ) + { + if (module_id == CELL_SYSMODULE_GCM_SYS) + { + if (get_paramsfo_ret == CELL_OK && read_from_ptr>(paramsfo, 0x10) && !retail_gcm_sys) + { + if (load_module(ppu, GCM_SYS_DEH_IDX, 8, paramsfo + 0x28) != CELL_OK) + { + sysmoduleModuleStop(ppu); + return 1; // SYS_PRX_NO_RESIDENT + } + } + else + { + if (load_module(ppu, GCM_SYS_DEH_IDX + retail_gcm_sys, 0, vm::null) != CELL_OK) + { + sysmoduleModuleStop(ppu); + return 1; // SYS_PRX_NO_RESIDENT + } + } + + s_sysmodule_context->module_states[CELL_SYSMODULE_GCM_SYS].loaded_count = + s_sysmodule_context->module_states[GCM_SYS_DEH_IDX + retail_gcm_sys].loaded_count; + } + else + { + if (cellSysmoduleLoadModule(ppu, module_id) != CELL_OK) + { + sysmoduleModuleStop(ppu); + return 1; // SYS_PRX_NO_RESIDENT + } + } + } + } + else + { + // Build a path list of the default modules + const vm::var paths(PATH_MAX_SIZE * size32(DEFAULT_MODULES)); + const vm::var[]> path_list(size32(DEFAULT_MODULES)); + + for (u32 i = 0; i < DEFAULT_MODULES.size(); i++) + { + const std::string_view path = DEFAULT_MODULES[i] == CELL_SYSMODULE_GCM_SYS + ? MODULE_INFOS[GCM_SYS_DEH_IDX + retail_gcm_sys].path + : DEFAULT_MODULES[i] >= INTERNAL_MODULE_ID_BASE + ? MODULE_INFOS[INTERNAL_MODULES_OFFSET + (DEFAULT_MODULES[i] & INTERNAL_MODULE_ID_MASK)].path + : MODULE_INFOS[DEFAULT_MODULES[i]].path; + + std::memcpy(paths.get_ptr() + (i * PATH_MAX_SIZE), MODULE_BASE_PATH.data(), MODULE_BASE_PATH.size()); + std::memcpy(paths.get_ptr() + (i * PATH_MAX_SIZE) + MODULE_BASE_PATH.size(), path.data(), path.size() + 1); + + path_list[i] = paths + i * PATH_MAX_SIZE; + } + + // Load them all at once + const vm::var id_list(size32(DEFAULT_MODULES)); + + if (ppu_execute<&sys_prx_load_module_list>(ppu, DEFAULT_MODULES.size(), +path_list, 0, vm::null, +id_list) != CELL_OK) + { + sysmoduleModuleStop(ppu); + return 1; // SYS_PRX_NO_RESIDENT + } + + // Start the modules + for (const auto [module_id, prx_ix] : std::views::zip(DEFAULT_MODULES, std::span{ id_list.begin().get_ptr(), id_list.get_count() })) + { + if (module_id == CELL_SYSMODULE_GCM_SYS && read_from_ptr>(paramsfo, 0x10) && !retail_gcm_sys) + { + s_sysmodule_context->module_states[CELL_SYSMODULE_GCM_SYS].prx_id = static_cast(prx_ix); + + if (ppu_execute<&sys_prx_start_module>(ppu, +prx_ix, 8, paramsfo + 0x28, +vm::make_var(0), 0, vm::null) != CELL_OK) + { + sysmoduleModuleStop(ppu); + return 1; // SYS_PRX_NO_RESIDENT + } + + s_sysmodule_context->module_states[CELL_SYSMODULE_GCM_SYS].loaded_count++; + } + else + { + const u8 module_idx = module_id >= INTERNAL_MODULE_ID_BASE ? INTERNAL_MODULES_OFFSET + (module_id & INTERNAL_MODULE_ID_MASK) : module_id; + + s_sysmodule_context->module_states[module_idx].prx_id = static_cast(prx_ix); + + if (ppu_execute<&sys_prx_start_module>(ppu, +prx_ix, 0, vm::null, +vm::make_var(0), 0, vm::null) != CELL_OK) + { + sysmoduleModuleStop(ppu); + return 1;// SYS_PRX_NO_RESIDENT + } + + s_sysmodule_context->module_states[module_idx].loaded_count++; + } + + if (module_id == CELL_SYSMODULE_GCM_SYS) + { + s_sysmodule_context->module_states[GCM_SYS_DEH_IDX + retail_gcm_sys].loaded_count = + s_sysmodule_context->module_states[CELL_SYSMODULE_GCM_SYS].loaded_count; + } + else if (module_id == CELL_SYSMODULE_FS) + { + s_sysmodule_context->module_states[FS_IDX + check_special_handling(ppu)].loaded_count = + s_sysmodule_context->module_states[CELL_SYSMODULE_FS].loaded_count; + } + } + + // LLE overwrites the return value of sys_process_get_paramsfo() here and won't return an error if the allocation fails + get_paramsfo_ret = sys_memory_allocate(ppu, (!retail_gcm_sys + 1) * 0x10000ull, SYS_MEMORY_PAGE_SIZE_64K, s_sysmodule_context.ptr(&sysmodule_context::unk_addr)); + } + + if (get_paramsfo_ret != CELL_OK) + { + return CELL_OK; // SYS_PRX_RESIDENT + } + + // Load additional modules if certain ExtraLoadFlags are set + + if (read_from_ptr>(paramsfo, 0x10) && !retail_gcm_sys && read_from_ptr>(paramsfo, 0x18)) + { + cellSysmoduleSetDebugmode(true); + + if (load_module(ppu, GPAD_IDX, 8, paramsfo + 0x28) != CELL_OK) + { + ensure(unload_module(ppu, GPAD_IDX) == CELL_OK); // Not checked on LLE + } + + cellSysmoduleSetDebugmode(false); + } + + if (read_from_ptr>(paramsfo, 0x10) && read_from_ptr>(paramsfo, 0x18)) + { + if (load_module(ppu, PROF_IDX, 0, vm::null) != CELL_OK) + { + ensure(unload_module(ppu, PROF_IDX) == CELL_OK); // Not checked on LLE + } + } + + if (read_from_ptr>(paramsfo, 0x10)) + { + if (load_module(ppu, LV2COREDUMP_IDX, 0, vm::null) != CELL_OK) + { + ensure(unload_module(ppu, LV2COREDUMP_IDX) == CELL_OK); // Not checked on LLE + } + } + + if (read_from_ptr>(paramsfo, 0x10)) + { + if (cellSysmoduleLoadModuleInternal(ppu, 0xf022) != CELL_OK) + { + sysmoduleModuleStop(ppu); + return 1; // SYS_PRX_NO_RESIDENT + } + } + + return CELL_OK; // SYS_PRX_RESIDENT } error_code cellSysmoduleInitialize() { - cellSysmodule.warning("cellSysmoduleInitialize()"); + cellSysmodule.notice("cellSysmoduleInitialize()"); + // Doesn't do anything return CELL_OK; } error_code cellSysmoduleFinalize() { - cellSysmodule.warning("cellSysmoduleFinalize()"); + cellSysmodule.notice("cellSysmoduleFinalize()"); + // Doesn't do anything return CELL_OK; } -error_code cellSysmoduleSetMemcontainer(u32 ct_id) +error_code cellSysmoduleSetMemcontainer(ppu_thread& ppu, u32 ct_id) { - cellSysmodule.todo("cellSysmoduleSetMemcontainer(ct_id=0x%x)", ct_id); + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; + + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellSysmodule.notice("cellSysmoduleSetMemcontainer(ct_id=0x%x)", ct_id); + + if (ppu_execute<&sys_lwmutex_lock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex), 0) != CELL_OK) + { + return CELL_SYSMODULE_ERROR_FATAL; + } + + if (ct_id == SYS_MEMORY_CONTAINER_ID_INVALID) + { + s_sysmodule_context->mem_container_id.reset(); + } + else + { + if (const vm::var memory_info; + sys_memory_container_get_size(ppu, +memory_info, ct_id) != CELL_OK || memory_info->available_user_memory < 0x60000) + { + s_sysmodule_context->mem_container_id.reset(); + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + return CELL_SYSMODULE_ERROR_INVALID_MEMCONTAINER; + } + + s_sysmodule_context->mem_container_id = ct_id; + } + + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE return CELL_OK; } -error_code cellSysmoduleLoadModule(u16 id) +error_code cellSysmoduleLoadModule(ppu_thread& ppu, u16 id) { - cellSysmodule.warning("cellSysmoduleLoadModule(id=0x%04X=%s)", id, get_module_id(id)); + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; - const auto name = get_module_name(id); + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } - if (!name) + cellSysmodule.notice("cellSysmoduleLoadModule(id=0x%x)", id); + + if (id < INTERNAL_MODULES_OFFSET) + { + switch (id) + { + case CELL_SYSMODULE_FS: + { + const bool fs_155 = check_special_handling(ppu); + const error_code ret = load_module(ppu, FS_IDX + fs_155, 0, vm::null); + s_sysmodule_context->module_states[CELL_SYSMODULE_FS].loaded_count = s_sysmodule_context->module_states[FS_IDX + fs_155].loaded_count; + return ret; + } + case CELL_SYSMODULE_GCM_SYS: + { + const bool retail_gcm_sys = check_special_handling(ppu); + const error_code ret = load_module(ppu, GCM_SYS_DEH_IDX + retail_gcm_sys, 0, vm::null); + s_sysmodule_context->module_states[CELL_SYSMODULE_GCM_SYS].loaded_count = s_sysmodule_context->module_states[GCM_SYS_DEH_IDX + retail_gcm_sys].loaded_count; + return ret; + } + case CELL_SYSMODULE_SAIL: + { + if (check_special_handling(ppu)) + { + const vm::var sail_parameters(2); + sail_parameters[0] = 0x19; // Parameter type? Must be set to this, or else cellSail will not set the frame buffer release delay below (see module_start() of cellSail) + sail_parameters[1] = 3; // Delay the release of the frame buffer by three frames instead of two + return load_module(ppu, CELL_SYSMODULE_SAIL, 8, +sail_parameters); + } + + return load_module(ppu, CELL_SYSMODULE_SAIL, 0, vm::null); + } + case CELL_SYSMODULE_LV2DBG: + { + const bool cex_lv2dgb = check_special_handling(ppu); + const error_code ret = load_module(ppu, LV2_DBG_IDX + cex_lv2dgb, 0, vm::null); + s_sysmodule_context->module_states[CELL_SYSMODULE_LV2DBG].loaded_count = s_sysmodule_context->module_states[LV2_DBG_IDX + cex_lv2dgb].loaded_count; + return ret; + } + case 0x58: + { + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + default: + { + // Load dependencies + for (const u16 module_id : MODULE_INFOS[id].dependencies) + { + if (module_id >= INTERNAL_MODULE_ID_BASE) + { + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + if (const error_code ret = cellSysmoduleLoadModule(ppu, module_id); + ret != CELL_OK && ret != static_cast(CELL_SYSMODULE_ERROR_DUPLICATED)) + { + return ret; + } + } + + return load_module(ppu, static_cast(id), 0, vm::null); + } + } + } + + if ((id & INTERNAL_MODULE_ID_MASK) >= INTERNAL_MODULES_COUNT + || !LOADABLE_INTERNAL_MODULES[id & INTERNAL_MODULE_ID_MASK]) { return CELL_SYSMODULE_ERROR_UNKNOWN; } - //if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) - //{ - // // CELL_SYSMODULE_ERROR_DUPLICATED shouldn't be returned - // m->Load(); - //} - - return CELL_OK; + return cellSysmoduleLoadModuleInternal(ppu, id); } -error_code cellSysmoduleUnloadModule(u16 id) +error_code cellSysmoduleUnloadModule(ppu_thread& ppu, u16 id) { - cellSysmodule.warning("cellSysmoduleUnloadModule(id=0x%04X=%s)", id, get_module_id(id)); + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; - const auto name = get_module_name(id); + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } - if (!name) + cellSysmodule.notice("cellSysmoduleUnloadModule(id=0x%x)", id); + + if (id == 0x58) { return CELL_SYSMODULE_ERROR_UNKNOWN; } - //if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) - //{ - // if (!m->IsLoaded()) - // { - // cellSysmodule.error("cellSysmoduleUnloadModule() failed: module not loaded (id=0x%04x)", id); - // return CELL_SYSMODULE_ERROR_FATAL; - // } + if (id < INTERNAL_MODULES_OFFSET) + { + const vm::var sdk_version; + ensure(sys_process_get_sdk_version(sys_process_getpid(), sdk_version) == CELL_OK); // Not checked on LLE - // m->Unload(); - //} + // Do not unload a default module + for (const u16 module_id : DEFAULT_MODULES | std::views::take(*sdk_version < 0x330000 ? 5 : DEFAULT_MODULES.size())) + { + if (ppu_execute<&sys_lwmutex_lock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex), 0) != CELL_OK) + { + return CELL_SYSMODULE_ERROR_FATAL; + } - return CELL_OK; -} + if (module_id == id && s_sysmodule_context->module_states[id].loaded_count == 1) + { + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + return CELL_OK; + } -error_code cellSysmoduleIsLoaded(u16 id) -{ - cellSysmodule.warning("cellSysmoduleIsLoaded(id=0x%04X=%s)", id, get_module_id(id)); + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + } - const auto name = get_module_name(id); + error_code ret; + switch (id) + { + case CELL_SYSMODULE_FS: + { + const bool fs_155 = check_special_handling(ppu); + ret = unload_module(ppu, FS_IDX + fs_155); + s_sysmodule_context->module_states[CELL_SYSMODULE_FS].loaded_count = s_sysmodule_context->module_states[FS_IDX + fs_155].loaded_count; + break; + } + case CELL_SYSMODULE_GCM_SYS: + { + const bool retail_gcm_sys = check_special_handling(ppu); + ret = unload_module(ppu, GCM_SYS_DEH_IDX + retail_gcm_sys); + s_sysmodule_context->module_states[CELL_SYSMODULE_GCM_SYS].loaded_count = s_sysmodule_context->module_states[GCM_SYS_DEH_IDX + retail_gcm_sys].loaded_count; + break; + } + case CELL_SYSMODULE_LV2DBG: + { + const bool cex_lv2dbg = check_special_handling(ppu); + ret = unload_module(ppu, LV2_DBG_IDX + cex_lv2dbg); + s_sysmodule_context->module_states[CELL_SYSMODULE_LV2DBG].loaded_count = s_sysmodule_context->module_states[LV2_DBG_IDX + cex_lv2dbg].loaded_count; + break; + } + default: + { + ret = unload_module(ppu, static_cast(id)); + } + } - if (!name) + if (ret < CELL_OK) + { + return ret; + } + + // Unload dependencies in reverse order + for (const u16 module_id : MODULE_INFOS[id].dependencies | std::views::reverse) + { + if (module_id >= INTERNAL_MODULE_ID_BASE) + { + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + if (const error_code ret = cellSysmoduleUnloadModule(ppu, module_id); ret != CELL_OK) + { + return ret; + } + } + + return CELL_OK; + } + + if ((id & INTERNAL_MODULE_ID_MASK) >= INTERNAL_MODULES_COUNT + || !LOADABLE_INTERNAL_MODULES[id & INTERNAL_MODULE_ID_MASK]) { return CELL_SYSMODULE_ERROR_UNKNOWN; } - //if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) - //{ - // if (!m->IsLoaded()) - // { - // cellSysmodule.warning("cellSysmoduleIsLoaded(): module not loaded (id=0x%04x)", id); - // return CELL_SYSMODULE_ERROR_UNLOADED; - // } - //} - - return CELL_SYSMODULE_LOADED; + return cellSysmoduleUnloadModuleInternal(ppu, id); } -error_code cellSysmoduleGetImagesize() +error_code cellSysmoduleIsLoaded(ppu_thread& ppu, u16 id) { - UNIMPLEMENTED_FUNC(cellSysmodule); + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; + + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellSysmodule.notice("cellSysmoduleIsLoaded(id=0x%x)", id); + + if (id == 0x58) + { + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + if (id < INTERNAL_MODULES_OFFSET) + { + if (ppu_execute<&sys_lwmutex_lock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex), 0) != CELL_OK) + { + return CELL_SYSMODULE_ERROR_FATAL; + } + + const u16 module_id = MODULE_INFOS[id].path.empty() ? *MODULE_INFOS[id].dependencies.rbegin() : id; + const s32 loaded_count = s_sysmodule_context->module_states[module_id].loaded_count; + + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + + return loaded_count > 0 ? CELL_OK : not_an_error(CELL_SYSMODULE_ERROR_UNLOADED); + } + + if ((id & INTERNAL_MODULE_ID_MASK) >= INTERNAL_MODULES_COUNT + || !LOADABLE_INTERNAL_MODULES[id & INTERNAL_MODULE_ID_MASK]) + { + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + return cellSysmoduleIsLoadedEx(ppu, id); +} + +error_code cellSysmoduleGetImagesize(ppu_thread& ppu, u16 id, vm::ptr image_size) +{ + cellSysmodule.notice("cellSysmoduleGetImagesize(id=0x%x, image_size=*0x%x)", id, image_size); + + ensure(!!image_size); // Not checked on LLE + + *image_size = 0; + + if (id < UNK_MODULE_ID_BASE || (id & UNK_MODULE_ID_MASK) >= 2) + { + return CELL_SYSMODULE_ERROR_FATAL; + } + + const vm::var file_descriptor; + + if (const vm::var path = (id & UNK_MODULE_ID_MASK) == 0 ? vm::make_str("/dev_flash/sys/external/flashATRAC.pic") : vm::make_str(""); // The second string is empty on LLE + sys_fs_open(ppu, path, 0, file_descriptor, 0, vm::null, 0) != CELL_OK) + { + return CELL_SYSMODULE_ERROR_FATAL; + } + + const vm::var sb; + + if (sys_fs_fstat(ppu, *file_descriptor, sb) != CELL_OK) + { + ensure(sys_fs_close(ppu, *file_descriptor) == CELL_OK); // Not checked on LLE + return CELL_SYSMODULE_ERROR_FATAL; + } + + *image_size = static_cast(sb->size); + + ensure(sys_fs_close(ppu, *file_descriptor) == CELL_OK); // Not checked on LLE return CELL_OK; } -error_code cellSysmoduleFetchImage() +error_code cellSysmoduleFetchImage(ppu_thread& ppu, u16 id, vm::ptr image_buf, vm::ptr buf_size) { - UNIMPLEMENTED_FUNC(cellSysmodule); + cellSysmodule.notice("cellSysmoduleFetchImage(id=0x%x, image_buf=*0x%x, buf_size=*0x%x)", id, image_buf, buf_size); + + if (id < UNK_MODULE_ID_BASE) + { + return CELL_SYSMODULE_ERROR_FATAL; + } + + const vm::var file_descriptor; + + ensure(!!buf_size); // Not checked on LLE + + if (const vm::var path = (id & UNK_MODULE_ID_MASK) == 0 ? vm::make_str("/dev_flash/sys/external/flashATRAC.pic") : vm::make_str(""); // The second string is empty on LLE + (id & UNK_MODULE_ID_MASK) >= 1 || sys_fs_open(ppu, path, 0, file_descriptor, 0, vm::null, 0) != CELL_OK) + { + *buf_size = 0; + return CELL_SYSMODULE_ERROR_FATAL; + } + + const vm::var sb; + + if (sys_fs_fstat(ppu, *file_descriptor, sb) != CELL_OK) + { + ensure(sys_fs_close(ppu, *file_descriptor) == CELL_OK); // Not checked on LLE + *buf_size = 0; + return CELL_SYSMODULE_ERROR_FATAL; + } + + const s32 read_size = *buf_size <= sb->size ? static_cast(*buf_size) : static_cast(sb->size); + + if (const vm::var nread; sys_fs_read(ppu, *file_descriptor, image_buf, read_size, nread) != CELL_OK) + { + *buf_size = 0; + } + else + { + *buf_size = static_cast(*nread); + } + + ensure(sys_fs_close(ppu, *file_descriptor) == CELL_OK); // Not checked on LLE return CELL_OK; } -error_code cellSysmoduleUnloadModuleInternal() +error_code cellSysmoduleUnloadModuleInternal(ppu_thread& ppu, u16 id) { - UNIMPLEMENTED_FUNC(cellSysmodule); + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; + + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellSysmodule.notice("cellSysmoduleUnloadModuleInternal(id=0x%x)", id); + + if (id < INTERNAL_MODULE_ID_BASE || id == CELL_SYSMODULE_INVALID || (id & INTERNAL_MODULE_ID_MASK) >= INTERNAL_MODULES_COUNT) + { + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + if (const error_code ret = unload_module(ppu, INTERNAL_MODULES_OFFSET + (id & INTERNAL_MODULE_ID_MASK)); ret != CELL_OK) + { + return ret; + } + + // Unload dependencies in reverse order + for (const u16 module_id : MODULE_INFOS[INTERNAL_MODULES_OFFSET + (id & INTERNAL_MODULE_ID_MASK)].dependencies | std::views::reverse) + { + if (const error_code ret = module_id < INTERNAL_MODULE_ID_BASE ? cellSysmoduleUnloadModule(ppu, id) : cellSysmoduleUnloadModuleInternal(ppu, id); ret != CELL_OK) + { + return ret; + } + } + return CELL_OK; } -error_code cellSysmoduleLoadModuleInternal() +error_code cellSysmoduleLoadModuleInternal(ppu_thread& ppu, u16 id) { - UNIMPLEMENTED_FUNC(cellSysmodule); + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; + + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellSysmodule.notice("cellSysmoduleLoadModuleInternal(id=0x%x)", id); + + if (id < INTERNAL_MODULE_ID_BASE || id == CELL_SYSMODULE_INVALID || (id & INTERNAL_MODULE_ID_MASK) >= INTERNAL_MODULES_COUNT) + { + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + if (id == 0xf024 || id == 0xf03e || id == 0xf020) + { + // TODO replace with proper struct + const vm::var paramsfo(0x40); + std::memset(paramsfo.get_ptr(), 0, paramsfo.get_count()); + + if (ppu_execute<&sys_process_get_paramsfo>(ppu, +paramsfo) != CELL_OK + || (!read_from_ptr>(paramsfo, 0x18) && !read_from_ptr>(paramsfo, 0x30))) + { + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + } + + // Load dependencies + for (const u16 module_id : MODULE_INFOS[INTERNAL_MODULES_OFFSET + (id & INTERNAL_MODULE_ID_MASK)].dependencies) + { + if (const error_code ret = module_id < INTERNAL_MODULE_ID_BASE ? cellSysmoduleLoadModule(ppu, id) : cellSysmoduleLoadModuleInternal(ppu, id); + ret != CELL_OK && ret != static_cast(CELL_SYSMODULE_ERROR_DUPLICATED)) + { + return ret; + } + } + + return load_module(ppu, INTERNAL_MODULES_OFFSET + (id & INTERNAL_MODULE_ID_MASK), 0, vm::null); +} + +error_code cellSysmoduleUnloadModuleEx(ppu_thread& ppu, u16 id) +{ + cellSysmodule.notice("cellSysmoduleUnloadModuleEx(id=0x%x)", id); + + if (id >= INTERNAL_MODULE_ID_BASE && (id & INTERNAL_MODULE_ID_MASK) < INTERNAL_MODULES_COUNT + && LOADABLE_INTERNAL_MODULES_EX[id & INTERNAL_MODULE_ID_MASK]) + { + return cellSysmoduleUnloadModuleInternal(ppu, id); + } + + return cellSysmoduleUnloadModuleInternal(ppu, CELL_SYSMODULE_INVALID); +} + +error_code cellSysmoduleLoadModuleEx(ppu_thread& ppu, u16 id) +{ + cellSysmodule.notice("cellSysmoduleLoadModuleEx(id=0x%x)", id); + + if (id >= INTERNAL_MODULE_ID_BASE && (id & INTERNAL_MODULE_ID_MASK) < INTERNAL_MODULES_COUNT + && LOADABLE_INTERNAL_MODULES_EX[id & INTERNAL_MODULE_ID_MASK]) + { + return cellSysmoduleLoadModuleInternal(ppu, id); + } + + return cellSysmoduleLoadModuleInternal(ppu, CELL_SYSMODULE_INVALID); +} + +error_code cellSysmoduleIsLoadedEx(ppu_thread& ppu, u16 id) +{ + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; + + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellSysmodule.notice("cellSysmoduleIsLoadedEx(id=0x%x)", id); + + if (id < INTERNAL_MODULE_ID_BASE || id == CELL_SYSMODULE_INVALID || (id & INTERNAL_MODULE_ID_MASK) >= INTERNAL_MODULES_COUNT) + { + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + if (ppu_execute<&sys_lwmutex_lock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex), 0) != CELL_OK) + { + return CELL_SYSMODULE_ERROR_FATAL; + } + + if (s_sysmodule_context->module_states[INTERNAL_MODULES_OFFSET + (id & INTERNAL_MODULE_ID_MASK)].loaded_count == 0) + { + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + return not_an_error(CELL_SYSMODULE_ERROR_UNLOADED); + } + + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE return CELL_OK; } -error_code cellSysmoduleUnloadModuleEx() +error_code cellSysmoduleLoadModuleFile(ppu_thread& ppu, vm::cptr path, vm::ptr unk) { - UNIMPLEMENTED_FUNC(cellSysmodule); + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; + + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellSysmodule.notice("cellSysmoduleLoadModuleFile(path=*0x%x=%s, unk=*0x%x)", path, path, unk); + + if (ppu_execute<&sys_lwmutex_lock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex), 0) != CELL_OK) + { + return CELL_SYSMODULE_ERROR_FATAL; + } + + ensure(!!unk); // Not checked on LLE + + const error_code ret = ppu_execute<&sys_prx_load_module>(ppu, path, 0, vm::null); + unk->prx_id = ret; + unk->unk = -1; + + if (ret < 1) + { + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + return CELL_SYSMODULE_ERROR_FATAL; + } + + const vm::var file_name(0x200); + const vm::var segments(10); + const vm::var prx_module_info + {{ + .size = sizeof(sys_prx_module_info_t), + .filename = file_name, + .filename_size = file_name.get_count(), + .segments = segments, + .segments_num = segments.get_count() + }}; + + static_cast(ppu_execute<&sys_prx_get_module_info>(ppu, +unk->prx_id, 0, +prx_module_info)); + // LLE does "for (int i = 0; i < 0; i++) ..." after this, where the name of the prx would have been compared to "cellATRAC3enc_Library" and "cellATRACXenc_Library" + + if (const error_code ret = ppu_execute<&sys_prx_start_module>(ppu, +unk->prx_id, 0, vm::null, +vm::make_var(0), 0, vm::null); ret != CELL_OK) + { + ensure(ppu_execute<&sys_prx_unload_module>(ppu, +unk->prx_id, 0, vm::null) == CELL_OK); // Not checked on LLE + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + return ret; + } + + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE return CELL_OK; } -error_code cellSysmoduleLoadModuleEx() +error_code cellSysmoduleUnloadModuleFile(ppu_thread& ppu, vm::cptr unk) { - UNIMPLEMENTED_FUNC(cellSysmodule); + // Blocking savestate creation due to ppu_thread::fast_call() + const std::unique_lock savestate_lock{ g_fxo->get(), std::try_to_lock }; + + if (!savestate_lock) + { + ppu.state += cpu_flag::again; + return {}; + } + + cellSysmodule.notice("cellSysmoduleUnloadModuleFile(unk=*0x%x)", unk); + + if (ppu_execute<&sys_lwmutex_lock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex), 0) != CELL_OK) + { + return CELL_SYSMODULE_ERROR_FATAL; + } + + ensure(!!unk); // Not checked on LLE + + if (ppu_execute<&sys_prx_stop_module>(ppu, +unk->prx_id, 0, vm::null, +vm::make_var(0), 0, vm::null) != CELL_OK + || ppu_execute<&sys_prx_unload_module>(ppu, +unk->prx_id, 0, vm::null) != CELL_OK) + { + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE + return CELL_SYSMODULE_ERROR_FATAL; + } + + ensure(unk->unk >= -1); // If this is not the case, LLE accesses its equivalent of sysmodule_context::modules_states with a negative index + + ensure(ppu_execute<&sys_lwmutex_unlock>(ppu, s_sysmodule_context.ptr(&sysmodule_context::mutex)) == CELL_OK); // Not checked on LLE return CELL_OK; } -error_code cellSysmoduleIsLoadedEx() +error_code cellSysmoduleSetDebugmode(u32 debug_mode) { - UNIMPLEMENTED_FUNC(cellSysmodule); - return CELL_OK; -} + cellSysmodule.notice("cellSysmoduleSetDebugmode(debug_mode=%d)", debug_mode); -error_code cellSysmoduleLoadModuleFile() -{ - UNIMPLEMENTED_FUNC(cellSysmodule); - return CELL_OK; -} + if (debug_mode == 1) + { + std::memcpy(s_sysmodule_context->module_base_path.data(), MODULE_BASE_PATH_DEBUG.data(), MODULE_BASE_PATH_DEBUG.size() + 1); + s_sysmodule_context->module_base_path_size = static_cast(MODULE_BASE_PATH_DEBUG.size()); + } + else + { + std::memcpy(s_sysmodule_context->module_base_path.data(), MODULE_BASE_PATH.data(), MODULE_BASE_PATH.size() + 1); + s_sysmodule_context->module_base_path_size = static_cast(MODULE_BASE_PATH.size()); + } -error_code cellSysmoduleUnloadModuleFile() -{ - UNIMPLEMENTED_FUNC(cellSysmodule); - return CELL_OK; -} - -error_code cellSysmoduleSetDebugmode() -{ - UNIMPLEMENTED_FUNC(cellSysmodule); return CELL_OK; } error_code cellSysmoduleSetInternalmode() { - UNIMPLEMENTED_FUNC(cellSysmodule); + cellSysmodule.notice("cellSysmoduleSetInternalmode()"); + // Doesn't do anything + return CELL_OK; +} + +error_code cellSysmodule_0x59521326(vm::ptr output) +{ + cellSysmodule.notice("cellSysmodule_0x59521326(output=*0x%x)", output); + + const vm::var psid; + + if (!output || sys_ss_get_open_psid(psid) != CELL_OK) + { + return -22; + } + + std::swap(psid->high, psid->low); + + u8 iv[0x10]; + std::memcpy(iv, psid.get_ptr(), sizeof(iv)); + + ensure(vm::check_addr(output.addr(), vm::page_readable | vm::page_writable, 0x10)); + + aescbc128_decrypt(KEY_UNK.data(), iv, reinterpret_cast(psid.get_ptr()), output.get_ptr(), 0x10); + return CELL_OK; } DECLARE(ppu_module_manager::cellSysmodule)("cellSysmodule", []() { + REG_VAR(cellSysmodule, s_sysmodule_context).flag(MFF_HIDDEN).init = [] + { + s_sysmodule_context->unk_addr = 0; + s_sysmodule_context->mem_container_id = std::nullopt; + std::ranges::fill(s_sysmodule_context->module_states, module_state{ .loaded_count = 0, .prx_id = -1 }); + cellSysmoduleSetDebugmode(false); + }; + REG_FUNC(cellSysmodule, cellSysmoduleInitialize); REG_FUNC(cellSysmodule, cellSysmoduleFinalize); REG_FUNC(cellSysmodule, cellSysmoduleSetMemcontainer); @@ -449,4 +1391,8 @@ DECLARE(ppu_module_manager::cellSysmodule)("cellSysmodule", []() REG_FUNC(cellSysmodule, cellSysmoduleUnloadModuleFile); REG_FUNC(cellSysmodule, cellSysmoduleSetDebugmode); REG_FUNC(cellSysmodule, cellSysmoduleSetInternalmode); + REG_FNID(cellSysmodule, 0x59521326, cellSysmodule_0x59521326); + + REG_HIDDEN_FUNC(sysmoduleModuleStart); + REG_HIDDEN_FUNC(sysmoduleModuleStop); }); diff --git a/rpcs3/Emu/Cell/Modules/cellSysmodule.h b/rpcs3/Emu/Cell/Modules/cellSysmodule.h new file mode 100644 index 0000000000..7f3fa0fc6e --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellSysmodule.h @@ -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 prx_id; + be_t 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); diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index 4775224eb1..09becf88c3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -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" @@ -177,6 +178,9 @@ extern const std::map 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 argp); +extern error_code sysmoduleModuleStop(ppu_thread& ppu); + static error_code prx_load_module(const std::string& vpath, u64 flags, vm::ptr /*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(); + if (name == "libsysmodule.sprx") + { + prx->start = vm::cast(g_fxo->get().func_addr(FIND_FUNC(sysmoduleModuleStart))); + prx->stop = vm::cast(g_fxo->get().func_addr(FIND_FUNC(sysmoduleModuleStop))); + } + prx->name = std::move(name); prx->path = std::move(path); diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 770028936f..006a837182 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -960,6 +960,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 7280166c33..ecd0a3b425 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1914,6 +1914,9 @@ Emu\Cell\Modules + + Emu\Cell\Modules + Emu\Cell\Modules