From b2d224abfc6359f42c82de24c5c7fa4e69e94602 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 29 Oct 2020 22:05:09 +1000 Subject: [PATCH] System: Set BIOS before resetting Fixes incorrect first instruction executing in interpreter mode. --- src/core/bios.cpp | 54 ++++++++++++++++++++++++--------------------- src/core/bios.h | 8 +++---- src/core/system.cpp | 30 ++++++++++++------------- 3 files changed, 47 insertions(+), 45 deletions(-) diff --git a/src/core/bios.cpp b/src/core/bios.cpp index 6aa17f8e5..d9c9ef0f7 100644 --- a/src/core/bios.cpp +++ b/src/core/bios.cpp @@ -143,16 +143,16 @@ bool IsValidHashForRegion(ConsoleRegion region, const Hash& hash) return (ii->region == ConsoleRegion::Auto || ii->region == region); } -void PatchBIOS(Image& bios, u32 address, u32 value, u32 mask /*= UINT32_C(0xFFFFFFFF)*/) +void 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; - Assert(phys_address >= BIOS_BASE && offset < BIOS_SIZE); + Assert(phys_address >= BIOS_BASE && (offset + sizeof(u32)) <= image_size); u32 existing_value; - std::memcpy(&existing_value, &bios[offset], sizeof(existing_value)); + std::memcpy(&existing_value, &image[offset], sizeof(existing_value)); u32 new_value = (existing_value & ~mask) | value; - std::memcpy(&bios[offset], &new_value, sizeof(new_value)); + std::memcpy(&image[offset], &new_value, sizeof(new_value)); SmallString old_disasm, new_disasm; CPU::DisassembleInstruction(&old_disasm, address, existing_value); @@ -161,7 +161,7 @@ void PatchBIOS(Image& bios, u32 address, u32 value, u32 mask /*= UINT32_C(0xFFFF old_disasm.GetCharArray(), new_value, new_disasm.GetCharArray()); } -bool PatchBIOSEnableTTY(Image& image, const Hash& hash) +bool PatchBIOSEnableTTY(u8* image, u32 image_size, const Hash& hash) { const ImageInfo* ii = GetImageInfoForHash(hash); if (!ii) @@ -171,12 +171,12 @@ bool PatchBIOSEnableTTY(Image& image, const Hash& hash) } Log_InfoPrintf("Patching BIOS to enable TTY/printf"); - PatchBIOS(image, 0x1FC06F0C, 0x24010001); - PatchBIOS(image, 0x1FC06F14, 0xAF81A9C0); + PatchBIOS(image, image_size, 0x1FC06F0C, 0x24010001); + PatchBIOS(image, image_size, 0x1FC06F14, 0xAF81A9C0); return true; } -bool PatchBIOSFastBoot(Image& image, const Hash& hash) +bool PatchBIOSFastBoot(u8* image, u32 image_size, const Hash& hash) { const ImageInfo* ii = GetImageInfoForHash(hash); if (!ii) @@ -187,42 +187,46 @@ bool PatchBIOSFastBoot(Image& image, const Hash& hash) // Replace the shell entry point with a return back to the bootstrap. Log_InfoPrintf("Patching BIOS to skip intro"); - PatchBIOS(image, 0x1FC18000, 0x03E00008); - PatchBIOS(image, 0x1FC18004, 0x00000000); + PatchBIOS(image, image_size, 0x1FC18000, 0x03E00008); + PatchBIOS(image, image_size, 0x1FC18004, 0x00000000); return true; } -bool PatchBIOSForEXE(Image& image, u32 r_pc, u32 r_gp, u32 r_sp, u32 r_fp) +bool 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)) + // pc has to be done first because we can't load it in the delay slot - PatchBIOS(image, 0xBFC06FF0, UINT32_C(0x3C080000) | r_pc >> 16); // lui $t0, (r_pc >> 16) - PatchBIOS(image, 0xBFC06FF4, UINT32_C(0x35080000) | (r_pc & UINT32_C(0xFFFF))); // ori $t0, $t0, (r_pc & 0xFFFF) - PatchBIOS(image, 0xBFC06FF8, UINT32_C(0x3C1C0000) | r_gp >> 16); // lui $gp, (r_gp >> 16) - PatchBIOS(image, 0xBFC06FFC, UINT32_C(0x379C0000) | (r_gp & UINT32_C(0xFFFF))); // ori $gp, $gp, (r_gp & 0xFFFF) + PATCH(0xBFC06FF0, UINT32_C(0x3C080000) | r_pc >> 16); // lui $t0, (r_pc >> 16) + PATCH(0xBFC06FF4, UINT32_C(0x35080000) | (r_pc & UINT32_C(0xFFFF))); // ori $t0, $t0, (r_pc & 0xFFFF) + PATCH(0xBFC06FF8, UINT32_C(0x3C1C0000) | r_gp >> 16); // lui $gp, (r_gp >> 16) + PATCH(0xBFC06FFC, UINT32_C(0x379C0000) | (r_gp & UINT32_C(0xFFFF))); // ori $gp, $gp, (r_gp & 0xFFFF) if (r_sp != 0) { - PatchBIOS(image, 0xBFC07000, UINT32_C(0x3C1D0000) | r_sp >> 16); // lui $sp, (r_sp >> 16) - PatchBIOS(image, 0xBFC07004, UINT32_C(0x37BD0000) | (r_sp & UINT32_C(0xFFFF))); // ori $sp, $sp, (r_sp & 0xFFFF) + PATCH(0xBFC07000, UINT32_C(0x3C1D0000) | r_sp >> 16); // lui $sp, (r_sp >> 16) + PATCH(0xBFC07004, UINT32_C(0x37BD0000) | (r_sp & UINT32_C(0xFFFF))); // ori $sp, $sp, (r_sp & 0xFFFF) } else { - PatchBIOS(image, 0xBFC07000, UINT32_C(0x00000000)); // nop - PatchBIOS(image, 0xBFC07004, UINT32_C(0x00000000)); // nop + PATCH(0xBFC07000, UINT32_C(0x00000000)); // nop + PATCH(0xBFC07004, UINT32_C(0x00000000)); // nop } if (r_fp != 0) { - PatchBIOS(image, 0xBFC07008, UINT32_C(0x3C1E0000) | r_fp >> 16); // lui $fp, (r_fp >> 16) - PatchBIOS(image, 0xBFC0700C, UINT32_C(0x01000008)); // jr $t0 - PatchBIOS(image, 0xBFC07010, UINT32_C(0x37DE0000) | (r_fp & UINT32_C(0xFFFF))); // ori $fp, $fp, (r_fp & 0xFFFF) + PATCH(0xBFC07008, UINT32_C(0x3C1E0000) | r_fp >> 16); // lui $fp, (r_fp >> 16) + PATCH(0xBFC0700C, UINT32_C(0x01000008)); // jr $t0 + PATCH(0xBFC07010, UINT32_C(0x37DE0000) | (r_fp & UINT32_C(0xFFFF))); // ori $fp, $fp, (r_fp & 0xFFFF) } else { - PatchBIOS(image, 0xBFC07008, UINT32_C(0x00000000)); // nop - PatchBIOS(image, 0xBFC0700C, UINT32_C(0x01000008)); // jr $t0 - PatchBIOS(image, 0xBFC07010, UINT32_C(0x00000000)); // nop + PATCH(0xBFC07008, UINT32_C(0x00000000)); // nop + PATCH(0xBFC0700C, UINT32_C(0x01000008)); // jr $t0 + PATCH(0xBFC07010, UINT32_C(0x00000000)); // nop } +#undef PATCH + return true; } diff --git a/src/core/bios.h b/src/core/bios.h index 417c95df5..ee298399f 100644 --- a/src/core/bios.h +++ b/src/core/bios.h @@ -59,11 +59,11 @@ std::optional GetHashForFile(const char* filename); const ImageInfo* GetImageInfoForHash(const Hash& hash); bool IsValidHashForRegion(ConsoleRegion region, const Hash& hash); -void PatchBIOS(Image& image, u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF)); +void PatchBIOS(u8* image, u32 image_size, u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF)); -bool PatchBIOSEnableTTY(Image& image, const Hash& hash); -bool PatchBIOSFastBoot(Image& image, const Hash& hash); -bool PatchBIOSForEXE(Image& image, u32 r_pc, u32 r_gp, u32 r_sp, u32 r_fp); +bool PatchBIOSEnableTTY(u8* image, u32 image_size, const Hash& hash); +bool PatchBIOSFastBoot(u8* image, u32 image_size, const Hash& hash); +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); } // namespace BIOS \ No newline at end of file diff --git a/src/core/system.cpp b/src/core/system.cpp index 9e7c3c20f..2ab9b981c 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -49,9 +49,9 @@ SystemBootParameters::~SystemBootParameters() = default; namespace System { -static bool LoadEXE(const char* filename, std::vector& bios_image); -static bool LoadEXEFromBuffer(const void* buffer, u32 buffer_size, std::vector& bios_image); -static bool LoadPSF(const char* filename, std::vector& bios_image); +static bool LoadEXE(const char* filename); +static bool LoadEXEFromBuffer(const void* buffer, u32 buffer_size); +static bool LoadPSF(const char* filename); static bool SetExpansionROM(const char* filename); /// Opens CD image, preloading if needed. @@ -661,6 +661,7 @@ bool Boot(const SystemBootParameters& params) return false; } + Bus::SetBIOS(*bios_image); UpdateControllers(); UpdateMemoryCards(); Reset(); @@ -668,16 +669,16 @@ bool Boot(const SystemBootParameters& params) // Enable tty by patching bios. const BIOS::Hash bios_hash = BIOS::GetHash(*bios_image); if (g_settings.bios_patch_tty_enable) - BIOS::PatchBIOSEnableTTY(*bios_image, bios_hash); + BIOS::PatchBIOSEnableTTY(Bus::g_bios, Bus::BIOS_SIZE, bios_hash); // Load EXE late after BIOS. - if (exe_boot && !LoadEXE(params.filename.c_str(), *bios_image)) + if (exe_boot && !LoadEXE(params.filename.c_str())) { g_host_interface->ReportFormattedError("Failed to load EXE file '%s'", params.filename.c_str()); Shutdown(); return false; } - else if (psf_boot && !LoadPSF(params.filename.c_str(), *bios_image)) + else if (psf_boot && !LoadPSF(params.filename.c_str())) { g_host_interface->ReportFormattedError("Failed to load PSF file '%s'", params.filename.c_str()); Shutdown(); @@ -690,12 +691,9 @@ bool Boot(const SystemBootParameters& params) if (g_cdrom.HasMedia() && (params.override_fast_boot.has_value() ? params.override_fast_boot.value() : g_settings.bios_patch_fast_boot)) { - BIOS::PatchBIOSFastBoot(*bios_image, bios_hash); + BIOS::PatchBIOSFastBoot(Bus::g_bios, Bus::BIOS_SIZE, bios_hash); } - // Load the patched BIOS up. - Bus::SetBIOS(*bios_image); - // Good to go. s_state = State::Running; return true; @@ -1266,7 +1264,7 @@ void ResetPerformanceCounters() s_last_throttle_time = 0; } -bool LoadEXE(const char* filename, std::vector& bios_image) +bool LoadEXE(const char* filename) { std::FILE* fp = FileSystem::OpenCFile(filename, "rb"); if (!fp) @@ -1319,10 +1317,10 @@ bool LoadEXE(const char* filename, std::vector& bios_image) const u32 r_gp = header.initial_gp; const u32 r_sp = header.initial_sp_base + header.initial_sp_offset; const u32 r_fp = header.initial_sp_base + header.initial_sp_offset; - return BIOS::PatchBIOSForEXE(bios_image, r_pc, r_gp, r_sp, r_fp); + return BIOS::PatchBIOSForEXE(Bus::g_bios, Bus::BIOS_SIZE, r_pc, r_gp, r_sp, r_fp); } -bool LoadEXEFromBuffer(const void* buffer, u32 buffer_size, std::vector& bios_image) +bool LoadEXEFromBuffer(const void* buffer, u32 buffer_size) { const u8* buffer_ptr = static_cast(buffer); const u8* buffer_end = static_cast(buffer) + buffer_size; @@ -1370,10 +1368,10 @@ bool LoadEXEFromBuffer(const void* buffer, u32 buffer_size, std::vector& bio const u32 r_gp = header.initial_gp; const u32 r_sp = header.initial_sp_base + header.initial_sp_offset; const u32 r_fp = header.initial_sp_base + header.initial_sp_offset; - return BIOS::PatchBIOSForEXE(bios_image, r_pc, r_gp, r_sp, r_fp); + return BIOS::PatchBIOSForEXE(Bus::g_bios, Bus::BIOS_SIZE, r_pc, r_gp, r_sp, r_fp); } -bool LoadPSF(const char* filename, std::vector& bios_image) +bool LoadPSF(const char* filename) { Log_InfoPrintf("Loading PSF file from '%s'", filename); @@ -1382,7 +1380,7 @@ bool LoadPSF(const char* filename, std::vector& bios_image) return false; const std::vector& exe_data = psf.GetProgramData(); - return LoadEXEFromBuffer(exe_data.data(), static_cast(exe_data.size()), bios_image); + return LoadEXEFromBuffer(exe_data.data(), static_cast(exe_data.size())); } bool SetExpansionROM(const char* filename)