|
|
|
@ -11,10 +11,9 @@
|
|
|
|
|
#include <cerrno>
|
|
|
|
|
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<u32>(image.size()));
|
|
|
|
|
digest.Final(hash.bytes);
|
|
|
|
|
return hash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<Image> LoadImageFromFile(const char* filename)
|
|
|
|
|
std::optional<BIOS::Image> BIOS::LoadImageFromFile(const char* filename)
|
|
|
|
|
{
|
|
|
|
|
Image ret(BIOS_SIZE);
|
|
|
|
|
auto fp = FileSystem::OpenManagedCFile(filename, "rb");
|
|
|
|
@ -123,39 +129,37 @@ std::optional<Image> 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<Hash> 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<std::vector<u8>> BIOS::GetBIOSImage(ConsoleRegion region)
|
|
|
|
|
{
|
|
|
|
|
std::string bios_name;
|
|
|
|
@ -312,11 +300,9 @@ std::optional<std::vector<u8>> 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<std::vector<u8>> 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<std::pair<std::string, const BIOS::ImageInfo*>> 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|