rpcsx/rpcs3/Emu/System.cpp

479 lines
9.6 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "Utilities/Log.h"
2015-04-24 23:38:11 +02:00
#include "Utilities/File.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/GameInfo.h"
#include "Emu/ARMv7/PSVFuncList.h"
2015-01-26 13:55:26 +01:00
#include "Emu/ARMv7/PSVObjectList.h"
#include "Emu/SysCalls/ModuleManager.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/Cell/PPUInstrTable.h"
#include "Emu/FS/vfsFile.h"
#include "Emu/FS/vfsLocalFile.h"
2014-06-28 03:19:44 +02:00
#include "Emu/FS/vfsDeviceLocalFile.h"
2014-07-12 09:02:39 +02:00
#include "Emu/DbgCommand.h"
2014-08-26 01:55:37 +02:00
#include "Emu/CPU/CPUThreadManager.h"
#include "Emu/SysCalls/Callback.h"
2014-08-26 01:55:37 +02:00
#include "Emu/IdManager.h"
#include "Emu/Io/Pad.h"
#include "Emu/Io/Keyboard.h"
#include "Emu/Io/Mouse.h"
#include "Emu/RSX/GSManager.h"
#include "Emu/Audio/AudioManager.h"
#include "Emu/FS/VFS.h"
2015-03-04 05:42:04 +01:00
#include "Emu/Event.h"
2014-08-26 01:55:37 +02:00
#include "Loader/PSF.h"
2015-04-20 00:26:28 +02:00
#include "Loader/ELF64.h"
#include "Loader/ELF32.h"
2014-08-09 17:16:21 +02:00
#include "../Crypto/unself.h"
2013-11-27 20:16:19 +01:00
#include <fstream>
using namespace PPU_instr;
2013-11-27 20:16:19 +01:00
static const std::string& BreakPointsDBName = "BreakPoints.dat";
static const u16 bpdb_version = 0x1000;
extern std::atomic<u32> g_thread_count;
2015-03-16 22:38:21 +01:00
extern void finalize_ppu_exec_map();
Emulator::Emulator()
: m_status(Stopped)
, m_mode(DisAsm)
, m_rsx_callback(0)
2014-08-26 01:55:37 +02:00
, m_thread_manager(new CPUThreadManager())
, m_pad_manager(new PadManager())
, m_keyboard_manager(new KeyboardManager())
, m_mouse_manager(new MouseManager())
, m_id_manager(new ID_manager())
2014-08-26 01:55:37 +02:00
, m_gs_manager(new GSManager())
, m_audio_manager(new AudioManager())
, m_callback_manager(new CallbackManager())
, m_event_manager(new EventManager())
, m_module_manager(new ModuleManager())
2014-08-26 01:55:37 +02:00
, m_vfs(new VFS())
{
m_loader.register_handler(new loader::handlers::elf32);
m_loader.register_handler(new loader::handlers::elf64);
2014-08-26 01:55:37 +02:00
}
Emulator::~Emulator()
{
2014-08-26 01:55:37 +02:00
delete m_thread_manager;
delete m_pad_manager;
delete m_keyboard_manager;
delete m_mouse_manager;
delete m_id_manager;
delete m_gs_manager;
delete m_audio_manager;
delete m_callback_manager;
delete m_event_manager;
delete m_module_manager;
delete m_vfs;
}
void Emulator::Init()
{
}
void Emulator::SetPath(const std::string& path, const std::string& elf_path)
{
m_path = path;
m_elf_path = elf_path;
}
void Emulator::SetTitleID(const std::string& id)
{
m_title_id = id;
}
void Emulator::SetTitle(const std::string& title)
{
m_title = title;
}
void Emulator::CheckStatus()
{
2015-03-16 22:38:21 +01:00
//auto threads = GetCPU().GetThreads();
2014-12-24 00:38:13 +01:00
//if (!threads.size())
//{
// Stop();
// return;
//}
2015-03-16 22:38:21 +01:00
//bool AllPaused = true;
//for (auto& t : threads)
2014-12-24 00:38:13 +01:00
//{
2015-03-16 22:38:21 +01:00
// if (t->IsPaused()) continue;
// AllPaused = false;
2014-12-24 00:38:13 +01:00
// break;
//}
2015-03-16 22:38:21 +01:00
//if (AllPaused)
2014-12-24 00:38:13 +01:00
//{
// Pause();
// return;
//}
2015-03-16 22:38:21 +01:00
//bool AllStopped = true;
//for (auto& t : threads)
2014-12-24 00:38:13 +01:00
//{
2015-03-16 22:38:21 +01:00
// if (t->IsStopped()) continue;
// AllStopped = false;
2014-12-24 00:38:13 +01:00
// break;
//}
2015-03-16 22:38:21 +01:00
//if (AllStopped)
2014-12-24 00:38:13 +01:00
//{
2015-03-16 22:38:21 +01:00
// Pause();
2014-12-24 00:38:13 +01:00
//}
}
2014-12-26 17:16:57 +01:00
bool Emulator::BootGame(const std::string& path, bool direct)
{
static const char* elf_path[6] =
{
2014-03-11 17:36:17 +01:00
"/PS3_GAME/USRDIR/BOOT.BIN",
"/USRDIR/BOOT.BIN",
"/BOOT.BIN",
"/PS3_GAME/USRDIR/EBOOT.BIN",
"/USRDIR/EBOOT.BIN",
"/EBOOT.BIN"
};
2015-04-19 15:19:24 +02:00
auto curpath = path;
2014-12-26 17:16:57 +01:00
if (direct)
{
2015-04-24 23:38:11 +02:00
if (fs::is_file(curpath))
{
2014-12-26 17:16:57 +01:00
SetPath(curpath);
Load();
2014-12-26 17:16:57 +01:00
return true;
}
}
2014-12-26 17:16:57 +01:00
for (int i = 0; i < sizeof(elf_path) / sizeof(*elf_path); i++)
{
curpath = path + elf_path[i];
2015-04-24 23:38:11 +02:00
if (fs::is_file(curpath))
{
SetPath(curpath);
Load();
return true;
}
}
return false;
}
void Emulator::Load()
{
GetModuleManager().Init();
2015-04-24 23:38:11 +02:00
if (!fs::is_file(m_path)) return;
2015-04-23 18:58:37 +02:00
const std::string elf_dir = m_path.substr(0, m_path.find_last_of("/\\", std::string::npos, 2) + 1);
if (IsSelf(m_path))
{
2015-04-23 18:58:37 +02:00
const std::string full_name = m_path.substr(elf_dir.length());
const std::string base_name = full_name.substr(0, full_name.find_last_of('.', std::string::npos));
const std::string ext = full_name.substr(base_name.length());
2015-04-23 18:58:37 +02:00
if (fmt::toupper(full_name) == "EBOOT.BIN")
{
2015-04-23 18:58:37 +02:00
m_path = elf_dir + "BOOT.BIN";
}
else if (fmt::toupper(ext) == ".SELF")
{
m_path = elf_dir + base_name + ".elf";
}
else if (fmt::toupper(ext) == ".SPRX")
{
m_path = elf_dir + base_name + ".prx";
}
else
{
2015-04-23 18:58:37 +02:00
m_path = elf_dir + base_name + ".decrypted" + ext;
}
2015-04-23 18:58:37 +02:00
LOG_NOTICE(LOADER, "Decrypting '%s%s'...", elf_dir, full_name);
2015-04-23 18:58:37 +02:00
if (!DecryptSelf(m_path, elf_dir + full_name))
{
return;
}
}
LOG_NOTICE(LOADER, "Loading '%s'...", m_path.c_str());
GetInfo().Reset();
2015-04-23 18:58:37 +02:00
GetVFS().Init(elf_dir);
2015-04-24 02:35:42 +02:00
// /dev_bdvd/ mounting
vfsFile f("/app_home/../dev_bdvd.path");
if (f.IsOpened())
{
// load specified /dev_bdvd/ directory and mount it
std::string bdvd;
bdvd.resize(f.GetSize());
f.Read(&bdvd[0], bdvd.size());
Emu.GetVFS().Mount("/dev_bdvd/", bdvd, new vfsDeviceLocalFile());
}
2015-04-24 23:38:11 +02:00
else if (fs::is_file(elf_dir + "../../PS3_DISC.SFB")) // guess loading disc game
2015-04-24 02:35:42 +02:00
{
const auto dir_list = fmt::split(elf_dir, { "/", "\\" });
// check latest two directories
if (dir_list.size() >= 2 && dir_list.back() == "USRDIR" && *(dir_list.end() - 2) == "PS3_GAME")
{
// mount detected /dev_bdvd/ directory
Emu.GetVFS().Mount("/dev_bdvd/", elf_dir.substr(0, elf_dir.length() - 17), new vfsDeviceLocalFile());
}
}
LOG_NOTICE(LOADER, " "); //used to be skip_line
LOG_NOTICE(LOADER, "Mount info:");
for (uint i = 0; i < GetVFS().m_devices.size(); ++i)
{
2014-08-26 01:55:37 +02:00
LOG_NOTICE(LOADER, "%s -> %s", GetVFS().m_devices[i]->GetPs3Path().c_str(), GetVFS().m_devices[i]->GetLocalPath().c_str());
}
2014-08-09 17:16:21 +02:00
2014-12-28 23:53:31 +01:00
LOG_NOTICE(LOADER, " "); //used to be skip_line
2015-04-24 02:35:42 +02:00
f.Open("/app_home/../PARAM.SFO");
2015-04-17 16:05:28 +02:00
const PSFLoader psf(f);
2014-08-09 17:16:21 +02:00
std::string title = psf.GetString("TITLE");
std::string title_id = psf.GetString("TITLE_ID");
LOG_NOTICE(LOADER, "Title: %s", title.c_str());
LOG_NOTICE(LOADER, "Serial: %s", title_id.c_str());
title.length() ? SetTitle(title) : SetTitle(m_path);
SetTitleID(title_id);
2014-12-28 23:53:31 +01:00
if (m_elf_path.empty())
{
GetVFS().GetDeviceLocal(m_path, m_elf_path);
2015-04-24 02:35:42 +02:00
2015-04-23 18:58:37 +02:00
LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
}
2015-04-17 16:05:28 +02:00
f.Open(m_elf_path);
2014-12-28 23:53:31 +01:00
if (!f.IsOpened())
{
2015-04-23 18:58:37 +02:00
LOG_ERROR(LOADER, "Opening '%s' failed", m_path.c_str());
return;
}
if (!m_loader.load(f))
{
LOG_ERROR(LOADER, "Loading '%s' failed", m_path.c_str());
vm::close();
return;
}
2015-02-28 15:41:15 +01:00
LoadPoints(BreakPointsDBName);
2014-09-11 21:18:19 +02:00
m_status = Ready;
GetGSManager().Init();
GetCallbackManager().Init();
GetAudioManager().Init();
GetEventManager().Init();
SendDbgCommand(DID_READY_EMU);
}
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
SendDbgCommand(DID_START_EMU);
2013-08-12 11:56:56 +02:00
m_status = Running;
GetCPU().Exec();
SendDbgCommand(DID_STARTED_EMU);
}
void Emulator::Pause()
{
2014-12-28 23:53:31 +01:00
if (!IsRunning()) return;
SendDbgCommand(DID_PAUSE_EMU);
if (__sync_bool_compare_and_swap((volatile u32*)&m_status, Running, Paused))
{
SendDbgCommand(DID_PAUSED_EMU);
GetCallbackManager().RunPauseCallbacks(true);
}
}
void Emulator::Resume()
{
2014-12-28 23:53:31 +01:00
if (!IsPaused()) return;
SendDbgCommand(DID_RESUME_EMU);
2013-08-12 11:56:56 +02:00
m_status = Running;
CheckStatus();
2014-12-28 23:53:31 +01:00
SendDbgCommand(DID_RESUMED_EMU);
GetCallbackManager().RunPauseCallbacks(false);
}
extern std::map<u32, std::string> g_armv7_dump;
void Emulator::Stop()
{
if(IsStopped()) return;
SendDbgCommand(DID_STOP_EMU);
2015-03-16 22:38:21 +01:00
m_status = Stopped;
2015-03-16 22:38:21 +01:00
{
auto threads = GetCPU().GetThreads();
for (auto& t : threads)
{
t->AddEvent(CPU_EVENT_STOP);
}
}
2015-01-18 00:01:08 +01:00
while (g_thread_count)
{
2014-07-12 09:02:39 +02:00
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
2015-01-18 00:01:08 +01:00
LOG_NOTICE(HLE, "All threads stopped...");
finalize_psv_modules();
2015-01-26 13:55:26 +01:00
clear_all_psv_objects();
2015-04-20 03:54:19 +02:00
for (auto& v : decltype(g_armv7_dump)(std::move(g_armv7_dump)))
{
LOG_NOTICE(ARMv7, v.second);
}
m_rsx_callback = 0;
// TODO: check finalization order
SavePoints(BreakPointsDBName);
m_break_points.clear();
m_marked_points.clear();
2014-08-26 01:55:37 +02:00
GetVFS().UnMountAll();
GetGSManager().Close();
GetAudioManager().Close();
GetEventManager().Clear();
GetCPU().Close();
GetIdManager().clear();
GetPadManager().Close();
GetKeyboardManager().Close();
GetMouseManager().Close();
GetCallbackManager().Clear();
GetModuleManager().Close();
CurGameInfo.Reset();
Memory.Close();
2015-03-16 22:38:21 +01:00
finalize_ppu_exec_map();
SendDbgCommand(DID_STOPPED_EMU);
}
2013-11-27 20:16:19 +01:00
void Emulator::SavePoints(const std::string& path)
{
2013-11-27 20:16:19 +01:00
std::ofstream f(path, std::ios::binary | std::ios::trunc);
2014-08-30 22:41:01 +02:00
u32 break_count = (u32)m_break_points.size();
u32 marked_count = (u32)m_marked_points.size();
2013-11-27 20:16:19 +01:00
f << bpdb_version << break_count << marked_count;
2014-12-28 23:53:31 +01:00
if (break_count)
{
2013-11-27 20:16:19 +01:00
f.write(reinterpret_cast<char*>(&m_break_points[0]), sizeof(u64) * break_count);
}
2014-12-28 23:53:31 +01:00
if (marked_count)
{
2013-11-27 20:16:19 +01:00
f.write(reinterpret_cast<char*>(&m_marked_points[0]), sizeof(u64) * marked_count);
}
}
2013-11-27 20:16:19 +01:00
void Emulator::LoadPoints(const std::string& path)
{
2015-04-24 23:38:11 +02:00
if (!fs::is_file(path)) return;
2013-11-27 20:16:19 +01:00
std::ifstream f(path, std::ios::binary);
if (!f.is_open())
return;
f.seekg(0, std::ios::end);
2014-08-30 22:41:01 +02:00
int length = (int)f.tellg();
2013-11-27 20:16:19 +01:00
f.seekg(0, std::ios::beg);
u32 break_count, marked_count;
u16 version;
2013-11-27 20:16:19 +01:00
f >> version >> break_count >> marked_count;
2014-12-28 23:53:31 +01:00
if (version != bpdb_version || (sizeof(u16) + break_count * sizeof(u64) + sizeof(u32) + marked_count * sizeof(u64) + sizeof(u32)) != length)
{
2015-04-19 21:25:04 +02:00
LOG_ERROR(LOADER, "'%s' is broken (version=0x%x, break_count=0x%x, marked_count=0x%x, length=0x%x)", path, version, break_count, marked_count, length);
return;
}
2014-12-28 23:53:31 +01:00
if (break_count > 0)
{
m_break_points.resize(break_count);
2013-11-27 20:16:19 +01:00
f.read(reinterpret_cast<char*>(&m_break_points[0]), sizeof(u64) * break_count);
}
2014-12-28 23:53:31 +01:00
if (marked_count > 0)
{
m_marked_points.resize(marked_count);
2013-11-27 20:16:19 +01:00
f.read(reinterpret_cast<char*>(&m_marked_points[0]), sizeof(u64) * marked_count);
}
}
Emulator Emu;
2014-08-24 19:42:19 +02:00
CallAfterCbType CallAfterCallback = nullptr;
void CallAfter(std::function<void()> func)
{
CallAfterCallback(func);
}
void SetCallAfterCallback(CallAfterCbType cb)
{
CallAfterCallback = cb;
2014-12-28 23:53:31 +01:00
}