GBA Unlicensed Carts: Prevent multicarts from remapping after being locked

This commit is contained in:
Vicki Pfau 2024-11-23 19:46:44 -08:00
parent 822a2c8df5
commit a5e3e746b2
5 changed files with 20 additions and 8 deletions

View File

@ -42,6 +42,7 @@ struct GBAMulticart {
uint8_t offset;
uint8_t size;
bool sramActive;
bool locked;
uint8_t unk;
};

View File

@ -295,6 +295,7 @@ DECL_BITS(GBASerializedUnlCartFlags, Subtype, 5, 3);
DECL_BITFIELD(GBASerializedMulticartFlags, uint32_t);
DECL_BIT(GBASerializedMulticartFlags, DustSettling, 0);
DECL_BIT(GBASerializedMulticartFlags, Locked, 1);
DECL_BITFIELD(GBASerializedSavedataFlags, uint8_t);
DECL_BITS(GBASerializedSavedataFlags, FlashState, 0, 2);

View File

@ -69,6 +69,7 @@ void GBAUnlCartReset(struct GBA* gba) {
gba->memory.unl.multi.bank = 0;
gba->memory.unl.multi.offset = 0;
gba->memory.unl.multi.size = 0;
gba->memory.unl.multi.locked = false;
gba->memory.rom = gba->memory.unl.multi.rom;
gba->memory.romSize = GBA_SIZE_ROM0;
}
@ -93,22 +94,25 @@ void GBAUnlCartWriteSRAM(struct GBA* gba, uint32_t address, uint8_t value) {
mLOG(GBA_MEM, DEBUG, "Multicart writing SRAM %06X:%02X", address, value);
switch (address) {
case GBA_MULTICART_CFG_BANK:
unl->multi.bank = value >> 4;
if (!(unl->multi.offset & 0x80)) {
if (!unl->multi.locked) {
unl->multi.bank = value >> 4;
mTimingDeschedule(&gba->timing, &unl->multi.settle);
mTimingSchedule(&gba->timing, &unl->multi.settle, MULTI_SETTLE);
}
break;
case GBA_MULTICART_CFG_OFFSET:
unl->multi.offset = value;
if (!(unl->multi.offset & 0x80)) {
if (!unl->multi.locked) {
unl->multi.offset = value;
mTimingDeschedule(&gba->timing, &unl->multi.settle);
mTimingSchedule(&gba->timing, &unl->multi.settle, MULTI_SETTLE);
if (unl->multi.offset & 0x80) {
unl->multi.locked = true;
}
}
break;
case GBA_MULTICART_CFG_SIZE:
unl->multi.size = 0x40 - (value & 0x3F);
if (!(unl->multi.offset & 0x80)) {
if (!unl->multi.locked) {
mTimingDeschedule(&gba->timing, &unl->multi.settle);
mTimingSchedule(&gba->timing, &unl->multi.settle, MULTI_SETTLE);
}
@ -167,6 +171,7 @@ static void _multicartSettle(struct mTiming* timing, void* context, uint32_t cyc
void GBAUnlCartSerialize(const struct GBA* gba, struct GBASerializedState* state) {
GBASerializedUnlCartFlags flags = 0;
GBASerializedMulticartFlags multiFlags = 0;
const struct GBAUnlCart* unl = &gba->memory.unl;
switch (unl->type) {
case GBA_UNL_CART_NONE:
@ -187,11 +192,13 @@ void GBAUnlCartSerialize(const struct GBA* gba, struct GBASerializedState* state
state->multicart.sramActive = unl->multi.sramActive;
state->multicart.unk = unl->multi.unk;
state->multicart.currentSize = gba->memory.romSize / MULTI_BLOCK;
multiFlags = GBASerializedMulticartFlagsSetLocked(flags, unl->multi.locked);
STORE_16((gba->memory.rom - unl->multi.rom) / 0x20000, 0, &state->multicart.currentOffset);
STORE_32(unl->multi.settle.when, 0, &state->multicart.settleNextEvent);
if (mTimingIsScheduled(&gba->timing, &unl->multi.settle)) {
STORE_32(GBASerializedMulticartFlagsFillDustSettling(0), 0, &state->multicart.flags);
multiFlags = GBASerializedMulticartFlagsFillDustSettling(multiFlags);
}
STORE_32(multiFlags, 0, &state->multicart.flags);
break;
}
STORE_32(flags, 0, &state->hw.unlCartFlags);
@ -238,6 +245,7 @@ void GBAUnlCartDeserialize(struct GBA* gba, const struct GBASerializedState* sta
gba->memory.rom = unl->multi.rom + offset;
}
LOAD_32(multiFlags, 0, &state->multicart.flags);
unl->multi.locked = GBASerializedMulticartFlagsGetLocked(multiFlags);
if (GBASerializedMulticartFlagsIsDustSettling(multiFlags)) {
LOAD_32(when, 0, &state->multicart.settleNextEvent);
mTimingSchedule(&gba->timing, &unl->multi.settle, when);

View File

@ -1033,7 +1033,6 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
STORE_32(gba->bus, 0, &state->bus);
GBAHardwareSerialize(&gba->memory.hw, state);
GBAUnlCartSerialize(gba, state);
}
void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
@ -1083,5 +1082,4 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
GBADMARecalculateCycles(gba);
GBADMAUpdate(gba);
GBAHardwareDeserialize(&gba->memory.hw, state);
GBAUnlCartDeserialize(gba, state);
}

View File

@ -83,6 +83,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
GBAMemorySerialize(&gba->memory, state);
GBAIOSerialize(gba, state);
GBAUnlCartSerialize(gba, state);
GBAVideoSerialize(&gba->video, state);
GBAAudioSerialize(&gba->audio, state);
GBASavedataSerialize(&gba->memory.savedata, state);
@ -180,6 +181,9 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
mLOG(GBA_STATE, WARN, "Savestate has unaligned PC and is probably corrupted");
gba->cpu->gprs[ARM_PC] &= ~1;
}
// Since this can remap the ROM, we need to do this before we reset the pipeline
GBAUnlCartDeserialize(gba, state);
gba->memory.activeRegion = -1;
gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
if (state->biosPrefetch) {