Skip to content
Permalink
Browse files

Merge pull request #4614 from jackoalan/gba-hle-cleanup

DSP: Clean up GBA crypto HLE implementation
  • Loading branch information...
Parlane committed Jan 16, 2017
2 parents ed7589c + 3869eec commit 3415a1ca18a9fc8b366ec6860b20ed29b8cfa4f1
Showing with 93 additions and 66 deletions.
  1. +45 −62 Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp
  2. +48 −4 Source/Core/Core/HW/DSPHLE/UCodes/UCodes.h
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.

#include "Core/HW/DSPHLE/UCodes/GBA.h"
#include "Common/Align.h"
#include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
@@ -15,75 +16,57 @@ namespace HLE
{
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);
}
// Nonce challenge (first read from GBA, hence already little-endian)
const u32 challenge = HLEMemory_Read_U32LE(address);

s32 rounded_sub = ((sec_params.length + 7) & ~7) - 0x200;
u16 size = (rounded_sub < 0) ? 0 : rounded_sub >> 3;
// Palette of pulsing logo on GBA during transmission [0,6]
const u32 logo_palette = HLEMemory_Read_U32(address + 4);

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);
// Speed and direction of palette interpolation [-4,4]
const u32 logo_speed_32 = HLEMemory_Read_U32(address + 8);

u16 final11 = 0, final12 = 0;
final11 = x11 | ((t >> 8) & 0xff00) | 0x8080;
final12 = x12 | 0x8080;
// Length of JoyBoot program to upload
const u32 length = HLEMemory_Read_U32(address + 12);

if ((final12 & 0x200) != 0)
{
x22 = final11 ^ 0x6f64;
x23 = final12 ^ 0x6573;
}
else
{
x22 = final11 ^ 0x6177;
x23 = final12 ^ 0x614b;
}
// Address to return results to game
const u32 dest_addr = HLEMemory_Read_U32(address + 16);

// Unwrap key from challenge using 'sedo' magic number (to encrypt JoyBoot program)
const u32 key = challenge ^ 0x6f646573;
HLEMemory_Write_U32(dest_addr, key);

// Pack palette parameters
u16 palette_speed_coded;
const s16 logo_speed = static_cast<s8>(logo_speed_32);
if (logo_speed < 0)
palette_speed_coded = ((-logo_speed + 2) * 2) | (logo_palette << 4);
else if (logo_speed == 0)
palette_speed_coded = (logo_palette * 2) | 0x70;
else // logo_speed > 0
palette_speed_coded = ((logo_speed - 1) * 2) | (logo_palette << 4);

// JoyBoot ROMs start with a padded header; this is the length beyond that header
const s32 length_no_header = Common::AlignUp(length, 8) - 0x200;

// The JoyBus protocol transmits in 4-byte packets while flipping a state flag;
// so the GBA BIOS counts the program length in 8-byte packet-pairs
const u16 packet_pair_count = (length_no_header < 0) ? 0 : length_no_header / 8;
palette_speed_coded |= (packet_pair_count & 0x4000) >> 14;

// Pack together encoded transmission parameters
u32 t1 = (((packet_pair_count << 16) | 0x3f80) & 0x3f80ffff) * 2;
t1 += (static_cast<s16>(static_cast<s8>(t1 >> 8)) & packet_pair_count) << 16;
const u32 t2 = ((palette_speed_coded & 0xff) << 16) + (t1 & 0xff0000) + ((t1 >> 8) & 0xffff00);
u32 t3 = palette_speed_coded << 16 | ((t2 << 8) & 0xff000000) | (t1 >> 16) | 0x80808080;

// 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);
// Wrap with 'Kawa' or 'sedo' (Kawasedo is the author of the BIOS cipher)
t3 ^= ((t3 & 0x200) != 0 ? 0x6f646573 : 0x6177614b);
HLEMemory_Write_U32(dest_addr + 4, t3);

// 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);
DEBUG_LOG(DSPHLE, "\n%08x -> challenge: %08x, len: %08x, dest_addr: %08x, "
"palette: %08x, speed: %08x key: %08x, auth_code: %08x",
address, challenge, length, dest_addr, logo_palette, logo_speed_32, key, t3);
}

GBAUCode::GBAUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc)
@@ -35,7 +35,15 @@ inline u8 HLEMemory_Read_U8(u32 address)
return Memory::m_pRAM[address & Memory::RAM_MASK];
}

inline u16 HLEMemory_Read_U16(u32 address)
inline void HLEMemory_Write_U8(u32 address, u8 value)
{
if (ExramRead(address))
Memory::m_pEXRAM[address & Memory::EXRAM_MASK] = value;
else
Memory::m_pRAM[address & Memory::RAM_MASK] = value;
}

inline u16 HLEMemory_Read_U16LE(u32 address)
{
u16 value;

@@ -44,10 +52,28 @@ inline u16 HLEMemory_Read_U16(u32 address)
else
std::memcpy(&value, &Memory::m_pRAM[address & Memory::RAM_MASK], sizeof(u16));

return Common::swap16(value);
return value;
}

inline u32 HLEMemory_Read_U32(u32 address)
inline u16 HLEMemory_Read_U16(u32 address)
{
return Common::swap16(HLEMemory_Read_U16LE(address));
}

inline void HLEMemory_Write_U16LE(u32 address, u16 value)
{
if (ExramRead(address))
std::memcpy(&Memory::m_pEXRAM[address & Memory::EXRAM_MASK], &value, sizeof(u16));
else
std::memcpy(&Memory::m_pRAM[address & Memory::RAM_MASK], &value, sizeof(u16));
}

inline void HLEMemory_Write_U16(u32 address, u16 value)
{
HLEMemory_Write_U16LE(address, Common::swap16(value));
}

inline u32 HLEMemory_Read_U32LE(u32 address)
{
u32 value;

@@ -56,7 +82,25 @@ inline u32 HLEMemory_Read_U32(u32 address)
else
std::memcpy(&value, &Memory::m_pRAM[address & Memory::RAM_MASK], sizeof(u32));

return Common::swap32(value);
return value;
}

inline u32 HLEMemory_Read_U32(u32 address)
{
return Common::swap32(HLEMemory_Read_U32LE(address));
}

inline void HLEMemory_Write_U32LE(u32 address, u32 value)
{
if (ExramRead(address))
std::memcpy(&Memory::m_pEXRAM[address & Memory::EXRAM_MASK], &value, sizeof(u32));
else
std::memcpy(&Memory::m_pRAM[address & Memory::RAM_MASK], &value, sizeof(u32));
}

inline void HLEMemory_Write_U32(u32 address, u32 value)
{
HLEMemory_Write_U32LE(address, Common::swap32(value));
}

inline void* HLEMemory_Get_Pointer(u32 address)

0 comments on commit 3415a1c

Please sign in to comment.
You can’t perform that action at this time.