GBA Memory: Prevent writing to mirrored BG VRAM (fixes #743)
Vicki Pfau vi@endrift.com
Wed, 08 May 2019 16:38:30 -0700
2 files changed,
46 insertions(+),
37 deletions(-)
M
CHANGES
→
CHANGES
@@ -7,6 +7,7 @@ - GB Video: Fix more window edge cases (fixes mgba.io/i/1346)
- GB Timer: Fix timing adjustments when writing to TAC (fixes mgba.io/i/1340) - GBA Memory: Fix writing to OBJ memory in modes 3 and 5 - GBA: Fix RTC on non-standard sized ROMs (fixes mgba.io/i/1400) + - GBA Memory: Prevent writing to mirrored BG VRAM (fixes mgba.io/i/743) Other fixes: - Qt: More app metadata fixes - Qt: Fix load recent from archive (fixes mgba.io/i/1325)
M
src/gba/memory.c
→
src/gba/memory.c
@@ -390,11 +390,15 @@ LOAD_32(value, address & (SIZE_PALETTE_RAM - 4), gba->video.palette); \
wait += waitstatesRegion[REGION_PALETTE_RAM]; #define LOAD_VRAM \ - if ((address & 0x0001FFFF) < SIZE_VRAM) { \ - LOAD_32(value, address & 0x0001FFFC, gba->video.vram); \ - } else { \ - LOAD_32(value, address & 0x00017FFC, gba->video.vram); \ + if ((address & 0x0001FFFF) >= SIZE_VRAM) { \ + if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { \ + mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load32: 0x%08X", address); \ + value = 0; \ + break; \ + } \ + address &= 0x00017FFC; \ } \ + LOAD_32(value, address & 0x0001FFFC, gba->video.vram); \ wait += waitstatesRegion[REGION_VRAM]; #define LOAD_OAM LOAD_32(value, address & (SIZE_OAM - 4), gba->video.oam.raw);@@ -520,11 +524,15 @@ case REGION_PALETTE_RAM:
LOAD_16(value, address & (SIZE_PALETTE_RAM - 2), gba->video.palette); break; case REGION_VRAM: - if ((address & 0x0001FFFF) < SIZE_VRAM) { - LOAD_16(value, address & 0x0001FFFE, gba->video.vram); - } else { - LOAD_16(value, address & 0x00017FFE, gba->video.vram); + if ((address & 0x0001FFFF) >= SIZE_VRAM) { + if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { + mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load16: 0x%08X", address); + value = 0; + break; + } + address &= 0x00017FFE; } + LOAD_16(value, address & 0x0001FFFE, gba->video.vram); break; case REGION_OAM: LOAD_16(value, address & (SIZE_OAM - 2), gba->video.oam.raw);@@ -631,11 +639,15 @@ case REGION_PALETTE_RAM:
value = ((uint8_t*) gba->video.palette)[address & (SIZE_PALETTE_RAM - 1)]; break; case REGION_VRAM: - if ((address & 0x0001FFFF) < SIZE_VRAM) { - value = ((uint8_t*) gba->video.vram)[address & 0x0001FFFF]; - } else { - value = ((uint8_t*) gba->video.vram)[address & 0x00017FFF]; + if ((address & 0x0001FFFF) >= SIZE_VRAM) { + if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { + mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load8: 0x%08X", address); + value = 0; + break; + } + address &= 0x00017FFF; } + value = ((uint8_t*) gba->video.vram)[address & 0x0001FFFF]; break; case REGION_OAM: value = ((uint8_t*) gba->video.oam.raw)[address & (SIZE_OAM - 1)];@@ -717,20 +729,18 @@ } \
wait += waitstatesRegion[REGION_PALETTE_RAM]; #define STORE_VRAM \ - if ((address & 0x0001FFFF) < SIZE_VRAM) { \ - LOAD_32(oldValue, address & 0x0001FFFC, gba->video.vram); \ - if (oldValue != value) { \ - STORE_32(value, address & 0x0001FFFC, gba->video.vram); \ - gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC) + 2); \ - gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC)); \ + if ((address & 0x0001FFFF) >= SIZE_VRAM) { \ + if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { \ + mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Store32: 0x%08X", address); \ + break; \ } \ - } else { \ - LOAD_32(oldValue, address & 0x00017FFC, gba->video.vram); \ - if (oldValue != value) { \ - STORE_32(value, address & 0x00017FFC, gba->video.vram); \ - gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC) + 2); \ - gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC)); \ - } \ + address &= 0x00017FFC; \ + } \ + LOAD_32(oldValue, address & 0x0001FFFC, gba->video.vram); \ + if (oldValue != value) { \ + STORE_32(value, address & 0x0001FFFC, gba->video.vram); \ + gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC) + 2); \ + gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC)); \ } \ wait += waitstatesRegion[REGION_VRAM];@@ -840,18 +850,17 @@ gba->video.renderer->writePalette(gba->video.renderer, address & (SIZE_PALETTE_RAM - 2), value);
} break; case REGION_VRAM: - if ((address & 0x0001FFFF) < SIZE_VRAM) { - LOAD_16(oldValue, address & 0x0001FFFE, gba->video.vram); - if (value != oldValue) { - STORE_16(value, address & 0x0001FFFE, gba->video.vram); - gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE); + if ((address & 0x0001FFFF) >= SIZE_VRAM) { + if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { + mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Store16: 0x%08X", address); + break; } - } else { - LOAD_16(oldValue, address & 0x00017FFE, gba->video.vram); - if (value != oldValue) { - STORE_16(value, address & 0x00017FFE, gba->video.vram); - gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x00017FFE); - } + address &= 0x00017FFE; + } + LOAD_16(oldValue, address & 0x0001FFFE, gba->video.vram); + if (value != oldValue) { + STORE_16(value, address & 0x0001FFFE, gba->video.vram); + gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE); } break; case REGION_OAM:@@ -939,7 +948,6 @@ GBAStore16(cpu, address & ~1, ((uint8_t) value) | ((uint8_t) value << 8), cycleCounter);
break; case REGION_VRAM: if ((address & 0x0001FFFF) >= ((GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3) ? 0x00014000 : 0x00010000)) { - // TODO: check BG mode mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address); break; }