mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-09-21 16:58:45 +00:00
Improved Triforce IPL compatibility and simplify logic changes
Refactored AMMediaboard.cpp to remove legacy memory patching, introducing cryptographic key handling for Triforce IPL commands Enhanced DVDInterface.cpp to ensure cover closure during initialization for Triforce IPL Adjusted VideoInterface.cpp region flags for Triforce IPL compatibility Added detailed comments to clarify new logic and removed outdated code Added loading of region for Triforce games from boot.id Prevent test menu access without SegaBoot present Changed insert coin button to X
This commit is contained in:
parent
49541626ff
commit
994fd7d900
7 changed files with 90 additions and 46 deletions
|
@ -375,7 +375,8 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename)
|
|||
constexpr u32 PAL_v1_0 = 0x4F319F43;
|
||||
// DOL-101(EUR) (PAL Revision 1.2)
|
||||
constexpr u32 PAL_v1_2 = 0xAD1B7F16;
|
||||
constexpr u32 Triforce = 0xD1883221; // The Triforce's special IPL
|
||||
// Triforce Arcade IPL (DEV Revision 1.0)
|
||||
constexpr u32 Triforce = 0xD1883221;
|
||||
|
||||
// Load the IPL ROM dump, limited to 2MiB which is the size of the official IPLs.
|
||||
constexpr size_t max_ipl_size = 2 * 1024 * 1024;
|
||||
|
|
|
@ -83,6 +83,7 @@ namespace AMMediaboard
|
|||
|
||||
static bool s_firmwaremap = false;
|
||||
static bool s_segaboot = false;
|
||||
static bool s_test_menu = false;
|
||||
static SOCKET s_namco_cam = 0;
|
||||
static u32 s_timeouts[3] = {20000, 20000, 20000};
|
||||
static u32 s_last_error = SSC_SUCCESS;
|
||||
|
@ -186,6 +187,7 @@ void Init(void)
|
|||
|
||||
s_segaboot = false;
|
||||
s_firmwaremap = false;
|
||||
s_test_menu = false;
|
||||
|
||||
s_last_error = SSC_SUCCESS;
|
||||
|
||||
|
@ -230,6 +232,8 @@ void Init(void)
|
|||
|
||||
u64 length = std::min<u64>(sega_boot.GetSize(), sizeof(s_firmware));
|
||||
sega_boot.ReadBytes(s_firmware, length);
|
||||
|
||||
s_test_menu = true;
|
||||
}
|
||||
|
||||
u8* InitDIMM(u32 size)
|
||||
|
@ -305,7 +309,7 @@ static s32 NetDIMMConnect(int fd, struct sockaddr_in* addr, int len)
|
|||
{
|
||||
addr->sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
/*
|
||||
BUG: An invalid family value is used
|
||||
BUG: An invalid family value is being used
|
||||
*/
|
||||
addr->sin_family = htons(AF_INET);
|
||||
s_namco_cam = fd;
|
||||
|
@ -395,44 +399,10 @@ u32 ExecuteCommand(std::array<u32, 3>& DICMDBUF, u32 address, u32 length)
|
|||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& memory = system.GetMemory();
|
||||
auto& ppc_state = system.GetPPCState();
|
||||
auto& jit_interface = system.GetJitInterface();
|
||||
|
||||
/*
|
||||
The triforce IPL sends these commands first
|
||||
01010000 00000101 00000000
|
||||
01010000 00000000 0000ffff
|
||||
*/
|
||||
if (s_GCAM_key_a == 0)
|
||||
{
|
||||
/*
|
||||
Since it is currently unknown how the seed is created
|
||||
we have to patch out the crypto.
|
||||
*/
|
||||
if (memory.Read_U32(0x8131ecf4))
|
||||
{
|
||||
memory.Write_U32(0, 0x8131ecf4);
|
||||
memory.Write_U32(0, 0x8131ecf8);
|
||||
memory.Write_U32(0, 0x8131ecfC);
|
||||
memory.Write_U32(0, 0x8131ebe0);
|
||||
memory.Write_U32(0, 0x8131ed6c);
|
||||
memory.Write_U32(0, 0x8131ed70);
|
||||
memory.Write_U32(0, 0x8131ed74);
|
||||
|
||||
memory.Write_U32(0x4E800020, 0x813025C8);
|
||||
memory.Write_U32(0x4E800020, 0x81302674);
|
||||
|
||||
ppc_state.iCache.Invalidate(memory, jit_interface, 0x813025C8);
|
||||
ppc_state.iCache.Invalidate(memory, jit_interface, 0x81302674);
|
||||
|
||||
HLE::Patch(system, 0x813048B8, "OSReport");
|
||||
HLE::Patch(system, 0x8130095C, "OSReport"); // Apploader
|
||||
}
|
||||
}
|
||||
|
||||
DICMDBUF[0] ^= s_GCAM_key_a;
|
||||
DICMDBUF[1] ^= s_GCAM_key_b;
|
||||
// length ^= s_GCAM_key_c; // DMA length is always plain
|
||||
DICMDBUF[2] ^= s_GCAM_key_c;
|
||||
|
||||
u32 seed = DICMDBUF[0] >> 16;
|
||||
|
||||
|
@ -440,6 +410,22 @@ u32 ExecuteCommand(std::array<u32, 3>& DICMDBUF, u32 address, u32 length)
|
|||
s_GCAM_key_b *= seed;
|
||||
s_GCAM_key_c *= seed;
|
||||
|
||||
/*
|
||||
Key setup for Triforce IPL:
|
||||
These RAM offset always hold the keys for the next command and since it sends two dummy
|
||||
commands before a real read we can just use the key from RAM without missing any real commands.
|
||||
*/
|
||||
if (s_GCAM_key_a == 0)
|
||||
{
|
||||
if (memory.Read_U32(0))
|
||||
{
|
||||
HLE::Patch(system, 0x813048B8, "OSReport");
|
||||
HLE::Patch(system, 0x8130095C, "OSReport"); // Apploader
|
||||
|
||||
InitKeys(memory.Read_U32(0), memory.Read_U32(4), memory.Read_U32(8));
|
||||
}
|
||||
}
|
||||
|
||||
DICMDBUF[0] <<= 24;
|
||||
DICMDBUF[1] <<= 2;
|
||||
|
||||
|
@ -669,7 +655,6 @@ u32 ExecuteCommand(std::array<u32, 3>& DICMDBUF, u32 address, u32 length)
|
|||
// Empty reply
|
||||
case AMMBCommand::Unknown_103:
|
||||
break;
|
||||
// Network Commands
|
||||
case AMMBCommand::Accept:
|
||||
{
|
||||
u32 fd = s_sockets[SocketCheck(media_buffer_32[2])];
|
||||
|
@ -710,8 +695,8 @@ u32 ExecuteCommand(std::array<u32, 3>& DICMDBUF, u32 address, u32 length)
|
|||
*(u32*)(&addr.sin_addr) = Common::swap32(*(u32*)(&addr.sin_addr));
|
||||
|
||||
/*
|
||||
Triforce games usually use hardcoded IPs
|
||||
This is replaced to listen to the ANY address instead
|
||||
Triforce titles typically rely on hardcoded IP addresses.
|
||||
This behavior has been modified to bind to the wildcard address instead.
|
||||
*/
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
|
@ -1825,7 +1810,10 @@ u32 GetGameType(void)
|
|||
}
|
||||
// never reached
|
||||
}
|
||||
|
||||
bool GetTestMenu(void)
|
||||
{
|
||||
return s_test_menu;
|
||||
}
|
||||
void Shutdown(void)
|
||||
{
|
||||
if (s_netcfg)
|
||||
|
|
|
@ -212,5 +212,6 @@ void InitKeys(u32 KeyA, u32 KeyB, u32 KeyC);
|
|||
u32 ExecuteCommand(std::array<u32, 3>& DICMDBUF, u32 Address, u32 Length);
|
||||
u32 GetGameType(void);
|
||||
u32 GetMediaType(void);
|
||||
bool GetTestMenu(void);
|
||||
void Shutdown(void);
|
||||
}; // namespace AMMediaboard
|
||||
|
|
|
@ -291,6 +291,9 @@ void DVDInterface::Init()
|
|||
if (m_enable_gcam)
|
||||
{
|
||||
AMMediaboard::Init();
|
||||
|
||||
// The Trifoce IPL expects the cover to be closed
|
||||
m_DICVR.Hex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1547,7 +1547,17 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
|
||||
// Test button
|
||||
if (PadStatus.button & PAD_TRIGGER_Z)
|
||||
message.addData(0x80);
|
||||
{
|
||||
// Trying to access the test menu without SegaBoot present will cause a crash
|
||||
if (AMMediaboard::GetTestMenu())
|
||||
{
|
||||
message.addData(0x80);
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlertFmt("Test menu is disabled due missing SegaBoot");
|
||||
}
|
||||
}
|
||||
else
|
||||
message.addData((u32)0x00);
|
||||
|
||||
|
@ -1833,11 +1843,11 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
{
|
||||
GCPadStatus PadStatus;
|
||||
PadStatus = Pad::GetStatus(i);
|
||||
if ((PadStatus.button & PAD_TRIGGER_Z) && !m_coin_pressed[i])
|
||||
if ((PadStatus.button & PAD_BUTTON_X) && !m_coin_pressed[i])
|
||||
{
|
||||
m_coin[i]++;
|
||||
}
|
||||
m_coin_pressed[i] = PadStatus.button & PAD_TRIGGER_Z;
|
||||
m_coin_pressed[i] = PadStatus.button & PAD_BUTTON_X;
|
||||
message.addData((m_coin[i] >> 8) & 0x3f);
|
||||
message.addData(m_coin[i] & 0xff);
|
||||
}
|
||||
|
|
|
@ -163,7 +163,16 @@ void VideoInterfaceManager::Preset(bool _bNTSC)
|
|||
|
||||
// Say component cable is plugged
|
||||
m_dtv_status.component_plugged = Config::Get(Config::SYSCONF_PROGRESSIVE_SCAN);
|
||||
m_dtv_status.ntsc_j = region == DiscIO::Region::NTSC_J;
|
||||
|
||||
// Triforce IPL requires this to be set
|
||||
if (region == DiscIO::Region::DEV || region == DiscIO::Region::NTSC_J)
|
||||
{
|
||||
m_dtv_status.ntsc_j = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dtv_status.ntsc_j = false;
|
||||
}
|
||||
|
||||
m_fb_width.Hex = 0;
|
||||
m_border_hblank.Hex = 0;
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
namespace DiscIO
|
||||
{
|
||||
Region g_triforce_region;
|
||||
|
||||
VolumeGC::VolumeGC(std::unique_ptr<BlobReader> reader)
|
||||
: m_reader(std::move(reader)), m_is_triforce(false)
|
||||
{
|
||||
|
@ -40,6 +42,7 @@ VolumeGC::VolumeGC(std::unique_ptr<BlobReader> reader)
|
|||
};
|
||||
|
||||
m_converted_banner = [this] { return LoadBannerFile(); };
|
||||
g_triforce_region = Region::Unknown;
|
||||
|
||||
constexpr u32 BTID_MAGIC = 0x44495442;
|
||||
auto tmp_fs = GetFileSystem(PARTITION_NONE);
|
||||
|
@ -103,6 +106,9 @@ std::string VolumeGC::GetTriforceID() const
|
|||
|
||||
Region VolumeGC::GetRegion() const
|
||||
{
|
||||
if (g_triforce_region != Region::Unknown)
|
||||
return g_triforce_region;
|
||||
|
||||
return RegionCodeToRegion(m_reader->ReadSwapped<u32>(0x458));
|
||||
}
|
||||
|
||||
|
@ -187,6 +193,32 @@ std::array<u8, 20> VolumeGC::GetSyncHash() const
|
|||
|
||||
VolumeGC::ConvertedGCBanner VolumeGC::LoadBannerFile() const
|
||||
{
|
||||
/*
|
||||
There is at least one Triforce game that has an opening.bnr file but from a different game.
|
||||
Check for boot.id and then just skip loading the banner.
|
||||
*/
|
||||
u8 bootid[0x1E0];
|
||||
const u64 bootid_size = ReadFile(*this, PARTITION_NONE, "boot.id", reinterpret_cast<u8*>(&bootid), sizeof(bootid));
|
||||
if (bootid_size)
|
||||
{
|
||||
// Load region from the file
|
||||
switch (bootid[0x38])
|
||||
{
|
||||
default:
|
||||
case 0x02: // JAPAN
|
||||
case 0x08: // ASIA
|
||||
g_triforce_region = Region::NTSC_J;
|
||||
break;
|
||||
case 0x0E: // USA
|
||||
g_triforce_region = Region::NTSC_U;
|
||||
break;
|
||||
case 0x0C: // EXPORT
|
||||
g_triforce_region = Region::PAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
GCBanner banner_file;
|
||||
const u64 file_size = ReadFile(*this, PARTITION_NONE, "opening.bnr",
|
||||
reinterpret_cast<u8*>(&banner_file), sizeof(GCBanner));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue