VMManager: Refactor and improve boot process

[SAVEVERSION+] VM struct changes.

 - Serial/title is now linked to disc, instead of running ELF.
 - Save states can be created during BIOS boot.
 - Patches now apply based on the executing CRC, and only after the
   entry point starts executing (fixes multi-game discs).
 - Add "Fast Forward Boot" option.
 - Split achievements download and activation, downloads occur on
   initialization, but are not activated until after the ELF loads.
 - Prevent HostFS access while in PS1 mode.
 - Remove multiple sources of truth for ELF/CRC/etc.
 - Move ELF state from global scope to VMManager.
 - Prevent game fixes and hw fixes being active while booting game.
 - Simplify game update.
 - Flush recompilers after ELF loads. No point keeping boot code around
   which gets overwritten.
This commit is contained in:
Stenzek 2023-06-13 22:43:11 +10:00 committed by Connor McLaughlin
parent 0cf4cb6e4f
commit 36c27188a4
50 changed files with 1195 additions and 984 deletions

View File

@ -293,8 +293,8 @@ void Host::OnVMResumed()
{
}
void Host::OnGameChanged(const std::string& disc_path, const std::string& elf_override, const std::string& game_serial,
const std::string& game_name, u32 game_crc)
void Host::OnGameChanged(const std::string& title, const std::string& elf_override, const std::string& disc_path,
const std::string& disc_serial, u32 disc_crc, u32 current_crc)
{
}

View File

@ -746,9 +746,9 @@ void MainWindow::updateWindowTitle()
{
QString suffix(QtHost::GetAppConfigSuffix());
QString main_title(QtHost::GetAppNameAndVersion() + suffix);
QString display_title(m_current_game_name + suffix);
QString display_title(m_current_title + suffix);
if (!s_vm_valid || m_current_game_name.isEmpty())
if (!s_vm_valid || m_current_title.isEmpty())
display_title = main_title;
else if (isRenderingToMain())
main_title = display_title;
@ -920,7 +920,7 @@ bool MainWindow::requestShutdown(bool allow_confirm, bool allow_save_to_state, b
return true;
// If we don't have a crc, we can't save state.
allow_save_to_state &= (m_current_game_crc != 0);
allow_save_to_state &= (m_current_disc_crc != 0);
bool save_state = allow_save_to_state && default_save_to_state;
// Only confirm on UI thread because we need to display a msgbox.
@ -1213,15 +1213,15 @@ void MainWindow::onChangeDiscMenuAboutToHide()
void MainWindow::onLoadStateMenuAboutToShow()
{
m_ui.menuLoadState->clear();
updateSaveStateMenusEnableState(!m_current_game_serial.isEmpty());
populateLoadStateMenu(m_ui.menuLoadState, m_current_disc_path, m_current_game_serial, m_current_game_crc);
updateSaveStateMenusEnableState(!m_current_disc_serial.isEmpty());
populateLoadStateMenu(m_ui.menuLoadState, m_current_disc_path, m_current_disc_serial, m_current_disc_crc);
}
void MainWindow::onSaveStateMenuAboutToShow()
{
m_ui.menuSaveState->clear();
updateSaveStateMenusEnableState(!m_current_game_serial.isEmpty());
populateSaveStateMenu(m_ui.menuSaveState, m_current_game_serial, m_current_game_crc);
updateSaveStateMenusEnableState(!m_current_disc_serial.isEmpty());
populateSaveStateMenu(m_ui.menuSaveState, m_current_disc_serial, m_current_disc_crc);
}
void MainWindow::onViewToolbarActionToggled(bool checked)
@ -1269,23 +1269,29 @@ void MainWindow::onViewGamePropertiesActionTriggered()
return;
// prefer to use a game list entry, if we have one, that way the summary is populated
if (!m_current_disc_path.isEmpty() || !m_current_elf_override.isEmpty())
if (!m_current_disc_path.isEmpty() && m_current_elf_override.isEmpty())
{
auto lock = GameList::GetLock();
const GameList::Entry* entry = m_current_elf_override.isEmpty() ?
GameList::GetEntryForPath(m_current_disc_path.toUtf8().constData()) :
GameList::GetEntryForPath(m_current_elf_override.toUtf8().constData());
const GameList::Entry* entry = GameList::GetEntryForPath(m_current_disc_path.toUtf8().constData());
if (entry)
{
SettingsDialog::openGamePropertiesDialog(
entry, m_current_elf_override.isEmpty() ? std::string_view(entry->serial) : std::string_view(), entry->crc);
SettingsDialog::openGamePropertiesDialog(entry, entry->serial, entry->crc);
return;
}
}
// open properties for the current running file (isn't in the game list)
if (m_current_game_crc != 0)
SettingsDialog::openGamePropertiesDialog(nullptr, m_current_game_serial.toStdString(), m_current_game_crc);
if (m_current_disc_crc == 0)
{
QMessageBox::critical(this, tr("Game Properties"), tr("Game properties is unavailable for the current game."));
return;
}
// can't use serial for ELFs, because they might have a disc set
if (m_current_elf_override.isEmpty())
SettingsDialog::openGamePropertiesDialog(nullptr, m_current_disc_serial.toStdString(), m_current_disc_crc);
else
SettingsDialog::openGamePropertiesDialog(nullptr, std::string_view(), m_current_disc_crc);
}
void MainWindow::onGitHubRepositoryActionTriggered()
@ -1602,13 +1608,15 @@ void MainWindow::onVMStopped()
m_game_list_widget->refresh(false);
}
void MainWindow::onGameChanged(const QString& path, const QString& elf_override, const QString& serial, const QString& name, quint32 crc)
void MainWindow::onGameChanged(const QString& title, const QString& elf_override, const QString& disc_path,
const QString& serial, quint32 disc_crc, quint32 crc)
{
m_current_disc_path = path;
m_current_title = title;
m_current_elf_override = elf_override;
m_current_game_serial = serial;
m_current_game_name = name;
m_current_game_crc = crc;
m_current_disc_path = disc_path;
m_current_disc_serial = serial;
m_current_disc_crc = disc_crc;
m_current_running_crc = crc;
updateWindowTitle();
updateSaveStateMenusEnableState(!serial.isEmpty());
}

View File

@ -179,7 +179,8 @@ private Q_SLOTS:
void onVMResumed();
void onVMStopped();
void onGameChanged(const QString& path, const QString& elf_override, const QString& serial, const QString& name, quint32 crc);
void onGameChanged(const QString& title, const QString& elf_override, const QString& disc_path,
const QString& serial, quint32 disc_crc, quint32 crc);
protected:
void showEvent(QShowEvent* event) override;
@ -279,11 +280,12 @@ private:
QMenu* m_settings_toolbar_menu = nullptr;
QString m_current_disc_path;
QString m_current_title;
QString m_current_elf_override;
QString m_current_game_serial;
QString m_current_game_name;
quint32 m_current_game_crc;
QString m_current_disc_path;
QString m_current_disc_serial;
quint32 m_current_disc_crc;
quint32 m_current_running_crc;
bool m_display_created = false;
bool m_relative_mouse_mode = false;

View File

@ -667,14 +667,7 @@ void EmuThread::reloadPatches()
return;
}
if (!VMManager::HasValidVM())
return;
Patch::ReloadPatches(true, false, true, true);
// Might change widescreen mode.
if (Patch::ReloadPatchAffectingOptions())
applySettings();
VMManager::ReloadPatches(true, false, true, true);
}
void EmuThread::reloadInputSources()
@ -968,11 +961,11 @@ void Host::OnVMResumed()
emit g_emu_thread->onVMResumed();
}
void Host::OnGameChanged(const std::string& disc_path, const std::string& elf_override, const std::string& game_serial,
const std::string& game_name, u32 game_crc)
void Host::OnGameChanged(const std::string& title, const std::string& elf_override, const std::string& disc_path,
const std::string& disc_serial, u32 disc_crc, u32 current_crc)
{
emit g_emu_thread->onGameChanged(QString::fromStdString(disc_path), QString::fromStdString(elf_override),
QString::fromStdString(game_serial), QString::fromStdString(game_name), game_crc);
emit g_emu_thread->onGameChanged(QString::fromStdString(title), QString::fromStdString(elf_override),
QString::fromStdString(disc_path), QString::fromStdString(disc_serial), disc_crc, current_crc);
}
void EmuThread::updatePerformanceMetrics(bool force)
@ -1124,7 +1117,7 @@ void Host::VSyncOnCPUThread()
void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false */)
{
if (g_emu_thread->isOnEmuThread())
if (block && g_emu_thread->isOnEmuThread())
{
// probably shouldn't ever happen, but just in case..
function();

View File

@ -137,7 +137,8 @@ Q_SIGNALS:
void onVMStopped();
/// Provided by the host; called when the running executable changes.
void onGameChanged(const QString& path, const QString& elf_override, const QString& serial, const QString& name, quint32 crc);
void onGameChanged(const QString& title, const QString& elf_override, const QString& disc_path,
const QString& serial, quint32 disc_crc, quint32 crc);
void onInputDevicesEnumerated(const QList<QPair<QString, QString>>& devices);
void onInputDeviceConnected(const QString& identifier, const QString& device_name);

View File

@ -30,23 +30,29 @@
BIOSSettingsWidget::BIOSSettingsWidget(SettingsDialog* dialog, QWidget* parent)
: QWidget(parent)
, m_dialog(dialog)
{
SettingsInterface* sif = dialog->getSettingsInterface();
m_ui.setupUi(this);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastBoot, "EmuCore", "EnableFastBoot", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastBootFastForward, "EmuCore", "EnableFastBootFastForward", false);
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.searchDirectory, m_ui.browseSearchDirectory, m_ui.openSearchDirectory,
m_ui.resetSearchDirectory, "Folders", "Bios", Path::Combine(EmuFolders::DataRoot, "bios"));
dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Checked"),
tr("Patches the BIOS to skip the console's boot animation."));
dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Forward Boot"), tr("Unchecked"),
tr("Removes emulation speed throttle until the game starts to reduce startup time."));
refreshList();
connect(m_ui.searchDirectory, &QLineEdit::textChanged, this, &BIOSSettingsWidget::refreshList);
connect(m_ui.refresh, &QPushButton::clicked, this, &BIOSSettingsWidget::refreshList);
connect(m_ui.fileList, &QTreeWidget::currentItemChanged, this, &BIOSSettingsWidget::listItemChanged);
connect(m_ui.fastBoot, &QCheckBox::stateChanged, this, &BIOSSettingsWidget::fastBootChanged);
}
BIOSSettingsWidget::~BIOSSettingsWidget()
@ -139,6 +145,12 @@ void BIOSSettingsWidget::listItemChanged(const QTreeWidgetItem* current, const Q
g_emu_thread->applySettings();
}
void BIOSSettingsWidget::fastBootChanged()
{
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore", "EnableFastBoot", true);
m_ui.fastBootFastForward->setEnabled(enabled);
}
BIOSSettingsWidget::RefreshThread::RefreshThread(BIOSSettingsWidget* parent, const QString& directory)
: QThread(parent)
, m_parent(parent)

View File

