mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-25 15:15:40 +00:00
System: Fix triple popup on missing BIOS
This commit is contained in:
parent
be920acf38
commit
318fd0b0fd
|
@ -1,16 +1,20 @@
|
|||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> and contributors.
|
||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> and contributors.
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "bios.h"
|
||||
#include "cpu_disasm.h"
|
||||
#include "host.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/file_system.h"
|
||||
#include "common/log.h"
|
||||
#include "common/md5_digest.h"
|
||||
#include "common/path.h"
|
||||
#include "cpu_disasm.h"
|
||||
#include "host.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
Log_SetChannel(BIOS);
|
||||
|
||||
static constexpr BIOS::Hash MakeHashFromString(const char str[])
|
||||
|
@ -164,13 +168,13 @@ BIOS::Hash BIOS::GetImageHash(const BIOS::Image& image)
|
|||
return hash;
|
||||
}
|
||||
|
||||
std::optional<BIOS::Image> BIOS::LoadImageFromFile(const char* filename)
|
||||
std::optional<BIOS::Image> BIOS::LoadImageFromFile(const char* filename, Error* error)
|
||||
{
|
||||
Image ret(BIOS_SIZE);
|
||||
auto fp = FileSystem::OpenManagedCFile(filename, "rb");
|
||||
auto fp = FileSystem::OpenManagedCFile(filename, "rb", error);
|
||||
if (!fp)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to open BIOS image '%s', errno=%d", filename, errno);
|
||||
Error::AddPrefixFmt(error, "Failed to open BIOS '{}': ", Path::GetFileName(filename));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -180,14 +184,15 @@ std::optional<BIOS::Image> BIOS::LoadImageFromFile(const char* filename)
|
|||
|
||||
if (size != BIOS_SIZE && size != BIOS_SIZE_PS2 && size != BIOS_SIZE_PS3)
|
||||
{
|
||||
Log_ErrorPrintf("BIOS image '%s' size mismatch, expecting either %u or %u or %u bytes but got %u bytes", filename,
|
||||
BIOS_SIZE, BIOS_SIZE_PS2, BIOS_SIZE_PS3, size);
|
||||
Error::SetStringFmt(error, "BIOS image '{}' size mismatch, expecting either {} or {} bytes but got {} bytes",
|
||||
Path::GetFileName(filename), static_cast<unsigned>(BIOS_SIZE),
|
||||
static_cast<unsigned>(BIOS_SIZE_PS2), size);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (std::fread(ret.data(), 1, ret.size(), fp.get()) != ret.size())
|
||||
{
|
||||
Log_ErrorPrintf("Failed to read BIOS image '%s'", filename);
|
||||
Error::SetErrno(error, TinyString::from_format("Failed to read BIOS '{}': ", Path::GetFileName(filename)), errno);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -326,7 +331,7 @@ DiscRegion BIOS::GetPSExeDiscRegion(const PSEXEHeader& header)
|
|||
return DiscRegion::Other;
|
||||
}
|
||||
|
||||
std::optional<std::vector<u8>> BIOS::GetBIOSImage(ConsoleRegion region)
|
||||
std::optional<std::vector<u8>> BIOS::GetBIOSImage(ConsoleRegion region, Error* error)
|
||||
{
|
||||
std::string bios_name;
|
||||
switch (region)
|
||||
|
@ -345,31 +350,37 @@ std::optional<std::vector<u8>> BIOS::GetBIOSImage(ConsoleRegion region)
|
|||
break;
|
||||
}
|
||||
|
||||
std::optional<Image> image;
|
||||
|
||||
if (bios_name.empty())
|
||||
{
|
||||
// auto-detect
|
||||
return FindBIOSImageInDirectory(region, EmuFolders::Bios.c_str());
|
||||
image = FindBIOSImageInDirectory(region, EmuFolders::Bios.c_str(), error);
|
||||
}
|
||||
|
||||
// try the configured path
|
||||
std::optional<Image> image = LoadImageFromFile(Path::Combine(EmuFolders::Bios, bios_name).c_str());
|
||||
if (!image.has_value())
|
||||
else
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("Error", TRANSLATE("HostInterface", "Failed to load configured BIOS file '%s'"),
|
||||
bios_name.c_str());
|
||||
return std::nullopt;
|
||||
// try the configured path
|
||||
image = LoadImageFromFile(Path::Combine(EmuFolders::Bios, bios_name).c_str(), error);
|
||||
}
|
||||
|
||||
// verify region
|
||||
if (image.has_value())
|
||||
{
|
||||
const ImageInfo* ii = GetInfoForImage(image.value());
|
||||
if (!ii || !IsValidBIOSForRegion(region, ii->region))
|
||||
Log_WarningPrintf("BIOS '%s' does not match region. This may cause issues.", bios_name.c_str());
|
||||
{
|
||||
Log_WarningFmt("BIOS region {} does not match requested region {}. This may cause issues.",
|
||||
ii ? Settings::GetConsoleRegionName(ii->region) : "UNKNOWN",
|
||||
Settings::GetConsoleRegionName(region));
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
std::optional<std::vector<u8>> BIOS::FindBIOSImageInDirectory(ConsoleRegion region, const char* directory)
|
||||
std::optional<std::vector<u8>> BIOS::FindBIOSImageInDirectory(ConsoleRegion region, const char* directory, Error* error)
|
||||
{
|
||||
Log_InfoPrintf("Searching for a %s BIOS in '%s'...", Settings::GetConsoleRegionDisplayName(region), directory);
|
||||
Log_InfoFmt("Searching for a {} BIOS in '{}'...", Settings::GetConsoleRegionName(region), directory);
|
||||
|
||||
FileSystem::FindResultsArray results;
|
||||
FileSystem::FindFiles(
|
||||
|
@ -383,20 +394,21 @@ std::optional<std::vector<u8>> BIOS::FindBIOSImageInDirectory(ConsoleRegion regi
|
|||
{
|
||||
if (fd.Size != BIOS_SIZE && fd.Size != BIOS_SIZE_PS2 && fd.Size != BIOS_SIZE_PS3)
|
||||
{
|
||||
Log_WarningPrintf("Skipping '%s': incorrect size", fd.FileName.c_str());
|
||||
Log_WarningFmt("Skipping '{}': incorrect size", fd.FileName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string full_path(Path::Combine(directory, fd.FileName));
|
||||
std::optional<Image> found_image = LoadImageFromFile(full_path.c_str());
|
||||
std::optional<Image> found_image = LoadImageFromFile(full_path.c_str(), nullptr);
|
||||
if (!found_image)
|
||||
continue;
|
||||
|
||||
const ImageInfo* ii = GetInfoForImage(found_image.value());
|
||||
if (ii && IsValidBIOSForRegion(region, ii->region))
|
||||
{
|
||||
Log_InfoPrintf("Using BIOS '%s': %s", fd.FileName.c_str(), ii->description);
|
||||
return found_image;
|
||||
Log_InfoFmt("Using BIOS '{}': {}", fd.FileName.c_str(), ii->description);
|
||||
fallback_image = std::move(found_image);
|
||||
return fallback_image;
|
||||
}
|
||||
|
||||
// don't let an unknown bios take precedence over a known one
|
||||
|
@ -410,53 +422,24 @@ std::optional<std::vector<u8>> BIOS::FindBIOSImageInDirectory(ConsoleRegion regi
|
|||
|
||||
if (!fallback_image.has_value())
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("Error", TRANSLATE("HostInterface", "No BIOS image found for %s region"),
|
||||
Settings::GetConsoleRegionDisplayName(region));
|
||||
return std::nullopt;
|
||||
Error::SetStringFmt(error, TRANSLATE_FS("System", "No BIOS image found for {} region."),
|
||||
Settings::GetConsoleRegionName(region));
|
||||
return fallback_image;
|
||||
}
|
||||
|
||||
if (!fallback_info)
|
||||
{
|
||||
Log_WarningPrintf("Using unknown BIOS '%s'. This may crash.", fallback_path.c_str());
|
||||
Log_WarningFmt("Using unknown BIOS '{}'. This may crash.", Path::GetFileName(fallback_path));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_WarningPrintf("Falling back to possibly-incompatible image '%s': %s", fallback_path.c_str(),
|
||||
Log_WarningFmt("Falling back to possibly-incompatible image '{}': {}", Path::GetFileName(fallback_path),
|
||||
fallback_info->description);
|
||||
}
|
||||
|
||||
return fallback_image;
|
||||
}
|
||||
|
||||
std::string BIOS::FindBIOSPathWithHash(const char* directory, const Hash& hash)
|
||||
{
|
||||
FileSystem::FindResultsArray files;
|
||||
FileSystem::FindFiles(directory, "*",
|
||||
FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RELATIVE_PATHS, &files);
|
||||
|
||||
std::string ret;
|
||||
|
||||
for (FILESYSTEM_FIND_DATA& fd : files)
|
||||
{
|
||||
if (fd.Size != BIOS_SIZE && fd.Size != BIOS_SIZE_PS2 && fd.Size != BIOS_SIZE_PS3)
|
||||
continue;
|
||||
|
||||
std::string full_path(Path::Combine(directory, fd.FileName));
|
||||
std::optional<Image> found_image = LoadImageFromFile(full_path.c_str());
|
||||
if (!found_image)
|
||||
continue;
|
||||
|
||||
const BIOS::Hash found_hash = GetImageHash(found_image.value());
|
||||
if (found_hash == hash)
|
||||
{
|
||||
ret = std::move(full_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, const BIOS::ImageInfo*>> BIOS::FindBIOSImagesInDirectory(const char* directory)
|
||||
{
|
||||
std::vector<std::pair<std::string, const ImageInfo*>> results;
|
||||
|
@ -471,7 +454,7 @@ std::vector<std::pair<std::string, const BIOS::ImageInfo*>> BIOS::FindBIOSImages
|
|||
continue;
|
||||
|
||||
std::string full_path(Path::Combine(directory, fd.FileName));
|
||||
std::optional<Image> found_image = LoadImageFromFile(full_path.c_str());
|
||||
std::optional<Image> found_image = LoadImageFromFile(full_path.c_str(), nullptr);
|
||||
if (!found_image)
|
||||
continue;
|
||||
|
||||
|
@ -484,5 +467,5 @@ std::vector<std::pair<std::string, const BIOS::ImageInfo*>> BIOS::FindBIOSImages
|
|||
|
||||
bool BIOS::HasAnyBIOSImages()
|
||||
{
|
||||
return FindBIOSImageInDirectory(ConsoleRegion::Auto, EmuFolders::Bios.c_str()).has_value();
|
||||
return FindBIOSImageInDirectory(ConsoleRegion::Auto, EmuFolders::Bios.c_str(), nullptr).has_value();
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>.
|
||||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>.
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
class Error;
|
||||
|
||||
namespace BIOS {
|
||||
enum : u32
|
||||
{
|
||||
|
@ -58,7 +62,7 @@ struct PSEXEHeader
|
|||
static_assert(sizeof(PSEXEHeader) == 0x800);
|
||||
#pragma pack(pop)
|
||||
|
||||
std::optional<Image> LoadImageFromFile(const char* filename);
|
||||
std::optional<Image> LoadImageFromFile(const char* filename, Error* error);
|
||||
Hash GetImageHash(const Image& image);
|
||||
|
||||
const ImageInfo* GetInfoForImage(const Image& image);
|
||||
|
@ -74,14 +78,11 @@ bool IsValidPSExeHeader(const PSEXEHeader& header, u32 file_size);
|
|||
DiscRegion GetPSExeDiscRegion(const PSEXEHeader& header);
|
||||
|
||||
/// Loads the BIOS image for the specified region.
|
||||
std::optional<std::vector<u8>> GetBIOSImage(ConsoleRegion region);
|
||||
std::optional<std::vector<u8>> GetBIOSImage(ConsoleRegion region, Error* error);
|
||||
|
||||
/// Searches for a BIOS image for the specified region in the specified directory. If no match is found, the first
|
||||
/// BIOS image within 512KB and 4MB will be used.
|
||||
std::optional<std::vector<u8>> FindBIOSImageInDirectory(ConsoleRegion region, const char* directory);
|
||||
|
||||
/// Returns a BIOS image which matches the specified hash.
|
||||
std::string FindBIOSPathWithHash(const char* directory, const BIOS::Hash& hash);
|
||||
std::optional<std::vector<u8>> FindBIOSImageInDirectory(ConsoleRegion region, const char* directory, Error* error);
|
||||
|
||||
/// Returns a list of filenames and descriptions for BIOS images in a directory.
|
||||
std::vector<std::pair<std::string, const BIOS::ImageInfo*>> FindBIOSImagesInDirectory(const char* directory);
|
||||
|
|
|
@ -102,7 +102,7 @@ static std::string GetExecutableNameForImage(IsoReader& iso, bool strip_subdirec
|
|||
static bool ReadExecutableFromImage(IsoReader& iso, std::string* out_executable_name,
|
||||
std::vector<u8>* out_executable_data);
|
||||
|
||||
static bool LoadBIOS(const std::string& override_bios_path);
|
||||
static bool LoadBIOS(const std::string& override_bios_path, Error* error);
|
||||
static void InternalReset();
|
||||
static void ClearRunningGame();
|
||||
static void DestroySystem();
|
||||
|
@ -1465,7 +1465,7 @@ bool System::BootSystem(SystemBootParameters parameters, Error* error)
|
|||
}
|
||||
|
||||
// Load BIOS image.
|
||||
if (!LoadBIOS(parameters.override_bios))
|
||||
if (!LoadBIOS(parameters.override_bios, error))
|
||||
{
|
||||
s_state = State::Shutdown;
|
||||
ClearRunningGame();
|
||||
|
@ -2251,20 +2251,29 @@ bool System::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di
|
|||
return !sw.HasError();
|
||||
}
|
||||
|
||||
bool System::LoadBIOS(const std::string& override_bios_path)
|
||||
bool System::LoadBIOS(const std::string& override_bios_path, Error* error)
|
||||
{
|
||||
std::optional<BIOS::Image> bios_image(
|
||||
override_bios_path.empty() ? BIOS::GetBIOSImage(s_region) : FileSystem::ReadBinaryFile(override_bios_path.c_str()));
|
||||
std::optional<BIOS::Image> bios_image;
|
||||
if (!override_bios_path.empty())
|
||||
{
|
||||
bios_image = FileSystem::ReadBinaryFile(override_bios_path.c_str(), error);
|
||||
if (!bios_image.has_value())
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("Error", TRANSLATE("System", "Failed to load %s BIOS."),
|
||||
Error::AddPrefixFmt(error, TRANSLATE_FS("System", "Failed to load {} BIOS."),
|
||||
Settings::GetConsoleRegionName(s_region));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bios_image = BIOS::GetBIOSImage(s_region, error);
|
||||
if (!bios_image.has_value())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bios_image->size() != static_cast<u32>(Bus::BIOS_SIZE))
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("Error", TRANSLATE("System", "Incorrect BIOS image size"));
|
||||
Error::SetStringView(error, TRANSLATE_SV("System", "Incorrect BIOS image size"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue