1 /* Copyright (c) 2013-2016 Jeffrey Pfau
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <mgba/internal/gba/serialize.h>
7 
8 #include <mgba/internal/arm/macros.h>
9 #include <mgba/internal/gba/bios.h>
10 #include <mgba/internal/gba/io.h>
11 #include <mgba/internal/gba/rr/rr.h>
12 
13 #include <mgba-util/memory.h>
14 #include <mgba-util/vfs.h>
15 
16 #include <fcntl.h>
17 
18 const uint32_t GBA_SAVESTATE_MAGIC = 0x01000000;
19 const uint32_t GBA_SAVESTATE_VERSION = 0x00000003;
20 
21 mLOG_DEFINE_CATEGORY(GBA_STATE, "GBA Savestate", "gba.serialize");
22 
23 struct GBABundledState {
24 	struct GBASerializedState* state;
25 	struct mStateExtdata* extdata;
26 };
27 
GBASerialize(struct GBA * gba,struct GBASerializedState * state)28 void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
29 	STORE_32(GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION, 0, &state->versionMagic);
30 	STORE_32(gba->biosChecksum, 0, &state->biosChecksum);
31 	STORE_32(gba->romCrc32, 0, &state->romCrc32);
32 	STORE_32(gba->timing.masterCycles, 0, &state->masterCycles);
33 
34 	if (gba->memory.rom) {
35 		state->id = ((struct GBACartridge*) gba->memory.rom)->id;
36 		memcpy(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title));
37 	} else {
38 		state->id = 0;
39 		memset(state->title, 0, sizeof(state->title));
40 	}
41 
42 	int i;
43 	for (i = 0; i < 16; ++i) {
44 		STORE_32(gba->cpu->gprs[i], i * sizeof(state->cpu.gprs[0]), state->cpu.gprs);
45 	}
46 	STORE_32(gba->cpu->cpsr.packed, 0, &state->cpu.cpsr.packed);
47 	STORE_32(gba->cpu->spsr.packed, 0, &state->cpu.spsr.packed);
48 	STORE_32(gba->cpu->cycles, 0, &state->cpu.cycles);
49 	STORE_32(gba->cpu->nextEvent, 0, &state->cpu.nextEvent);
50 	for (i = 0; i < 6; ++i) {
51 		int j;
52 		for (j = 0; j < 7; ++j) {
53 			STORE_32(gba->cpu->bankedRegisters[i][j], (i * 7 + j) * sizeof(gba->cpu->bankedRegisters[0][0]), state->cpu.bankedRegisters);
54 		}
55 		STORE_32(gba->cpu->bankedSPSRs[i], i * sizeof(gba->cpu->bankedSPSRs[0]), state->cpu.bankedSPSRs);
56 	}
57 
58 	STORE_32(gba->memory.biosPrefetch, 0, &state->biosPrefetch);
59 	STORE_32(gba->cpu->prefetch[0], 0, state->cpuPrefetch);
60 	STORE_32(gba->cpu->prefetch[1], 4, state->cpuPrefetch);
61 	STORE_32(gba->memory.lastPrefetchedPc, 0, &state->lastPrefetchedPc);
62 
63 	GBASerializedMiscFlags miscFlags = 0;
64 	miscFlags = GBASerializedMiscFlagsSetHalted(miscFlags, gba->cpu->halted);
65 	miscFlags = GBASerializedMiscFlagsSetPOSTFLG(miscFlags, gba->memory.io[REG_POSTFLG >> 1] & 1);
66 	if (mTimingIsScheduled(&gba->timing, &gba->irqEvent)) {
67 		miscFlags = GBASerializedMiscFlagsFillIrqPending(miscFlags);
68 		STORE_32(gba->irqEvent.when - mTimingCurrentTime(&gba->timing), 0, &state->nextIrq);
69 	}
70 	STORE_32(miscFlags, 0, &state->miscFlags);
71 
72 	GBAMemorySerialize(&gba->memory, state);
73 	GBAIOSerialize(gba, state);
74 	GBAVideoSerialize(&gba->video, state);
75 	GBAAudioSerialize(&gba->audio, state);
76 	GBASavedataSerialize(&gba->memory.savedata, state);
77 
78 	state->associatedStreamId = 0;
79 	if (gba->rr) {
80 		gba->rr->stateSaved(gba->rr, state);
81 	}
82 }
83 
GBADeserialize(struct GBA * gba,const struct GBASerializedState * state)84 bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
85 	bool error = false;
86 	int32_t check;
87 	uint32_t ucheck;
88 	LOAD_32(ucheck, 0, &state->versionMagic);
89 	if (ucheck > GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION) {
90 		mLOG(GBA_STATE, WARN, "Invalid or too new savestate: expected %08X, got %08X", GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION, ucheck);
91 		error = true;
92 	} else if (ucheck < GBA_SAVESTATE_MAGIC) {
93 		mLOG(GBA_STATE, WARN, "Invalid savestate: expected %08X, got %08X", GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION, ucheck);
94 		error = true;
95 	} else if (ucheck < GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION) {
96 		mLOG(GBA_STATE, WARN, "Old savestate: expected %08X, got %08X, continuing anyway", GBA_SAVESTATE_MAGIC + GBA_SAVESTATE_VERSION, ucheck);
97 	}
98 	LOAD_32(ucheck, 0, &state->biosChecksum);
99 	if (ucheck != gba->biosChecksum) {
100 		mLOG(GBA_STATE, WARN, "Savestate created using a different version of the BIOS: expected %08X, got %08X", gba->biosChecksum, ucheck);
101 		uint32_t pc;
102 		LOAD_32(pc, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs);
103 		if ((ucheck == GBA_BIOS_CHECKSUM || gba->biosChecksum == GBA_BIOS_CHECKSUM) && pc < SIZE_BIOS && pc >= 0x20) {
104 			error = true;
105 		}
106 	}
107 	if (gba->memory.rom && (state->id != ((struct GBACartridge*) gba->memory.rom)->id || memcmp(state->title, ((struct GBACartridge*) gba->memory.rom)->title, sizeof(state->title)))) {
108 		mLOG(GBA_STATE, WARN, "Savestate is for a different game");
109 		error = true;
110 	} else if (!gba->memory.rom && state->id != 0) {
111 		mLOG(GBA_STATE, WARN, "Savestate is for a game, but no game loaded");
112 		error = true;
113 	}
114 	LOAD_32(ucheck, 0, &state->romCrc32);
115 	if (ucheck != gba->romCrc32) {
116 		mLOG(GBA_STATE, WARN, "Savestate is for a different version of the game");
117 	}
118 	LOAD_32(check, 0, &state->cpu.cycles);
119 	if (check < 0) {
120 		mLOG(GBA_STATE, WARN, "Savestate is corrupted: CPU cycles are negative");
121 		error = true;
122 	}
123 	if (check >= (int32_t) GBA_ARM7TDMI_FREQUENCY) {
124 		mLOG(GBA_STATE, WARN, "Savestate is corrupted: CPU cycles are too high");
125 		error = true;
126 	}
127 	LOAD_32(check, ARM_PC * sizeof(state->cpu.gprs[0]), state->cpu.gprs);
128 	int region = (check >> BASE_OFFSET);
129 	if ((region == REGION_CART0 || region == REGION_CART1 || region == REGION_CART2) && ((check - WORD_SIZE_ARM) & SIZE_CART0) >= gba->memory.romSize - WORD_SIZE_ARM) {
130 		mLOG(GBA_STATE, WARN, "Savestate created using a differently sized version of the ROM");
131 		error = true;
132 	}
133 	if (error) {
134 		return false;
135 	}
136 	mTimingClear(&gba->timing);
137 	LOAD_32(gba->timing.masterCycles, 0, &state->masterCycles);
138 
139 	size_t i;
140 	for (i = 0; i < 16; ++i) {
141 		LOAD_32(gba->cpu->gprs[i], i * sizeof(gba->cpu->gprs[0]), state->cpu.gprs);
142 	}
143 	LOAD_32(gba->cpu->cpsr.packed, 0, &state->cpu.cpsr.packed);
144 	LOAD_32(gba->cpu->spsr.packed, 0, &state->cpu.spsr.packed);
145 	LOAD_32(gba->cpu->cycles, 0, &state->cpu.cycles);
146 	LOAD_32(gba->cpu->nextEvent, 0, &state->cpu.nextEvent);
147 	for (i = 0; i < 6; ++i) {
148 		int j;
149 		for (j = 0; j < 7; ++j) {
150 			LOAD_32(gba->cpu->bankedRegisters[i][j], (i * 7 + j) * sizeof(gba->cpu->bankedRegisters[0][0]), state->cpu.bankedRegisters);
151 		}
152 		LOAD_32(gba->cpu->bankedSPSRs[i], i * sizeof(gba->cpu->bankedSPSRs[0]), state->cpu.bankedSPSRs);
153 	}
154 	gba->cpu->privilegeMode = gba->cpu->cpsr.priv;
155 	uint32_t pcMask = (gba->cpu->executionMode == MODE_THUMB ? WORD_SIZE_THUMB : WORD_SIZE_ARM) - 1;
156 	if (gba->cpu->gprs[ARM_PC] & pcMask) {
157 		mLOG(GBA_STATE, WARN, "Savestate has unaligned PC and is probably corrupted");
158 		gba->cpu->gprs[ARM_PC] &= ~pcMask;
159 	}
160 	gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
161 	if (state->biosPrefetch) {
162 		LOAD_32(gba->memory.biosPrefetch, 0, &state->biosPrefetch);
163 	}
164 	LOAD_32(gba->memory.lastPrefetchedPc, 0, &state->lastPrefetchedPc);
165 	if (gba->cpu->cpsr.t) {
166 		gba->cpu->executionMode = MODE_THUMB;
167 		if (state->cpuPrefetch[0] && state->cpuPrefetch[1]) {
168 			LOAD_32(gba->cpu->prefetch[0], 0, state->cpuPrefetch);
169 			LOAD_32(gba->cpu->prefetch[1], 4, state->cpuPrefetch);
170 			gba->cpu->prefetch[0] &= 0xFFFF;
171 			gba->cpu->prefetch[1] &= 0xFFFF;
172 		} else {
173 			// Maintain backwards compat
174 			LOAD_16(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_THUMB) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
175 			LOAD_16(gba->cpu->prefetch[1], (gba->cpu->gprs[ARM_PC]) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
176 		}
177 	} else {
178 		gba->cpu->executionMode = MODE_ARM;
179 		if (state->cpuPrefetch[0] && state->cpuPrefetch[1]) {
180 			LOAD_32(gba->cpu->prefetch[0], 0, state->cpuPrefetch);
181 			LOAD_32(gba->cpu->prefetch[1], 4, state->cpuPrefetch);
182 		} else {
183 			// Maintain backwards compat
184 			LOAD_32(gba->cpu->prefetch[0], (gba->cpu->gprs[ARM_PC] - WORD_SIZE_ARM) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
185 			LOAD_32(gba->cpu->prefetch[1], (gba->cpu->gprs[ARM_PC]) & gba->cpu->memory.activeMask, gba->cpu->memory.activeRegion);
186 		}
187 	}
188 	GBASerializedMiscFlags miscFlags = 0;
189 	LOAD_32(miscFlags, 0, &state->miscFlags);
190 	gba->cpu->halted = GBASerializedMiscFlagsGetHalted(miscFlags);
191 	gba->memory.io[REG_POSTFLG >> 1] = GBASerializedMiscFlagsGetPOSTFLG(miscFlags);
192 	if (GBASerializedMiscFlagsIsIrqPending(miscFlags)) {
193 		int32_t when;
194 		LOAD_32(when, 0, &state->nextIrq);
195 		mTimingSchedule(&gba->timing, &gba->irqEvent, when);
196 	}
197 
198 	GBAVideoDeserialize(&gba->video, state);
199 	GBAMemoryDeserialize(&gba->memory, state);
200 	GBAIODeserialize(gba, state);
201 	GBAAudioDeserialize(&gba->audio, state);
202 	GBASavedataDeserialize(&gba->memory.savedata, state);
203 
204 	if (gba->rr) {
205 		gba->rr->stateLoaded(gba->rr, state);
206 	}
207 
208 	gba->timing.reroot = gba->timing.root;
209 	gba->timing.root = NULL;
210 
211 	return true;
212 }
213