mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 05:32:47 +00:00
104 lines
3.5 KiB
C
104 lines
3.5 KiB
C
#include "gba.h"
|
|
#include "sha.h"
|
|
#include "sdmmc.h"
|
|
|
|
#define AGBLOGO_SHA256 \
|
|
0x08, 0xA0, 0x15, 0x3C, 0xFD, 0x6B, 0x0E, 0xA5, 0x4B, 0x93, 0x8F, 0x7D, 0x20, 0x99, 0x33, 0xFA, \
|
|
0x84, 0x9D, 0xA0, 0xD5, 0x6F, 0x5A, 0x34, 0xC4, 0x81, 0x06, 0x0C, 0x9F, 0xF2, 0xFA, 0xD8, 0x18
|
|
|
|
u32 ValidateAgbSaveHeader(AgbSaveHeader* header) {
|
|
static u8 magic[] = { AGBSAVE_MAGIC };
|
|
|
|
// basic checks
|
|
if ((memcmp(header->magic, magic, sizeof(magic)) != 0) ||
|
|
(header->unknown0 != 1) || (header->save_start != 0x200) ||
|
|
(header->save_size > AGBSAVE_MAX_SSIZE) || !(GBASAVE_VALID(header->save_size)))
|
|
return 1;
|
|
|
|
// reserved area checks
|
|
// disabled due to a weird quirk https://github.com/d0k3/GodMode9/issues/412
|
|
// for (u32 i = 0; i < sizeof(header->reserved0); i++) if (header->reserved0[i] != 0xFF) return 1;
|
|
// for (u32 i = 0; i < sizeof(header->reserved1); i++) if (header->reserved1[i] != 0xFF) return 1;
|
|
// for (u32 i = 0; i < sizeof(header->reserved2); i++) if (header->reserved2[i] != 0xFF) return 1;
|
|
// for (u32 i = 0; i < sizeof(header->reserved3); i++) if (header->reserved3[i] != 0xFF) return 1;
|
|
|
|
// all fine if arriving here
|
|
return 0;
|
|
}
|
|
|
|
// http://problemkaputt.de/gbatek.htm#gbacartridgeheader
|
|
u32 ValidateAgbHeader(AgbHeader* agb) {
|
|
static const u8 logo_sha[0x20] = { AGBLOGO_SHA256 };
|
|
u8 logo[0x9C] __attribute__((aligned(4)));
|
|
|
|
// check fixed value
|
|
if (agb->fixed != 0x96) return 1;
|
|
|
|
// header checksum
|
|
u8* hdr = (u8*) agb;
|
|
u8 checksum = 0x00 - 0x19;
|
|
for (u32 i = 0xA0; i < 0xBD; i++)
|
|
checksum -= hdr[i];
|
|
if (agb->checksum != checksum) return 1;
|
|
|
|
// logo SHA check
|
|
memcpy(logo, agb->logo, 0x9C);
|
|
logo[0x98] &= ~0x84;
|
|
logo[0x9A] &= ~0x03;
|
|
if (sha_cmp(logo_sha, logo, 0x9C, SHA256_MODE) != 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* u32 ValidateAgbVc(void* data, u32 len) {
|
|
const u8 magic[] = { GBAVC_MAGIC };
|
|
|
|
if (len < sizeof(AgbHeader) + sizeof(AgbVcFooter))
|
|
return 1;
|
|
|
|
AgbHeader* header = (AgbHeader*) data;
|
|
AgbVcFooter* footer = (AgbVcFooter*) (((u8*) data) + len - sizeof(AgbVcFooter));
|
|
|
|
if ((ValidateAgbHeader(header) != 0) || (memcmp(footer->magic, magic, sizeof(magic)) != 0) ||
|
|
(footer->rom_size != len - sizeof(AgbVcFooter)))
|
|
return 1;
|
|
|
|
return 0;
|
|
} */
|
|
|
|
// basically reverse ValidateAgbSaveHeader()
|
|
/* u32 BuildAgbSaveHeader(AgbSaveHeader* header, u64 title_id, u32 save_size) {
|
|
const u8 magic[] = { AGBSAVE_MAGIC };
|
|
|
|
memset(header, 0x00, sizeof(AgbSaveHeader));
|
|
memset(header->reserved0, 0xFF, sizeof(header->reserved0));
|
|
memset(header->reserved1, 0xFF, sizeof(header->reserved1));
|
|
memset(header->reserved2, 0xFF, sizeof(header->reserved2));
|
|
memset(header->reserved3, 0xFF, sizeof(header->reserved3));
|
|
|
|
memcpy(header->magic, magic, sizeof(magic));
|
|
header->unknown0 = 0x01;
|
|
header->title_id = title_id;
|
|
header->save_start = 0x200;
|
|
header->save_size = save_size;
|
|
|
|
sdmmc_get_cid(0, (u32*) (void*) &(header->sd_cid));
|
|
|
|
return 0;
|
|
} */
|
|
|
|
// see: http://problemkaputt.de/gbatek.htm#gbacartridgeheader
|
|
const char* AgbDestStr(const char* code) {
|
|
switch(code[3]) {
|
|
case 'J': return STR_REGION_JAPAN;
|
|
case 'E': return STR_REGION_AMERICAS;
|
|
case 'P': return STR_REGION_EUROPE;
|
|
case 'D': return STR_REGION_GERMANY;
|
|
case 'F': return STR_REGION_FRANCE;
|
|
case 'I': return STR_REGION_ITALY;
|
|
case 'S': return STR_REGION_SPAIN;
|
|
default: return STR_REGION_UNKNOWN;
|
|
}
|
|
}
|