1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | * Mupen64plus - cheat.c * |
3 | * Mupen64Plus homepage: https://mupen64plus.org/ * |
4 | * Copyright (C) 2009 Richard Goedeken * |
5 | * Copyright (C) 2008 Okaygo * |
6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * |
9 | * the Free Software Foundation; either version 2 of the License, or * |
10 | * (at your option) any later version. * |
11 | * * |
12 | * This program is distributed in the hope that it will be useful, * |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
15 | * GNU General Public License for more details. * |
16 | * * |
17 | * You should have received a copy of the GNU General Public License * |
18 | * along with this program; if not, write to the * |
19 | * Free Software Foundation, Inc., * |
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
21 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
22 | |
23 | /* gameshark and xploder64 reference: http://doc.kodewerx.net/hacking_n64.html */ |
24 | |
25 | #include <SDL.h> |
26 | #include <SDL_thread.h> |
27 | |
28 | #define __STDC_FORMAT_MACROS |
29 | #include <inttypes.h> |
30 | |
31 | #include <stdint.h> |
32 | #include <stdio.h> |
33 | #include <stdlib.h> |
34 | #include <string.h> |
35 | |
36 | #include "cheat.h" |
37 | #include "eventloop.h" |
38 | #include "list.h" |
39 | |
40 | #include "api/callbacks.h" |
41 | #include "api/m64p_types.h" |
42 | #include "device/r4300/r4300_core.h" |
43 | #include "device/rdram/rdram.h" |
44 | #include "osal/preproc.h" |
45 | |
46 | /* local definitions */ |
47 | #define CHEAT_CODE_MAGIC_VALUE UINT32_C(0xDEAD0000) |
48 | |
49 | typedef struct cheat_code { |
50 | uint32_t address; |
51 | uint32_t value; |
52 | uint32_t old_value; |
53 | struct list_head list; |
54 | } cheat_code_t; |
55 | |
56 | typedef struct cheat { |
57 | char *name; |
58 | int enabled; |
59 | int was_enabled; |
60 | struct list_head cheat_codes; |
61 | struct list_head list; |
62 | } cheat_t; |
63 | |
64 | /* private functions */ |
65 | static uint16_t read_address_16bit(struct r4300_core* r4300, uint32_t address) |
66 | { |
67 | return *(uint16_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S16))); |
68 | } |
69 | |
70 | static uint8_t read_address_8bit(struct r4300_core* r4300, uint32_t address) |
71 | { |
72 | return *(uint8_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S8))); |
73 | } |
74 | |
75 | static void update_address_16bit(struct r4300_core* r4300, uint32_t address, uint16_t new_value) |
76 | { |
77 | *(uint16_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S16))) = new_value; |
78 | /* mask out bit 24 which is used by GS codes to specify 8/16 bits */ |
79 | address &= 0xfeffffff; |
80 | invalidate_r4300_cached_code(r4300, address, 2); |
81 | } |
82 | |
83 | static void update_address_8bit(struct r4300_core* r4300, uint32_t address, uint8_t new_value) |
84 | { |
85 | *(uint8_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S8))) = new_value; |
86 | invalidate_r4300_cached_code(r4300, address, 1); |
87 | } |
88 | |
89 | static int address_equal_to_8bit(struct r4300_core* r4300, uint32_t address, uint8_t value) |
90 | { |
91 | uint8_t value_read; |
92 | value_read = *(uint8_t*)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S8))); |
93 | return value_read == value; |
94 | } |
95 | |
96 | static int address_equal_to_16bit(struct r4300_core* r4300, uint32_t address, uint16_t value) |
97 | { |
98 | uint16_t value_read; |
99 | value_read = *(unsigned short *)(((unsigned char*)r4300->rdram->dram + ((address & 0xFFFFFF)^S16))); |
100 | return value_read == value; |
101 | } |
102 | |
103 | /* individual application - returns 0 if we are supposed to skip the next cheat |
104 | * (only really used on conditional codes) |
105 | */ |
106 | static int execute_cheat(struct r4300_core* r4300, uint32_t address, uint32_t value, uint32_t* old_value) |
107 | { |
108 | switch (address & 0xFF000000) |
109 | { |
110 | case 0x80000000: |
111 | case 0x88000000: |
112 | case 0xA0000000: |
113 | case 0xA8000000: |
114 | case 0xF0000000: |
115 | /* if pointer to old value is valid and uninitialized, write current value to it */ |
116 | if (old_value && (*old_value == CHEAT_CODE_MAGIC_VALUE)) { |
117 | *old_value = read_address_8bit(r4300, address); |
118 | } |
119 | update_address_8bit(r4300, address, (uint8_t)value); |
120 | return 1; |
121 | case 0x81000000: |
122 | case 0x89000000: |
123 | case 0xA1000000: |
124 | case 0xA9000000: |
125 | case 0xF1000000: |
126 | /* if pointer to old value is valid and uninitialized, write current value to it */ |
127 | if (old_value && (*old_value == CHEAT_CODE_MAGIC_VALUE)) { |
128 | *old_value = read_address_16bit(r4300, address); |
129 | } |
130 | update_address_16bit(r4300, address, (uint16_t)value); |
131 | return 1; |
132 | case 0xD0000000: |
133 | case 0xD8000000: |
134 | return address_equal_to_8bit(r4300, address, (uint8_t)value); |
135 | case 0xD1000000: |
136 | case 0xD9000000: |
137 | return address_equal_to_16bit(r4300, address, (uint16_t)value); |
138 | case 0xD2000000: |
139 | case 0xDB000000: |
140 | return !(address_equal_to_8bit(r4300, address, (uint8_t)value)); |
141 | case 0xD3000000: |
142 | case 0xDA000000: |
143 | return !(address_equal_to_16bit(r4300, address, (uint16_t)value)); |
144 | case 0xEE000000: |
145 | /* most likely, this doesnt do anything. */ |
146 | execute_cheat(r4300, 0xF1000318, 0x0040, NULL); |
147 | execute_cheat(r4300, 0xF100031A, 0x0000, NULL); |
148 | return 1; |
149 | default: |
150 | return 1; |
151 | } |
152 | } |
153 | |
154 | static cheat_t *find_or_create_cheat(struct cheat_ctx* ctx, const char *name) |
155 | { |
156 | cheat_t *cheat; |
157 | int found = 0; |
158 | |
159 | list_for_each_entry_t(cheat, &ctx->active_cheats, cheat_t, list) { |
160 | if (strcmp(cheat->name, name) == 0) { |
161 | found = 1; |
162 | break; |
163 | } |
164 | } |
165 | |
166 | if (found) |
167 | { |
168 | /* delete any pre-existing cheat codes */ |
169 | cheat_code_t *code, *safe; |
170 | |
171 | list_for_each_entry_safe_t(code, safe, &cheat->cheat_codes, cheat_code_t, list) { |
172 | list_del(&code->list); |
173 | free(code); |
174 | } |
175 | |
176 | cheat->enabled = 0; |
177 | cheat->was_enabled = 0; |
178 | } |
179 | else |
180 | { |
181 | cheat = malloc(sizeof(*cheat)); |
182 | cheat->name = strdup(name); |
183 | cheat->enabled = 0; |
184 | cheat->was_enabled = 0; |
185 | INIT_LIST_HEAD(&cheat->cheat_codes); |
186 | list_add_tail(&cheat->list, &ctx->active_cheats); |
187 | } |
188 | |
189 | return cheat; |
190 | } |
191 | |
192 | |
193 | /* public functions */ |
194 | void cheat_init(struct cheat_ctx* ctx) |
195 | { |
196 | ctx->mutex = SDL_CreateMutex(); |
197 | INIT_LIST_HEAD(&ctx->active_cheats); |
198 | } |
199 | |
200 | void cheat_uninit(struct cheat_ctx* ctx) |
201 | { |
202 | if (ctx->mutex != NULL) { |
203 | SDL_DestroyMutex(ctx->mutex); |
204 | } |
205 | ctx->mutex = NULL; |
206 | } |
207 | |
208 | void cheat_apply_cheats(struct cheat_ctx* ctx, struct r4300_core* r4300, int entry) |
209 | { |
210 | cheat_t *cheat; |
211 | cheat_code_t *code; |
212 | int cond_failed; |
213 | |
214 | if (list_empty(&ctx->active_cheats)) |
215 | return; |
216 | |
217 | if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0) |
218 | { |
219 | DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_apply_cheats()" ); |
220 | return; |
221 | } |
222 | |
223 | list_for_each_entry_t(cheat, &ctx->active_cheats, cheat_t, list) { |
224 | if (cheat->enabled) |
225 | { |
226 | cheat->was_enabled = 1; |
227 | switch(entry) |
228 | { |
229 | case ENTRY_BOOT: |
230 | list_for_each_entry_t(code, &cheat->cheat_codes, cheat_code_t, list) { |
231 | /* code should only be written once at boot time */ |
232 | if ((code->address & 0xF0000000) == 0xF0000000) { |
233 | execute_cheat(r4300, code->address, code->value, &code->old_value); |
234 | } |
235 | } |
236 | break; |
237 | case ENTRY_VI: |
238 | /* a cheat starts without failed preconditions */ |
239 | cond_failed = 0; |
240 | |
241 | list_for_each_entry_t(code, &cheat->cheat_codes, cheat_code_t, list) { |
242 | /* conditional cheat codes */ |
243 | if ((code->address & 0xF0000000) == 0xD0000000) |
244 | { |
245 | /* if code needs GS button pressed and it's not, skip it */ |
246 | if (((code->address & 0xFF000000) == 0xD8000000 || |
247 | (code->address & 0xFF000000) == 0xD9000000 || |
248 | (code->address & 0xFF000000) == 0xDA000000 || |
249 | (code->address & 0xFF000000) == 0xDB000000) && |
250 | !event_gameshark_active()) { |
251 | /* if condition false, skip next code non-test code */ |
252 | cond_failed = 1; |
253 | } |
254 | |
255 | /* if condition false, skip next code non-test code */ |
256 | if (!execute_cheat(r4300, code->address, code->value, NULL)) { |
257 | cond_failed = 1; |
258 | } |
259 | } |
260 | else { |
261 | /* preconditions were false for this non-test code |
262 | * reset the condition state and skip the cheat |
263 | */ |
264 | if (cond_failed) { |
265 | cond_failed = 0; |
266 | continue; |
267 | } |
268 | |
269 | switch (code->address & 0xFF000000) { |
270 | /* GS button triggers cheat code */ |
271 | case 0x88000000: |
272 | case 0x89000000: |
273 | case 0xA8000000: |
274 | case 0xA9000000: |
275 | if (event_gameshark_active()) { |
276 | execute_cheat(r4300, code->address, code->value, NULL); |
277 | } |
278 | break; |
279 | /* normal cheat code */ |
280 | default: |
281 | /* exclude boot-time cheat codes */ |
282 | if ((code->address & 0xF0000000) != 0xF0000000) { |
283 | execute_cheat(r4300, code->address, code->value, &code->old_value); |
284 | } |
285 | break; |
286 | } |
287 | } |
288 | } |
289 | break; |
290 | default: |
291 | break; |
292 | } |
293 | } |
294 | /* if cheat was enabled, but is now disabled, restore old memory values */ |
295 | else if (cheat->was_enabled) |
296 | { |
297 | cheat->was_enabled = 0; |
298 | switch(entry) |
299 | { |
300 | case ENTRY_VI: |
301 | list_for_each_entry_t(code, &cheat->cheat_codes, cheat_code_t, list) { |
302 | /* set memory back to old value and clear saved copy of old value */ |
303 | if(code->old_value != CHEAT_CODE_MAGIC_VALUE) |
304 | { |
305 | execute_cheat(r4300, code->address, code->old_value, NULL); |
306 | code->old_value = CHEAT_CODE_MAGIC_VALUE; |
307 | } |
308 | } |
309 | break; |
310 | default: |
311 | break; |
312 | } |
313 | } |
314 | } |
315 | |
316 | SDL_UnlockMutex(ctx->mutex); |
317 | } |
318 | |
319 | |
320 | void cheat_delete_all(struct cheat_ctx* ctx) |
321 | { |
322 | cheat_t *cheat, *safe_cheat; |
323 | cheat_code_t *code, *safe_code; |
324 | |
325 | if (list_empty(&ctx->active_cheats)) |
326 | return; |
327 | |
328 | if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0) |
329 | { |
330 | DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_delete_all()" ); |
331 | return; |
332 | } |
333 | |
334 | list_for_each_entry_safe_t(cheat, safe_cheat, &ctx->active_cheats, cheat_t, list) { |
335 | free(cheat->name); |
336 | |
337 | list_for_each_entry_safe_t(code, safe_code, &cheat->cheat_codes, cheat_code_t, list) { |
338 | list_del(&code->list); |
339 | free(code); |
340 | } |
341 | list_del(&cheat->list); |
342 | free(cheat); |
343 | } |
344 | |
345 | SDL_UnlockMutex(ctx->mutex); |
346 | } |
347 | |
348 | int cheat_set_enabled(struct cheat_ctx* ctx, const char* name, int enabled) |
349 | { |
350 | cheat_t *cheat = NULL; |
351 | |
352 | if (list_empty(&ctx->active_cheats)) |
353 | return 0; |
354 | |
355 | if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0) |
356 | { |
357 | DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_set_enabled()" ); |
358 | return 0; |
359 | } |
360 | |
361 | list_for_each_entry_t(cheat, &ctx->active_cheats, cheat_t, list) { |
362 | if (strcmp(name, cheat->name) == 0) |
363 | { |
364 | cheat->enabled = enabled; |
365 | SDL_UnlockMutex(ctx->mutex); |
366 | return 1; |
367 | } |
368 | } |
369 | |
370 | SDL_UnlockMutex(ctx->mutex); |
371 | return 0; |
372 | } |
373 | |
374 | int cheat_add_new(struct cheat_ctx* ctx, const char* name, m64p_cheat_code* code_list, int num_codes) |
375 | { |
376 | cheat_t *cheat; |
377 | int i, j; |
378 | |
379 | if (ctx->mutex == NULL || SDL_LockMutex(ctx->mutex) != 0) |
380 | { |
381 | DebugMessage(M64MSG_ERROR, "Internal error: failed to lock mutex in cheat_add_new()" ); |
382 | return 0; |
383 | } |
384 | |
385 | /* create a new cheat function or erase the codes in an existing cheat function */ |
386 | cheat = find_or_create_cheat(ctx, name); |
387 | if (cheat == NULL) |
388 | { |
389 | SDL_UnlockMutex(ctx->mutex); |
390 | return 0; |
391 | } |
392 | |
393 | /* default for new cheats is enabled */ |
394 | cheat->enabled = 1; |
395 | |
396 | for (i = 0; i < num_codes; i++) |
397 | { |
398 | /* if this is a 'patch' code, convert it and dump out all of the individual codes */ |
399 | if ((code_list[i].address & 0xFFFF0000) == 0x50000000 && i < num_codes - 1) |
400 | { |
401 | int code_count = ((code_list[i].address & 0xFF00) >> 8); |
402 | int incr_addr = code_list[i].address & 0xFF; |
403 | int incr_value = code_list[i].value; |
404 | int cur_addr = code_list[i+1].address; |
405 | int cur_value = code_list[i+1].value; |
406 | i += 1; |
407 | for (j = 0; j < code_count; j++) |
408 | { |
409 | cheat_code_t *code = malloc(sizeof(*code)); |
410 | code->address = cur_addr; |
411 | code->value = cur_value; |
412 | code->old_value = CHEAT_CODE_MAGIC_VALUE; |
413 | list_add_tail(&code->list, &cheat->cheat_codes); |
414 | cur_addr += incr_addr; |
415 | cur_value += incr_value; |
416 | } |
417 | } |
418 | else |
419 | { |
420 | /* just a normal code */ |
421 | cheat_code_t *code = malloc(sizeof(*code)); |
422 | code->address = code_list[i].address; |
423 | code->value = code_list[i].value; |
424 | code->old_value = CHEAT_CODE_MAGIC_VALUE; |
425 | list_add_tail(&code->list, &cheat->cheat_codes); |
426 | } |
427 | } |
428 | |
429 | SDL_UnlockMutex(ctx->mutex); |
430 | return 1; |
431 | } |
432 | |
433 | static char *strtok_compat(char *str, const char *delim, char **saveptr) |
434 | { |
435 | char *p; |
436 | |
437 | if (str == NULL) |
438 | str = *saveptr; |
439 | |
440 | if (str == NULL) |
441 | return NULL; |
442 | |
443 | str += strspn(str, delim); |
444 | if ((p = strpbrk(str, delim)) != NULL) { |
445 | *saveptr = p + 1; |
446 | *p = '\0'; |
447 | } else { |
448 | *saveptr = NULL; |
449 | } |
450 | return str; |
451 | } |
452 | |
453 | static int cheat_parse_hacks_code(char *code, m64p_cheat_code **hack) |
454 | { |
455 | char *saveptr = NULL; |
456 | char *input, *token; |
457 | int num_codes; |
458 | m64p_cheat_code *hackbuf; |
459 | int ret; |
460 | |
461 | *hack = NULL; |
462 | |
463 | /* count number of possible cheatcodes */ |
464 | input = code; |
465 | num_codes = 0; |
466 | while ((strchr(input, ','))) { |
467 | input++; |
468 | num_codes++; |
469 | } |
470 | num_codes++; |
471 | |
472 | /* allocate buffer */ |
473 | hackbuf = malloc(sizeof(*hackbuf) * num_codes); |
474 | if (!hackbuf) |
475 | return 0; |
476 | |
477 | /* parse cheatcodes */ |
478 | input = code; |
479 | num_codes = 0; |
480 | while ((token = strtok_compat(input, "," , &saveptr))) { |
481 | input = NULL; |
482 | |
483 | ret = sscanf(token, "%08" SCNx32 " %04X" , &hackbuf[num_codes].address, |
484 | (unsigned int*)&hackbuf[num_codes].value); |
485 | if (ret == 2) |
486 | num_codes++; |
487 | } |
488 | |
489 | if (num_codes == 0) |
490 | free(hackbuf); |
491 | else |
492 | *hack = hackbuf; |
493 | |
494 | return num_codes; |
495 | } |
496 | |
497 | int cheat_add_hacks(struct cheat_ctx* ctx, const char* rom_cheats) |
498 | { |
499 | char *cheat_raw = NULL; |
500 | char *saveptr = NULL; |
501 | char *input, *token; |
502 | unsigned int i = 0; |
503 | int num_codes; |
504 | char cheatname[32]; |
505 | m64p_cheat_code *hack; |
506 | |
507 | if (!rom_cheats) |
508 | return 0; |
509 | |
510 | /* copy ini entry for tokenizing */ |
511 | cheat_raw = strdup(rom_cheats); |
512 | if (!cheat_raw) |
513 | goto out; |
514 | |
515 | /* split into cheats for the cheat engine */ |
516 | input = cheat_raw; |
517 | while ((token = strtok_compat(input, ";" , &saveptr))) { |
518 | input = NULL; |
519 | |
520 | snprintf(cheatname, sizeof(cheatname), "HACK%u" , i); |
521 | cheatname[sizeof(cheatname) - 1] = '\0'; |
522 | |
523 | /* parse and add cheat */ |
524 | num_codes = cheat_parse_hacks_code(token, &hack); |
525 | if (num_codes <= 0) |
526 | continue; |
527 | |
528 | cheat_add_new(ctx, cheatname, hack, num_codes); |
529 | free(hack); |
530 | i++; |
531 | } |
532 | |
533 | out: |
534 | free(cheat_raw); |
535 | return 0; |
536 | } |
537 | |