rpcsx/rpcs3/Emu/System.cpp

726 lines
17 KiB
C++
Raw Normal View History

#include "stdafx.h"
2016-04-14 00:59:00 +02:00
#include "Utilities/event.h"
2017-03-29 01:54:05 +02:00
#include "Utilities/bin_patch.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUThread.h"
2016-04-14 00:59:00 +02:00
#include "Emu/Cell/PPUCallback.h"
#include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Cell/SPUThread.h"
2016-05-13 16:01:48 +02:00
#include "Emu/Cell/RawSPUThread.h"
2016-04-14 00:59:00 +02:00
#include "Emu/Cell/lv2/sys_sync.h"
2016-05-13 16:01:48 +02:00
#include "Emu/PSP2/ARMv7Thread.h"
2014-08-26 01:55:37 +02:00
#include "Emu/IdManager.h"
2016-04-14 00:59:00 +02:00
#include "Emu/RSX/GSRender.h"
2014-08-26 01:55:37 +02:00
#include "Loader/PSF.h"
2016-04-14 00:59:00 +02:00
#include "Loader/ELF.h"
2014-08-09 17:16:21 +02:00
#include "Utilities/StrUtil.h"
#include "../Crypto/unself.h"
2016-05-13 16:01:48 +02:00
#include <thread>
2017-04-02 20:10:06 +02:00
#include "Utilities/GDBDebugServer.h"
2017-05-20 13:45:02 +02:00
cfg_root g_cfg;
2017-05-20 13:45:02 +02:00
system_type g_system;
2016-06-02 17:16:01 +02:00
std::string g_cfg_defaults;
2016-04-14 00:59:00 +02:00
extern atomic_t<u32> g_thread_count;
2015-07-04 21:23:10 +02:00
extern u64 get_system_time();
2016-04-14 00:59:00 +02:00
extern void ppu_load_exec(const ppu_exec_object&);
extern void spu_load_exec(const spu_exec_object&);
extern void arm_load_exec(const arm_exec_object&);
2017-02-26 16:56:31 +01:00
extern std::shared_ptr<struct lv2_prx> ppu_load_prx(const ppu_prx_object&, const std::string&);
fs::file g_tty;
2017-05-20 13:45:02 +02:00
template <>
void fmt_class_string<keyboard_handler>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](keyboard_handler value)
{
switch (value)
{
case keyboard_handler::null: return "Null";
case keyboard_handler::basic: return "Basic";
}
return unknown;
});
}
template <>
void fmt_class_string<mouse_handler>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](mouse_handler value)
{
switch (value)
{
case mouse_handler::null: return "Null";
case mouse_handler::basic: return "Basic";
}
return unknown;
});
}
template <>
void fmt_class_string<pad_handler>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](pad_handler value)
{
switch (value)
{
case pad_handler::null: return "Null";
case pad_handler::keyboard: return "Keyboard";
case pad_handler::ds4: return "DualShock 4";
#ifdef _MSC_VER
case pad_handler::xinput: return "XInput";
#endif
#ifdef _WIN32
case pad_handler::mm: return "MMJoystick";
#endif
}
return unknown;
});
}
template <>
void fmt_class_string<video_renderer>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](video_renderer value)
{
switch (value)
{
case video_renderer::null: return "Null";
case video_renderer::opengl: return "OpenGL";
#ifdef _WIN32
case video_renderer::vulkan: return "Vulkan";
#endif
#ifdef _MSC_VER
case video_renderer::dx12: return "D3D12";
#endif
}
return unknown;
});
}
template <>
void fmt_class_string<audio_renderer>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](audio_renderer value)
{
switch (value)
{
case audio_renderer::null: return "Null";
#ifdef _WIN32
case audio_renderer::xaudio: return "XAudio2";
#elif __linux__
case audio_renderer::alsa: return "ALSA";
#endif
case audio_renderer::openal: return "OpenAL";
}
return unknown;
});
}
template <>
void fmt_class_string<video_resolution>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](video_resolution value)
{
switch (value)
{
case video_resolution::_1080: return "1920x1080";
case video_resolution::_720: return "1280x720";
case video_resolution::_480: return "720x480";
case video_resolution::_576: return "720x576";
case video_resolution::_1600x1080: return "1600x1080";
case video_resolution::_1440x1080: return "1440x1080";
case video_resolution::_1280x1080: return "1280x1080";
case video_resolution::_960x1080: return "960x1080";
}
return unknown;
});
}
template <>
void fmt_class_string<video_aspect>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](video_aspect value)
{
switch (value)
{
case video_aspect::_auto: return "Auto";
case video_aspect::_4_3: return "4:3";
case video_aspect::_16_9: return "16:9";
}
return unknown;
});
}
2016-04-14 00:59:00 +02:00
namespace rpcs3
{
event<void>& on_run() { static event<void> on_run; return on_run; }
event<void>& on_stop() { static event<void> on_stop; return on_stop; }
event<void>& on_pause() { static event<void> on_pause; return on_pause; }
event<void>& on_resume() { static event<void> on_resume; return on_resume; }
}
void Emulator::Init()
{
if (!g_tty)
{
g_tty.open(fs::get_config_dir() + "TTY.log", fs::rewrite + fs::append);
}
2016-04-14 00:59:00 +02:00
idm::init();
fxm::init();
// Reset defaults, cache them
2017-05-20 13:45:02 +02:00
g_cfg.from_default();
g_cfg_defaults = g_cfg.to_string();
2016-04-14 00:59:00 +02:00
// Reload global configuration
2017-05-20 13:45:02 +02:00
g_cfg.from_string(fs::file(fs::get_config_dir() + "/config.yml", fs::read + fs::create).to_string());
2017-02-22 15:22:27 +01:00
// Create directories
2017-05-20 13:45:02 +02:00
const std::string emu_dir_ = g_cfg.vfs.emulator_dir;
2017-02-22 15:22:27 +01:00
const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
2017-05-20 13:45:02 +02:00
const std::string dev_hdd0 = fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir);
const std::string dev_hdd1 = fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir);
const std::string dev_usb = fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir);
2017-02-22 15:22:27 +01:00
fs::create_path(dev_hdd0);
fs::create_dir(dev_hdd0 + "game/");
fs::create_dir(dev_hdd0 + "game/TEST12345/");
fs::create_dir(dev_hdd0 + "game/TEST12345/USRDIR/");
fs::create_dir(dev_hdd0 + "home/");
fs::create_dir(dev_hdd0 + "home/00000001/");
fs::create_dir(dev_hdd0 + "home/00000001/exdata/");
fs::create_dir(dev_hdd0 + "home/00000001/savedata/");
fs::create_dir(dev_hdd0 + "home/00000001/trophy/");
2017-03-23 21:16:20 +01:00
fs::write_file(dev_hdd0 + "home/00000001/localusername", fs::create + fs::excl + fs::write, "User"s);
2017-02-22 15:22:27 +01:00
fs::create_dir(dev_hdd1 + "cache/");
fs::create_dir(dev_hdd1 + "game/");
fs::create_path(dev_hdd1);
fs::create_path(dev_usb);
2017-04-02 20:10:06 +02:00
#ifdef WITH_GDB_DEBUGGER
fxm::make<GDBDebugServer>();
#endif
2017-03-29 01:54:05 +02:00
// Initialize patch engine
fxm::make_always<patch_engine>()->append(fs::get_config_dir() + "/patch.yml");
}
void Emulator::SetPath(const std::string& path, const std::string& elf_path)
{
m_path = path;
m_elf_path = elf_path;
}
2014-12-26 17:16:57 +01:00
bool Emulator::BootGame(const std::string& path, bool direct)
{
2016-01-06 00:52:48 +01:00
static const char* boot_list[] =
{
2014-03-11 17:36:17 +01:00
"/PS3_GAME/USRDIR/EBOOT.BIN",
"/USRDIR/EBOOT.BIN",
2016-01-06 00:52:48 +01:00
"/EBOOT.BIN",
2017-02-22 11:13:06 +01:00
"/eboot.bin",
};
2015-04-19 15:19:24 +02:00
2016-01-06 00:52:48 +01:00
if (direct && fs::is_file(path))
{
2016-01-06 00:52:48 +01:00
SetPath(path);
Load();
2016-01-06 00:52:48 +01:00
return true;
}
2016-01-06 00:52:48 +01:00
for (std::string elf : boot_list)
2014-12-26 17:16:57 +01:00
{
2016-01-06 00:52:48 +01:00
elf = path + elf;
if (fs::is_file(elf))
{
2016-01-06 00:52:48 +01:00
SetPath(elf);
Load();
return true;
}
}
return false;
}
2016-06-02 17:16:01 +02:00
std::string Emulator::GetGameDir()
{
2017-05-20 13:45:02 +02:00
const std::string& emu_dir_ = g_cfg.vfs.emulator_dir;
2017-02-22 14:08:53 +01:00
const std::string& emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
2016-06-02 17:16:01 +02:00
2017-05-20 13:45:02 +02:00
return fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir) + "game/";
2016-06-02 17:16:01 +02:00
}
std::string Emulator::GetLibDir()
{
2017-05-20 13:45:02 +02:00
const std::string& emu_dir_ = g_cfg.vfs.emulator_dir;
2017-02-22 14:08:53 +01:00
const std::string& emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
2016-06-02 17:16:01 +02:00
2017-05-20 13:45:02 +02:00
return fmt::replace_all(g_cfg.vfs.dev_flash, "$(EmulatorDir)", emu_dir) + "sys/external/";
2016-06-02 17:16:01 +02:00
}
void Emulator::Load()
{
2016-04-14 00:59:00 +02:00
Stop();
2015-07-01 00:25:52 +02:00
2016-04-14 00:59:00 +02:00
try
2015-07-04 21:23:10 +02:00
{
2016-04-14 00:59:00 +02:00
Init();
// Open SELF or ELF
fs::file elf_file(m_path);
if (!elf_file)
2015-04-23 18:58:37 +02:00
{
LOG_ERROR(LOADER, "Failed to open file: %s", m_path);
2015-04-23 18:58:37 +02:00
return;
}
2015-10-24 12:38:24 +02:00
2017-02-22 13:21:30 +01:00
LOG_NOTICE(LOADER, "Path: %s", m_path);
const std::string elf_dir = fs::get_parent_dir(m_path);
const fs::file sfov(elf_dir + "/sce_sys/param.sfo");
const fs::file sfo1(elf_dir + "/../PARAM.SFO");
// Load PARAM.SFO (TODO)
const auto _psf = psf::load_object(sfov ? sfov : sfo1);
m_title = psf::get_string(_psf, "TITLE", m_path);
m_title_id = psf::get_string(_psf, "TITLE_ID");
LOG_NOTICE(LOADER, "Title: %s", GetTitle());
LOG_NOTICE(LOADER, "Serial: %s", GetTitleID());
2017-02-22 13:21:30 +01:00
// Initialize data/cache directory
2017-02-22 14:08:53 +01:00
m_cache_path = fs::get_data_dir(m_title_id, m_path);
LOG_NOTICE(LOADER, "Cache: %s", GetCachePath());
// Load custom config-0
if (fs::file cfg_file{m_cache_path + "/config.yml"})
{
LOG_NOTICE(LOADER, "Applying custom config: %s/config.yml", m_cache_path);
2017-05-20 13:45:02 +02:00
g_cfg.from_string(cfg_file.to_string());
}
// Load custom config-1
if (fs::file cfg_file{fs::get_config_dir() + "data/" + m_title_id + "/config.yml"})
{
LOG_NOTICE(LOADER, "Applying custom config: data/%s/config.yml", m_title_id);
2017-05-20 13:45:02 +02:00
g_cfg.from_string(cfg_file.to_string());
}
// Load custom config-2
if (fs::file cfg_file{m_path + ".yml"})
{
LOG_NOTICE(LOADER, "Applying custom config: %s.yml", m_path);
2017-05-20 13:45:02 +02:00
g_cfg.from_string(cfg_file.to_string());
}
2017-05-20 13:45:02 +02:00
LOG_NOTICE(LOADER, "Used configuration:\n%s\n", g_cfg.to_string());
2017-03-29 01:54:05 +02:00
// Load patches from different locations
fxm::check_unlocked<patch_engine>()->append(fs::get_config_dir() + "data/" + m_title_id + "/patch.yml");
fxm::check_unlocked<patch_engine>()->append(m_cache_path + "/patch.yml");
// Mount all devices
2017-05-20 13:45:02 +02:00
const std::string emu_dir_ = g_cfg.vfs.emulator_dir;
const std::string emu_dir = emu_dir_.empty() ? fs::get_config_dir() : emu_dir_;
2017-05-20 13:45:02 +02:00
const std::string home_dir = g_cfg.vfs.app_home;
std::string bdvd_dir = g_cfg.vfs.dev_bdvd;
vfs::mount("dev_hdd0", fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_hdd1", fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_flash", fmt::replace_all(g_cfg.vfs.dev_flash, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_usb", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
vfs::mount("dev_usb000", fmt::replace_all(g_cfg.vfs.dev_usb000, "$(EmulatorDir)", emu_dir));
vfs::mount("app_home", home_dir.empty() ? elf_dir + '/' : fmt::replace_all(home_dir, "$(EmulatorDir)", emu_dir));
// Mount /dev_bdvd/ if necessary
if (bdvd_dir.empty())
{
size_t pos = elf_dir.rfind("PS3_GAME");
std::string temp = elf_dir.substr(0, pos);
if ((pos != std::string::npos) && fs::is_file(temp + "/PS3_DISC.SFB")) {
bdvd_dir = temp;
}
}
if (!bdvd_dir.empty() && fs::is_dir(bdvd_dir))
{
vfs::mount("dev_bdvd", fmt::replace_all(bdvd_dir, "$(EmulatorDir)", emu_dir));
LOG_NOTICE(LOADER, "Disc: %s", vfs::get("/dev_bdvd"));
}
// Mount /host_root/ if necessary
2017-05-20 13:45:02 +02:00
if (g_cfg.vfs.host_root)
{
vfs::mount("host_root", {});
}
// Check SELF header
if (elf_file.size() >= 4 && elf_file.read<u32>() == "SCE\0"_u32)
2015-04-24 02:35:42 +02:00
{
2017-02-22 14:08:53 +01:00
const std::string decrypted_path = m_cache_path + "boot.elf";
2016-04-14 00:59:00 +02:00
2017-02-22 13:21:30 +01:00
fs::stat_t encrypted_stat = elf_file.stat();
fs::stat_t decrypted_stat;
2017-02-22 13:21:30 +01:00
// Check modification time and try to load decrypted ELF
if (fs::stat(decrypted_path, decrypted_stat) && decrypted_stat.mtime == encrypted_stat.mtime)
2016-04-14 00:59:00 +02:00
{
2017-02-22 13:21:30 +01:00
elf_file.open(decrypted_path);
2016-04-14 00:59:00 +02:00
}
else
{
2017-02-22 13:21:30 +01:00
// Decrypt SELF
elf_file = decrypt_self(std::move(elf_file));
if (fs::file elf_out{decrypted_path, fs::rewrite})
{
elf_out.write(elf_file.to_vector<u8>());
elf_out.close();
fs::utime(decrypted_path, encrypted_stat.atime, encrypted_stat.mtime);
}
else
{
2017-02-22 14:08:53 +01:00
LOG_ERROR(LOADER, "Failed to create boot.elf");
2017-02-22 13:21:30 +01:00
}
2016-04-14 00:59:00 +02:00
}
2017-02-22 13:21:30 +01:00
}
2016-04-14 00:59:00 +02:00
ppu_exec_object ppu_exec;
ppu_prx_object ppu_prx;
spu_exec_object spu_exec;
arm_exec_object arm_exec;
2015-04-24 02:35:42 +02:00
2016-04-14 00:59:00 +02:00
if (!elf_file)
{
LOG_ERROR(LOADER, "Failed to decrypt SELF: %s", m_path);
2016-04-14 00:59:00 +02:00
return;
}
else if (ppu_exec.open(elf_file) == elf_error::ok)
{
// PS3 executable
g_system = system_type::ps3;
2017-05-20 13:45:02 +02:00
m_state = system_state::ready;
2016-04-14 00:59:00 +02:00
vm::ps3::init();
if (m_elf_path.empty())
{
m_elf_path = "/host_root/" + m_path;
LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
}
ppu_load_exec(ppu_exec);
2016-04-14 00:59:00 +02:00
2016-08-14 02:22:19 +02:00
fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall
2016-04-14 00:59:00 +02:00
}
else if (ppu_prx.open(elf_file) == elf_error::ok)
{
// PPU PRX (experimental)
g_system = system_type::ps3;
2017-05-20 13:45:02 +02:00
m_state = system_state::ready;
2016-04-14 00:59:00 +02:00
vm::ps3::init();
2017-02-26 16:56:31 +01:00
ppu_load_prx(ppu_prx, "");
2016-04-14 00:59:00 +02:00
}
else if (spu_exec.open(elf_file) == elf_error::ok)
{
// SPU executable (experimental)
g_system = system_type::ps3;
2017-05-20 13:45:02 +02:00
m_state = system_state::ready;
2016-04-14 00:59:00 +02:00
vm::ps3::init();
spu_load_exec(spu_exec);
2016-04-14 00:59:00 +02:00
}
else if (arm_exec.open(elf_file) == elf_error::ok)
{
// ARMv7 executable
g_system = system_type::psv;
2017-05-20 13:45:02 +02:00
m_state = system_state::ready;
2016-04-14 00:59:00 +02:00
vm::psv::init();
if (m_elf_path.empty())
{
m_elf_path = "host_root:" + m_path;
LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
}
arm_load_exec(arm_exec);
2016-04-14 00:59:00 +02:00
}
else
{
LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);
LOG_WARNING(LOADER, "** ppu_exec -> %s", ppu_exec.get_error());
LOG_WARNING(LOADER, "** ppu_prx -> %s", ppu_prx.get_error());
LOG_WARNING(LOADER, "** spu_exec -> %s", spu_exec.get_error());
LOG_WARNING(LOADER, "** arm_exec -> %s", arm_exec.get_error());
2016-04-14 00:59:00 +02:00
return;
}
2017-05-20 13:45:02 +02:00
if (g_cfg.misc.autostart && IsReady())
2017-04-13 01:31:42 +02:00
{
Run();
}
else if (IsPaused())
{
2017-05-20 13:45:02 +02:00
m_state = system_state::ready;
2017-04-13 01:31:42 +02:00
}
}
2016-04-14 00:59:00 +02:00
catch (const std::exception& e)
{
2016-04-14 00:59:00 +02:00
LOG_FATAL(LOADER, "%s thrown: %s", typeid(e).name(), e.what());
Stop();
}
}
void Emulator::Run()
{
2014-12-28 23:53:31 +01:00
if (!IsReady())
{
Load();
if(!IsReady()) return;
}
2014-12-28 23:53:31 +01:00
if (IsRunning()) Stop();
if (IsPaused())
{
Resume();
return;
}
2014-12-28 23:53:31 +01:00
2016-04-14 00:59:00 +02:00
rpcs3::on_run()();
2015-07-04 21:23:10 +02:00
m_pause_start_time = 0;
m_pause_amend_time = 0;
2017-05-20 13:45:02 +02:00
m_state = system_state::running;
auto on_select = [](u32, cpu_thread& cpu)
2016-04-14 00:59:00 +02:00
{
cpu.run();
};
idm::select<ppu_thread>(on_select);
idm::select<ARMv7Thread>(on_select);
idm::select<RawSPUThread>(on_select);
idm::select<SPUThread>(on_select);
}
2015-09-13 00:37:57 +02:00
bool Emulator::Pause()
{
2015-07-04 21:23:10 +02:00
const u64 start = get_system_time();
2016-04-14 00:59:00 +02:00
// Try to pause
2017-05-20 13:45:02 +02:00
if (!m_state.compare_and_swap_test(system_state::running, system_state::paused))
{
2017-05-20 13:45:02 +02:00
return m_state.compare_and_swap_test(system_state::ready, system_state::paused);
2015-07-04 21:23:10 +02:00
}
2016-04-14 00:59:00 +02:00
rpcs3::on_pause()();
2016-04-14 00:59:00 +02:00
// Update pause start time
2015-07-04 21:23:10 +02:00
if (m_pause_start_time.exchange(start))
{
2015-07-06 21:35:34 +02:00
LOG_ERROR(GENERAL, "Emulator::Pause() error: concurrent access");
2015-07-04 21:23:10 +02:00
}
2015-07-01 00:25:52 +02:00
auto on_select = [](u32, cpu_thread& cpu)
2015-07-04 21:23:10 +02:00
{
cpu.state += cpu_flag::dbg_global_pause;
};
idm::select<ppu_thread>(on_select);
idm::select<ARMv7Thread>(on_select);
idm::select<RawSPUThread>(on_select);
idm::select<SPUThread>(on_select);
if (auto mfc = fxm::check<mfc_thread>())
{
on_select(0, *mfc);
}
2015-09-13 00:37:57 +02:00
return true;
}
void Emulator::Resume()
{
2016-04-14 00:59:00 +02:00
// Get pause start time
const u64 time = m_pause_start_time.exchange(0);
2016-04-14 00:59:00 +02:00
// Try to increment summary pause time
if (time)
{
m_pause_amend_time += get_system_time() - time;
}
2016-04-14 00:59:00 +02:00
// Try to resume
2017-05-20 13:45:02 +02:00
if (!m_state.compare_and_swap_test(system_state::paused, system_state::running))
2015-07-04 21:23:10 +02:00
{
return;
}
if (!time)
2015-07-04 21:23:10 +02:00
{
2015-07-06 21:35:34 +02:00
LOG_ERROR(GENERAL, "Emulator::Resume() error: concurrent access");
2015-07-04 21:23:10 +02:00
}
2017-02-05 14:35:10 +01:00
auto on_select = [](u32, cpu_thread& cpu)
2015-07-01 00:25:52 +02:00
{
2017-02-05 14:35:10 +01:00
cpu.state -= cpu_flag::dbg_global_pause;
cpu.notify();
};
2017-02-05 14:35:10 +01:00
idm::select<ppu_thread>(on_select);
idm::select<ARMv7Thread>(on_select);
idm::select<RawSPUThread>(on_select);
idm::select<SPUThread>(on_select);
2014-12-28 23:53:31 +01:00
if (auto mfc = fxm::check<mfc_thread>())
{
on_select(0, *mfc);
}
2016-04-14 00:59:00 +02:00
rpcs3::on_resume()();
}
void Emulator::Stop()
{
2017-05-20 13:45:02 +02:00
if (m_state.exchange(system_state::stopped) == system_state::stopped)
2015-07-04 21:23:10 +02:00
{
return;
}
2016-04-14 00:59:00 +02:00
LOG_NOTICE(GENERAL, "Stopping emulator...");
rpcs3::on_stop()();
2015-03-16 22:38:21 +01:00
2017-04-02 20:10:06 +02:00
#ifdef WITH_GDB_DEBUGGER
//fxm for some reason doesn't call on_stop
fxm::get<GDBDebugServer>()->on_stop();
fxm::remove<GDBDebugServer>();
#endif
2017-02-24 17:56:59 +01:00
auto e_stop = std::make_exception_ptr(cpu_flag::dbg_global_stop);
auto on_select = [&](u32, cpu_thread& cpu)
2015-03-16 22:38:21 +01:00
{
2017-02-05 14:35:10 +01:00
cpu.state += cpu_flag::dbg_global_stop;
2017-02-24 17:56:59 +01:00
cpu.get()->set_exception(e_stop);
2017-02-05 14:35:10 +01:00
};
2015-07-06 21:35:34 +02:00
2017-02-05 14:35:10 +01:00
idm::select<ppu_thread>(on_select);
idm::select<ARMv7Thread>(on_select);
idm::select<RawSPUThread>(on_select);
idm::select<SPUThread>(on_select);
2015-03-16 22:38:21 +01:00
if (auto mfc = fxm::check<mfc_thread>())
{
on_select(0, *mfc);
}
2015-07-21 22:14:04 +02:00
LOG_NOTICE(GENERAL, "All threads signaled...");
2015-01-18 00:01:08 +01:00
while (g_thread_count)
{
m_cb.process_events();
std::this_thread::sleep_for(10ms);
}
2015-07-03 18:07:36 +02:00
LOG_NOTICE(GENERAL, "All threads stopped...");
2015-01-18 00:01:08 +01:00
2017-02-06 19:36:46 +01:00
lv2_obj::cleanup();
idm::clear();
2015-08-06 15:05:33 +02:00
fxm::clear();
2015-08-06 15:05:33 +02:00
LOG_NOTICE(GENERAL, "Objects cleared...");
2015-07-12 13:52:55 +02:00
RSXIOMem.Clear();
2015-07-11 22:44:53 +02:00
vm::close();
2017-05-20 13:45:02 +02:00
if (g_cfg.misc.autoexit)
{
2016-04-14 00:59:00 +02:00
GetCallbacks().exit();
}
else
{
Init();
}
}
s32 error_code::error_report(const fmt_type_info* sup, u64 arg)
{
2017-02-02 18:47:25 +01:00
logs::channel* channel = &logs::GENERAL;
logs::level level = logs::level::error;
const char* func = "Unknown function";
if (auto thread = get_current_cpu_thread())
{
2017-01-25 18:50:30 +01:00
if (g_system == system_type::ps3 && thread->id_type() == 1)
{
2017-02-02 18:47:25 +01:00
auto& ppu = static_cast<ppu_thread&>(*thread);
// Filter some annoying reports
switch (arg)
{
2017-02-03 00:16:09 +01:00
case CELL_ESRCH:
2017-02-05 01:06:05 +01:00
case CELL_EDEADLK:
2017-02-03 00:16:09 +01:00
{
2017-02-05 01:06:05 +01:00
if (ppu.m_name == "_cellsurMixerMain" || ppu.m_name == "_sys_MixerChStripMain")
2017-02-03 00:16:09 +01:00
{
2017-02-05 01:06:05 +01:00
if (std::memcmp(ppu.last_function, "sys_mutex_lock", 15) == 0 ||
2017-04-13 17:37:46 +02:00
std::memcmp(ppu.last_function, "sys_lwmutex_lock", 17) == 0 ||
std::memcmp(ppu.last_function, "_sys_mutex_lock", 16) == 0 ||
std::memcmp(ppu.last_function, "_sys_lwmutex_lock", 18) == 0)
2017-02-05 01:06:05 +01:00
{
level = logs::level::trace;
}
2017-02-03 00:16:09 +01:00
}
break;
}
2017-02-02 18:47:25 +01:00
}
if (ppu.last_function)
{
2017-02-02 18:47:25 +01:00
func = ppu.last_function;
}
}
if (g_system == system_type::psv)
{
2017-02-02 18:47:25 +01:00
if (auto _func = static_cast<ARMv7Thread*>(thread)->last_function)
{
2017-02-02 18:47:25 +01:00
func = _func;
}
}
}
2017-02-02 18:47:25 +01:00
channel->format(level, "'%s' failed with 0x%08x%s%s", func, arg, sup ? " : " : "", std::make_pair(sup, arg));
return static_cast<s32>(arg);
}
Emulator Emu;