GBA DMA: Fix invalid DMA reads (fixes #142)

This commit is contained in:
Vicki Pfau 2017-11-01 16:55:31 -07:00
parent 20754b772e
commit 679630701e
5 changed files with 38 additions and 15 deletions

View File

@ -23,6 +23,7 @@ Bugfixes:
- GB Video: Only trigger STAT write IRQs when screen is on (fixes mgba.io/i/912) - GB Video: Only trigger STAT write IRQs when screen is on (fixes mgba.io/i/912)
- GBA Cheats: Fix PARv3 slide codes (fixes mgba.io/i/919) - GBA Cheats: Fix PARv3 slide codes (fixes mgba.io/i/919)
- GBA Video: OBJWIN can change blend params after OBJ is drawn (fixes mgba.io/i/921) - GBA Video: OBJWIN can change blend params after OBJ is drawn (fixes mgba.io/i/921)
- GBA DMA: Fix invalid DMA reads (fixes mgba.io/i/142)
Misc: Misc:
- GBA Timer: Use global cycles for timers - GBA Timer: Use global cycles for timers
- GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)

View File

@ -106,6 +106,7 @@ struct GBAMemory {
struct GBADMA dma[4]; struct GBADMA dma[4];
struct mTimingEvent dmaEvent; struct mTimingEvent dmaEvent;
int activeDMA; int activeDMA;
uint32_t dmaTransferRegister;
bool mirroring; bool mirroring;
}; };

View File

@ -169,7 +169,8 @@ mLOG_DECLARE_CATEGORY(GBA_STATE);
* | bits 4 - 8: GB Player transmit position * | bits 4 - 8: GB Player transmit position
* | bits 9 - 23: Reserved * | bits 9 - 23: Reserved
* 0x002C4 - 0x002C7: Game Boy Player next event * 0x002C4 - 0x002C7: Game Boy Player next event
* 0x002C8 - 0x002DF: Reserved (leave zero) * 0x002C8 - 0x002CB: Current DMA transfer word
* 0x002CC - 0x002DF: Reserved (leave zero)
* 0x002E0 - 0x002EF: Savedata state * 0x002E0 - 0x002EF: Savedata state
* | 0x002E0 - 0x002E0: Savedata type * | 0x002E0 - 0x002E0: Savedata type
* | 0x002E1 - 0x002E1: Savedata command (see savedata.h) * | 0x002E1 - 0x002E1: Savedata command (see savedata.h)
@ -293,7 +294,9 @@ struct GBASerializedState {
uint32_t gbpNextEvent; uint32_t gbpNextEvent;
} hw; } hw;
uint32_t reservedHardware[6]; uint32_t dmaTransferRegister;
uint32_t reservedHardware[5];
struct { struct {
uint8_t type; uint8_t type;

View File

@ -46,6 +46,8 @@ uint32_t GBADMAWriteSAD(struct GBA* gba, int dma, uint32_t address) {
address &= 0x0FFFFFFE; address &= 0x0FFFFFFE;
if (_isValidDMASAD(dma, address)) { if (_isValidDMASAD(dma, address)) {
memory->dma[dma].source = address; memory->dma[dma].source = address;
} else {
memory->dma[dma].source = 0;
} }
return memory->dma[dma].source; return memory->dma[dma].source;
} }
@ -242,31 +244,44 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) {
info->when += cycles; info->when += cycles;
gba->performingDMA = 1 | (number << 1); gba->performingDMA = 1 | (number << 1);
uint32_t word;
if (width == 4) { if (width == 4) {
word = cpu->memory.load32(cpu, source, 0); if (source) {
gba->bus = word; memory->dmaTransferRegister = cpu->memory.load32(cpu, source, 0);
cpu->memory.store32(cpu, dest, word, 0); }
gba->bus = memory->dmaTransferRegister;
cpu->memory.store32(cpu, dest, memory->dmaTransferRegister, 0);
memory->dmaTransferRegister &= 0xFFFF0000;
memory->dmaTransferRegister |= memory->dmaTransferRegister >> 16;
} else { } else {
if (sourceRegion == REGION_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) { if (sourceRegion == REGION_CART2_EX && memory->savedata.type == SAVEDATA_EEPROM) {
word = GBASavedataReadEEPROM(&memory->savedata);
cpu->memory.store16(cpu, dest, word, 0);
} else if (destRegion == REGION_CART2_EX) {
if (memory->savedata.type == SAVEDATA_AUTODETECT) { if (memory->savedata.type == SAVEDATA_AUTODETECT) {
mLOG(GBA_MEM, INFO, "Detected EEPROM savegame"); mLOG(GBA_MEM, INFO, "Detected EEPROM savegame");
GBASavedataInitEEPROM(&memory->savedata, gba->realisticTiming); GBASavedataInitEEPROM(&memory->savedata, gba->realisticTiming);
} }
word = cpu->memory.load16(cpu, source, 0); memory->dmaTransferRegister = GBASavedataReadEEPROM(&memory->savedata);
GBASavedataWriteEEPROM(&memory->savedata, word, wordsRemaining);
} else { } else {
word = cpu->memory.load16(cpu, source, 0); if (source) {
cpu->memory.store16(cpu, dest, word, 0); memory->dmaTransferRegister = cpu->memory.load16(cpu, source, 0);
}
} }
gba->bus = word | (word << 16); if (destRegion == REGION_CART2_EX) {
if (memory->savedata.type == SAVEDATA_AUTODETECT) {
mLOG(GBA_MEM, INFO, "Detected EEPROM savegame");
GBASavedataInitEEPROM(&memory->savedata, gba->realisticTiming);
}
GBASavedataWriteEEPROM(&memory->savedata, memory->dmaTransferRegister, wordsRemaining);
} else {
cpu->memory.store16(cpu, dest, memory->dmaTransferRegister, 0);
}
memory->dmaTransferRegister |= memory->dmaTransferRegister << 16;
gba->bus = memory->dmaTransferRegister;
} }
int sourceOffset = DMA_OFFSET[GBADMARegisterGetSrcControl(info->reg)] * width; int sourceOffset = DMA_OFFSET[GBADMARegisterGetSrcControl(info->reg)] * width;
int destOffset = DMA_OFFSET[GBADMARegisterGetDestControl(info->reg)] * width; int destOffset = DMA_OFFSET[GBADMARegisterGetDestControl(info->reg)] * width;
source += sourceOffset; if (source) {
source += sourceOffset;
}
dest += destOffset; dest += destOffset;
--wordsRemaining; --wordsRemaining;
gba->performingDMA = 0; gba->performingDMA = 0;

View File

@ -939,6 +939,8 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
STORE_32(gba->memory.dma[i].when, 0, &state->dma[i].when); STORE_32(gba->memory.dma[i].when, 0, &state->dma[i].when);
} }
state->dmaTransferRegister = gba->memory.dmaTransferRegister;
GBAHardwareSerialize(&gba->memory.hw, state); GBAHardwareSerialize(&gba->memory.hw, state);
} }
@ -984,6 +986,7 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
} }
} }
GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]); GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]);
gba->memory.dmaTransferRegister = state->dmaTransferRegister;
GBADMAUpdate(gba); GBADMAUpdate(gba);
GBAHardwareDeserialize(&gba->memory.hw, state); GBAHardwareDeserialize(&gba->memory.hw, state);
} }