rpcs3/rpcs3/Gui/MainFrame.cpp
Nekotekina e8bfce4ebd decrypt_self() function
Fixed SPU self decryption
Fixed PSV debug self load
2017-02-11 21:36:48 +03:00

568 lines
16 KiB
C++

#include "stdafx.h"
#include "stdafx_gui.h"
#include "rpcs3.h"
#include "MainFrame.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Gui/PADManager.h"
#include "Gui/AboutDialog.h"
#include "Gui/GameViewer.h"
#include "Gui/AutoPauseManager.h"
#include "Gui/SaveDataUtility.h"
#include "Gui/KernelExplorer.h"
#include "Gui/MemoryViewer.h"
#include "Gui/RSXDebugger.h"
#include "Gui/SettingsDialog.h"
#include "Gui/MemoryStringSearcher.h"
#include "Gui/CgDisasm.h"
#include "Crypto/unpkg.h"
#include "Utilities/Thread.h"
#include "Utilities/StrUtil.h"
#include "../Crypto/unself.h"
#include <thread>
#ifndef _WIN32
#include "frame_icon.xpm"
#endif
enum IDs
{
id_boot_elf = 0x555,
id_boot_game,
id_boot_install_pkg,
id_boot_exit,
id_sys_pause,
id_sys_stop,
id_sys_send_open_menu,
id_sys_send_exit,
id_config_emu,
id_config_pad,
id_config_vfs_manager,
id_config_vhdd_manager,
id_config_autopause_manager,
id_config_savedata_manager,
id_tools_compiler,
id_tools_kernel_explorer,
id_tools_memory_viewer,
id_tools_rsx_debugger,
id_tools_string_search,
id_tools_decrypt_sprx_libraries,
id_tools_cg_disasm,
id_help_about,
id_update_dbg
};
wxString GetPaneName()
{
static int pane_num = 0;
return wxString::Format("Pane_%d", pane_num++);
}
MainFrame::MainFrame()
: FrameBase(nullptr, wxID_ANY, "", "MainFrame", wxSize(900, 600))
, m_timer(this, id_update_dbg)
, m_aui_mgr(this)
, m_sys_menu_opened(false)
{
SetLabel("RPCS3 v" + rpcs3::version.to_string());
wxMenuBar* menubar = new wxMenuBar();
wxMenu* menu_boot = new wxMenu();
menubar->Append(menu_boot, "&Boot");
menu_boot->Append(id_boot_elf, "Boot &ELF / SELF file");
menu_boot->Append(id_boot_game, "Boot &game");
menu_boot->AppendSeparator();
menu_boot->Append(id_boot_install_pkg, "&Install PKG");
menu_boot->AppendSeparator();
menu_boot->Append(id_boot_exit, "&Exit");
wxMenu* menu_sys = new wxMenu();
menubar->Append(menu_sys, "&System");
menu_sys->Append(id_sys_pause, "&Pause")->Enable(false);
menu_sys->Append(id_sys_stop, "&Stop\tCtrl + S")->Enable(false);
menu_sys->AppendSeparator();
menu_sys->Append(id_sys_send_open_menu, "Send &open system menu cmd")->Enable(false);
menu_sys->Append(id_sys_send_exit, "Send &exit cmd")->Enable(false);
wxMenu* menu_conf = new wxMenu();
menubar->Append(menu_conf, "&Config");
menu_conf->Append(id_config_emu, "&Settings");
menu_conf->Append(id_config_pad, "&PAD Settings");
menu_conf->AppendSeparator();
menu_conf->Append(id_config_autopause_manager, "&Auto Pause Settings");
//menu_conf->AppendSeparator();
//menu_conf->Append(id_config_vfs_manager, "Virtual &File System Manager");
//menu_conf->Append(id_config_vhdd_manager, "Virtual &HDD Manager");
//menu_conf->Append(id_config_savedata_manager, "Save &Data Utility");
wxMenu* menu_tools = new wxMenu();
menubar->Append(menu_tools, "&Tools");
//menu_tools->Append(id_tools_compiler, "&ELF Compiler");
menu_tools->Append(id_tools_cg_disasm, "&Cg Disasm")->Enable();
menu_tools->Append(id_tools_kernel_explorer, "&Kernel Explorer")->Enable(false);
menu_tools->Append(id_tools_memory_viewer, "&Memory Viewer")->Enable(false);
menu_tools->Append(id_tools_rsx_debugger, "&RSX Debugger")->Enable(false);
menu_tools->Append(id_tools_string_search, "&String Search")->Enable(false);
menu_tools->AppendSeparator();
menu_tools->Append(id_tools_decrypt_sprx_libraries, "&Decrypt SPRX libraries");
wxMenu* menu_help = new wxMenu();
menubar->Append(menu_help, "&Help");
menu_help->Append(id_help_about, "&About...");
SetMenuBar(menubar);
SetIcon(wxICON(frame_icon));
// Panels
m_log_frame = new LogFrame(this);
m_game_viewer = new GameViewer(this);
m_debugger_frame = new DebuggerPanel(this);
AddPane(m_game_viewer, "Game List", wxAUI_DOCK_CENTRE);
AddPane(m_log_frame, "Log", wxAUI_DOCK_BOTTOM);
AddPane(m_debugger_frame, "Debugger", wxAUI_DOCK_RIGHT);
// Events
Bind(wxEVT_MENU, &MainFrame::BootElf, this, id_boot_elf);
Bind(wxEVT_MENU, &MainFrame::BootGame, this, id_boot_game);
Bind(wxEVT_MENU, &MainFrame::InstallPkg, this, id_boot_install_pkg);
Bind(wxEVT_MENU, [](wxCommandEvent&){ wxGetApp().Exit(); }, id_boot_exit);
Bind(wxEVT_MENU, &MainFrame::Pause, this, id_sys_pause);
Bind(wxEVT_MENU, &MainFrame::Stop, this, id_sys_stop);
Bind(wxEVT_MENU, &MainFrame::SendOpenCloseSysMenu, this, id_sys_send_open_menu);
Bind(wxEVT_MENU, &MainFrame::SendExit, this, id_sys_send_exit);
Bind(wxEVT_MENU, &MainFrame::Config, this, id_config_emu);
Bind(wxEVT_MENU, &MainFrame::ConfigPad, this, id_config_pad);
Bind(wxEVT_MENU, &MainFrame::ConfigAutoPause, this, id_config_autopause_manager);
Bind(wxEVT_MENU, &MainFrame::ConfigVFS, this, id_config_vfs_manager);
Bind(wxEVT_MENU, &MainFrame::ConfigVHDD, this, id_config_vhdd_manager);
Bind(wxEVT_MENU, &MainFrame::ConfigSaveData, this, id_config_savedata_manager);
Bind(wxEVT_MENU, &MainFrame::DecryptSPRXLibraries, this, id_tools_decrypt_sprx_libraries);
Bind(wxEVT_MENU, &MainFrame::OpenELFCompiler, this, id_tools_compiler);
Bind(wxEVT_MENU, &MainFrame::OpenKernelExplorer, this, id_tools_kernel_explorer);
Bind(wxEVT_MENU, &MainFrame::OpenMemoryViewer, this, id_tools_memory_viewer);
Bind(wxEVT_MENU, &MainFrame::OpenRSXDebugger, this, id_tools_rsx_debugger);
Bind(wxEVT_MENU, &MainFrame::OpenStringSearch, this, id_tools_string_search);
Bind(wxEVT_MENU, &MainFrame::OpenCgDisasm, this, id_tools_cg_disasm);
Bind(wxEVT_MENU, &MainFrame::AboutDialogHandler, this, id_help_about);
Bind(wxEVT_MENU, &MainFrame::UpdateUI, this, id_update_dbg);
Bind(wxEVT_TIMER, &MainFrame::UpdateUI, this, id_update_dbg);
Bind(wxEVT_CLOSE_WINDOW, [&](wxCloseEvent&)
{
DoSettings(false);
TheApp->Exit();
});
wxGetApp().Bind(wxEVT_KEY_DOWN, &MainFrame::OnKeyDown, this);
// Check for updates every ~10 ms
m_timer.Start(10);
}
MainFrame::~MainFrame()
{
m_aui_mgr.UnInit();
}
void MainFrame::AddPane(wxWindow* wind, const wxString& caption, int flags)
{
wind->SetSize(-1, 300);
m_aui_mgr.AddPane(wind, wxAuiPaneInfo().Name(GetPaneName()).Caption(caption).Direction(flags).CloseButton(false).MaximizeButton());
}
void MainFrame::DoSettings(bool load)
{
auto&& cfg = g_gui_cfg[ini_name]["aui"];
if (load)
{
const auto& perspective = fmt::FromUTF8(cfg.Scalar());
m_aui_mgr.LoadPerspective(perspective.empty() ? m_aui_mgr.SavePerspective() : perspective);
}
else
{
cfg = fmt::ToUTF8(m_aui_mgr.SavePerspective());
save_gui_cfg();
}
}
void MainFrame::BootGame(wxCommandEvent& WXUNUSED(event))
{
bool stopped = false;
if(Emu.IsRunning())
{
Emu.Pause();
stopped = true;
}
wxDirDialog ctrl(this, L"Select game folder", wxEmptyString);
if(ctrl.ShowModal() == wxID_CANCEL)
{
if(stopped) Emu.Resume();
return;
}
Emu.Stop();
if(!Emu.BootGame(ctrl.GetPath().ToStdString()))
{
LOG_ERROR(GENERAL, "PS3 executable not found in selected folder (%s)", fmt::ToUTF8(ctrl.GetPath())); // passing std::string (test)
}
}
void MainFrame::InstallPkg(wxCommandEvent& WXUNUSED(event))
{
const bool paused = Emu.Pause();
wxFileDialog ctrl(this, L"Select PKG", wxEmptyString, wxEmptyString, "PKG files (*.pkg)|*.pkg|All files (*.*)|*.*", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (ctrl.ShowModal() == wxID_CANCEL)
{
if (paused) Emu.Resume();
return;
}
Emu.Stop();
// Open PKG file
fs::file pkg_f(ctrl.GetPath().ToStdString());
if (!pkg_f || pkg_f.size() < 64)
{
LOG_ERROR(LOADER, "PKG: Failed to open %s", ctrl.GetPath().ToStdString());
return;
}
// Get title ID
std::vector<char> title_id(9);
pkg_f.seek(55);
pkg_f.read(title_id);
pkg_f.seek(0);
// Get full path
const auto& local_path = Emu.GetGameDir() + std::string(std::begin(title_id), std::end(title_id));
if (!fs::create_dir(local_path))
{
if (fs::is_dir(local_path))
{
if (wxMessageDialog(this, "Another installation found. Do you want to overwrite it?", "PKG Decrypter / Installer", wxYES_NO | wxCENTRE).ShowModal() != wxID_YES)
{
LOG_ERROR(LOADER, "PKG: Cancelled installation to existing directory %s", local_path);
return;
}
}
else
{
LOG_ERROR(LOADER, "PKG: Could not create the installation directory %s", local_path);
return;
}
}
wxProgressDialog pdlg("PKG Installer", "Please wait, unpacking...", 1000, this, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
// Synchronization variable
atomic_t<double> progress(0.);
{
// Run PKG unpacking asynchronously
scope_thread worker("PKG Installer", [&]
{
if (pkg_install(pkg_f, local_path + '/', progress))
{
progress = 1.;
return;
}
// TODO: Ask user to delete files on cancellation/failure?
progress = -1.;
});
// Wait for the completion
while (std::this_thread::sleep_for(5ms), std::abs(progress) < 1.)
{
// Update progress window
if (!pdlg.Update(static_cast<int>(progress * pdlg.GetRange())))
{
// Installation cancelled (signal with negative value)
progress -= 1.;
break;
}
}
if (progress > 0.)
{
pdlg.Update(pdlg.GetRange());
std::this_thread::sleep_for(100ms);
}
}
pdlg.Close();
if (progress >= 1.)
{
// Refresh game list
m_game_viewer->Refresh();
}
}
void MainFrame::BootElf(wxCommandEvent& WXUNUSED(event))
{
bool stopped = false;
if(Emu.IsRunning())
{
Emu.Pause();
stopped = true;
}
wxFileDialog ctrl(this, L"Select (S)ELF", wxEmptyString, wxEmptyString,
"(S)ELF files (*BOOT.BIN;*.elf;*.self)|*BOOT.BIN;*.elf;*.self"
"|ELF files (BOOT.BIN;*.elf)|BOOT.BIN;*.elf"
"|SELF files (EBOOT.BIN;*.self)|EBOOT.BIN;*.self"
"|BOOT files (*BOOT.BIN)|*BOOT.BIN"
"|BIN files (*.bin)|*.bin"
"|All files (*.*)|*.*",
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if(ctrl.ShowModal() == wxID_CANCEL)
{
if(stopped) Emu.Resume();
return;
}
LOG_NOTICE(LOADER, "(S)ELF: booting...");
Emu.Stop();
Emu.SetPath(fmt::ToUTF8(ctrl.GetPath()));
Emu.Load();
LOG_SUCCESS(LOADER, "(S)ELF: boot done.");
}
void MainFrame::DecryptSPRXLibraries(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog ctrl(this, L"Select SPRX files", wxEmptyString, wxEmptyString,
"SPRX files (*.sprx)|*sprx",
wxFD_OPEN | wxFD_MULTIPLE);
if (ctrl.ShowModal() == wxID_CANCEL)
{
return;
}
wxArrayString modules;
ctrl.GetPaths(modules);
LOG_NOTICE(GENERAL, "Decrypting SPRX libraries...");
for (const wxString& module : modules)
{
std::string prx_path = fmt::ToUTF8(module);
const std::string& prx_dir = fs::get_parent_dir(prx_path);
fs::file elf_file(prx_path);
if (elf_file && elf_file.size() >= 4 && elf_file.read<u32>() == "SCE\0"_u32)
{
const std::size_t prx_ext_pos = prx_path.find_last_of('.');
const std::string& prx_ext = fmt::to_upper(prx_path.substr(prx_ext_pos != -1 ? prx_ext_pos : prx_path.size()));
const std::string& prx_name = prx_path.substr(prx_dir.size());
elf_file = decrypt_self(std::move(elf_file));
prx_path.erase(prx_path.size() - 4, 1); // change *.sprx to *.prx
if (elf_file)
{
if (fs::file new_file{prx_path, fs::rewrite})
{
new_file.write(elf_file.to_string());
LOG_SUCCESS(GENERAL, "Decrypted %s", prx_dir + prx_name);
}
else
{
LOG_ERROR(GENERAL, "Failed to create %s", prx_path);
}
}
else
{
LOG_ERROR(GENERAL, "Failed to decrypt %s", prx_dir + prx_name);
}
}
}
LOG_NOTICE(GENERAL, "Finished decrypting all SPRX libraries.");
}
void MainFrame::Pause(wxCommandEvent& WXUNUSED(event))
{
if(Emu.IsReady())
{
Emu.Run();
}
else if(Emu.IsPaused())
{
Emu.Resume();
}
else if(Emu.IsRunning())
{
Emu.Pause();
}
}
void MainFrame::Stop(wxCommandEvent& WXUNUSED(event))
{
Emu.Stop();
}
// This is ugly, but PS3 headers shall not be included there.
extern void sysutil_send_system_cmd(u64 status, u64 param);
void MainFrame::SendExit(wxCommandEvent& event)
{
sysutil_send_system_cmd(0x0101 /* CELL_SYSUTIL_REQUEST_EXITGAME */, 0);
}
void MainFrame::SendOpenCloseSysMenu(wxCommandEvent& event)
{
sysutil_send_system_cmd(m_sys_menu_opened ? 0x0132 /* CELL_SYSUTIL_SYSTEM_MENU_CLOSE */ : 0x0131 /* CELL_SYSUTIL_SYSTEM_MENU_OPEN */, 0);
m_sys_menu_opened = !m_sys_menu_opened;
wxCommandEvent ce;
UpdateUI(ce);
}
void MainFrame::Config(wxCommandEvent& WXUNUSED(event))
{
SettingsDialog(this);
}
void MainFrame::ConfigPad(wxCommandEvent& WXUNUSED(event))
{
PADManager(this).ShowModal();
}
void MainFrame::ConfigVFS(wxCommandEvent& WXUNUSED(event))
{
//VFSManagerDialog(this).ShowModal();
}
void MainFrame::ConfigVHDD(wxCommandEvent& WXUNUSED(event))
{
//VHDDManagerDialog(this).ShowModal();
}
void MainFrame::ConfigAutoPause(wxCommandEvent& WXUNUSED(event))
{
AutoPauseManagerDialog(this).ShowModal();
}
void MainFrame::ConfigSaveData(wxCommandEvent& event)
{
SaveDataListDialog(this, true).ShowModal();
}
void MainFrame::OpenELFCompiler(wxCommandEvent& WXUNUSED(event))
{
//(new CompilerELF(this))->Show();
}
void MainFrame::OpenKernelExplorer(wxCommandEvent& WXUNUSED(event))
{
(new KernelExplorer(this))->Show();
}
void MainFrame::OpenMemoryViewer(wxCommandEvent& WXUNUSED(event))
{
(new MemoryViewerPanel(this))->Show();
}
void MainFrame::OpenRSXDebugger(wxCommandEvent& WXUNUSED(event))
{
(new RSXDebugger(this))->Show();
}
void MainFrame::OpenStringSearch(wxCommandEvent& WXUNUSED(event))
{
(new MemoryStringSearcher(this))->Show();
}
void MainFrame::OpenCgDisasm(wxCommandEvent& WXUNUSED(event))
{
(new CgDisasm(this))->Show();
}
void MainFrame::AboutDialogHandler(wxCommandEvent& WXUNUSED(event))
{
AboutDialog(this).ShowModal();
}
void MainFrame::UpdateUI(wxEvent& event)
{
const bool is_running = Emu.IsRunning();
const bool is_stopped = Emu.IsStopped();
const bool is_ready = Emu.IsReady();
// Update menu items based on the state of the emulator
wxMenuBar& menubar( *GetMenuBar() );
// Emulation
wxMenuItem& pause = *menubar.FindItem(id_sys_pause);
wxMenuItem& stop = *menubar.FindItem(id_sys_stop);
pause.SetItemLabel(is_running ? "&Pause\tCtrl + P" : is_ready ? "&Start\tCtrl + E" : "&Resume\tCtrl + E");
pause.Enable(!is_stopped);
stop.Enable(!is_stopped);
// PS3 Commands
wxMenuItem& send_exit = *menubar.FindItem(id_sys_send_exit);
wxMenuItem& send_open_menu = *menubar.FindItem(id_sys_send_open_menu);
bool enable_commands = !is_stopped;
send_open_menu.SetItemLabel(wxString::Format("Send &%s system menu cmd", (m_sys_menu_opened ? "close" : "open")));
send_open_menu.Enable(enable_commands);
send_exit.Enable(enable_commands);
// Tools
wxMenuItem& kernel_explorer = *menubar.FindItem(id_tools_kernel_explorer);
wxMenuItem& memory_viewer = *menubar.FindItem(id_tools_memory_viewer);
wxMenuItem& rsx_debugger = *menubar.FindItem(id_tools_rsx_debugger);
wxMenuItem& string_search = *menubar.FindItem(id_tools_string_search);
kernel_explorer.Enable(!is_stopped);
memory_viewer.Enable(!is_stopped);
rsx_debugger.Enable(!is_stopped);
string_search.Enable(!is_stopped);
// Debugger
m_debugger_frame->UpdateUI();
// Logs
m_log_frame->UpdateUI();
}
void MainFrame::OnKeyDown(wxKeyEvent& event)
{
if(wxGetActiveWindow() /*== this*/ && event.ControlDown())
{
switch(event.GetKeyCode())
{
case 'E': case 'e': if(Emu.IsPaused()) Emu.Resume(); else if(Emu.IsReady()) Emu.Run(); return;
case 'P': case 'p': if(Emu.IsRunning()) Emu.Pause(); return;
case 'S': case 's': if(!Emu.IsStopped()) Emu.Stop(); return;
case 'R': case 'r': if(!Emu.GetPath().empty()) {Emu.Stop(); Emu.Run();} return;
}
}
event.Skip();
}