@ -52,8 +52,11 @@ private Q_SLOTS:
void listItemChanged(const QTreeWidgetItem* current, const QTreeWidgetItem* previous);
void listRefreshed(const QVector<BIOSInfo>& items);
void fastBootChanged();
private:
Ui::BIOSSettingsWidget m_ui;
SettingsDialog* m_dialog;
class RefreshThread final : public QThread
{

View File

@ -136,11 +136,22 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="fastBoot">
<property name="text">
<string>Fast Boot</string>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="fastBoot">
<property name="text">
<string>Fast Boot</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="fastBootFastForward">
<property name="text">
<string>Fast Forward Boot</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>

View File

@ -92,8 +92,7 @@ namespace Achievements
static unsigned PeekMemoryBlock(unsigned address, unsigned char* buffer, unsigned num_bytes);
static void PokeMemory(unsigned address, unsigned num_bytes, void* ud, unsigned value);
static bool IsMastered();
static void ActivateLockedAchievements();
static bool ActivateAchievement(Achievement* achievement);
static void ActivateAchievementsAndLeaderboards();
static void DeactivateAchievement(Achievement* achievement);
static void SendPing();
static void SendPlaying();
@ -150,7 +149,8 @@ namespace Achievements
static std::string s_username;
static std::string s_api_token;
static u32 s_last_game_crc;
static u32 s_last_disc_crc;
static u32 s_current_crc;
static std::string s_game_path;
static std::string s_game_hash;
static std::string s_game_title;
@ -379,7 +379,8 @@ void Achievements::ClearGameInfo(bool clear_achievements, bool clear_leaderboard
while (!s_leaderboards.empty())
{
Leaderboard& lb = s_leaderboards.back();
rc_runtime_deactivate_lboard(&s_rcheevos_runtime, lb.id);
if (lb.active)
rc_runtime_deactivate_lboard(&s_rcheevos_runtime, lb.id);
s_leaderboards.pop_back();
}
@ -406,7 +407,7 @@ void Achievements::ClearGameInfo(bool clear_achievements, bool clear_leaderboard
void Achievements::ClearGameHash()
{
s_last_game_crc = 0;
s_last_disc_crc = 0;
std::string().swap(s_game_hash);
}
@ -515,7 +516,7 @@ void Achievements::Initialize()
s_logged_in = (!s_username.empty() && !s_api_token.empty());
if (VMManager::HasValidVM())
GameChanged(VMManager::GetGameCRC());
GameChanged(VMManager::GetDiscCRC(), VMManager::GetCurrentCRC());
}
void Achievements::UpdateSettings(const Pcsx2Config::AchievementsOptions& old_config)
@ -645,7 +646,13 @@ void Achievements::SetChallengeMode(bool enabled)
achievement.locked = true;
}
for (Leaderboard& leaderboard : s_leaderboards)
rc_runtime_deactivate_lboard(&s_rcheevos_runtime, leaderboard.id);
{
if (leaderboard.active)
{
rc_runtime_deactivate_lboard(&s_rcheevos_runtime, leaderboard.id);
leaderboard.active = false;
}
}
}
// re-grab unlocks, this will reactivate what's locked in non-hardcore mode later on
@ -767,8 +774,8 @@ void Achievements::LoadState(const u8* state_data, u32 state_data_size)
return;
// this assumes that the CRC and ELF name has been loaded prior to the cheevos state (it should be).
if (ElfCRC != s_last_game_crc)
GameChanged(ElfCRC);
if (VMManager::GetDiscCRC() != s_last_disc_crc)
GameChanged(VMManager::GetDiscCRC(), VMManager::GetCurrentCRC());
#ifdef ENABLE_RAINTEGRATION
if (IsUsingRAIntegration())
@ -1118,7 +1125,7 @@ void Achievements::GetUserUnlocksCallback(s32 status_code, const std::string& co
}
// start scanning for locked achievements
ActivateLockedAchievements();
ActivateAchievementsAndLeaderboards();
DisplayAchievementSummary();
SendPlaying();
UpdateRichPresence();
@ -1227,16 +1234,10 @@ void Achievements::GetPatchesCallback(s32 status_code, const std::string& conten
lboard.id = defn.id;
lboard.title = defn.title;
lboard.description = defn.description;
lboard.memaddr = defn.definition;
lboard.format = defn.format;
lboard.active = false;
s_leaderboards.push_back(std::move(lboard));
// Always track the leaderboard, if we don't have leaderboards enabled we just won't submit it.
// That way if someone activates them later on, current progress will count.
const int err = rc_runtime_activate_lboard(&s_rcheevos_runtime, defn.id, defn.definition, nullptr, 0);
if (err != RC_OK)
Console.Error("Leaderboard %u memaddr parse error: %s", defn.id, rc_error_str(err));
else
DevCon.WriteLn("Activated leaderboard %s (%u)", defn.title, defn.id);
}
// Parse rich presence.
@ -1265,7 +1266,7 @@ void Achievements::GetPatchesCallback(s32 status_code, const std::string& conten
}
else
{
ActivateLockedAchievements();
ActivateAchievementsAndLeaderboards();
DisplayAchievementSummary();
Host::OnAchievementsRefreshed();
}
@ -1399,7 +1400,7 @@ std::optional<std::vector<u8>> Achievements::ReadELFFromCurrentDisc(const std::s
std::string Achievements::GetGameHash()
{
const std::string& elf_path = LastELF;
const std::string elf_path = VMManager::GetDiscELF();
if (elf_path.empty())
return {};
@ -1457,15 +1458,21 @@ void Achievements::GetGameIdCallback(s32 status_code, const std::string& content
GetPatches(game_id);
}
void Achievements::GameChanged(u32 crc)
void Achievements::GameChanged(u32 disc_crc, u32 crc)
{
std::unique_lock lock(s_achievements_mutex);
if (!s_active)
return;
// avoid reading+hashing the executable if the crc hasn't changed
if (s_last_game_crc == crc)
if (s_last_disc_crc == disc_crc)
{
// but we might've just finished booting the game, in which case we need to activate.
if (crc != 0)
ActivateAchievementsAndLeaderboards();
return;
}
std::string game_hash(GetGameHash());
if (s_game_hash == game_hash)
@ -1481,7 +1488,8 @@ void Achievements::GameChanged(u32 crc)
ClearGameInfo();
ClearGameHash();
s_last_game_crc = crc;
s_last_disc_crc = disc_crc;
s_current_crc = crc;
s_game_hash = std::move(game_hash);
#ifdef ENABLE_RAINTEGRATION
@ -1495,13 +1503,14 @@ void Achievements::GameChanged(u32 crc)
if (s_game_hash.empty())
{
// when we're booting the bios, or shutting down, this will fail
if (crc != 0)
if (disc_crc != 0)
{
Host::AddKeyedOSDMessage("retroachievements_disc_read_failed", "Failed to read executable from disc. Achievements disabled.",
Host::OSD_CRITICAL_ERROR_DURATION);
}
s_last_game_crc = 0;
s_last_disc_crc = 0;
s_current_crc = crc;
return;
}
@ -1733,31 +1742,48 @@ bool Achievements::IsMastered()
return true;
}
void Achievements::ActivateLockedAchievements()
void Achievements::ActivateAchievementsAndLeaderboards()
{
if (!VMManager::Internal::HasBootedELF())
{
Console.Warning("Deferring achievement activate until ELF has booted.");
return;
}
for (Achievement& cheevo : s_achievements)
{
if (cheevo.locked)
ActivateAchievement(&cheevo);
if (cheevo.active || !cheevo.locked)
continue;
const int err =
rc_runtime_activate_achievement(&s_rcheevos_runtime, cheevo.id, cheevo.memaddr.c_str(), nullptr, 0);
if (err != RC_OK)
{
Console.Error("Achievement %u memaddr parse error: %s", cheevo.id, rc_error_str(err));
continue;
}
DevCon.WriteLn("Activated achievement %s (%u)", cheevo.title.c_str(), cheevo.id);
cheevo.active = true;
}
}
bool Achievements::ActivateAchievement(Achievement* achievement)
{
if (achievement->active)
return true;
const int err = rc_runtime_activate_achievement(&s_rcheevos_runtime, achievement->id, achievement->memaddr.c_str(), nullptr, 0);
if (err != RC_OK)
for (Leaderboard& lb : s_leaderboards)
{
Console.Error("Achievement %u memaddr parse error: %s", achievement->id, rc_error_str(err));
return false;
// Always track the leaderboard, if we don't have leaderboards enabled we just won't submit it.
// That way if someone activates them later on, current progress will count.
if (lb.active)
continue;
const int err = rc_runtime_activate_lboard(&s_rcheevos_runtime, lb.id, lb.memaddr.c_str(), nullptr, 0);
if (err != RC_OK)
{
Console.Error("Leaderboard %u memaddr parse error: %s", lb.id, rc_error_str(err));
continue;
}
DevCon.WriteLn("Activated leaderboard %s (%u)", lb.title.c_str(), lb.id);
lb.active = true;
}
achievement->active = true;
DevCon.WriteLn("Activated achievement %s (%u)", achievement->title.c_str(), achievement->id);
return true;
}
void Achievements::DeactivateAchievement(Achievement* achievement)
@ -2249,7 +2275,7 @@ void Achievements::RAIntegration::RACallbackRebuildMenu()
void Achievements::RAIntegration::RACallbackEstimateTitle(char* buf)
{
std::string title(fmt::format("{0} ({1}) [{2:08X}]", VMManager::GetGameName(), VMManager::GetGameSerial(), VMManager::GetGameCRC()));
std::string title(fmt::format("{0} ({1}) [{2:08X}]", VMManager::GetTitle(), VMManager::GetDiscSerial(), VMManager::GetDiscCRC()));
StringUtil::Strlcpy(buf, title, 256);
}

View File

@ -62,7 +62,9 @@ namespace Achievements
u32 id;
std::string title;
std::string description;
std::string memaddr;
int format;
bool active;
};
struct LeaderboardEntry
@ -131,7 +133,7 @@ namespace Achievements
bool Login(const char* username, const char* password);
void Logout();
void GameChanged(u32 crc);
void GameChanged(u32 disc_crc, u32 crc);
const std::string& GetGameTitle();
const std::string& GetGameIcon();

View File

@ -40,12 +40,6 @@
#include "Recording/InputRecording.h"
#include "Host.h"
// This typically reflects the Sony-assigned serial code for the Disc, if one exists.
// (examples: SLUS-2113, etc).
// If the disc is homebrew then it probably won't have a valid serial; in which case
// this string will be empty.
std::string DiscSerial;
cdvdStruct cdvd;
s64 PSXCLK = 36864000;
@ -389,13 +383,13 @@ s32 cdvdWriteConfig(const u8* config)
}
// Sets ElfCRC to the CRC of the game bound to the CDVD source.
static __fi ElfObject* loadElf(std::string filename, bool isPSXElf)
std::unique_ptr<ElfObject> cdvdLoadElf(std::string filename, bool isPSXElf)
{
if (StringUtil::StartsWith(filename, "host:"))
{
std::string host_filename(filename.substr(5));
s64 host_size = FileSystem::GetPathFileSize(host_filename.c_str());
return new ElfObject(std::move(host_filename), static_cast<u32>(std::max<s64>(host_size, 0)), isPSXElf);
return std::make_unique<ElfObject>(std::move(host_filename), static_cast<u32>(std::max<s64>(host_size, 0)), isPSXElf);
}
// Mimic PS2 behavior!
@ -420,31 +414,13 @@ static __fi ElfObject* loadElf(std::string filename, bool isPSXElf)
filename += ";1";
}
// Fix cdrom:path, the iso reader doesn't like it.
if (StringUtil::StartsWith(filename, "cdrom:") && filename[6] != '\\' && filename[6] != '/')
filename.insert(6, 1, '\\');
IsoFSCDVD isofs;
IsoFile file(isofs, filename);
return new ElfObject(std::move(filename), file, isPSXElf);
}
static __fi void _reloadElfInfo(std::string elfpath)
{
// Now's a good time to reload the ELF info...
if (elfpath == LastELF)
return;
std::unique_ptr<ElfObject> elfptr(loadElf(elfpath, false));
elfptr->loadHeaders();
ElfCRC = elfptr->getCRC();
ElfEntry = elfptr->header.e_entry;
ElfTextRange = elfptr->getTextRange();
LastELF = std::move(elfpath);
Console.WriteLn(Color_StrongBlue, "ELF (%s) Game CRC = 0x%08X, EntryPoint = 0x%08X", LastELF.c_str(), ElfCRC, ElfEntry);
// Note: Do not load game database info here. This code is generic and called from
// BIOS key encryption as well as eeloadReplaceOSDSYS. The first is actually still executing
// BIOS code, and patches and cheats should not be applied yet. (they are applied when
// eeGameStarting is invoked, which is when the VM starts executing the actual game ELF
// binary).
return std::make_unique<ElfObject>(std::move(filename), file, isPSXElf);
}
u32 cdvdGetElfCRC(const std::string& path)
@ -466,6 +442,84 @@ u32 cdvdGetElfCRC(const std::string& path)
}
}
// return value:
// 0 - Invalid or unknown disc.
// 1 - PS1 CD
// 2 - PS2 CD
static CDVDDiscType GetPS2ElfName(std::string* name, std::string* version)
{
CDVDDiscType retype = CDVDDiscType::Other;
name->clear();
version->clear();
try {
IsoFSCDVD isofs;
IsoFile file( isofs, "SYSTEM.CNF;1");
int size = file.getLength();
if( size == 0 ) return CDVDDiscType::Other;
while( !file.eof() )
{
const std::string line(file.readLine());
std::string_view key, value;
if (!StringUtil::ParseAssignmentString(line, &key, &value))
continue;
if( value.empty() && file.getLength() != file.getSeekPos() )
{ // Some games have a character on the last line of the file, don't print the error in those cases.
Console.Warning( "(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:" );
Console.Indent().WriteLn(line);
continue;
}
if( key == "BOOT2" )
{
Console.WriteLn( Color_StrongBlue, "(SYSTEM.CNF) Detected PS2 Disc = %.*s",
static_cast<int>(value.size()), value.data());
*name = value;
retype = CDVDDiscType::PS2Disc;
}
else if( key == "BOOT" )
{
Console.WriteLn( Color_StrongBlue, "(SYSTEM.CNF) Detected PSX/PSone Disc = %.*s",
static_cast<int>(value.size()), value.data());
*name = value;
retype = CDVDDiscType::PS1Disc;
}
else if( key == "VMODE" )
{
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Disc region type = %.*s",
static_cast<int>(value.size()), value.data());
}
else if( key == "VER" )
{
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Software version = %.*s",
static_cast<int>(value.size()), value.data());
*version = value;
}
}
if( retype == CDVDDiscType::Other )
{
Console.Error("(GetElfName) Disc image is *not* a PlayStation or PS2 game!");
return CDVDDiscType::Other;
}
}
catch( Exception::FileNotFound& )
{
//Console.Warning(ex.FormatDiagnosticMessage());
return CDVDDiscType::Other; // no SYSTEM.CNF, not a PS1/PS2 disc.
}
catch (Exception::BadStream& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
return CDVDDiscType::Other; // ISO error
}
return retype;
}
static std::string ExecutablePathToSerial(const std::string& path)
{
// cdrom:\SCES_123.45;1
@ -478,7 +532,7 @@ static std::string ExecutablePathToSerial(const std::string& path)
else
{
// cdrom:SCES_123.45;1
pos = serial.rfind(':');
pos = path.rfind(':');
if (pos != std::string::npos)
serial = path.substr(pos + 1);
else
@ -492,8 +546,11 @@ static std::string ExecutablePathToSerial(const std::string& path)
// check that it matches our expected format.
// this maintains the old behavior of PCSX2.
if (!StringUtil::WildcardMatch(serial.c_str(), "????_???.??*"))
if (!StringUtil::WildcardMatch(serial.c_str(), "????_???.??*") &&
!StringUtil::WildcardMatch(serial.c_str(), "????""-???.??*")) // double quote because trigraphs
{
serial.clear();
}
// SCES_123.45 -> SCES-12345
for (std::string::size_type pos = 0; pos < serial.size();)
@ -515,60 +572,62 @@ static std::string ExecutablePathToSerial(const std::string& path)
return serial;
}
void cdvdReloadElfInfo(std::string elfoverride)
void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
CDVDDiscType* out_disc_type)
{
// called from context of executing VM code (recompilers), so we need to trap exceptions
// and route them through the VM's exception handler. (needed for non-SEH platforms, such
// as Linux/GCC)
DevCon.WriteLn(Color_Green, "Reload ELF");
try
{
std::string elfpath;
u32 discType = GetPS2ElfName(elfpath);
DiscSerial = ExecutablePathToSerial(elfpath);
std::string elfpath, version;
const CDVDDiscType disc_type = GetPS2ElfName(&elfpath, &version);
// Use the serial from the disc (if any), and the ELF CRC of the override.
if (!elfoverride.empty())
// Don't bother parsing it if we don't need the CRC.
if (out_crc)
{
u32 crc = 0;
if (disc_type == CDVDDiscType::PS2Disc || disc_type == CDVDDiscType::PS1Disc)
{
_reloadElfInfo(std::move(elfoverride));
return;
try
{
const bool isPSXElf = (disc_type == CDVDDiscType::PS1Disc);
std::unique_ptr<ElfObject> elfptr(cdvdLoadElf(elfpath, isPSXElf));
elfptr->loadHeaders();
crc = elfptr->getCRC();
}
catch ([[maybe_unused]] Exception::FileNotFound& e)
{
Console.Error(fmt::format("Failed to load ELF info for {}", elfpath));
}
catch (Exception::BadStream& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
}
}
if (discType == 1)
{
// PCSX2 currently only recognizes *.elf executables in proper PS2 format.
// To support different PSX titles in the console title and for savestates, this code bypasses all the detection,
// simply using the exe name, stripped of problematic characters.
return;
}
// Isn't a disc we recognize?
if (discType == 0)
return;
// Recognized and PS2 (BOOT2). Good job, user.
_reloadElfInfo(std::move(elfpath));
*out_crc = crc;
}
catch ([[maybe_unused]] Exception::FileNotFound& e)
if (out_serial)
{
Console.Error("Failed to load ELF info");
LastELF.clear();
DiscSerial.clear();
ElfCRC = 0;
ElfEntry = 0;
ElfTextRange = {};
return;
if (disc_type != CDVDDiscType::Other)
*out_serial = ExecutablePathToSerial(elfpath);
else
out_serial->clear();
}
if (out_elf_path)
*out_elf_path = std::move(elfpath);
if (out_version)
*out_version = std::move(version);
if (out_disc_type)
*out_disc_type = disc_type;
}
void cdvdReadKey(u8, u16, u32 arg2, u8* key)
{
const std::string DiscSerial = VMManager::GetDiscSerial();
s32 numbers = 0, letters = 0;
u32 key_0_3;
u8 key_4, key_14;
cdvdReloadElfInfo();
// clear key values
memset(key, 0, 16);
@ -697,7 +756,7 @@ s32 cdvdCtrlTrayClose()
DevCon.WriteLn(Color_Green, "Close virtual disk tray");
if (!g_GameStarted && g_SkipBiosHack)
if (VMManager::Internal::IsFastBootInProgress())
{
DevCon.WriteLn(Color_Green, "Media already loaded (fast boot)");
cdvdUpdateReady(CDVD_DRIVE_READY);
@ -901,10 +960,6 @@ void cdvdReset()
cdvd.RTC.year = (u8)(curtime.tm_year - 100); // offset from 2000
}
g_GameStarted = false;
g_GameLoading = false;
g_SkipBiosHack = EmuConfig.UseBOOT2Injection;
cdvdCtrlTrayClose();
}
@ -930,7 +985,7 @@ void cdvdNewDiskCB()
cdvdDetectDisk();
// If not ejected but we've swapped source pretend it got ejected
if ((g_GameStarted || !g_SkipBiosHack) && cdvd.Tray.trayState != CDVD_DISC_EJECT)
if (!VMManager::Internal::IsFastBootInProgress() && cdvd.Tray.trayState != CDVD_DISC_EJECT)
{
DevCon.WriteLn(Color_Green, "Ejecting media");
cdvdUpdateStatus(CDVD_STATUS_TRAY_OPEN);
@ -1448,12 +1503,6 @@ void cdvdUpdateTrayState()
cdvd.Tray.trayState = CDVD_DISC_SEEKING;
cdvdUpdateStatus(CDVD_STATUS_SEEK);
cdvd.Tray.cdvdActionSeconds = 2;
// If we're swapping disc, reload the elf, patches etc to reflect the new disc.
if (g_GameStarted)
{
cdvdReloadElfInfo();
VMManager::Internal::SwappingGameOnCPUThread();
}
break;
case CDVD_DISC_SEEKING:
cdvd.Spinning = true;
@ -2568,22 +2617,25 @@ static void cdvdWrite16(u8 rt) // SCOMMAND
// break;
case 0x27: // GetPS1BootParam (0:13) - called only by China region PS2 models
{
// Return Disc Serial which is passed to PS1DRV and later used to find matching config.
SetSCMDResultSize(13);
// Return Disc Serial which is passed to PS1DRV and later used to find matching config.
SetSCMDResultSize(13);
cdvd.SCMDResult[0] = 0;
cdvd.SCMDResult[1] = DiscSerial[0];
cdvd.SCMDResult[2] = DiscSerial[1];
cdvd.SCMDResult[3] = DiscSerial[2];
cdvd.SCMDResult[4] = DiscSerial[3];
cdvd.SCMDResult[5] = DiscSerial[4];
cdvd.SCMDResult[6] = DiscSerial[5];
cdvd.SCMDResult[7] = DiscSerial[6];
cdvd.SCMDResult[8] = DiscSerial[7];
cdvd.SCMDResult[9] = DiscSerial[9]; // Skipping dot here is required.
cdvd.SCMDResult[10] = DiscSerial[10];
cdvd.SCMDResult[11] = DiscSerial[11];
cdvd.SCMDResult[12] = DiscSerial[12];
const std::string DiscSerial = VMManager::GetDiscSerial();
cdvd.SCMDResult[0] = 0;
cdvd.SCMDResult[1] = DiscSerial[0];
cdvd.SCMDResult[2] = DiscSerial[1];
cdvd.SCMDResult[3] = DiscSerial[2];
cdvd.SCMDResult[4] = DiscSerial[3];
cdvd.SCMDResult[5] = DiscSerial[4];
cdvd.SCMDResult[6] = DiscSerial[5];
cdvd.SCMDResult[7] = DiscSerial[6];
cdvd.SCMDResult[8] = DiscSerial[7];
cdvd.SCMDResult[9] = DiscSerial[9]; // Skipping dot here is required.
cdvd.SCMDResult[10] = DiscSerial[10];
cdvd.SCMDResult[11] = DiscSerial[11];
cdvd.SCMDResult[12] = DiscSerial[12];
}
break;
// case 0x28: // cdvdman_call150 (1:1) - In V10 Bios

View File

@ -17,9 +17,12 @@
#include "CDVDcommon.h"
#include <memory>
#include <string>
#include <string_view>
class ElfObject;
#define btoi(b) ((b) / 16 * 10 + (b) % 16) /* BCD to u_char */
#define itob(i) ((i) / 10 * 16 + (i) % 10) /* u_char to BCD */
@ -76,6 +79,13 @@ struct cdvdRTC
u8 year;
};
enum class CDVDDiscType : u8
{
Other,
PS1Disc,
PS2Disc
};
enum TrayStates
{
CDVD_DISC_ENGAGED,
@ -176,9 +186,11 @@ extern void cdvdNewDiskCB();
extern u8 cdvdRead(u8 key);
extern void cdvdWrite(u8 key, u8 rt);
extern void cdvdReloadElfInfo(std::string elfoverride = std::string());
extern void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
CDVDDiscType* out_disc_type);
extern u32 cdvdGetElfCRC(const std::string& path);
extern std::unique_ptr<ElfObject> cdvdLoadElf(std::string filename, bool isPSXElf);
extern s32 cdvdCtrlTrayOpen();
extern s32 cdvdCtrlTrayClose();
extern std::string DiscSerial;

View File

@ -346,6 +346,12 @@ CDVD_SourceType CDVDsys_GetSourceType()
return m_CurrentSourceType;
}
void CDVDsys_ClearFiles()
{
for (u32 i = 0; i < std::size(m_SourceFilename); i++)
m_SourceFilename[i] = {};
}
void CDVDsys_ChangeSource(CDVD_SourceType type)
{
if (CDVD != NULL)
@ -375,14 +381,6 @@ bool DoCDVDopen()
CDVD->newDiskCB(cdvdNewDiskCB);
// Win32 Fail: the old CDVD api expects MBCS on Win32 platforms, but generating a MBCS
// from unicode is problematic since we need to know the codepage of the text being
// converted (which isn't really practical knowledge). A 'best guess' would be the
// default codepage of the user's Windows install, but even that will fail and return
// question marks if the filename is another language.
//TODO_CDVD check if ISO and Disc use UTF8
auto CurrentSourceType = enum_cast(m_CurrentSourceType);
int ret = CDVD->open(!m_SourceFilename[CurrentSourceType].empty() ? m_SourceFilename[CurrentSourceType].c_str() : nullptr);
if (ret == -1)
@ -396,19 +394,14 @@ bool DoCDVDopen()
return true;
}
std::string somepick(Path::StripExtension(FileSystem::GetDisplayNameFromPath(m_SourceFilename[CurrentSourceType])));
//FWIW Disc serial availability doesn't seem reliable enough, sometimes it's there and sometime it's just null
//Shouldn't the serial be available all time? Potentially need to look into Elfreloadinfo() reliability
//TODO: Add extra fallback case for CRC.
if (somepick.empty() && !DiscSerial.empty())
somepick = StringUtil::StdStringFromFormat("Untitled-%s", DiscSerial.c_str());
else if (somepick.empty())
somepick = "Untitled";
std::string dump_name(Path::StripExtension(FileSystem::GetDisplayNameFromPath(m_SourceFilename[CurrentSourceType])));
if (dump_name.empty())
dump_name = "Untitled";
if (EmuConfig.CurrentBlockdump.empty())
EmuConfig.CurrentBlockdump = FileSystem::GetWorkingDirectory();
std::string temp(Path::Combine(EmuConfig.CurrentBlockdump, somepick));
std::string temp(Path::Combine(EmuConfig.CurrentBlockdump, dump_name));
#ifdef ENABLE_TIMESTAMPS
std::time_t curtime_t = std::time(nullptr);

