#include "stdafx.h" #include "cellGame.h" #include "Emu/Cell/PPUModule.h" #include "Emu/IdManager.h" #include "Emu/System.h" #include "Emu/VFS.h" #include "Emu/system_config.h" #include "Emu/Cell/lv2/sys_game.h" #include "Emu/Cell/lv2/sys_process.h" #include "cellSysutil.h" #include "util/StrUtil.h" #include "util/lockless.h" #include #include LOG_CHANNEL(cellSysutil); template <> void fmt_class_string::format(std::string& out, u64 arg) { format_enum(out, arg, [](auto error) { switch (error) { STR_CASE(CELL_SYSUTIL_ERROR_TYPE); STR_CASE(CELL_SYSUTIL_ERROR_VALUE); STR_CASE(CELL_SYSUTIL_ERROR_SIZE); STR_CASE(CELL_SYSUTIL_ERROR_NUM); STR_CASE(CELL_SYSUTIL_ERROR_BUSY); STR_CASE(CELL_SYSUTIL_ERROR_STATUS); STR_CASE(CELL_SYSUTIL_ERROR_MEMORY); STR_CASE(CELL_SYSUTIL_ERROR_3D_SUPPORT); } return unknown; }); } template <> void fmt_class_string::format(std::string& out, u64 arg) { format_enum(out, arg, [](auto error) { switch (error) { STR_CASE(CELL_SYSUTIL_BGMPLAYBACK_ERROR_PARAM); STR_CASE(CELL_SYSUTIL_BGMPLAYBACK_ERROR_BUSY); STR_CASE(CELL_SYSUTIL_BGMPLAYBACK_ERROR_GENERIC); STR_CASE(CELL_SYSUTIL_BGMPLAYBACK_EX_ERROR_PARAM); STR_CASE(CELL_SYSUTIL_BGMPLAYBACK_EX_ERROR_ALREADY_SETPARAM); STR_CASE(CELL_SYSUTIL_BGMPLAYBACK_EX_ERROR_DISABLE_SETPARAM); STR_CASE(CELL_SYSUTIL_BGMPLAYBACK_EX_ERROR_GENERIC); } return unknown; }); } atomic_t g_sysutil_callback_id_assigner = 0; struct sysutil_cb_manager { struct alignas(8) registered_dispatcher { u32 event_code = 0; u32 func_addr = 0; }; std::array, 32> dispatchers{}; struct alignas(8) registered_cb { ENABLE_BITWISE_SERIALIZATION; vm::ptr callback; vm::ptr user_data; }; atomic_t callbacks[4]{}; struct dispatcher_cb { std::function func; std::shared_ptr> call_active; }; std::deque>>> registered_callbacks_abort_handles = []() { // Do resize for deque (cheap container which can store all non-movable // value types) std::deque>>> result; for (usz i = 0; i < g_sysutil_callback_id_assigner; i++) { result.emplace_back(); } return result; }(); lf_queue registered; atomic_t draw_cb_started{}; atomic_t read_counter{0}; SAVESTATE_INIT_POS(13); sysutil_cb_manager() = default; sysutil_cb_manager(utils::serial& ar) { ar(callbacks); } void save(utils::serial& ar) { ensure(!registered); ar(callbacks); } }; void sysutil_register_cb_with_id_internal(std::function&& cb, usz call_id) { auto& cbm = *ensure(g_fxo->try_get()); sysutil_cb_manager::dispatcher_cb info{std::move(cb)}; if (call_id != umax) { info.call_active = std::make_shared>(true); ::at32(cbm.registered_callbacks_abort_handles, call_id) .push(info.call_active); } cbm.registered.push(std::move(info)); } extern void sysutil_unregister_cb_with_id_internal(usz call_id) { const auto cbm = g_fxo->try_get(); if (!cbm) { return; } for (auto&& abort_handle : ::at32(cbm->registered_callbacks_abort_handles, call_id).pop_all()) { // Deactivate the existing event once abort_handle->store(false); } } extern void sysutil_register_cb(std::function&& cb) { sysutil_register_cb_with_id_internal(std::move(cb), umax); } extern s32 sysutil_send_system_cmd(u64 status, u64 param) { s32 count = 0; if (auto cbm = g_fxo->try_get()) { if (status == CELL_SYSUTIL_DRAWING_BEGIN) { if (cbm->draw_cb_started.exchange(true)) { cellSysutil.error( "Tried to enqueue a second or more DRAWING_BEGIN callback!"); return CELL_SYSUTIL_ERROR_BUSY; } } else if (status == CELL_SYSUTIL_DRAWING_END) { if (!cbm->draw_cb_started.exchange(false)) { cellSysutil.error("Tried to enqueue a DRAWING_END callback without a " "BEGIN callback!"); return -1; } } else if (status == CELL_SYSUTIL_REQUEST_EXITGAME) { abort_lv2_watchdog(); } for (sysutil_cb_manager::registered_cb cb : cbm->callbacks) { if (cb.callback) { cbm->registered.push( sysutil_cb_manager::dispatcher_cb{[=](ppu_thread& ppu) -> s32 { // TODO: check it and find the source of the return value (void // isn't equal to CELL_OK) cb.callback(ppu, status, param, cb.user_data); return CELL_OK; }}); count++; } } } return count; } extern u64 get_sysutil_cb_manager_read_count() { if (auto cbm = g_fxo->try_get()) { return cbm->read_counter; } return 0; } extern bool send_open_home_menu_cmds() { auto status = g_fxo->try_get(); if (!status || status->active) { return false; } // TODO: handle CELL_SYSUTIL_BGMPLAYBACK_STATUS_DISABLE if (sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0) < 0 || sysutil_send_system_cmd(CELL_SYSUTIL_SYSTEM_MENU_OPEN, 0) < 0 || sysutil_send_system_cmd(CELL_SYSUTIL_BGMPLAYBACK_PLAY, 0) < 0) { return false; } status->active = true; return true; } extern void send_close_home_menu_cmds() { auto status = g_fxo->try_get(); if (!status || !status->active) { return; } // TODO: handle CELL_SYSUTIL_BGMPLAYBACK_STATUS_DISABLE sysutil_send_system_cmd(CELL_SYSUTIL_BGMPLAYBACK_STOP, 0); sysutil_send_system_cmd(CELL_SYSUTIL_SYSTEM_MENU_CLOSE, 0); sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0); status->active = false; } template <> void fmt_class_string::format(std::string& out, u64 arg) { format_enum(out, arg, [](CellSysutilLang value) { switch (value) { case CELL_SYSUTIL_LANG_JAPANESE: return "Japanese"; case CELL_SYSUTIL_LANG_ENGLISH_US: return "English (US)"; case CELL_SYSUTIL_LANG_FRENCH: return "French"; case CELL_SYSUTIL_LANG_SPANISH: return "Spanish"; case CELL_SYSUTIL_LANG_GERMAN: return "German"; case CELL_SYSUTIL_LANG_ITALIAN: return "Italian"; case CELL_SYSUTIL_LANG_DUTCH: return "Dutch"; case CELL_SYSUTIL_LANG_PORTUGUESE_PT: return "Portuguese (Portugal)"; case CELL_SYSUTIL_LANG_RUSSIAN: return "Russian"; case CELL_SYSUTIL_LANG_KOREAN: return "Korean"; case CELL_SYSUTIL_LANG_CHINESE_T: return "Chinese (Traditional)"; case CELL_SYSUTIL_LANG_CHINESE_S: return "Chinese (Simplified)"; case CELL_SYSUTIL_LANG_FINNISH: return "Finnish"; case CELL_SYSUTIL_LANG_SWEDISH: return "Swedish"; case CELL_SYSUTIL_LANG_DANISH: return "Danish"; case CELL_SYSUTIL_LANG_NORWEGIAN: return "Norwegian"; case CELL_SYSUTIL_LANG_POLISH: return "Polish"; case CELL_SYSUTIL_LANG_ENGLISH_GB: return "English (UK)"; case CELL_SYSUTIL_LANG_PORTUGUESE_BR: return "Portuguese (Brazil)"; case CELL_SYSUTIL_LANG_TURKISH: return "Turkish"; } return unknown; }); } template <> void fmt_class_string::format(std::string& out, u64 arg) { format_enum(out, arg, [](CellSysutilLicenseArea value) { switch (value) { case CELL_SYSUTIL_LICENSE_AREA_J: return "SCEJ"; case CELL_SYSUTIL_LICENSE_AREA_A: return "SCEA"; case CELL_SYSUTIL_LICENSE_AREA_E: return "SCEE"; case CELL_SYSUTIL_LICENSE_AREA_H: return "SCEH"; case CELL_SYSUTIL_LICENSE_AREA_K: return "SCEK"; case CELL_SYSUTIL_LICENSE_AREA_C: return "SCH"; case CELL_SYSUTIL_LICENSE_AREA_OTHER: return "Other"; } return unknown; }); } template <> void fmt_class_string::format(std::string& out, u64 arg) { format_enum(out, arg, [](auto value) { switch (value) { case CELL_SYSUTIL_SYSTEMPARAM_ID_LANG: return "ID_LANG"; case CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN: return "ID_ENTER_BUTTON_ASSIGN"; case CELL_SYSUTIL_SYSTEMPARAM_ID_DATE_FORMAT: return "ID_DATE_FORMAT"; case CELL_SYSUTIL_SYSTEMPARAM_ID_TIME_FORMAT: return "ID_TIME_FORMAT"; case CELL_SYSUTIL_SYSTEMPARAM_ID_TIMEZONE: return "ID_TIMEZONE"; case CELL_SYSUTIL_SYSTEMPARAM_ID_SUMMERTIME: return "ID_SUMMERTIME"; case CELL_SYSUTIL_SYSTEMPARAM_ID_GAME_PARENTAL_LEVEL: return "ID_GAME_PARENTAL_LEVEL"; case CELL_SYSUTIL_SYSTEMPARAM_ID_LICENSE_AREA: return "ID_LICENSE_AREA"; case CELL_SYSUTIL_SYSTEMPARAM_ID_GAME_PARENTAL_LEVEL0_RESTRICT: return "ID_GAME_PARENTAL_LEVEL0_RESTRICT"; case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USER_HAS_NP_ACCOUNT: return "ID_CURRENT_USER_HAS_NP_ACCOUNT"; case CELL_SYSUTIL_SYSTEMPARAM_ID_CAMERA_PLFREQ: return "ID_CAMERA_PLFREQ"; case CELL_SYSUTIL_SYSTEMPARAM_ID_PAD_RUMBLE: return "ID_PAD_RUMBLE"; case CELL_SYSUTIL_SYSTEMPARAM_ID_KEYBOARD_TYPE: return "ID_KEYBOARD_TYPE"; case CELL_SYSUTIL_SYSTEMPARAM_ID_JAPANESE_KEYBOARD_ENTRY_METHOD: return "ID_JAPANESE_KEYBOARD_ENTRY_METHOD"; case CELL_SYSUTIL_SYSTEMPARAM_ID_CHINESE_KEYBOARD_ENTRY_METHOD: return "ID_CHINESE_KEYBOARD_ENTRY_METHOD"; case CELL_SYSUTIL_SYSTEMPARAM_ID_PAD_AUTOOFF: return "ID_PAD_AUTOOFF"; case CELL_SYSUTIL_SYSTEMPARAM_ID_MAGNETOMETER: return "ID_MAGNETOMETER"; case CELL_SYSUTIL_SYSTEMPARAM_ID_NICKNAME: return "ID_NICKNAME"; case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USERNAME: return "ID_CURRENT_USERNAME"; case CELL_SYSUTIL_SYSTEMPARAM_ID_x1008: return "ID_x1008"; case CELL_SYSUTIL_SYSTEMPARAM_ID_x1011: return "ID_x1011"; case CELL_SYSUTIL_SYSTEMPARAM_ID_x1012: return "ID_x1012"; case CELL_SYSUTIL_SYSTEMPARAM_ID_x1024: return "ID_x1024"; } return unknown; }); } // Common string checks used in libsysutil functions s32 sysutil_check_name_string(const char* src, s32 minlen, s32 maxlen) { s32 lastpos; if (g_ps3_process_info.sdk_ver > 0x36FFFF) { // Limit null terminator boundary to before buffer max size lastpos = std::max(maxlen - 1, 0); } else { // Limit null terminator boundary to one after buffer max size lastpos = maxlen; } char cur = src[0]; if (cur == '_') { // Invalid character at start return -1; } for (s32 index = 0;; cur = src[++index]) { if (cur == '\0' || index == maxlen) { if (minlen > index || (maxlen == index && src[lastpos])) { // String length is invalid return -2; } // OK return 0; } if (cur >= 'A' && cur <= 'Z') { continue; } if (cur >= '0' && cur <= '9') { continue; } if (cur == '-' || cur == '_') { continue; } // Invalid character found return -1; } } error_code _cellSysutilGetSystemParamInt() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code cellSysutilGetSystemParamInt(CellSysutilParamId id, vm::ptr value) { cellSysutil.warning("cellSysutilGetSystemParamInt(id=0x%x(%s), value=*0x%x)", id, id, value); if (!value) { return CELL_SYSUTIL_ERROR_VALUE; } // TODO: load this information from config (preferably "sys/" group) switch (id) { case CELL_SYSUTIL_SYSTEMPARAM_ID_LANG: *value = g_cfg.sys.language; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN: *value = static_cast(g_cfg.sys.enter_button_assignment.get()); break; case CELL_SYSUTIL_SYSTEMPARAM_ID_DATE_FORMAT: *value = CELL_SYSUTIL_DATE_FMT_DDMMYYYY; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_TIME_FORMAT: *value = CELL_SYSUTIL_TIME_FMT_CLOCK24; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_TIMEZONE: *value = 180; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_SUMMERTIME: *value = 0; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_GAME_PARENTAL_LEVEL: *value = CELL_SYSUTIL_GAME_PARENTAL_OFF; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_LICENSE_AREA: { if (g_ps3_process_info.sdk_ver > 0x23FFFFu) { return CELL_SYSUTIL_ERROR_VALUE; } extern s32 cellSysutilGetLicenseArea(); // Identical until proved otherwise *value = cellSysutilGetLicenseArea(); break; } case CELL_SYSUTIL_SYSTEMPARAM_ID_GAME_PARENTAL_LEVEL0_RESTRICT: *value = CELL_SYSUTIL_GAME_PARENTAL_LEVEL0_RESTRICT_OFF; break; // Report user has an NP account when np_psn_status is Fake or RPCN case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USER_HAS_NP_ACCOUNT: *value = g_cfg.net.psn_status != np_psn_status::disabled; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_CAMERA_PLFREQ: *value = CELL_SYSUTIL_CAMERA_PLFREQ_DISABLED; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_PAD_RUMBLE: *value = CELL_SYSUTIL_PAD_RUMBLE_ON; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_KEYBOARD_TYPE: *value = g_cfg.sys.keyboard_type; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_JAPANESE_KEYBOARD_ENTRY_METHOD: *value = CELL_SYSUTIL_KEYBOARD_ENTRY_METHOD_ROMAJI_INPUT; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_CHINESE_KEYBOARD_ENTRY_METHOD: *value = CELL_SYSUTIL_KEYBOARD_ENTRY_METHOD_ZHUYIN_INPUT; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_PAD_AUTOOFF: *value = CELL_SYSUTIL_PAD_AUTOOFF_OFF; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_MAGNETOMETER: *value = CELL_SYSUTIL_MAGNETOMETER_OFF; break; default: return CELL_SYSUTIL_ERROR_VALUE; } return CELL_OK; } error_code cellSysutilGetSystemParamString(CellSysutilParamId id, vm::ptr buf, u32 bufsize) { cellSysutil.trace( "cellSysutilGetSystemParamString(id=0x%x(%s), buf=*0x%x, bufsize=%d)", id, id, buf, bufsize); if (!buf) { return CELL_SYSUTIL_ERROR_VALUE; } u32 copy_size; std::string param_str = "Unknown"; bool report_use = false; switch (id) { case CELL_SYSUTIL_SYSTEMPARAM_ID_NICKNAME: { copy_size = CELL_SYSUTIL_SYSTEMPARAM_NICKNAME_SIZE; param_str = g_cfg.sys.system_name.to_string(); break; } case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USERNAME: { const fs::file username(vfs::get( fmt::format("/dev_hdd0/home/%08u/localusername", Emu.GetUsrId()))); if (!username) { cellSysutil.error("cellSysutilGetSystemParamString(): Username for user " "%08u doesn't exist. Did you delete the username file?", Emu.GetUsrId()); } else { // Read current username param_str = username.to_string(); } copy_size = CELL_SYSUTIL_SYSTEMPARAM_CURRENT_USERNAME_SIZE; break; } case CELL_SYSUTIL_SYSTEMPARAM_ID_x1011: // Same as x1012 case CELL_SYSUTIL_SYSTEMPARAM_ID_x1012: copy_size = 0x400; report_use = true; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_x1024: copy_size = 0x100; report_use = true; break; case CELL_SYSUTIL_SYSTEMPARAM_ID_x1008: copy_size = 0x4; report_use = true; break; default: { return CELL_SYSUTIL_ERROR_VALUE; } } if (bufsize != copy_size) { return CELL_SYSUTIL_ERROR_SIZE; } if (report_use) { cellSysutil.error("cellSysutilGetSystemParamString: Unknown ParamId 0x%x", id); } std::span dst(buf.get_ptr(), copy_size); strcpy_trunc(dst, param_str); return CELL_OK; } // Note: the way we do things here is inaccurate(but maybe sufficient) // The real function goes over a table of 0x20 entries[ event_code:u32 // callback_addr:u32 ] Those callbacks are registered through // cellSysutilRegisterCallbackDispatcher(u32 event_code, vm::ptr // func_addr) The function goes through all the callback looking for one // callback associated with event 0x100, if any is found it is called with // parameters r3=0x101 r4=0 This particular CB seems to be associated with // sysutil itself Then it checks for events on an event_queue associated with // sysutil, checks if any cb is associated with that event and calls them with // parameters that come from the event error_code cellSysutilCheckCallback(ppu_thread& ppu) { cellSysutil.trace("cellSysutilCheckCallback()"); auto& cbm = g_fxo->get(); bool read = false; for (auto&& func : cbm.registered.pop_all()) { if (func.call_active && !*func.call_active) { continue; } read = true; if (s32 res = func.func(ppu)) { // Currently impossible return not_an_error(res); } if (ppu.is_stopped()) { return {}; } } if (read) { cbm.read_counter++; } return CELL_OK; } error_code cellSysutilRegisterCallback(u32 slot, vm::ptr func, vm::ptr userdata) { cellSysutil.warning( "cellSysutilRegisterCallback(slot=%d, func=*0x%x, userdata=*0x%x)", slot, func, userdata); if (slot >= 4) { return CELL_SYSUTIL_ERROR_VALUE; } auto& cbm = g_fxo->get(); cbm.callbacks[slot].store({func, userdata}); return CELL_OK; } error_code cellSysutilUnregisterCallback(u32 slot) { cellSysutil.warning("cellSysutilUnregisterCallback(slot=%d)", slot); if (slot >= 4) { return CELL_SYSUTIL_ERROR_VALUE; } auto& cbm = g_fxo->get(); cbm.callbacks[slot].store({}); return CELL_OK; } struct bgm_manager { shared_mutex mtx; CellSysutilBgmPlaybackExtraParam param{}; CellSysutilBgmPlaybackStatus status{}; bgm_manager() { status.enableState = CELL_SYSUTIL_BGMPLAYBACK_STATUS_DISABLE; status.playerState = CELL_SYSUTIL_BGMPLAYBACK_STATUS_STOP; } }; error_code cellSysutilEnableBgmPlayback() { cellSysutil.warning("cellSysutilEnableBgmPlayback()"); auto& bgm = g_fxo->get(); std::lock_guard lock(bgm.mtx); bgm.status.enableState = CELL_SYSUTIL_BGMPLAYBACK_STATUS_ENABLE; return CELL_OK; } error_code cellSysutilEnableBgmPlaybackEx( vm::ptr param) { cellSysutil.warning("cellSysutilEnableBgmPlaybackEx(param=*0x%x)", param); if (!param || param->systemBgmFadeInTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->systemBgmFadeInTime > 60000 || param->systemBgmFadeOutTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->systemBgmFadeOutTime > 60000 || param->gameBgmFadeInTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->gameBgmFadeInTime > 60000 || param->gameBgmFadeOutTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->gameBgmFadeOutTime > 60000) { return CELL_SYSUTIL_BGMPLAYBACK_EX_ERROR_PARAM; } auto& bgm = g_fxo->get(); std::lock_guard lock(bgm.mtx); bgm.param.systemBgmFadeInTime = param->systemBgmFadeInTime; bgm.param.systemBgmFadeOutTime = param->systemBgmFadeOutTime; bgm.param.gameBgmFadeInTime = param->gameBgmFadeInTime; bgm.param.gameBgmFadeOutTime = param->gameBgmFadeOutTime; bgm.status.enableState = CELL_SYSUTIL_BGMPLAYBACK_STATUS_ENABLE; return CELL_OK; } error_code cellSysutilDisableBgmPlayback() { cellSysutil.warning("cellSysutilDisableBgmPlayback()"); auto& bgm = g_fxo->get(); std::lock_guard lock(bgm.mtx); bgm.status.enableState = CELL_SYSUTIL_BGMPLAYBACK_STATUS_DISABLE; // TODO: fade from system bgm to game bgm if necessary return CELL_OK; } error_code cellSysutilDisableBgmPlaybackEx( vm::ptr param) { cellSysutil.warning("cellSysutilDisableBgmPlaybackEx(param=*0x%x)", param); if (!param || param->systemBgmFadeInTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->systemBgmFadeInTime > 60000 || param->systemBgmFadeOutTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->systemBgmFadeOutTime > 60000 || param->gameBgmFadeInTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->gameBgmFadeInTime > 60000 || param->gameBgmFadeOutTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->gameBgmFadeOutTime > 60000) { return CELL_SYSUTIL_BGMPLAYBACK_EX_ERROR_PARAM; } auto& bgm = g_fxo->get(); std::lock_guard lock(bgm.mtx); bgm.param.systemBgmFadeInTime = param->systemBgmFadeInTime; bgm.param.systemBgmFadeOutTime = param->systemBgmFadeOutTime; bgm.param.gameBgmFadeInTime = param->gameBgmFadeInTime; bgm.param.gameBgmFadeOutTime = param->gameBgmFadeOutTime; bgm.status.enableState = CELL_SYSUTIL_BGMPLAYBACK_STATUS_DISABLE; // TODO: fade from system bgm to game bgm if necessary return CELL_OK; } error_code cellSysutilGetBgmPlaybackStatus(vm::ptr status) { cellSysutil.trace("cellSysutilGetBgmPlaybackStatus(status=*0x%x)", status); if (!status) { return CELL_SYSUTIL_BGMPLAYBACK_ERROR_PARAM; } auto& bgm = g_fxo->get(); std::lock_guard lock(bgm.mtx); *status = bgm.status; return CELL_OK; } error_code cellSysutilGetBgmPlaybackStatus2( vm::ptr status2) { cellSysutil.trace("cellSysutilGetBgmPlaybackStatus2(status2=*0x%x)", status2); if (!status2) { return CELL_SYSUTIL_BGMPLAYBACK_EX_ERROR_PARAM; } auto& bgm = g_fxo->get(); std::lock_guard lock(bgm.mtx); status2->playerState = bgm.status.playerState; memset(status2->reserved, 0, sizeof(status2->reserved)); return CELL_OK; } error_code cellSysutilSetBgmPlaybackExtraParam( vm::ptr param) { cellSysutil.warning("cellSysutilSetBgmPlaybackExtraParam(param=*0x%x)", param); if (!param || param->systemBgmFadeInTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->systemBgmFadeInTime > 60000 || param->systemBgmFadeOutTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->systemBgmFadeOutTime > 60000 || param->gameBgmFadeInTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->gameBgmFadeInTime > 60000 || param->gameBgmFadeOutTime < CELL_SYSUTIL_BGMPLAYBACK_FADE_INVALID || param->gameBgmFadeOutTime > 60000) { return CELL_SYSUTIL_BGMPLAYBACK_EX_ERROR_PARAM; } auto& bgm = g_fxo->get(); std::lock_guard lock(bgm.mtx); bgm.param.systemBgmFadeInTime = param->systemBgmFadeInTime; bgm.param.systemBgmFadeOutTime = param->systemBgmFadeOutTime; bgm.param.gameBgmFadeInTime = param->gameBgmFadeInTime; bgm.param.gameBgmFadeOutTime = param->gameBgmFadeOutTime; // TODO: apparently you are only able to set this only once and while bgm is // enabled return CELL_OK; } error_code cellSysutilRegisterCallbackDispatcher(u32 event_code, u32 func_addr) { cellSysutil.warning( "cellSysutilRegisterCallbackDispatcher(event_code=0x%x, func_addr=0x%x)", event_code, func_addr); auto& cbm = g_fxo->get(); for (u32 i = 0; i < cbm.dispatchers.size(); i++) { if (cbm.dispatchers[i].atomic_op( [&](sysutil_cb_manager::registered_dispatcher& dispatcher) { if (dispatcher.event_code == 0) { dispatcher.event_code = event_code; dispatcher.func_addr = func_addr; return true; } return false; })) { return CELL_OK; } } return 0x8002b004; } error_code cellSysutilUnregisterCallbackDispatcher(u32 event_code) { cellSysutil.warning( "cellSysutilUnregisterCallbackDispatcher(event_code=0x%x)", event_code); auto& cbm = g_fxo->get(); for (u32 i = 0; i < cbm.dispatchers.size(); i++) { if (cbm.dispatchers[i].atomic_op( [&](sysutil_cb_manager::registered_dispatcher& dispatcher) { if (dispatcher.event_code == event_code) { dispatcher.event_code = 0; dispatcher.func_addr = 0; return true; } return false; })) { return CELL_OK; } } return 0x8002b005; } error_code cellSysutilPacketRead() { cellSysutil.todo("cellSysutilPacketRead()"); return CELL_OK; } error_code cellSysutilPacketWrite() { cellSysutil.todo("cellSysutilPacketWrite()"); return CELL_OK; } error_code cellSysutilPacketBegin() { cellSysutil.todo("cellSysutilPacketBegin()"); return CELL_OK; } error_code cellSysutilPacketEnd() { cellSysutil.todo("cellSysutilPacketEnd()"); return CELL_OK; } error_code cellSysutilGameDataAssignVmc() { cellSysutil.todo("cellSysutilGameDataAssignVmc()"); return CELL_OK; } error_code cellSysutilGameDataExit(u32 unk) { cellSysutil.todo("cellSysutilGameDataExit(unk=%d)", unk); if (unk > 4) { return CELL_GAMEDATA_ERROR_PARAM; } return CELL_OK; } error_code cellSysutilGameExit_I() { cellSysutil.warning("cellSysutilGameExit_I()"); return cellSysutilGameDataExit(0); } error_code cellSysutilGamePowerOff_I() { cellSysutil.warning("cellSysutilGamePowerOff_I()"); return cellSysutilGameDataExit(1); } error_code cellSysutilGameReboot_I() { cellSysutil.warning("cellSysutilGameReboot_I()"); return cellSysutilGameDataExit(4); } error_code cellSysutilSharedMemoryAlloc() { cellSysutil.todo("cellSysutilSharedMemoryAlloc()"); return CELL_OK; } error_code cellSysutilSharedMemoryFree() { cellSysutil.todo("cellSysutilSharedMemoryFree()"); return CELL_OK; } error_code cellSysutilNotification() { cellSysutil.todo("cellSysutilNotification()"); return CELL_OK; } error_code _ZN4cxml7Element11AppendChildERS0_() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN4cxml8DocumentC1Ev() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN4cxml8DocumentD1Ev() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN4cxml8Document5ClearEv() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN4cxml8Document5WriteEPFiPKvjPvES3_() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN4cxml8Document12RegisterFileEPKvjPNS_4FileE() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN4cxml8Document13CreateElementEPKciPNS_7ElementE() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN4cxml8Document14SetHeaderMagicEPKc() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN4cxml8Document16CreateFromBufferEPKvjb() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN4cxml8Document18GetDocumentElementEv() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZNK4cxml4File7GetAddrEv() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZNK4cxml7Element12GetAttributeEPKcPNS_9AttributeE() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZNK4cxml7Element13GetFirstChildEv() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZNK4cxml7Element14GetNextSiblingEv() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZNK4cxml9Attribute6GetIntEPi() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZNK4cxml9Attribute7GetFileEPNS_4FileE() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN8cxmlutil6SetIntERKN4cxml7ElementEPKci() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN8cxmlutil6GetIntERKN4cxml7ElementEPKcPi() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN8cxmlutil7SetFileERKN4cxml7ElementEPKcRKNS0_4FileE() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN8cxmlutil8GetFloatERKN4cxml7ElementEPKcPf() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN8cxmlutil8SetFloatERKN4cxml7ElementEPKcf() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN8cxmlutil9GetStringERKN4cxml7ElementEPKcPS5_Pj() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN8cxmlutil9SetStringERKN4cxml7ElementEPKcS5_() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN8cxmlutil16CheckElementNameERKN4cxml7ElementEPKc() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN8cxmlutil16FindChildElementERKN4cxml7ElementEPKcS5_S5_() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN8cxmlutil7GetFileERKN4cxml7ElementEPKcPNS0_4FileE() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN16sysutil_cxmlutil11FixedMemory3EndEi() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN16sysutil_cxmlutil11FixedMemory5BeginEi() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN16sysutil_cxmlutil11FixedMemory8AllocateEN4cxml14AllocationTypeEPvS3_jPS3_Pj() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN16sysutil_cxmlutil12PacketWriter5WriteEPKvjPv() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code _ZN16sysutil_cxmlutil12PacketWriterC1EiiRN4cxml8DocumentE() { UNIMPLEMENTED_FUNC(cellSysutil); return CELL_OK; } error_code cellSysutil_E1EC7B6A(vm::ptr unk) { cellSysutil.todo("cellSysutil_E1EC7B6A(unk=*0x%x)", unk); *unk = 0; return CELL_OK; } extern void cellSysutil_SaveData_init(); extern void cellSysutil_GameData_init(); extern void cellSysutil_MsgDialog_init(); extern void cellSysutil_OskDialog_init(); extern void cellSysutil_Storage_init(); extern void cellSysutil_Sysconf_init(); extern void cellSysutil_SysutilAvc_init(); extern void cellSysutil_WebBrowser_init(); extern void cellSysutil_AudioOut_init(); extern void cellSysutil_VideoOut_init(); extern void cellSysutil_SysCache_init(); DECLARE(ppu_module_manager::cellSysutil)("cellSysutil", []() { cellSysutil_SaveData_init(); // cellSaveData functions cellSysutil_GameData_init(); // cellGameData, cellHddGame functions cellSysutil_MsgDialog_init(); // cellMsgDialog functions cellSysutil_OskDialog_init(); // cellOskDialog functions cellSysutil_Storage_init(); // cellStorage functions cellSysutil_Sysconf_init(); // cellSysconf functions cellSysutil_SysutilAvc_init(); // cellSysutilAvc functions cellSysutil_WebBrowser_init(); // cellWebBrowser, cellWebComponent functions cellSysutil_AudioOut_init(); // cellAudioOut functions cellSysutil_VideoOut_init(); // cellVideoOut functions cellSysutil_SysCache_init(); // cellSysCache functions REG_FUNC(cellSysutil, _cellSysutilGetSystemParamInt); REG_FUNC(cellSysutil, cellSysutilGetSystemParamInt); REG_FUNC(cellSysutil, cellSysutilGetSystemParamString); REG_FUNC(cellSysutil, cellSysutilCheckCallback); REG_FUNC(cellSysutil, cellSysutilRegisterCallback); REG_FUNC(cellSysutil, cellSysutilUnregisterCallback); REG_FUNC(cellSysutil, cellSysutilGetBgmPlaybackStatus); REG_FUNC(cellSysutil, cellSysutilGetBgmPlaybackStatus2); REG_FUNC(cellSysutil, cellSysutilEnableBgmPlayback); REG_FUNC(cellSysutil, cellSysutilEnableBgmPlaybackEx); REG_FUNC(cellSysutil, cellSysutilDisableBgmPlayback); REG_FUNC(cellSysutil, cellSysutilDisableBgmPlaybackEx); REG_FUNC(cellSysutil, cellSysutilSetBgmPlaybackExtraParam); REG_FUNC(cellSysutil, cellSysutilRegisterCallbackDispatcher); REG_FUNC(cellSysutil, cellSysutilUnregisterCallbackDispatcher); REG_FUNC(cellSysutil, cellSysutilPacketRead); REG_FUNC(cellSysutil, cellSysutilPacketWrite); REG_FUNC(cellSysutil, cellSysutilPacketBegin); REG_FUNC(cellSysutil, cellSysutilPacketEnd); REG_FUNC(cellSysutil, cellSysutilGameDataAssignVmc); REG_FUNC(cellSysutil, cellSysutilGameDataExit); REG_FUNC(cellSysutil, cellSysutilGameExit_I); REG_FUNC(cellSysutil, cellSysutilGamePowerOff_I); REG_FUNC(cellSysutil, cellSysutilGameReboot_I); REG_FUNC(cellSysutil, cellSysutilSharedMemoryAlloc); REG_FUNC(cellSysutil, cellSysutilSharedMemoryFree); REG_FUNC(cellSysutil, cellSysutilNotification); REG_FUNC(cellSysutil, _ZN4cxml7Element11AppendChildERS0_); REG_FUNC(cellSysutil, _ZN4cxml8DocumentC1Ev); REG_FUNC(cellSysutil, _ZN4cxml8DocumentD1Ev); REG_FUNC(cellSysutil, _ZN4cxml8Document5ClearEv); REG_FUNC(cellSysutil, _ZN4cxml8Document5WriteEPFiPKvjPvES3_); REG_FUNC(cellSysutil, _ZN4cxml8Document12RegisterFileEPKvjPNS_4FileE); REG_FUNC(cellSysutil, _ZN4cxml8Document13CreateElementEPKciPNS_7ElementE); REG_FUNC(cellSysutil, _ZN4cxml8Document14SetHeaderMagicEPKc); REG_FUNC(cellSysutil, _ZN4cxml8Document16CreateFromBufferEPKvjb); REG_FUNC(cellSysutil, _ZN4cxml8Document18GetDocumentElementEv); REG_FUNC(cellSysutil, _ZNK4cxml4File7GetAddrEv); REG_FUNC(cellSysutil, _ZNK4cxml7Element12GetAttributeEPKcPNS_9AttributeE); REG_FUNC(cellSysutil, _ZNK4cxml7Element13GetFirstChildEv); REG_FUNC(cellSysutil, _ZNK4cxml7Element14GetNextSiblingEv); REG_FUNC(cellSysutil, _ZNK4cxml9Attribute6GetIntEPi); REG_FUNC(cellSysutil, _ZNK4cxml9Attribute7GetFileEPNS_4FileE); REG_FUNC(cellSysutil, _ZN8cxmlutil6SetIntERKN4cxml7ElementEPKci); REG_FUNC(cellSysutil, _ZN8cxmlutil6GetIntERKN4cxml7ElementEPKcPi); REG_FUNC(cellSysutil, _ZN8cxmlutil7SetFileERKN4cxml7ElementEPKcRKNS0_4FileE); REG_FUNC(cellSysutil, _ZN8cxmlutil8GetFloatERKN4cxml7ElementEPKcPf); REG_FUNC(cellSysutil, _ZN8cxmlutil8SetFloatERKN4cxml7ElementEPKcf); REG_FUNC(cellSysutil, _ZN8cxmlutil9GetStringERKN4cxml7ElementEPKcPS5_Pj); REG_FUNC(cellSysutil, _ZN8cxmlutil9SetStringERKN4cxml7ElementEPKcS5_); REG_FUNC(cellSysutil, _ZN8cxmlutil16CheckElementNameERKN4cxml7ElementEPKc); REG_FUNC(cellSysutil, _ZN8cxmlutil16FindChildElementERKN4cxml7ElementEPKcS5_S5_); REG_FUNC(cellSysutil, _ZN8cxmlutil7GetFileERKN4cxml7ElementEPKcPNS0_4FileE); REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil11FixedMemory3EndEi); REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil11FixedMemory5BeginEi); REG_FUNC( cellSysutil, _ZN16sysutil_cxmlutil11FixedMemory8AllocateEN4cxml14AllocationTypeEPvS3_jPS3_Pj); REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil12PacketWriter5WriteEPKvjPv); REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil12PacketWriterC1EiiRN4cxml8DocumentE); REG_FNID(cellSysutil, 0xE1EC7B6A, cellSysutil_E1EC7B6A); });