diff --git a/CHANGES b/CHANGES index 1d8523743..b184ec92e 100644 --- a/CHANGES +++ b/CHANGES @@ -46,6 +46,7 @@ Bugfixes: - GBA Memory: Partially revert prefetch changes (fixes mgba.io/i/840) - PSP2: Fix issues causing poor audio - Wii: Fix screen tear when unpausing + - GBA: Fix some GBA ROM misdetection (fixes mgba.io/i/978) Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/src/gba/gba.c b/src/gba/gba.c index 196aa8493..1390fd31c 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -33,6 +33,9 @@ const uint32_t GBA_COMPONENT_MAGIC = 0x1000000; static const size_t GBA_ROM_MAGIC_OFFSET = 3; static const uint8_t GBA_ROM_MAGIC[] = { 0xEA }; +static const size_t GBA_ROM_MAGIC_OFFSET2 = 0xB2; +static const uint8_t GBA_ROM_MAGIC2[] = { 0x96 }; + static const size_t GBA_MB_MAGIC_OFFSET = 0xC0; static void GBAInit(void* cpu, struct mCPUComponent* component); @@ -543,17 +546,48 @@ bool GBAIsROM(struct VFile* vf) { if (!vf) { return false; } + + uint8_t signature[sizeof(GBA_ROM_MAGIC) + sizeof(GBA_ROM_MAGIC2)]; if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET, SEEK_SET) < 0) { return false; } - uint8_t signature[sizeof(GBA_ROM_MAGIC)]; - if (vf->read(vf, &signature, sizeof(signature)) != sizeof(signature)) { + if (vf->read(vf, &signature, sizeof(GBA_ROM_MAGIC)) != sizeof(GBA_ROM_MAGIC)) { return false; } + if (memcmp(signature, GBA_ROM_MAGIC, sizeof(GBA_ROM_MAGIC)) != 0) { + return false; + } + + if (vf->seek(vf, GBA_ROM_MAGIC_OFFSET2, SEEK_SET) < 0) { + return false; + } + if (vf->read(vf, &signature, sizeof(GBA_ROM_MAGIC2)) != sizeof(GBA_ROM_MAGIC2)) { + return false; + } + if (memcmp(signature, GBA_ROM_MAGIC2, sizeof(GBA_ROM_MAGIC2)) != 0) { + // If the signature byte is missing then we must be using an unfixed ROM + uint32_t buffer[0x9C / sizeof(uint32_t)]; + if (vf->seek(vf, 0x4, SEEK_SET) < 0) { + return false; + } + if (vf->read(vf, &buffer, sizeof(buffer)) != sizeof(buffer)) { + return false; + } + uint32_t bits = 0; + size_t i; + for (i = 0; i < sizeof(buffer) / sizeof(*buffer); ++i) { + bits |= buffer[i]; + } + if (bits) { + return false; + } + } + + if (GBAIsBIOS(vf)) { return false; } - return memcmp(signature, GBA_ROM_MAGIC, sizeof(signature)) == 0; + return true; } bool GBAIsMB(struct VFile* vf) {