View File

@ -158,6 +158,7 @@ extern void CDVDsys_ChangeSource(CDVD_SourceType type);
extern void CDVDsys_SetFile(CDVD_SourceType srctype, std::string newfile);
extern const std::string& CDVDsys_GetFile(CDVD_SourceType srctype);
extern CDVD_SourceType CDVDsys_GetSourceType();
extern void CDVDsys_ClearFiles();
extern bool DoCDVDopen();
extern void DoCDVDclose();

View File

@ -1244,14 +1244,15 @@ struct Pcsx2Config
EnablePINE : 1, // enables inter-process communication
EnableWideScreenPatches : 1,
EnableNoInterlacingPatches : 1,
EnableFastBoot : 1,
EnableFastBootFastForward : 1,
EnablePerGameSettings : 1,
// TODO - Vaser - where are these settings exposed in the Qt UI?
EnableRecordingTools : 1,
EnableGameFixes : 1, // enables automatic game fixes
SaveStateOnShutdown : 1, // default value for saving state on shutdown
EnableDiscordPresence : 1, // enables discord rich presence integration
InhibitScreensaver : 1,
// when enabled uses BOOT2 injection, skipping sony bios splashes
UseBOOT2Injection : 1,
BackupSavestate : 1,
SavestateZstdCompression : 1,
// enables simulated ejection of memory cards when loading savestates

View File

