From fbe727b0bb1645940c983449ed812012b66f225e Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 8 Aug 2015 21:21:42 +0200 Subject: [PATCH] ZeldaHLE: Support GBA crypto through command 0C. Reuses the pre-existing GBA crypto code from the separate UCode. --- Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp | 148 ++++++++++---------- Source/Core/Core/HW/DSPHLE/UCodes/GBA.h | 5 + Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp | 4 +- 3 files changed, 83 insertions(+), 74 deletions(-) diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp index a15f6e2af1..1c6d50674f 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp @@ -7,6 +7,81 @@ #include "Core/HW/DSPHLE/UCodes/GBA.h" #include "Core/HW/DSPHLE/UCodes/UCodes.h" +void ProcessGBACrypto(u32 address) +{ + struct sec_params_t + { + u16 key[2]; + u16 unk1[2]; + u16 unk2[2]; + u32 length; + u32 dest_addr; + u32 pad[3]; + } sec_params; + + // 32 bytes from mram addr to DRAM @ 0 + for (int i = 0; i < 8; i++, address += 4) + ((u32*)&sec_params)[i] = HLEMemory_Read_U32(address); + + // This is the main decrypt routine + u16 x11 = 0, x12 = 0, + x20 = 0, x21 = 0, x22 = 0, x23 = 0; + + x20 = Common::swap16(sec_params.key[0]) ^ 0x6f64; + x21 = Common::swap16(sec_params.key[1]) ^ 0x6573; + + s16 unk2 = (s8)sec_params.unk2[0]; + if (unk2 < 0) + { + x11 = ((~unk2 + 3) << 1) | (sec_params.unk1[0] << 4); + } + else if (unk2 == 0) + { + x11 = (sec_params.unk1[0] << 1) | 0x70; + } + else // unk2 > 0 + { + x11 = ((unk2 - 1) << 1) | (sec_params.unk1[0] << 4); + } + + s32 rounded_sub = ((sec_params.length + 7) & ~7) - 0x200; + u16 size = (rounded_sub < 0) ? 0 : rounded_sub >> 3; + + u32 t = (((size << 16) | 0x3f80) & 0x3f80ffff) << 1; + s16 t_low = (s8)(t >> 8); + t += (t_low & size) << 16; + x12 = t >> 16; + x11 |= (size & 0x4000) >> 14; // this would be stored in ac0.h if we weren't constrained to 32bit :) + t = ((x11 & 0xff) << 16) + ((x12 & 0xff) << 16) + (x12 << 8); + + u16 final11 = 0, final12 = 0; + final11 = x11 | ((t >> 8) & 0xff00) | 0x8080; + final12 = x12 | 0x8080; + + if ((final12 & 0x200) != 0) + { + x22 = final11 ^ 0x6f64; + x23 = final12 ^ 0x6573; + } + else + { + x22 = final11 ^ 0x6177; + x23 = final12 ^ 0x614b; + } + + // Send the result back to mram + *(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr) = Common::swap32((x20 << 16) | x21); + *(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr+4) = Common::swap32((x22 << 16) | x23); + + // Done! + DEBUG_LOG(DSPHLE, "\n%08x -> key: %08x, len: %08x, dest_addr: %08x, unk1: %08x, unk2: %08x" + " 22: %04x, 23: %04x", + address, + *(u32*)sec_params.key, sec_params.length, sec_params.dest_addr, + *(u32*)sec_params.unk1, *(u32*)sec_params.unk2, + x22, x23); +} + GBAUCode::GBAUCode(DSPHLE *dsphle, u32 crc) : UCodeInterface(dsphle, crc) { @@ -48,79 +123,8 @@ void GBAUCode::HandleMail(u32 mail) else if (nextmail_is_mramaddr) { nextmail_is_mramaddr = false; - u32 mramaddr = mail; - struct sec_params_t - { - u16 key[2]; - u16 unk1[2]; - u16 unk2[2]; - u32 length; - u32 dest_addr; - u32 pad[3]; - } sec_params; - - // 32 bytes from mram addr to DRAM @ 0 - for (int i = 0; i < 8; i++, mramaddr += 4) - ((u32*)&sec_params)[i] = HLEMemory_Read_U32(mramaddr); - - // This is the main decrypt routine - u16 x11 = 0, x12 = 0, - x20 = 0, x21 = 0, x22 = 0, x23 = 0; - - x20 = Common::swap16(sec_params.key[0]) ^ 0x6f64; - x21 = Common::swap16(sec_params.key[1]) ^ 0x6573; - - s16 unk2 = (s8)sec_params.unk2[0]; - if (unk2 < 0) - { - x11 = ((~unk2 + 3) << 1) | (sec_params.unk1[0] << 4); - } - else if (unk2 == 0) - { - x11 = (sec_params.unk1[0] << 1) | 0x70; - } - else // unk2 > 0 - { - x11 = ((unk2 - 1) << 1) | (sec_params.unk1[0] << 4); - } - - s32 rounded_sub = ((sec_params.length + 7) & ~7) - 0x200; - u16 size = (rounded_sub < 0) ? 0 : rounded_sub >> 3; - - u32 t = (((size << 16) | 0x3f80) & 0x3f80ffff) << 1; - s16 t_low = (s8)(t >> 8); - t += (t_low & size) << 16; - x12 = t >> 16; - x11 |= (size & 0x4000) >> 14; // this would be stored in ac0.h if we weren't constrained to 32bit :) - t = ((x11 & 0xff) << 16) + ((x12 & 0xff) << 16) + (x12 << 8); - - u16 final11 = 0, final12 = 0; - final11 = x11 | ((t >> 8) & 0xff00) | 0x8080; - final12 = x12 | 0x8080; - - if ((final12 & 0x200) != 0) - { - x22 = final11 ^ 0x6f64; - x23 = final12 ^ 0x6573; - } - else - { - x22 = final11 ^ 0x6177; - x23 = final12 ^ 0x614b; - } - - // Send the result back to mram - *(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr) = Common::swap32((x20 << 16) | x21); - *(u32*)HLEMemory_Get_Pointer(sec_params.dest_addr+4) = Common::swap32((x22 << 16) | x23); - - // Done! - DEBUG_LOG(DSPHLE, "\n%08x -> key: %08x, len: %08x, dest_addr: %08x, unk1: %08x, unk2: %08x" - " 22: %04x, 23: %04x", - mramaddr, - *(u32*)sec_params.key, sec_params.length, sec_params.dest_addr, - *(u32*)sec_params.unk1, *(u32*)sec_params.unk2, - x22, x23); + ProcessGBACrypto(mail); calc_done = true; m_mail_handler.PushMail(DSP_DONE); diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h index 50530134bf..751750cce1 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.h @@ -6,6 +6,11 @@ #include "Core/HW/DSPHLE/UCodes/UCodes.h" +// Computes two 32 bit integers to be returned to the game, based on the +// provided crypto parameters at the provided MRAM address. The integers are +// written back to RAM at the dest address provided in the crypto parameters. +void ProcessGBACrypto(u32 address); + struct GBAUCode : public UCodeInterface { GBAUCode(DSPHLE *dsphle, u32 crc); diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp index 8700264825..61006e9b44 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp @@ -4,6 +4,7 @@ #include "Core/ConfigManager.h" #include "Core/HW/DSPHLE/MailHandler.h" +#include "Core/HW/DSPHLE/UCodes/GBA.h" #include "Core/HW/DSPHLE/UCodes/UCodes.h" #include "Core/HW/DSPHLE/UCodes/Zelda.h" @@ -474,8 +475,7 @@ void ZeldaUCode::RunPendingCommands() case 0x0C: if (m_flags & SUPPORTS_GBA_CRYPTO) { - // TODO - NOTICE_LOG(DSPHLE, "Received an unhandled GBA crypto command, param: %08x", Read32()); + ProcessGBACrypto(Read32()); } else if (m_flags & WEIRD_CMD_0C) {