diff --git a/src/core/bios.cpp b/src/core/bios.cpp index 87222fb1f..6f1d78d9f 100644 --- a/src/core/bios.cpp +++ b/src/core/bios.cpp @@ -1,16 +1,20 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin and contributors. +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin 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 + 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::LoadImageFromFile(const char* filename) +std::optional 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::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(BIOS_SIZE), + static_cast(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> BIOS::GetBIOSImage(ConsoleRegion region) +std::optional> BIOS::GetBIOSImage(ConsoleRegion region, Error* error) { std::string bios_name; switch (region) @@ -345,31 +350,37 @@ std::optional> BIOS::GetBIOSImage(ConsoleRegion region) break; } + std::optional 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 = 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); } - 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()); + // verify region + if (image.has_value()) + { + const ImageInfo* ii = GetInfoForImage(image.value()); + if (!ii || !IsValidBIOSForRegion(region, ii->region)) + { + 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> BIOS::FindBIOSImageInDirectory(ConsoleRegion region, const char* directory) +std::optional> 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> 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 found_image = LoadImageFromFile(full_path.c_str()); + std::optional 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> 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(), - fallback_info->description); + 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 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> BIOS::FindBIOSImagesInDirectory(const char* directory) { std::vector> results; @@ -471,7 +454,7 @@ std::vector> BIOS::FindBIOSImages continue; std::string full_path(Path::Combine(directory, fd.FileName)); - std::optional found_image = LoadImageFromFile(full_path.c_str()); + std::optional found_image = LoadImageFromFile(full_path.c_str(), nullptr); if (!found_image) continue; @@ -484,5 +467,5 @@ std::vector> 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(); } diff --git a/src/core/bios.h b/src/core/bios.h index d5f114abb..7f3ca0f7d 100644 --- a/src/core/bios.h +++ b/src/core/bios.h @@ -1,13 +1,17 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin . +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin . // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once + #include "types.h" + #include #include #include #include +class Error; + namespace BIOS { enum : u32 { @@ -58,7 +62,7 @@ struct PSEXEHeader static_assert(sizeof(PSEXEHeader) == 0x800); #pragma pack(pop) -std::optional LoadImageFromFile(const char* filename); +std::optional 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> GetBIOSImage(ConsoleRegion region); +std::optional> 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> 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> FindBIOSImageInDirectory(ConsoleRegion region, const char* directory, Error* error); /// Returns a list of filenames and descriptions for BIOS images in a directory. std::vector> FindBIOSImagesInDirectory(const char* directory); diff --git a/src/core/system.cpp b/src/core/system.cpp index 30652edd6..dd44fc9bf 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -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* 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( - override_bios_path.empty() ? BIOS::GetBIOSImage(s_region) : FileSystem::ReadBinaryFile(override_bios_path.c_str())); - if (!bios_image.has_value()) + std::optional bios_image; + if (!override_bios_path.empty()) { - Host::ReportFormattedErrorAsync("Error", TRANSLATE("System", "Failed to load %s BIOS."), - Settings::GetConsoleRegionName(s_region)); - return false; + bios_image = FileSystem::ReadBinaryFile(override_bios_path.c_str(), error); + if (!bios_image.has_value()) + { + 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(Bus::BIOS_SIZE)) { - Host::ReportFormattedErrorAsync("Error", TRANSLATE("System", "Incorrect BIOS image size")); + Error::SetStringView(error, TRANSLATE_SV("System", "Incorrect BIOS image size")); return false; }