@ -22,40 +22,54 @@
#include "Elfheader.h"
#include "DebugTools/SymbolMap.h"
u32 ElfCRC;
u32 ElfEntry;
std::pair<u32,u32> ElfTextRange;
std::string LastELF;
bool isPSXElf;
std::string ElfVersion;
#pragma pack(push, 1)
struct PSXEXEHeader
{
char id[8]; // 0x000-0x007 PS-X EXE
char pad1[8]; // 0x008-0x00F
u32 initial_pc; // 0x010
u32 initial_gp; // 0x014
u32 load_address; // 0x018
u32 file_size; // 0x01C excluding 0x800-byte header
u32 unk0; // 0x020
u32 unk1; // 0x024
u32 memfill_start; // 0x028
u32 memfill_size; // 0x02C
u32 initial_sp_base; // 0x030
u32 initial_sp_offset; // 0x034
u32 reserved[5]; // 0x038-0x04B
char marker[0x7B4]; // 0x04C-0x7FF
};
static_assert(sizeof(PSXEXEHeader) == 0x800);
#pragma pack(pop)
// All of ElfObjects functions.
ElfObject::ElfObject(std::string srcfile, IsoFile& isofile, bool isPSXElf)
ElfObject::ElfObject(std::string srcfile, IsoFile& isofile, bool isPSXElf_)
: data(isofile.getLength(), "ELF headers")
, filename(std::move(srcfile))
, header(*(ELF_HEADER*)data.GetPtr())
, filename(std::move(srcfile))
, isPSXElf(isPSXElf_)
{
checkElfSize(data.GetSizeInBytes());
readIso(isofile);
initElfHeaders(isPSXElf);
initElfHeaders();
}
ElfObject::ElfObject(std::string srcfile, u32 hdrsize, bool isPSXElf)
ElfObject::ElfObject(std::string srcfile, u32 hdrsize, bool isPSXElf_)
: data(hdrsize, "ELF headers")
, filename(std::move(srcfile))
, header(*(ELF_HEADER*)data.GetPtr())
, filename(std::move(srcfile))
, isPSXElf(isPSXElf_)
{
checkElfSize(data.GetSizeInBytes());
readFile();
initElfHeaders(isPSXElf);
initElfHeaders();
}
void ElfObject::initElfHeaders(bool isPSXElf)
void ElfObject::initElfHeaders()
{
if (isPSXElf)
{
return;
}
DevCon.WriteLn("Initializing Elf: %d bytes", data.GetSizeInBytes());
@ -133,19 +147,57 @@ void ElfObject::initElfHeaders(bool isPSXElf)
//applyPatches();
}
bool ElfObject::hasValidPSXHeader()
{
if (data.GetSizeInBytes() < sizeof(PSXEXEHeader))
return false;
const PSXEXEHeader* header = reinterpret_cast<const PSXEXEHeader*>(data.GetPtr());
static constexpr char expected_id[] = {'P', 'S', '-', 'X', ' ', 'E', 'X', 'E'};
if (std::memcmp(header->id, expected_id, sizeof(expected_id)) != 0)
return false;
if ((header->file_size + sizeof(PSXEXEHeader)) > data.GetSizeInBytes())
{
Console.Warning("Incorrect file size in PS-EXE header: %u bytes should not be greater than %u bytes",
header->file_size, static_cast<unsigned>(data.GetSizeInBytes() - sizeof(PSXEXEHeader)));
}
return true;
}
bool ElfObject::hasProgramHeaders() { return (proghead != NULL); }
bool ElfObject::hasSectionHeaders() { return (secthead != NULL); }
bool ElfObject::hasHeaders() { return (hasProgramHeaders() && hasSectionHeaders()); }
u32 ElfObject::getEntryPoint()
{
if (isPSXElf)
{
if (hasValidPSXHeader())
return reinterpret_cast<const PSXEXEHeader*>(data.GetPtr())->initial_pc;
else
return 0xFFFFFFFFu;
}
else
{
return header.e_entry;
}
}
std::pair<u32,u32> ElfObject::getTextRange()
{
for (int i = 0; i < header.e_phnum; i++)
if (isPSXElf && hasProgramHeaders())
{
u32 start = proghead[i].p_vaddr;
u32 size = proghead[i].p_memsz;
for (int i = 0; i < header.e_phnum; i++)
{
const u32 start = proghead[i].p_vaddr;
const u32 size = proghead[i].p_memsz;
if (start <= header.e_entry && (start+size) > header.e_entry)
return std::make_pair(start,size);
if (start <= header.e_entry && (start + size) > header.e_entry)
return std::make_pair(start, size);
}
}
return std::make_pair(0,0);
@ -310,82 +362,9 @@ void ElfObject::loadSectionHeaders()
void ElfObject::loadHeaders()
{
if (isPSXElf)
return;
loadProgramHeaders();
loadSectionHeaders();
}
// return value:
// 0 - Invalid or unknown disc.
// 1 - PS1 CD
// 2 - PS2 CD
int GetPS2ElfName( std::string& name )
{
int retype = 0;
try {
IsoFSCDVD isofs;
IsoFile file( isofs, "SYSTEM.CNF;1");
int size = file.getLength();
if( size == 0 ) return 0;
while( !file.eof() )
{
const std::string line(file.readLine());
std::string_view key, value;
if (!StringUtil::ParseAssignmentString(line, &key, &value))
continue;
if( value.empty() && file.getLength() != file.getSeekPos() )
{ // Some games have a character on the last line of the file, don't print the error in those cases.
Console.Warning( "(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:" );
Console.Indent().WriteLn(line);
continue;
}
if( key == "BOOT2" )
{
Console.WriteLn( Color_StrongBlue, "(SYSTEM.CNF) Detected PS2 Disc = %.*s",
static_cast<int>(value.size()), value.data());
name = value;
retype = 2;
}
else if( key == "BOOT" )
{
Console.WriteLn( Color_StrongBlue, "(SYSTEM.CNF) Detected PSX/PSone Disc = %.*s",
static_cast<int>(value.size()), value.data());
name = value;
retype = 1;
}
else if( key == "VMODE" )
{
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Disc region type = %.*s",
static_cast<int>(value.size()), value.data());
}
else if( key == "VER" )
{
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Software version = %.*s",
static_cast<int>(value.size()), value.data());
ElfVersion = value;
}
}
if( retype == 0 )
{
Console.Error("(GetElfName) Disc image is *not* a PlayStation or PS2 game!");
return 0;
}
}
catch( Exception::FileNotFound& )
{
//Console.Warning(ex.FormatDiagnosticMessage());
return 0; // no SYSTEM.CNF, not a PS1/PS2 disc.
}
catch (Exception::BadStream& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
return 0; // ISO error
}
return retype;
}

View File

@ -122,24 +122,23 @@ class ElfObject
{
private:
SafeArray<u8> data;
ELF_HEADER& header;
ELF_PHR* proghead = nullptr;
ELF_SHR* secthead = nullptr;
std::string filename;
bool isPSXElf;
void initElfHeaders(bool isPSXElf);
void initElfHeaders();
bool hasValidPSXHeader();
void readIso(IsoFile& file);
void readFile();
void checkElfSize(s64 elfsize);
public:
ELF_HEADER& header;
ElfObject(std::string srcfile, IsoFile& isofile, bool isPSXElf_);
ElfObject(std::string srcfile, u32 hdrsize, bool isPSXElf_);
// Destructor!
// C++ does all the cleanup automagically for us.
virtual ~ElfObject() = default;
ElfObject(std::string srcfile, IsoFile& isofile, bool isPSXElf);
ElfObject(std::string srcfile, u32 hdrsize, bool isPSXElf);
bool IsPSXElf() const { return isPSXElf; }
void loadProgramHeaders();
void loadSectionHeaders();
@ -150,17 +149,8 @@ class ElfObject
bool hasHeaders();
std::pair<u32,u32> getTextRange();
u32 getEntryPoint();
u32 getCRC();
};
//-------------------
extern void loadElfFile(const std::string& filename);
extern int GetPS2ElfName( std::string& dest );
extern u32 ElfCRC;
extern u32 ElfEntry;
extern std::pair<u32,u32> ElfTextRange;
extern std::string LastELF;
extern bool isPSXElf;
extern std::string ElfVersion;

View File

