diff --git a/src/core/bios.cpp b/src/core/bios.cpp index 47cb63689..b02aa8e4e 100644 --- a/src/core/bios.cpp +++ b/src/core/bios.cpp @@ -11,10 +11,9 @@ #include Log_SetChannel(BIOS); -namespace BIOS { -static constexpr Hash MakeHashFromString(const char str[]) +static constexpr BIOS::Hash MakeHashFromString(const char str[]) { - Hash h{}; + BIOS::Hash h{}; for (int i = 0; str[i] != '\0'; i++) { u8 nibble = 0; @@ -31,7 +30,7 @@ static constexpr Hash MakeHashFromString(const char str[]) return h; } -std::string Hash::ToString() const +std::string BIOS::Hash::ToString() const { char str[33]; std::snprintf(str, sizeof(str), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", bytes[0], @@ -40,7 +39,7 @@ std::string Hash::ToString() const return str; } -static constexpr const ImageInfo s_image_infos[] = { +static constexpr const BIOS::ImageInfo s_image_info_by_hash[] = { {"SCPH-1000, DTL-H1000 (v1.0)", ConsoleRegion::NTSC_J, MakeHashFromString("239665b1a3dade1b5a52c06338011044"), true}, {"SCPH-1001, 5003, DTL-H1201, H3001 (v2.2 12-04-95 A)", ConsoleRegion::NTSC_U, MakeHashFromString("924e392ed05558ffdb115408c263dccf"), true}, @@ -85,18 +84,25 @@ static constexpr const ImageInfo s_image_infos[] = { true}, {"SCPH-1000R (v4.5 05-25-00 J)", ConsoleRegion::NTSC_J, MakeHashFromString("476d68a94ccec3b9c8303bbd1daf2810"), true}, {"PS3 (v5.0 06-23-03 A)", ConsoleRegion::Auto, MakeHashFromString("c02a6fbb1b27359f84e92fae8bc21316"), false}, - {"PS3 (v5.0 06-23-03 A)", ConsoleRegion::Auto, MakeHashFromString("81bbe60ba7a3d1cea1d48c14cbcc647b"), false}}; + {"PS3 (v5.0 06-23-03 A)", ConsoleRegion::Auto, MakeHashFromString("81bbe60ba7a3d1cea1d48c14cbcc647b"), false}, +}; -Hash GetHash(const Image& image) +// OpenBIOS is separate, because there's no fixed hash for it. So just in case something collides with a hash of zero... +// which would be unlikely. +static constexpr const BIOS::ImageInfo s_openbios_info = {"OpenBIOS", ConsoleRegion::Auto, {}, false}; +static constexpr const char s_openbios_signature[] = {'O', 'p', 'e', 'n', 'B', 'I', 'O', 'S'}; +static constexpr u32 s_openbios_signature_offset = 0x78; + +static BIOS::Hash GetHash(const BIOS::Image& image) { - Hash hash; + BIOS::Hash hash; MD5Digest digest; digest.Update(image.data(), static_cast(image.size())); digest.Final(hash.bytes); return hash; } -std::optional LoadImageFromFile(const char* filename) +std::optional BIOS::LoadImageFromFile(const char* filename) { Image ret(BIOS_SIZE); auto fp = FileSystem::OpenManagedCFile(filename, "rb"); @@ -123,39 +129,37 @@ std::optional LoadImageFromFile(const char* filename) return std::nullopt; } + Log_DevPrint(fmt::format("Hash for BIOS '{}': {}", FileSystem::GetDisplayNameFromPath(filename), GetHash(ret).ToString()).c_str()); return ret; } -std::optional GetHashForFile(const char* filename) +const BIOS::ImageInfo* BIOS::GetInfoForImage(const Image& image) { - auto image = LoadImageFromFile(filename); - if (!image) - return std::nullopt; + const Hash hash(GetHash(image)); - return GetHash(*image); -} + // check for openbios + if (image.size() >= (s_openbios_signature_offset + std::size(s_openbios_signature)) && + std::memcmp(&image[s_openbios_signature_offset], s_openbios_signature, std::size(s_openbios_signature)) == 0) + { + return &s_openbios_info; + } -const ImageInfo* GetImageInfoForHash(const Hash& hash) -{ - for (const ImageInfo& ii : s_image_infos) + for (const ImageInfo& ii : s_image_info_by_hash) { if (ii.hash == hash) return ⅈ } + Log_WarningPrintf("Unknown BIOS hash: %s", hash.ToString().c_str()); return nullptr; } -bool IsValidHashForRegion(ConsoleRegion region, const Hash& hash) +bool BIOS::IsValidBIOSForRegion(ConsoleRegion console_region, ConsoleRegion bios_region) { - const ImageInfo* ii = GetImageInfoForHash(hash); - if (!ii) - return false; - - return (ii->region == ConsoleRegion::Auto || ii->region == region); + return (bios_region == ConsoleRegion::Auto || bios_region == console_region); } -void PatchBIOS(u8* image, u32 image_size, u32 address, u32 value, u32 mask /*= UINT32_C(0xFFFFFFFF)*/) +void BIOS::PatchBIOS(u8* image, u32 image_size, u32 address, u32 value, u32 mask /*= UINT32_C(0xFFFFFFFF)*/) { const u32 phys_address = address & UINT32_C(0x1FFFFFFF); const u32 offset = phys_address - BIOS_BASE; @@ -173,30 +177,16 @@ void PatchBIOS(u8* image, u32 image_size, u32 address, u32 value, u32 mask /*= U old_disasm.GetCharArray(), new_value, new_disasm.GetCharArray()); } -bool PatchBIOSEnableTTY(u8* image, u32 image_size, const Hash& hash) +bool BIOS::PatchBIOSEnableTTY(u8* image, u32 image_size) { - const ImageInfo* ii = GetImageInfoForHash(hash); - if (!ii || !ii->patch_compatible) - { - Log_WarningPrintf("Incompatible version for TTY patch: %s", hash.ToString().c_str()); - return false; - } - Log_InfoPrintf("Patching BIOS to enable TTY/printf"); PatchBIOS(image, image_size, 0x1FC06F0C, 0x24010001); PatchBIOS(image, image_size, 0x1FC06F14, 0xAF81A9C0); return true; } -bool PatchBIOSFastBoot(u8* image, u32 image_size, const Hash& hash) +bool BIOS::PatchBIOSFastBoot(u8* image, u32 image_size) { - const ImageInfo* ii = GetImageInfoForHash(hash); - if (!ii || !ii->patch_compatible) - { - Log_WarningPrintf("Incompatible version for fast-boot patch: %s", hash.ToString().c_str()); - return false; - } - // Replace the shell entry point with a return back to the bootstrap. Log_InfoPrintf("Patching BIOS to skip intro"); PatchBIOS(image, image_size, 0x1FC18000, 0x3C011F80); // lui at, 1f80 @@ -207,7 +197,7 @@ bool PatchBIOSFastBoot(u8* image, u32 image_size, const Hash& hash) return true; } -bool PatchBIOSForEXE(u8* image, u32 image_size, u32 r_pc, u32 r_gp, u32 r_sp, u32 r_fp) +bool BIOS::PatchBIOSForEXE(u8* image, u32 image_size, u32 r_pc, u32 r_gp, u32 r_sp, u32 r_fp) { #define PATCH(offset, value) PatchBIOS(image, image_size, (offset), (value)) @@ -245,7 +235,7 @@ bool PatchBIOSForEXE(u8* image, u32 image_size, u32 r_pc, u32 r_gp, u32 r_sp, u3 return true; } -bool IsValidPSExeHeader(const PSEXEHeader& header, u32 file_size) +bool BIOS::IsValidPSExeHeader(const PSEXEHeader& header, u32 file_size) { static constexpr char expected_id[] = {'P', 'S', '-', 'X', ' ', 'E', 'X', 'E'}; if (std::memcmp(header.id, expected_id, sizeof(expected_id)) != 0) @@ -260,7 +250,7 @@ bool IsValidPSExeHeader(const PSEXEHeader& header, u32 file_size) return true; } -DiscRegion GetPSExeDiscRegion(const PSEXEHeader& header) +DiscRegion BIOS::GetPSExeDiscRegion(const PSEXEHeader& header) { static constexpr char ntsc_u_id[] = "Sony Computer Entertainment Inc. for North America area"; static constexpr char ntsc_j_id[] = "Sony Computer Entertainment Inc. for Japan area"; @@ -276,8 +266,6 @@ DiscRegion GetPSExeDiscRegion(const PSEXEHeader& header) return DiscRegion::Other; } -} // namespace BIOS - std::optional> BIOS::GetBIOSImage(ConsoleRegion region) { std::string bios_name; @@ -312,11 +300,9 @@ std::optional> BIOS::GetBIOSImage(ConsoleRegion region) return std::nullopt; } - Hash found_hash = GetHash(*image); - Log_DevPrintf("Hash for BIOS '%s': %s", bios_name.c_str(), found_hash.ToString().c_str()); - - if (!IsValidHashForRegion(region, found_hash)) - Log_WarningPrintf("Hash for BIOS '%s' does not match region. This may cause issues.", bios_name.c_str()); + 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()); return image; } @@ -346,14 +332,10 @@ std::optional> BIOS::FindBIOSImageInDirectory(ConsoleRegion regi if (!found_image) continue; - Hash found_hash = GetHash(*found_image); - Log_DevPrintf("Hash for BIOS '%s': %s", fd.FileName.c_str(), found_hash.ToString().c_str()); - - const ImageInfo* ii = GetImageInfoForHash(found_hash); - - if (IsValidHashForRegion(region, found_hash)) + const ImageInfo* ii = GetInfoForImage(found_image.value()); + if (ii && IsValidBIOSForRegion(region, ii->region)) { - Log_InfoPrintf("Using BIOS '%s': %s", fd.FileName.c_str(), ii ? ii->description : ""); + Log_InfoPrintf("Using BIOS '%s': %s", fd.FileName.c_str(), ii->description); return found_image; } @@ -405,8 +387,7 @@ std::vector> BIOS::FindBIOSImages if (!found_image) continue; - Hash found_hash = GetHash(*found_image); - const ImageInfo* ii = GetImageInfoForHash(found_hash); + const ImageInfo* ii = GetInfoForImage(found_image.value()); results.emplace_back(std::move(fd.FileName), ii); } diff --git a/src/core/bios.h b/src/core/bios.h index 8e85fcd35..3eb83cf54 100644 --- a/src/core/bios.h +++ b/src/core/bios.h @@ -55,17 +55,15 @@ struct PSEXEHeader static_assert(sizeof(PSEXEHeader) == 0x800); #pragma pack(pop) -Hash GetHash(const Image& image); std::optional LoadImageFromFile(const char* filename); -std::optional GetHashForFile(const char* filename); -const ImageInfo* GetImageInfoForHash(const Hash& hash); -bool IsValidHashForRegion(ConsoleRegion region, const Hash& hash); +const ImageInfo* GetInfoForImage(const Image& image); +bool IsValidBIOSForRegion(ConsoleRegion console_region, ConsoleRegion bios_region); void PatchBIOS(u8* image, u32 image_size, u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF)); -bool PatchBIOSEnableTTY(u8* image, u32 image_size, const Hash& hash); -bool PatchBIOSFastBoot(u8* image, u32 image_size, const Hash& hash); +bool PatchBIOSEnableTTY(u8* image, u32 image_size); +bool PatchBIOSFastBoot(u8* image, u32 image_size); bool PatchBIOSForEXE(u8* image, u32 image_size, u32 r_pc, u32 r_gp, u32 r_sp, u32 r_fp); bool IsValidPSExeHeader(const PSEXEHeader& header, u32 file_size); diff --git a/src/core/system.cpp b/src/core/system.cpp index c16c777d9..2ef782cd5 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1197,16 +1197,18 @@ bool System::BootSystem(SystemBootParameters parameters) // Allow controller analog mode for EXEs and PSFs. s_running_bios = s_running_game_path.empty() && !exe_boot && !psf_boot; - Bus::SetBIOS(*bios_image); + Bus::SetBIOS(bios_image.value()); UpdateControllers(); UpdateMemoryCardTypes(); UpdateMultitaps(); InternalReset(); // Enable tty by patching bios. - const BIOS::Hash bios_hash = BIOS::GetHash(*bios_image); - if (g_settings.bios_patch_tty_enable) - BIOS::PatchBIOSEnableTTY(Bus::g_bios, Bus::BIOS_SIZE, bios_hash); + const BIOS::ImageInfo* bios_info = BIOS::GetInfoForImage(bios_image.value()); + if (bios_info && bios_info->patch_compatible) + BIOS::PatchBIOSEnableTTY(Bus::g_bios, Bus::BIOS_SIZE); + else + Log_ErrorPrintf("Not patching TTY enable, as BIOS is not patch compatible."); // Load EXE late after BIOS. if (exe_boot && !LoadEXE(parameters.filename.c_str())) @@ -1228,7 +1230,10 @@ bool System::BootSystem(SystemBootParameters parameters) if (g_cdrom.HasMedia() && (parameters.override_fast_boot.has_value() ? parameters.override_fast_boot.value() : g_settings.bios_patch_fast_boot)) { - BIOS::PatchBIOSFastBoot(Bus::g_bios, Bus::BIOS_SIZE, bios_hash); + if (bios_info && bios_info->patch_compatible) + BIOS::PatchBIOSFastBoot(Bus::g_bios, Bus::BIOS_SIZE); + else + Log_ErrorPrintf("Not patching fast boot, as BIOS is not patch compatible."); } // Good to go.