@ -21,6 +21,7 @@
#include "Gif_Unit.h"
#include "Counters.h"
#include "Config.h"
#include "VMManager.h"
using namespace Threading;
using namespace R5900;
@ -45,7 +46,8 @@ void gsReset()
void gsUpdateFrequency(Pcsx2Config& config)
{
if (config.GS.FrameLimitEnable)
if (config.GS.FrameLimitEnable &&
(!config.EnableFastBootFastForward || !VMManager::Internal::IsFastBootInProgress()))
{
switch (config.LimiterMode)
{

View File

@ -667,7 +667,7 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
std::string_view compression_str;
if (GSConfig.GSDumpCompression == GSDumpCompressionMethod::Uncompressed)
{
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpUncompressed(m_snapshot, VMManager::GetGameSerial(), m_crc,
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpUncompressed(m_snapshot, VMManager::GetDiscSerial(), m_crc,
screenshot_width, screenshot_height,
screenshot_pixels.empty() ? nullptr : screenshot_pixels.data(),
fd, m_regs));
@ -675,7 +675,7 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
}
else if (GSConfig.GSDumpCompression == GSDumpCompressionMethod::LZMA)
{
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpXz(m_snapshot, VMManager::GetGameSerial(), m_crc,
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpXz(m_snapshot, VMManager::GetDiscSerial(), m_crc,
screenshot_width, screenshot_height,
screenshot_pixels.empty() ? nullptr : screenshot_pixels.data(),
fd, m_regs));
@ -683,7 +683,7 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
}
else
{
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpZst(m_snapshot, VMManager::GetGameSerial(), m_crc,
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpZst(m_snapshot, VMManager::GetDiscSerial(), m_crc,
screenshot_width, screenshot_height,
screenshot_pixels.empty() ? nullptr : screenshot_pixels.data(),
fd, m_regs));
@ -780,14 +780,14 @@ static std::string GSGetBaseFilename()
std::string filename;
// append the game serial and title
if (std::string name(VMManager::GetGameName()); !name.empty())
if (std::string name(VMManager::GetTitle()); !name.empty())
{
Path::SanitizeFileName(&name);
if (name.length() > 219)
name.resize(219);
filename += name;
}
if (std::string serial(VMManager::GetGameSerial()); !serial.empty())
if (std::string serial = VMManager::GetDiscSerial(); !serial.empty())
{
Path::SanitizeFileName(&serial);
filename += '_';

View File

@ -303,7 +303,7 @@ std::string GSTextureReplacements::GetDumpFilename(const TextureName& name, u32
void GSTextureReplacements::Initialize()
{
s_current_serial = VMManager::GetGameSerial();
s_current_serial = VMManager::GetDiscSerial();
if (GSConfig.DumpReplaceableTextures || GSConfig.LoadTextureReplacements)
StartWorkerThread();
@ -313,7 +313,7 @@ void GSTextureReplacements::Initialize()
void GSTextureReplacements::GameChanged()
{
std::string new_serial(VMManager::GetGameSerial());
std::string new_serial = VMManager::GetDiscSerial();
if (s_current_serial == new_serial)
return;

View File

@ -204,9 +204,6 @@ static void GSDumpReplayerLoadInitialState()
std::memcpy(PS2MEM_GS, s_dump_file->GetRegsData().data(),
std::min(Ps2MemSize::GSregs, static_cast<u32>(s_dump_file->GetRegsData().size())));
// update serial to load hw fixes
VMManager::Internal::GameStartingOnCPUThread();
// load GS state
freezeData fd = {static_cast<int>(s_dump_file->GetStateData().size()),
const_cast<u8*>(s_dump_file->GetStateData().data())};

View File

@ -60,22 +60,17 @@ std::string GameDatabaseSchema::GameEntry::memcardFiltersAsString() const
const std::string* GameDatabaseSchema::GameEntry::findPatch(u32 crc) const
{
Console.WriteLn(fmt::format("[GameDB] Searching for patch with CRC '{:08X}'", crc));
if (crc == 0)
return nullptr;
auto it = patches.find(crc);
if (it != patches.end())
{
Console.WriteLn(fmt::format("[GameDB] Found patch with CRC '{:08X}'", crc));
return &it->second;
}
it = patches.find(0);
if (it != patches.end())
{
Console.WriteLn("[GameDB] Found and falling back to default patch");
return &it->second;
}
Console.WriteLn("[GameDB] No CRC-specific patch or default patch found");
return nullptr;
}

View File

@ -173,19 +173,10 @@ bool GameList::GetIsoSerialAndCRC(const std::string& path, s32* disc_type, std::
if (CDVD->open(path.c_str()) != 0)
return false;
// TODO: we could include the version in the game list?
*disc_type = DoCDVDdetectDiskType();
cdvdReloadElfInfo();
*serial = DiscSerial;
*crc = ElfCRC;
cdvdGetDiscInfo(serial, nullptr, nullptr, crc, nullptr);
DoCDVDclose();
// TODO(Stenzek): These globals are **awful**. Clean it up.
DiscSerial.clear();
ElfCRC = 0;
ElfEntry = -1;
LastELF.clear();
return true;
}

View File

@ -79,9 +79,9 @@ static void HotkeyCycleSaveSlot(s32 delta)
else
s_current_save_slot = (s_current_save_slot % CYCLE_SAVE_STATE_SLOTS) + 1;
const u32 crc = VMManager::GetGameCRC();
const std::string serial(VMManager::GetGameSerial());
const std::string filename(VMManager::GetSaveStateFileName(serial.c_str(), crc, s_current_save_slot));
const u32 crc = VMManager::GetDiscCRC();
const std::string serial = VMManager::GetDiscSerial();
const std::string filename = VMManager::GetSaveStateFileName(serial.c_str(), crc, s_current_save_slot);
FILESYSTEM_STAT_DATA sd;
if (!filename.empty() && FileSystem::StatFile(filename.c_str(), &sd))
{
@ -109,34 +109,21 @@ static void HotkeyCycleSaveSlot(s32 delta)
static void HotkeyLoadStateSlot(s32 slot)
{
const u32 crc = VMManager::GetGameCRC();
if (crc == 0)
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE, "Cannot load state from a slot without a game running.",
Host::OSD_INFO_DURATION);
return;
}
// Can reapply settings and thus binds, therefore must be deferred.
Host::RunOnCPUThread([slot]() {
if (!VMManager::HasSaveStateInSlot(VMManager::GetDiscSerial().c_str(), VMManager::GetDiscCRC(), slot))
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE, fmt::format("No save state found in slot {}.", slot),
Host::OSD_INFO_DURATION);
return;
}
const std::string serial(VMManager::GetGameSerial());
if (!VMManager::HasSaveStateInSlot(serial.c_str(), crc, slot))
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE, fmt::format("No save state found in slot {}.", slot),
Host::OSD_INFO_DURATION);
return;
}
VMManager::LoadStateFromSlot(slot);
VMManager::LoadStateFromSlot(slot);
});
}
static void HotkeySaveStateSlot(s32 slot)
{
if (VMManager::GetGameCRC() == 0)
{
Host::AddIconOSDMessage("SaveStateToSlot", ICON_FA_EXCLAMATION_TRIANGLE, "Cannot save state to a slot without a game running.",
Host::OSD_INFO_DURATION);
return;
}
VMManager::SaveStateToSlot(slot);
}

View File

@ -200,7 +200,7 @@ namespace FullscreenUI
//////////////////////////////////////////////////////////////////////////
// Main
//////////////////////////////////////////////////////////////////////////
static void UpdateGameDetails(std::string path, std::string serial, std::string title, u32 crc);
static void UpdateGameDetails(std::string path, std::string serial, std::string title, u32 disc_crc, u32 crc);
static void ToggleTheme();
static void PauseForMenuOpen();
static void ClosePauseMenu();
@ -229,9 +229,9 @@ namespace FullscreenUI
// local copies of the currently-running game
static std::string s_current_game_title;
static std::string s_current_game_subtitle;
static std::string s_current_game_serial;
static std::string s_current_game_path;
static u32 s_current_game_crc;
static std::string s_current_disc_serial;
static std::string s_current_disc_path;
static u32 s_current_disc_crc;
//////////////////////////////////////////////////////////////////////////
// Resources
@ -578,7 +578,8 @@ bool FullscreenUI::Initialize()
if (VMManager::HasValidVM())
{
UpdateGameDetails(VMManager::GetDiscPath(), VMManager::GetGameSerial(), VMManager::GetGameName(), VMManager::GetGameCRC());
UpdateGameDetails(VMManager::GetDiscPath(), VMManager::GetDiscSerial(), VMManager::GetTitle(),
VMManager::GetDiscCRC(), VMManager::GetCurrentCRC());
}
else
{
@ -651,20 +652,21 @@ void FullscreenUI::OnVMDestroyed()
});
}
void FullscreenUI::GameChanged(std::string path, std::string serial, std::string title, u32 crc)
void FullscreenUI::GameChanged(std::string path, std::string serial, std::string title, u32 disc_crc, u32 crc)
{
if (!IsInitialized())
return;
GetMTGS().RunOnGSThread([path = std::move(path), serial = std::move(serial), title = std::move(title), crc]() {
if (!IsInitialized())
return;
GetMTGS().RunOnGSThread(
[path = std::move(path), serial = std::move(serial), title = std::move(title), disc_crc, crc]() {
if (!IsInitialized())
return;
UpdateGameDetails(std::move(path), std::move(serial), std::move(title), crc);
});
UpdateGameDetails(std::move(path), std::move(serial), std::move(title), disc_crc, crc);
});
}
void FullscreenUI::UpdateGameDetails(std::string path, std::string serial, std::string title, u32 crc)
void FullscreenUI::UpdateGameDetails(std::string path, std::string serial, std::string title, u32 disc_crc, u32 crc)
{
if (!serial.empty())
s_current_game_subtitle = fmt::format("{} / {:08X}", serial, crc);
@ -672,9 +674,9 @@ void FullscreenUI::UpdateGameDetails(std::string path, std::string serial, std::
s_current_game_subtitle = {};
s_current_game_title = std::move(title);
s_current_game_serial = std::move(serial);
s_current_game_path = std::move(path);
s_current_game_crc = crc;
s_current_disc_serial = std::move(serial);
s_current_disc_path = std::move(path);
s_current_disc_crc = disc_crc;
}
void FullscreenUI::ToggleTheme()
@ -744,9 +746,9 @@ void FullscreenUI::Shutdown(bool clear_state)
s_graphics_adapter_list_cache = {};
s_current_game_title = {};
s_current_game_subtitle = {};
s_current_game_serial = {};
s_current_game_path = {};
s_current_game_crc = 0;
s_current_disc_serial = {};
s_current_disc_path = {};
s_current_disc_crc = 0;
s_current_main_window = MainWindowType::None;
s_current_pause_submenu = PauseSubMenu::None;
@ -1053,7 +1055,7 @@ void FullscreenUI::DoChangeDiscFromFile()
};
OpenFileSelector(ICON_FA_COMPACT_DISC " Select Disc Image", false, std::move(callback), GetDiscImageFilters(),
std::string(Path::GetDirectory(s_current_game_path)));
std::string(Path::GetDirectory(s_current_disc_path)));
}
void FullscreenUI::DoChangeDisc()
@ -2333,13 +2335,13 @@ void FullscreenUI::SwitchToGameSettings(const std::string_view& serial, u32 crc)
void FullscreenUI::SwitchToGameSettings()
{
if (s_current_game_serial.empty() || s_current_game_crc == 0)
if (s_current_disc_serial.empty() || s_current_disc_crc == 0)
return;
auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(s_current_game_path.c_str());
const GameList::Entry* entry = GameList::GetEntryForPath(s_current_disc_path.c_str());
if (!entry)
entry = GameList::GetEntryBySerialAndCRC(s_current_game_serial.c_str(), s_current_game_crc);
entry = GameList::GetEntryBySerialAndCRC(s_current_disc_serial.c_str(), s_current_disc_crc);
if (entry)
SwitchToGameSettings(entry);
@ -4266,7 +4268,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
const float image_width = has_rich_presence ? 60.0f : 50.0f;
const float image_height = has_rich_presence ? 90.0f : 75.0f;
const std::string_view path_string(Path::GetFileName(s_current_game_path));
const std::string_view path_string(Path::GetFileName(s_current_disc_path));
const ImVec2 title_size(
g_large_font->CalcTextSizeA(g_large_font->FontSize, std::numeric_limits<float>::max(), -1.0f, s_current_game_title.c_str()));
const ImVec2 path_size(path_string.empty() ?
@ -4345,9 +4347,9 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
const ImVec2 time_pos(display_size.x - LayoutScale(10.0f) - time_size.x, LayoutScale(10.0f));
DrawShadowedText(dl, g_large_font, time_pos, IM_COL32(255, 255, 255, 255), buf);
if (!s_current_game_serial.empty())
if (!s_current_disc_serial.empty())
{
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(s_current_game_serial);
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(s_current_disc_serial);
const std::time_t session_time = static_cast<std::time_t>(VMManager::GetSessionPlayedTime());
const std::string played_time_str(GameList::FormatTimespan(cached_played_time + session_time, true));
const std::string session_time_str(GameList::FormatTimespan(session_time, true));
@ -4389,7 +4391,7 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
case PauseSubMenu::None:
{
// NOTE: Menu close must come first, because otherwise VM destruction options will race.
const bool can_load_or_save_state = s_current_game_crc != 0;
const bool can_load_or_save_state = s_current_disc_crc != 0;
if (ActiveButton(ICON_FA_PLAY " Resume Game", false) || WantsToCloseMenu())
ClosePauseMenu();
@ -4614,7 +4616,7 @@ bool FullscreenUI::OpenSaveStateSelector(bool is_loading)
s_save_state_selector_game_path = {};
s_save_state_selector_loading = is_loading;
s_save_state_selector_resuming = false;
if (PopulateSaveStateListEntries(s_current_game_title.c_str(), s_current_game_serial.c_str(), s_current_game_crc) > 0)
if (PopulateSaveStateListEntries(s_current_game_title.c_str(), s_current_disc_serial.c_str(), s_current_disc_crc) > 0)
{
s_save_state_selector_open = true;
return true;
@ -5815,7 +5817,7 @@ GSTexture* FullscreenUI::GetCoverForCurrentGame()
{
auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(s_current_game_path.c_str());
const GameList::Entry* entry = GameList::GetEntryForPath(s_current_disc_path.c_str());
if (!entry)
return s_fallback_disc_texture.get();

View File

@ -29,7 +29,7 @@ namespace FullscreenUI
void CheckForConfigChanges(const Pcsx2Config& old_config);
void OnVMStarted();
void OnVMDestroyed();
void GameChanged(std::string path, std::string serial, std::string title, u32 crc);
void GameChanged(std::string title, std::string path, std::string serial, u32 disc_crc, u32 crc);
void OpenPauseMenu();
void OpenAchievementsWindow();
void OpenLeaderboardsWindow();

View File

@ -513,30 +513,22 @@ static void intCancelInstruction()
static void intExecute()
{
enum ExecuteState {
RESET,
GAME_LOADING,
GAME_RUNNING
};
ExecuteState state = RESET;
// This will come back as zero the first time it runs, or on instruction cancel.
// It will come back as nonzero when we exit execution.
if (fastjmp_set(&intJmpBuf) != 0)
return;
// I hope this doesn't cause issues with the optimizer... infinite loop with a constant expression.
for (;;)
{
// The execution was splited in three parts so it is easier to
// resume it after a cancelled instruction.
switch (state) {
case RESET:
if (!VMManager::Internal::HasBootedELF())
{
// Avoid reloading every instruction.
u32 elf_entry_point = VMManager::Internal::GetCurrentELFEntryPoint();
u32 eeload_main = g_eeloadMain;
while (true)
{
do
{
execI();
} while (cpuRegs.pc != (g_eeloadMain ? g_eeloadMain : EELOAD_START));
execI();
if (cpuRegs.pc == EELOAD_START)
{
@ -544,11 +536,13 @@ static void intExecute()
u32 mainjump = memRead32(EELOAD_START + 0x9c);
if (mainjump >> 26 == 3) // JAL
g_eeloadMain = ((EELOAD_START + 0xa0) & 0xf0000000U) | (mainjump << 2 & 0x0fffffffU);
eeload_main = g_eeloadMain;
}
else if (cpuRegs.pc == g_eeloadMain)
{
eeloadHook();
if (g_SkipBiosHack)
if (VMManager::Internal::IsFastBootInProgress())
{
// See comments on this code in iR5900-32.cpp's recRecompile()
u32 typeAexecjump = memRead32(EELOAD_START + 0x470);
@ -562,39 +556,24 @@ static void intExecute()
else
Console.WriteLn("intExecute: Could not enable launch arguments for fast boot mode; unidentified BIOS version! Please report this to the PCSX2 developers.");
}
elf_entry_point = VMManager::Internal::GetCurrentELFEntryPoint();
}
else if (cpuRegs.pc == g_eeloadExec)
{
eeloadHook2();
}
if (!g_GameLoading)
break;
state = GAME_LOADING;
[[fallthrough]];
}
case GAME_LOADING:
{
if (ElfEntry != 0xFFFFFFFF)
else if (cpuRegs.pc == elf_entry_point)
{
do
{
execI();
} while (cpuRegs.pc != ElfEntry);
eeGameStarting();
VMManager::Internal::EntryPointCompilingOnCPUThread();
break;
}
state = GAME_RUNNING;
[[fallthrough]];
}
case GAME_RUNNING:
{
while (true)
execI();
}
break;
}
else
{
while (true)
execI();
}
}
}

View File

@ -23,6 +23,7 @@
#include "R5900.h"
#include "ps2/BiosTools.h"
#include "x86/iR3000A.h"
#include "VMManager.h"
#include "common/FileSystem.h"
#include "common/Path.h"
@ -170,6 +171,17 @@ namespace R3000A
else if (!hostRoot.empty()) // relative paths
new_path = Path::Combine(hostRoot, native_path);
// Allow opening the ELF override.
if (new_path == VMManager::Internal::GetELFOverride())
return new_path;
// Allow nothing if hostfs isn't enabled.
if (!EmuConfig.HostFs)
{
new_path.clear();
return new_path;
}
// Double-check that it falls within the directory of the elf.
// Not a real sandbox, but emulators shouldn't be treated as such. Don't run untrusted code!
std::string canonicalized_path(Path::Canonicalize(new_path));
@ -562,7 +574,7 @@ namespace R3000A
if (not_number_pos == std::string::npos)
return false;
return ((!g_GameStarted || EmuConfig.HostFs) && 0 == path.compare(0, 4, "host") && path[not_number_pos] == ':');
return (path.compare(0, 4, "host") == 0 && path[not_number_pos] == ':');
}
int open_HLE()

View File

@ -268,7 +268,7 @@ bool SysMtgsThread::TryOpenGS()
if (!GSopen(EmuConfig.GS, EmuConfig.GS.Renderer, RingBuffer.Regs))
return false;
GSSetGameCRC(ElfCRC);
GSSetGameCRC(VMManager::GetDiscCRC());
return true;
}

View File

@ -48,8 +48,6 @@ BIOS
#include "common/AlignedMalloc.h"
#include "GSDumpReplayer.h"
#ifdef ENABLECACHE
#include "Cache.h"
#endif
@ -841,11 +839,7 @@ void eeMemoryReserve::Reset()
vtlb_VMap(0x00000000,0x00000000,0x20000000);
vtlb_VMapUnmap(0x20000000,0x60000000);
const bool needs_bios = !GSDumpReplayer::IsReplayingDump();
// TODO(Stenzek): Move BIOS loading out and far away...
if (needs_bios && !LoadBIOS())
pxFailRel("Failed to load BIOS");
CopyBIOSToMemory();
}
void eeMemoryReserve::Release()

View File

@ -437,7 +437,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(gsl::span<u8> buf, std::vector<u8
{
if (!VMManager::HasValidVM())
goto error;
const std::string gameName = VMManager::GetGameName();
const std::string gameName = VMManager::GetTitle();
const u32 size = gameName.size() + 1;
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
@ -451,7 +451,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(gsl::span<u8> buf, std::vector<u8
{
if (!VMManager::HasValidVM())
goto error;
const std::string gameSerial = VMManager::GetGameSerial();
const std::string gameSerial = VMManager::GetDiscSerial();
const u32 size = gameSerial.size() + 1;
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
@ -465,7 +465,7 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(gsl::span<u8> buf, std::vector<u8
{
if (!VMManager::HasValidVM())
goto error;
const std::string crc(fmt::format("{:08x}", VMManager::GetGameCRC()));
const std::string crc = fmt::format("{:08x}", VMManager::GetDiscCRC());
const u32 size = crc.size() + 1;
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;
@ -479,6 +479,8 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(gsl::span<u8> buf, std::vector<u8
{
if (!VMManager::HasValidVM())
goto error;
const std::string ElfVersion = VMManager::GetDiscVersion();
const u32 size = ElfVersion.size() + 1;
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
goto error;

View File

@ -187,7 +187,6 @@ namespace Patch
static EnablePatchList s_enabled_cheats;
static EnablePatchList s_enabled_patches;
static u32 s_patches_crc;
static std::string s_patches_serial;
static std::optional<AspectRatioType> s_override_aspect_ratio;
static std::optional<GSInterlaceMode> s_override_interlace_mode;
@ -520,18 +519,16 @@ u32 Patch::EnablePatches(const PatchList& patches, const EnablePatchList& enable
return count;
}
void Patch::ReloadPatches(std::string serial, u32 crc, bool force_reload_files, bool reload_enabled_list, bool verbose, bool verbose_if_changed)
void Patch::ReloadPatches(const std::string& serial, u32 crc, bool reload_files, bool reload_enabled_list, bool verbose, bool verbose_if_changed)
{
const bool serial_changed = (s_patches_serial != serial);
reload_files |= (s_patches_crc != crc);
s_patches_crc = crc;
s_patches_serial = std::move(serial);
// Skip reloading gamedb patches if the serial hasn't changed.
if (serial_changed)
if (reload_files)
{
s_gamedb_patches.clear();
const GameDatabaseSchema::GameEntry* game = GameDatabase::findGame(s_patches_serial);
const GameDatabaseSchema::GameEntry* game = GameDatabase::findGame(serial);
if (game)
{
const std::string* patches = game->findPatch(crc);
@ -544,18 +541,10 @@ void Patch::ReloadPatches(std::string serial, u32 crc, bool force_reload_files,
LoadDynamicPatches(game->dynaPatches);
}
}
ReloadPatches(serial_changed, reload_enabled_list, verbose, verbose_if_changed);
}
void Patch::ReloadPatches(bool force_reload_files, bool reload_enabled_list, bool verbose, bool verbose_if_changed)
{
if (force_reload_files)
{
s_game_patches.clear();
EnumeratePnachFiles(
s_patches_serial, s_patches_crc, false, false, [](const std::string& filename, const std::string& pnach_data) {
serial, s_patches_crc, false, false, [](const std::string& filename, const std::string& pnach_data) {
const u32 patch_count = LoadPatchesFromString(&s_game_patches, pnach_data);
if (patch_count > 0)
Console.WriteLn(Color_Green, fmt::format("Found {} game patches in {}.", patch_count, filename));
@ -563,7 +552,7 @@ void Patch::ReloadPatches(bool force_reload_files, bool reload_enabled_list, boo
s_cheat_patches.clear();
EnumeratePnachFiles(
s_patches_serial, s_patches_crc, true, false, [](const std::string& filename, const std::string& pnach_data) {
serial, s_patches_crc, true, false, [](const std::string& filename, const std::string& pnach_data) {
const u32 patch_count = LoadPatchesFromString(&s_cheat_patches, pnach_data);
if (patch_count > 0)
Console.WriteLn(Color_Green, fmt::format("Found {} cheats in {}.", patch_count, filename));
@ -584,9 +573,10 @@ void Patch::UpdateActivePatches(bool reload_enabled_list, bool verbose, bool ver
s_override_interlace_mode.reset();
std::string message;
u32 gp_count = 0;
if (EmuConfig.EnablePatches)
{
const u32 gp_count = EnablePatches(s_gamedb_patches, EnablePatchList());
gp_count = EnablePatches(s_gamedb_patches, EnablePatchList());
if (gp_count > 0)
fmt::format_to(std::back_inserter(message), "{} GameDB patches", gp_count);
}
@ -600,7 +590,9 @@ void Patch::UpdateActivePatches(bool reload_enabled_list, bool verbose, bool ver
fmt::format_to(std::back_inserter(message), "{}{} cheat patches", message.empty() ? "" : ", ", c_count);
// Display message on first boot when we load patches.
if (verbose || (verbose_if_changed && prev_count != s_active_patches.size()))
// Except when it's just GameDB.
const bool just_gamedb = (p_count == 0 && c_count == 0 && gp_count > 0);
if (verbose || (verbose_if_changed && prev_count != s_active_patches.size() && !just_gamedb))
{
if (!message.empty())
{
@ -673,7 +665,6 @@ void Patch::UnloadPatches()
s_override_interlace_mode = {};
s_override_aspect_ratio = {};
s_patches_crc = 0;
s_patches_serial = {};
s_active_patches = {};
s_active_dynamic_patches = {};
s_enabled_patches = {};

View File

@ -96,8 +96,7 @@ namespace Patch
extern PatchInfoList GetPatchInfo(const std::string& serial, u32 crc, bool cheats, u32* num_unlabelled_patches);
/// Reloads cheats/patches. If verbose is set, the number of patches loaded will be shown in the OSD.
extern void ReloadPatches(std::string serial, u32 crc, bool force_reload_files, bool reload_enabled_list, bool verbose, bool verbose_if_changed);
extern void ReloadPatches(bool force_reload_files, bool reload_enabled_list, bool verbose, bool verbose_if_changed);
extern void ReloadPatches(const std::string& serial, u32 crc, bool reload_files, bool reload_enabled_list, bool verbose, bool verbose_if_changed);
extern void UpdateActivePatches(bool reload_enabled_list, bool verbose, bool verbose_if_changed);
extern void ApplyPatchSettingOverrides();

View File

@ -1305,6 +1305,8 @@ Pcsx2Config::Pcsx2Config()
McdEnableEjection = true;
McdFolderAutoManage = true;
EnablePatches = true;
EnableFastBoot = true;
EnablePerGameSettings = true;
EnableRecordingTools = true;
EnableGameFixes = true;
InhibitScreensaver = true;
@ -1348,6 +1350,9 @@ void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBool(EnablePINE);
SettingsWrapBitBool(EnableWideScreenPatches);
SettingsWrapBitBool(EnableNoInterlacingPatches);
SettingsWrapBitBool(EnableFastBoot);
SettingsWrapBitBool(EnableFastBootFastForward);
SettingsWrapBitBool(EnablePerGameSettings);
SettingsWrapBitBool(EnableRecordingTools);
SettingsWrapBitBool(EnableGameFixes);
SettingsWrapBitBool(SaveStateOnShutdown);
@ -1472,7 +1477,6 @@ bool Pcsx2Config::operator==(const Pcsx2Config& right) const
void Pcsx2Config::CopyRuntimeConfig(Pcsx2Config& cfg)
{
GS.LimitScalar = cfg.GS.LimitScalar;
UseBOOT2Injection = cfg.UseBOOT2Injection;
CurrentBlockdump = std::move(cfg.CurrentBlockdump);
CurrentIRX = std::move(cfg.CurrentIRX);
CurrentGameArgs = std::move(cfg.CurrentGameArgs);

View File

@ -51,10 +51,6 @@ alignas(16) fpuRegisters fpuRegs;
alignas(16) tlbs tlb[48];
R5900cpu *Cpu = NULL;
bool g_SkipBiosHack; // set at boot if the skip bios hack is on, reset before the game has started
bool g_GameStarted; // set when we reach the game's entry point or earlier if the entry point cannot be determined
bool g_GameLoading; // EELOAD has been called to load the game
static const uint eeWaitCycles = 3072;
bool eeEventTestIsActive = false;
@ -104,24 +100,12 @@ void cpuReset()
extern void Deci2Reset(); // lazy, no good header for it yet.
Deci2Reset();
g_SkipBiosHack = EmuConfig.UseBOOT2Injection;
AllowParams1 = !g_SkipBiosHack;
AllowParams2 = !g_SkipBiosHack;
AllowParams1 = !VMManager::Internal::IsFastBootInProgress();
AllowParams2 = !VMManager::Internal::IsFastBootInProgress();
ElfCRC = 0;
DiscSerial.clear();
ElfEntry = -1;
g_GameStarted = false;
g_GameLoading = false;
// FIXME: LastELF should be reset on media changes as well as on CPU resets, in
// the very unlikely case that a user swaps to another media source that "looks"
// the same (identical ELF names) but is actually different (devs actually could
// run into this while testing minor binary hacked changes to ISO images, which
// is why I found out about this) --air
LastELF.clear();
g_eeloadMain = 0, g_eeloadExec = 0, g_osdsys_str = 0;
g_eeloadMain = 0;
g_eeloadExec = 0;
g_osdsys_str = 0;
}
__ri void cpuException(u32 code, u32 bd)
@ -279,7 +263,7 @@ static __fi void TESTINT( u8 n, void (*callback)() )
{
if( !(cpuRegs.interrupt & (1 << n)) ) return;
if(!g_GameStarted || CHECK_INSTANTDMAHACK || cpuTestCycle( cpuRegs.sCycle[n], cpuRegs.eCycle[n] ) )
if(CHECK_INSTANTDMAHACK || cpuTestCycle( cpuRegs.sCycle[n], cpuRegs.eCycle[n] ) )
{
cpuClearInt( n );
callback();
@ -416,7 +400,7 @@ __fi void _cpuEventTest_Shared()
// where a DMA buffer is overwritten without waiting for the transfer to end, which causes the fonts to get all messed up
// so to fix it, we run all the DMA's instantly when in the BIOS.
// Only use the lower 17 bits of the cpuRegs.interrupt as the upper bits are for VU0/1 sync which can't be done in a tight loop
if ((!g_GameStarted || CHECK_INSTANTDMAHACK) && dmacRegs.ctrl.DMAE && !(psHu8(DMAC_ENABLER + 2) & 1) && (cpuRegs.interrupt & 0x1FFFF))
if (CHECK_INSTANTDMAHACK && dmacRegs.ctrl.DMAE && !(psHu8(DMAC_ENABLER + 2) & 1) && (cpuRegs.interrupt & 0x1FFFF))
{
while ((cpuRegs.interrupt & 0x1FFFF) && _cpuTestInterrupts())
;
@ -568,27 +552,6 @@ __fi void CPU_INT( EE_EventType n, s32 ecycle)
cpuSetNextEventDelta(cpuRegs.eCycle[n]);
}
// Called from recompilers; define is mandatory.
void eeGameStarting()
{
if (!g_GameStarted)
{
//Console.WriteLn( Color_Green, "(R5900) ELF Entry point! [addr=0x%08X]", ElfEntry );
g_GameStarted = true;
g_GameLoading = false;
// GameStartingInThread may issue a reset of the cpu and/or recompilers. Check for and
// handle such things here:
VMManager::Internal::GameStartingOnCPUThread();
if (VMManager::Internal::IsExecutionInterrupted())
Cpu->ExitExecution();
}
else
{
Console.WriteLn( Color_Green, "(R5900) Re-executed ELF Entry point (ignored) [addr=0x%08X]", ElfEntry );
}
}
// Count arguments, save their starting locations, and replace the space separators with null terminators so they're separate strings
int ParseArgumentString(u32 arg_block)
{
@ -635,16 +598,6 @@ int ParseArgumentString(u32 arg_block)
// Called from recompilers; define is mandatory.
void eeloadHook()
{
const std::string& elf_override(VMManager::Internal::GetElfOverride());
if (!elf_override.empty())
cdvdReloadElfInfo(StringUtil::StdStringFromFormat("host:%s", elf_override.c_str()));
else
cdvdReloadElfInfo();
std::string discelf;
int disctype = GetPS2ElfName(discelf);
std::string elfname;
int argc = cpuRegs.GPR.n.a0.SD[0];
if (argc) // calls to EELOAD *after* the first one during the startup process will come here
@ -664,7 +617,7 @@ void eeloadHook()
// mode). Then EELOAD is called with the argument "rom0:PS2LOGO". At this point, we do not need any additional tricks
// because EELOAD is now ready to accept launch arguments. So in full-boot mode, we simply wait for PS2LOGO to be called,
// then we add the desired launch arguments. PS2LOGO passes those on to the game itself as it calls EELOAD a third time.
if (!EmuConfig.CurrentGameArgs.empty() && !strcmp(elfname.c_str(), "rom0:PS2LOGO"))
if (!EmuConfig.CurrentGameArgs.empty() && elfname == "rom0:PS2LOGO")
{
const char *argString = EmuConfig.CurrentGameArgs.c_str();
Console.WriteLn("eeloadHook: Supplying launch argument(s) '%s' to module '%s'...", argString, elfname.c_str());
@ -711,24 +664,32 @@ void eeloadHook()
// If "fast boot" was chosen, then on EELOAD's first call we won't yet know what the game's ELF is. Find the name and write it
// into EELOAD's memory.
if (g_SkipBiosHack && elfname.empty())
if (VMManager::Internal::IsFastBootInProgress() && elfname.empty())
{
std::string elftoload;
const std::string& elf_override = VMManager::Internal::GetELFOverride();
if (!elf_override.empty())
{
elftoload = StringUtil::StdStringFromFormat("host:%s", elf_override.c_str());
elfname = fmt::format("host:{}", elf_override);
}
else
{
if (disctype == 2)
elftoload = discelf;
CDVDDiscType disc_type;
std::string disc_elf;
cdvdGetDiscInfo(nullptr, &disc_elf, nullptr, nullptr, &disc_type);
if (disc_type == CDVDDiscType::PS2Disc)
{
// only allow fast boot for PS2 games
elfname = std::move(disc_elf);
}
else
g_SkipBiosHack = false; // We're not fast booting, so disable it (Fixes some weirdness with the BIOS)
{
Console.Warning(fmt::format("Not allowing fast boot for non-PS2 ELF {}", disc_elf));
}
}
// When fast-booting, we insert the game's ELF name into EELOAD so that the game is called instead of the default call of
// "rom0:OSDSYS"; any launch arguments supplied by the user will be inserted into EELOAD later by eeloadHook2()
if (!elftoload.empty())
if (!elfname.empty())
{
// Find and save location of default/fallback call "rom0:OSDSYS"; to be used later by eeloadHook2()
for (g_osdsys_str = EELOAD_START; g_osdsys_str < EELOAD_START + EELOAD_SIZE; g_osdsys_str += 8) // strings are 64-bit aligned
@ -736,16 +697,20 @@ void eeloadHook()
if (!strcmp((char*)PSM(g_osdsys_str), "rom0:OSDSYS"))
{
// Overwrite OSDSYS with game's ELF name
strcpy((char*)PSM(g_osdsys_str), elftoload.c_str());
g_GameLoading = true;
return;
strcpy((char*)PSM(g_osdsys_str), elfname.c_str());
}
}
}
else
{
// Stop fast forwarding if we're doing that for boot.
VMManager::Internal::DisableFastBoot();
AllowParams1 = true;
AllowParams2 = true;
}
}
if (!g_GameStarted && ((disctype == 2 && elfname == discelf) || disctype == 1))
g_GameLoading = true;
VMManager::Internal::ELFLoadingOnCPUThread(std::move(elfname));
}
// Called from recompilers; define is mandatory.

View File

@ -26,10 +26,6 @@ class BaseR5900Exception;
// them in iR5900.h would mean having to include that into more files than I care to
// right now, so we're sticking them here for now until a better solution comes along.
extern bool g_SkipBiosHack;
extern bool g_GameStarted;
extern bool g_GameLoading;
namespace Exception
{
// Implementation Note: this exception has no meaningful type information and we don't
@ -276,7 +272,6 @@ const u32 EELOAD_START = 0x82000;
const u32 EELOAD_SIZE = 0x20000; // overestimate for searching
extern u32 g_eeloadMain, g_eeloadExec;
extern void eeGameStarting();
extern void eeloadHook();
extern void eeloadHook2();

View File

@ -969,7 +969,7 @@ void SYSCALL()
AllowParams1 = true;
break;
case Syscall::GetOsdConfigParam:
if(!NoOSD && g_SkipBiosHack && !AllowParams1)
if(!NoOSD && !AllowParams1)
{
u32 memaddr = cpuRegs.GPR.n.a0.UL[0];
u8 params[16];
@ -993,7 +993,7 @@ void SYSCALL()
AllowParams2 = true;
break;
case Syscall::GetOsdConfigParam2:
if (!NoOSD && g_SkipBiosHack && !AllowParams2)
if (!NoOSD && !AllowParams2)
{
u32 memaddr = cpuRegs.GPR.n.a0.UL[0];
u8 params[16];

View File

@ -78,7 +78,7 @@ bool InputRecording::create(const std::string& fileName, const bool fromSaveStat
m_file.setEmulatorVersion();
m_file.setAuthor(authorName);
m_file.setGameName(resolveGameName());
m_file.setGameName(VMManager::GetTitle());
m_file.writeHeader();
initializeState();
InputRec::log("Started new input recording");
@ -129,9 +129,9 @@ bool InputRecording::play(const std::string& filename)
initializeState();
InputRec::log("Replaying input recording");
m_file.logRecordingMetadata();
if (resolveGameName() != m_file.getGameName())
if (VMManager::GetTitle() != m_file.getGameName())
{
InputRec::consoleLog(fmt::format("Input recording was possibly constructed for a different game. Expected: {}, Actual: {}", m_file.getGameName(), resolveGameName()));
InputRec::consoleLog(fmt::format("Input recording was possibly constructed for a different game. Expected: {}, Actual: {}", m_file.getGameName(), VMManager::GetTitle()));
}
return true;
}
@ -229,21 +229,6 @@ void InputRecording::processRecordQueue()
}
}
std::string InputRecording::resolveGameName()
{
std::string gameName;
const std::string gameKey = SysGetDiscID();
if (!gameKey.empty())
{
auto game = GameDatabase::findGame(gameKey);
if (game)
{
gameName = fmt::format("{} ({})", game->name, game->region);
}
}
return !gameName.empty() ? gameName : VMManager::GetGameName();
}
void InputRecording::incFrameCounter()
{
if (!m_is_active)

View File

@ -70,11 +70,6 @@ private:
void initializeState();
void setStartingFrame(u32 startingFrame);
void closeActiveFile();
private:
// Resolve the name and region of the game currently loaded using the GameDB
// If the game cannot be found in the DB, the fallback is the ISO filename
std::string resolveGameName();
};
extern InputRecording g_InputRecording;

View File

@ -174,11 +174,11 @@ SaveStateBase& SaveStateBase::FreezeBios()
SaveStateBase& SaveStateBase::FreezeInternals()
{
const u32 previousCRC = ElfCRC;
// Print this until the MTVU problem in gifPathFreeze is taken care of (rama)
if (THREAD_VU1) Console.Warning("MTVU speedhack is enabled, saved states may not be stable");
vmFreeze();
// Second Block - Various CPU Registers and States
// -----------------------------------------------
FreezeTag( "cpuRegs" );
@ -188,30 +188,7 @@ SaveStateBase& SaveStateBase::FreezeInternals()
Freeze(tlb); // tlbs
Freeze(AllowParams1); //OSDConfig written (Fast Boot)
Freeze(AllowParams2);
Freeze(g_GameStarted);
Freeze(g_GameLoading);
Freeze(ElfCRC);
char localDiscSerial[256];
StringUtil::Strlcpy(localDiscSerial, DiscSerial.c_str(), sizeof(localDiscSerial));
Freeze(localDiscSerial);
if (IsLoading())
{
DiscSerial = localDiscSerial;
if (ElfCRC != previousCRC)
{
// HACK: LastELF isn't in the save state... Load it before we go too far into restoring state.
// When we next bump save states, we should include it. We need this for achievements, because
// we want to load and activate achievements before restoring any of their tracked state.
if (const std::string& elf_override = VMManager::Internal::GetElfOverride(); !elf_override.empty())
cdvdReloadElfInfo(fmt::format("host:{}", elf_override));
else
cdvdReloadElfInfo();
}
}
// Third Block - Cycle Timers and Events
// -------------------------------------
FreezeTag( "Cycles" );

View File

@ -36,7 +36,7 @@ enum class FreezeAction
// [SAVEVERSION+]
// This informs the auto updater that the users savestates will be invalidated.
static const u32 g_SaveVersion = (0x9A36 << 16) | 0x0000;
static const u32 g_SaveVersion = (0x9A37 << 16) | 0x0000;
// the freezing data between submodules and core
@ -147,6 +147,18 @@ public:
}
}
void FreezeString(std::string& s)
{
// overwritten when loading
u32 length = static_cast<u32>(s.length());
Freeze(length);
if (IsLoading())
s.resize(length);
FreezeMem(s.data(), length);
}
uint GetCurrentPos() const
{
return m_idx;
@ -189,8 +201,7 @@ public:
protected:
void Init( VmStateBuffer* memblock );
// Load/Save functions for the various components of our glorious emulator!
void vmFreeze();
void mtvuFreeze();
void rcntFreeze();
void vuMicroFreeze();

View File

@ -346,34 +346,3 @@ void SysClearExecutionCache()
dVifReset(1);
}
}
// This function returns part of EXTINFO data of the BIOS rom
// This module contains information about Sony build environment at offst 0x10
// first 15 symbols is build date/time that is unique per rom and can be used as unique serial
// Example for romver 0160EC20010704
// 20010704-160707,ROMconf,PS20160EC20010704.bin,kuma@rom-server/~/f10k/g/app/rom
// 20010704-160707 can be used as unique ID for Bios
std::string SysGetBiosDiscID()
{
if (!BiosSerial.empty())
return BiosSerial;
else
return {};
}
// This function always returns a valid DiscID -- using the Sony serial when possible, and
// falling back on the CRC checksum of the ELF binary if the PS2 software being run is
// homebrew or some other serial-less item.
std::string SysGetDiscID()
{
if (!DiscSerial.empty())
return DiscSerial;
if (!ElfCRC)
{
// system is currently running the BIOS
return SysGetBiosDiscID();
}
return StringUtil::StdStringFromFormat("%08x", ElfCRC);
}

View File

@ -144,9 +144,6 @@ extern SysCpuProviderPack& GetCpuProviders();
extern void SysLogMachineCaps(); // Detects cpu type and fills cpuInfo structs.
extern void SysClearExecutionCache(); // clears recompiled execution caches!
extern std::string SysGetBiosDiscID();
extern std::string SysGetDiscID();
extern SysMainMemory& GetVmMemory();
extern void SetCPUState(SSE_MXCSR sseMXCSR, SSE_MXCSR sseVU0MXCSR, SSE_MXCSR sseVU1MXCSR);

View File

@ -332,7 +332,7 @@ namespace usb_lightgun
void GunCon2State::AutoConfigure()
{
const std::string serial(VMManager::GetGameSerial());
const std::string serial = VMManager::GetDiscSerial();
for (const GameConfig& gc : s_game_config)
{
if (serial != gc.serial)

File diff suppressed because it is too large Load Diff

View File

@ -74,14 +74,23 @@ namespace VMManager
/// Returns the path of the disc currently running.
std::string GetDiscPath();
/// Returns the crc of the executable currently running.
u32 GetGameCRC();
/// Returns the serial of the disc currently running.
std::string GetDiscSerial();
/// Returns the serial of the disc/executable currently running.
std::string GetGameSerial();
/// Returns the path of the main ELF of the disc currently running.
std::string GetDiscELF();
/// Returns the name of the disc/executable currently running.
std::string GetGameName();
std::string GetTitle();
/// Returns the CRC for the main ELF of the disc currently running.
u32 GetDiscCRC();
/// Returns the version of the disc currently running.
std::string GetDiscVersion();
/// Returns the crc of the executable currently running.
u32 GetCurrentCRC();
/// Loads global settings (i.e. EmuConfig).
void LoadSettings();
@ -107,6 +116,9 @@ namespace VMManager
/// Reloads game specific settings, and applys any changes present.
bool ReloadGameSettings();
/// Reloads game patches.
void ReloadPatches(bool reload_files, bool reload_enabled_list, bool verbose, bool verbose_if_changed);
/// Returns the save state filename for the given game serial/crc.
std::string GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot);
@ -215,11 +227,22 @@ namespace VMManager
/// Updates the variables in the EmuFolders namespace, reloading subsystems if needed.
void UpdateEmuFolders();
const std::string& GetElfOverride();
/// Returns true if fast booting is active (requested but ELF not started).
bool IsFastBootInProgress();
/// Disables fast boot if it was requested, and found to be incompatible.
void DisableFastBoot();
/// Returns true if the current ELF has started executing.
bool HasBootedELF();
/// Returns the PC of the currently-executing ELF's entry point.
u32 GetCurrentELFEntryPoint();
const std::string& GetELFOverride();
bool IsExecutionInterrupted();
void ELFLoadingOnCPUThread(std::string elf_path);
void EntryPointCompilingOnCPUThread();
void GameStartingOnCPUThread();
void SwappingGameOnCPUThread();
void VSyncOnCPUThread();
} // namespace Internal
} // namespace VMManager
@ -262,8 +285,8 @@ namespace Host
void OnSaveStateSaved(const std::string_view& filename);
/// Provided by the host; called when the running executable changes.
void OnGameChanged(const std::string& disc_path, const std::string& elf_override, const std::string& game_serial,
const std::string& game_name, u32 game_crc);
void OnGameChanged(const std::string& title, const std::string& elf_override, const std::string& disc_path,
const std::string& disc_serial, u32 disc_crc, u32 current_crc);
/// Provided by the host; called once per frame at guest vsync.
void VSyncOnCPUThread();

View File

@ -54,9 +54,11 @@ bool NoOSD;
bool AllowParams1;
bool AllowParams2;
std::string BiosDescription;
std::string BiosZone;
std::string BiosSerial;
std::string BiosPath;
BiosDebugInformation CurrentBiosInformation;
std::vector<u8> BiosRom;
static bool LoadBiosVersion(std::FILE* fp, u32& version, std::string& description, u32& region, std::string& zone, std::string& serial)
{
@ -177,12 +179,12 @@ static bool LoadBiosVersion(std::FILE* fp, u32& version, std::string& descriptio
return true;
}
template <size_t _size>
void ChecksumIt(u32& result, const u8 (&srcdata)[_size])
static void ChecksumIt(u32& result, u32 offset, u32 size)
{
pxAssume((_size & 3) == 0);
for (size_t i = 0; i < _size / 4; ++i)
result ^= ((u32*)srcdata)[i];
const u8* srcdata = &BiosRom[offset];
pxAssume((size & 3) == 0);
for (size_t i = 0; i < size / 4; ++i)
result ^= reinterpret_cast<const u32*>(srcdata)[i];
}
// Attempts to load a BIOS rom sub-component, by trying multiple combinations of base
@ -192,8 +194,7 @@ void ChecksumIt(u32& result, const u8 (&srcdata)[_size])
// Parameters:
// ext - extension of the sub-component to load. Valid options are rom1 and rom2.
//
template <size_t _size>
static void LoadExtraRom(const char* ext, u8 (&dest)[_size])
static void LoadExtraRom(const char* ext, u32 offset, u32 size)
{
// Try first a basic extension concatenation (normally results in something like name.bin.rom1)
std::string Bios1(StringUtil::StdStringFromFormat("%s.%s", BiosPath.c_str(), ext));
@ -210,8 +211,10 @@ static void LoadExtraRom(const char* ext, u8 (&dest)[_size])
}
}
BiosRom.resize(offset + size);
auto fp = FileSystem::OpenManagedCFile(Bios1.c_str(), "rb");
if (!fp || std::fread(dest, static_cast<size_t>(std::min<s64>(_size, filesize)), 1, fp.get()) != 1)
if (!fp || std::fread(&BiosRom[offset], static_cast<size_t>(std::min<s64>(size, filesize)), 1, fp.get()) != 1)
{
Console.Warning("BIOS Warning: %s could not be read (permission denied?)", ext);
return;
@ -261,6 +264,29 @@ static std::string FindBiosImage()
return std::string();
}
bool IsBIOS(const char* filename, u32& version, std::string& description, u32& region, std::string& zone)
{
std::string serial;
const auto fp = FileSystem::OpenManagedCFile(filename, "rb");
if (!fp)
return false;
// FPS2BIOS is smaller and of variable size
//if (inway.Length() < 512*1024) return false;
return LoadBiosVersion(fp.get(), version, description, region, zone, serial);
}
bool IsBIOSAvailable(const std::string& full_path)
{
// We can't use EmuConfig here since it may not be loaded yet.
if (!full_path.empty() && FileSystem::FileExists(full_path.c_str()))
return true;
// No bios configured or the configured name is missing, check for one in the BIOS directory.
const std::string auto_path(FindBiosImage());
return !auto_path.empty() && FileSystem::FileExists(auto_path.c_str());
}
// Loads the configured bios rom file into PS2 memory. PS2 memory must be allocated prior to
// this method being called.
//
@ -297,11 +323,12 @@ bool LoadBIOS()
if (filesize <= 0)
return false;
std::string zone;
LoadBiosVersion(fp.get(), BiosVersion, BiosDescription, BiosRegion, zone, BiosSerial);
LoadBiosVersion(fp.get(), BiosVersion, BiosDescription, BiosRegion, BiosZone, BiosSerial);
BiosRom.resize(Ps2MemSize::Rom);
if (FileSystem::FSeek64(fp.get(), 0, SEEK_SET) ||
std::fread(eeMem->ROM, static_cast<size_t>(std::min<s64>(Ps2MemSize::Rom, filesize)), 1, fp.get()) != 1)
std::fread(BiosRom.data(), static_cast<size_t>(std::min<s64>(Ps2MemSize::Rom, filesize)), 1, fp.get()) != 1)
{
return false;
}
@ -314,40 +341,31 @@ bool LoadBIOS()
NoOSD = false;
BiosChecksum = 0;
ChecksumIt(BiosChecksum, eeMem->ROM);
ChecksumIt(BiosChecksum, 0, Ps2MemSize::Rom);
BiosPath = std::move(path);
//injectIRX("host.irx"); //not fully tested; still buggy
LoadExtraRom("rom1", eeMem->ROM1);
LoadExtraRom("rom2", eeMem->ROM2);
LoadExtraRom("rom1", Ps2MemSize::Rom, Ps2MemSize::Rom1);
LoadExtraRom("rom2", Ps2MemSize::Rom + Ps2MemSize::Rom1, Ps2MemSize::Rom2);
return true;
}
void CopyBIOSToMemory()
{
if (BiosRom.size() >= Ps2MemSize::Rom)
{
std::memcpy(eeMem->ROM, BiosRom.data(), sizeof(eeMem->ROM));
if (BiosRom.size() >= (Ps2MemSize::Rom + Ps2MemSize::Rom1))
{
std::memcpy(eeMem->ROM1, BiosRom.data() + Ps2MemSize::Rom, sizeof(eeMem->ROM1));
if (BiosRom.size() >= (Ps2MemSize::Rom + Ps2MemSize::Rom1 + Ps2MemSize::Rom2))
std::memcpy(eeMem->ROM2, BiosRom.data() + Ps2MemSize::Rom + Ps2MemSize::Rom1, sizeof(eeMem->ROM2));
}
}
if (EmuConfig.CurrentIRX.length() > 3)
LoadIrx(EmuConfig.CurrentIRX, &eeMem->ROM[0x3C0000], sizeof(eeMem->ROM) - 0x3C0000);
CurrentBiosInformation.eeThreadListAddr = 0;
return true;
}
bool IsBIOS(const char* filename, u32& version, std::string& description, u32& region, std::string& zone)
{
std::string serial;
const auto fp = FileSystem::OpenManagedCFile(filename, "rb");
if (!fp)
return false;
// FPS2BIOS is smaller and of variable size
//if (inway.Length() < 512*1024) return false;
return LoadBiosVersion(fp.get(), version, description, region, zone, serial);
}
bool IsBIOSAvailable(const std::string& full_path)
{
// We can't use EmuConfig here since it may not be loaded yet.
if (!full_path.empty() && FileSystem::FileExists(full_path.c_str()))
return true;
// No bios configured or the configured name is missing, check for one in the BIOS directory.
const std::string auto_path(FindBiosImage());
return !auto_path.empty() && FileSystem::FileExists(auto_path.c_str());
}

View File

@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@ -14,7 +14,9 @@
*/
#pragma once
#include <string>
#include <vector>
const u32 ThreadListInstructions[3] =
{
@ -30,6 +32,7 @@ struct BiosDebugInformation
u32 iopModListAddr;
};
// TODO: namespace this
extern BiosDebugInformation CurrentBiosInformation;
extern u32 BiosVersion; // Used by CDVD
extern u32 BiosRegion; // Used by CDVD
@ -38,9 +41,23 @@ extern bool AllowParams1;
extern bool AllowParams2;
extern u32 BiosChecksum;
extern std::string BiosDescription;
extern std::string BiosZone;
// This function returns part of EXTINFO data of the BIOS rom
// This module contains information about Sony build environment at offst 0x10
// first 15 symbols is build date/time that is unique per rom and can be used as unique serial
// Example for romver 0160EC20010704
// 20010704-160707,ROMconf,PS20160EC20010704.bin,kuma@rom-server/~/f10k/g/app/rom
// 20010704-160707 can be used as unique ID for Bios
extern std::string BiosSerial;
extern std::string BiosPath;
extern bool LoadBIOS();
// Copies of the BIOS ROM. Because the EE can write to the ROM area, we need to copy it on reset.
// If we ever support read-only physical mappings, we can remove this.
extern std::vector<u8> BiosRom;
extern bool IsBIOS(const char* filename, u32& version, std::string& description, u32& region, std::string& zone);
extern bool IsBIOSAvailable(const std::string& full_path);
extern bool LoadBIOS();
extern void CopyBIOSToMemory();

View File

@ -2220,6 +2220,9 @@ static void recRecompile(const u32 startpc)
if (recPtr >= (recMem->GetPtrEnd() - _64kb))
eeRecNeedsReset = true;
if (HWADDR(startpc) == VMManager::Internal::GetCurrentELFEntryPoint())
VMManager::Internal::EntryPointCompilingOnCPUThread();
if (eeRecNeedsReset)
{
eeRecNeedsReset = false;
@ -2229,9 +2232,6 @@ static void recRecompile(const u32 startpc)
xSetPtr(recPtr);
recPtr = xGetAlignedCallTarget();
if (0x8000d618 == startpc)
DbgCon.WriteLn("Compiling block @ 0x%08x", startpc);
s_pCurBlock = PC_GETBLOCK(startpc);
pxAssert(s_pCurBlock->GetFnptr() == (uptr)JITCompile || s_pCurBlock->GetFnptr() == (uptr)JITCompileInBlock);
@ -2254,7 +2254,7 @@ static void recRecompile(const u32 startpc)
if (g_eeloadMain && HWADDR(startpc) == HWADDR(g_eeloadMain))
{
xFastCall((void*)eeloadHook);
if (g_SkipBiosHack)
if (VMManager::Internal::IsFastBootInProgress())
{
// There are four known versions of EELOAD, identifiable by the location of the 'jal' to the EELOAD function which
// calls ExecPS2(). The function itself is at the same address in all BIOSs after v1.00-v1.10.
@ -2274,14 +2274,6 @@ static void recRecompile(const u32 startpc)
if (g_eeloadExec && HWADDR(startpc) == HWADDR(g_eeloadExec))
xFastCall((void*)eeloadHook2);
// this is the only way patches get applied, doesn't depend on a hack
if (g_GameLoading && HWADDR(startpc) == ElfEntry)
{
Console.WriteLn("Elf entry point @ 0x%08x about to get recompiled. Load patches first.", startpc);
xFastCall((void*)eeGameStarting);
VMManager::Internal::EntryPointCompilingOnCPUThread();
}
g_branch = 0;
// reset recomp state variables

View File

@ -137,8 +137,8 @@ void Host::OnVMResumed()
{
}
void Host::OnGameChanged(const std::string& disc_path, const std::string& elf_override, const std::string& game_serial,
const std::string& game_name, u32 game_crc)
void Host::OnGameChanged(const std::string& title, const std::string& elf_override, const std::string& disc_path,
const std::string& disc_serial, u32 disc_crc, u32 current_crc)
{
}