1 /*
2 	Copyright (C) 2009-2015 DeSmuME Team
3 
4 	This file is free software: you can redistribute it and/or modify
5 	it under the terms of the GNU General Public License as published by
6 	the Free Software Foundation, either version 2 of the License, or
7 	(at your option) any later version.
8 
9 	This file is distributed in the hope that it will be useful,
10 	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 	GNU General Public License for more details.
13 
14 	You should have received a copy of the GNU General Public License
15 	along with the this software.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "firmware.h"
19 
20 #include "NDSSystem.h"
21 #include "MMU.h"
22 #include "path.h"
23 #include "encrypt.h"
24 #include "wifi.h"
25 
26 #define DFC_ID_CODE	"DeSmuME Firmware User Settings"
27 #define DFC_ID_SIZE	sizeof(DFC_ID_CODE)
28 #define USER_SETTINGS_SIZE 0x100
29 #define WIFI_SETTINGS_SIZE 0x1D5
30 #define WIFI_AP_SETTINGS_SIZE 0x300
31 #define SETTINGS_SIZE (USER_SETTINGS_SIZE + WIFI_SETTINGS_SIZE + WIFI_AP_SETTINGS_SIZE)
32 #define DFC_FILE_SIZE (SETTINGS_SIZE + DFC_ID_SIZE)
33 #define WIFI_SETTINGS_OFF 0x0000002A
34 #define WIFI_AP_SETTINGS_OFF 0x0003FA00
35 
36 static _KEY1	enc(&MMU.ARM7_BIOS[0x0030]);
37 
getBootCodeCRC16()38 u16 CFIRMWARE::getBootCodeCRC16()
39 {
40 	unsigned int i, j;
41 	u32 crc = 0xFFFF;
42 	const u16 val[8] = {0xC0C1, 0xC181, 0xC301, 0xC601, 0xCC01, 0xD801, 0xF001, 0xA001};
43 
44 	for(i = 0; i < size9; i++)
45 	{
46 		crc = (crc ^ tmp_data9[i]);
47 
48 		for(j = 0; j < 8; j++)
49 		{
50 			if(crc & 0x0001)
51 				crc = ((crc >> 1) ^ (val[j] << (7-j)));
52 			else
53 				crc =  (crc >> 1);
54 		}
55 	}
56 
57 	for(i = 0; i < size7; i++)
58 	{
59 		crc = (crc ^ tmp_data7[i]);
60 
61 		for(j = 0; j < 8; j++)
62 		{
63 			if(crc & 0x0001)
64 				crc = ((crc >> 1) ^ (val[j] << (7-j)));
65 			else
66 				crc =  (crc >> 1);
67 		}
68 	}
69 
70 	return (crc & 0xFFFF);
71 }
72 
decrypt(const u8 * in,u8 * & out)73 u32 CFIRMWARE::decrypt(const u8 *in, u8* &out)
74 {
75 	u32 curBlock[2] = { 0 };
76 	u32 blockSize = 0;
77 	u32 xLen = 0;
78 
79 	u32 i = 0, j = 0;
80 	u32 xIn = 4, xOut = 0;
81 	u32 len = 0;
82 	u32 offset = 0;
83 	u32 windowOffset = 0;
84 	u8 d = 0;
85 	u16 data = 0;
86 
87 	memcpy(curBlock, in, 8);
88 	enc.decrypt(curBlock);
89 	blockSize = (curBlock[0] >> 8);
90 
91 	if (blockSize == 0) return (0);
92 
93 	out = new u8 [blockSize];
94 	if (!out ) return (0);
95 	memset(out, 0xFF, blockSize);
96 
97 	xLen = blockSize;
98 	while(xLen > 0)
99 	{
100 		d = T1ReadByte((u8*)curBlock, (xIn % 8));
101 		xIn++;
102 		if((xIn % 8) == 0)
103 		{
104 			memcpy(curBlock, in + xIn, 8);
105 			enc.decrypt(curBlock);
106 		}
107 
108 		for(i = 0; i < 8; i++)
109 		{
110 			if(d & 0x80)
111 			{
112 				data = (T1ReadByte((u8*)curBlock, (xIn % 8)) << 8);
113 				xIn++;
114 				if((xIn % 8) == 0)
115 				{
116 					memcpy(curBlock, in + xIn, 8);
117 					enc.decrypt(curBlock);
118 				}
119 				data |= T1ReadByte((u8*)curBlock, (xIn % 8));
120 				xIn++;
121 				if((xIn % 8) == 0)
122 				{
123 					memcpy(curBlock, in + xIn, 8);
124 					enc.decrypt(curBlock);
125 				}
126 
127 				len = (data >> 12) + 3;
128 				offset = (data & 0xFFF);
129 				windowOffset = (xOut - offset - 1);
130 
131 				for(j = 0; j < len; j++)
132 				{
133 					T1WriteByte(out, xOut, T1ReadByte(out, windowOffset));
134 					xOut++;
135 					windowOffset++;
136 
137 					xLen--;
138 					if(xLen == 0) return (blockSize);
139 				}
140 			}
141 			else
142 			{
143 				T1WriteByte(out, xOut, T1ReadByte((u8*)curBlock, (xIn % 8)));
144 				xOut++;
145 				xIn++;
146 				if((xIn % 8) == 0)
147 				{
148 					memcpy(curBlock, in + xIn, 8);
149 					enc.decrypt(curBlock);
150 				}
151 
152 				xLen--;
153 				if(xLen == 0) return (blockSize);
154 			}
155 
156 			d = ((d << 1) & 0xFF);
157 		}
158 	}
159 
160 	return (blockSize);
161 }
162 
decompress(const u8 * in,u8 * & out)163 u32 CFIRMWARE::decompress(const u8 *in, u8* &out)
164 {
165 	u32 curBlock[2] = { 0 };
166 	u32 blockSize = 0;
167 	u32 xLen = 0;
168 
169 	u32 i = 0, j = 0;
170 	u32 xIn = 4, xOut = 0;
171 	u32 len = 0;
172 	u32 offset = 0;
173 	u32 windowOffset = 0;
174 	u8 d = 0;
175 	u16 data = 0;
176 
177 	memcpy(curBlock, in, 8);
178 	blockSize = (curBlock[0] >> 8);
179 
180 	if (blockSize == 0) return (0);
181 
182 	out = new u8 [blockSize];
183 	if (!out ) return (0);
184 	memset(out, 0xFF, blockSize);
185 
186 	xLen = blockSize;
187 	while(xLen > 0)
188 	{
189 		d = T1ReadByte((u8*)curBlock, (xIn % 8));
190 		xIn++;
191 		if((xIn % 8) == 0)
192 		{
193 			memcpy(curBlock, in + xIn, 8);
194 		}
195 
196 		for(i = 0; i < 8; i++)
197 		{
198 			if(d & 0x80)
199 			{
200 				data = (T1ReadByte((u8*)curBlock, (xIn % 8)) << 8);
201 				xIn++;
202 				if((xIn % 8) == 0)
203 				{
204 					memcpy(curBlock, in + xIn, 8);
205 				}
206 				data |= T1ReadByte((u8*)curBlock, (xIn % 8));
207 				xIn++;
208 				if((xIn % 8) == 0)
209 				{
210 					memcpy(curBlock, in + xIn, 8);
211 				}
212 
213 				len = (data >> 12) + 3;
214 				offset = (data & 0xFFF);
215 				windowOffset = (xOut - offset - 1);
216 
217 				for(j = 0; j < len; j++)
218 				{
219 					T1WriteByte(out, xOut, T1ReadByte(out, windowOffset));
220 					xOut++;
221 					windowOffset++;
222 
223 					xLen--;
224 					if(xLen == 0) return (blockSize);
225 				}
226 			}
227 			else
228 			{
229 				T1WriteByte(out, xOut, T1ReadByte((u8*)curBlock, (xIn % 8)));
230 				xOut++;
231 				xIn++;
232 				if((xIn % 8) == 0)
233 				{
234 					memcpy(curBlock, in + xIn, 8);
235 				}
236 
237 				xLen--;
238 				if(xLen == 0) return (blockSize);
239 			}
240 
241 			d = ((d << 1) & 0xFF);
242 		}
243 	}
244 
245 	return (blockSize);
246 }
247 //================================================================================
load()248 bool CFIRMWARE::load()
249 {
250 	u32 size = 0;
251 	u8	*data = NULL;
252 
253 	if (CommonSettings.UseExtFirmware == false)
254 		return false;
255 	if (strlen(CommonSettings.Firmware) == 0)
256 		return false;
257 
258 	FILE	*fp = fopen(CommonSettings.Firmware, "rb");
259 	if (!fp)
260 		return false;
261 	fseek(fp, 0, SEEK_END);
262 	size = ftell(fp);
263 	fseek(fp, 0, SEEK_SET);
264 	if( (size != NDS_FW_SIZE_V1) && (size != NDS_FW_SIZE_V2) )
265 	{
266 		fclose(fp);
267 		return false;
268 	}
269 
270 	data = new u8 [size];
271 	if (!data)
272 	{
273 		fclose(fp);
274 		return false;
275 	}
276 
277 	if (fread(data, 1, size, fp) != size)
278 	{
279 		delete [] data;
280 		data = NULL;
281 		fclose(fp);
282 		return false;
283 	}
284 
285 	memcpy(&header, data, sizeof(header));
286 	if ((header.fw_identifier & 0x00FFFFFF) != 0x0043414D)
287 	{
288 		delete [] data;
289 		data = NULL;
290 		fclose(fp);
291 		return false;
292 	}
293 	fclose(fp);
294 
295 	if (MMU.fw.size != size)	// reallocate
296 		mc_alloc(&MMU.fw, size);
297 
298 	userDataAddr = T1ReadWord(data, 0x20) * 8;
299 
300 	// fix bad dump of firmware? (wrong DS type)
301 	// fix mario kart touch screen calibration
302 	if ((T1ReadWord(data, 0x1E) != 0xFFFF) && data[0x1D] == 0x63)
303 	{
304 		data[0x1D] = NDS_CONSOLE_TYPE_FAT;
305 		data[0x1E] = 0xFF;
306 		data[0x1F] = 0xFF;
307 	}
308 
309 	memcpy(MMU.fw.data, data, size);
310 
311 	delete [] data;
312 	data = NULL;
313 
314 	// Generate the path for the external firmware config file.
315 	std::string extFilePath = CFIRMWARE::GetExternalFilePath();
316 	strncpy(MMU.fw.userfile, extFilePath.c_str(), PATH_MAX_LENGTH);
317 
318 	successLoad = true;
319 	return true;
320 }
321 
unpack()322 bool CFIRMWARE::unpack()
323 {
324 	u32	src = 0;
325 	u16 shift1 = 0, shift2 = 0, shift3 = 0, shift4 = 0;
326 	u32 part1addr = 0, part2addr = 0, part3addr = 0, part4addr = 0, part5addr = 0;
327 	u32 part1ram = 0, part2ram = 0;
328 	u32 size = MMU.fw.size;
329 
330 	if (size == 512*1024)
331 	{
332 #ifdef DEBUG
333 		INFO("ERROR: 32Mbit (512Kb) firmware not supported\n");
334 #endif
335 		return false;
336 	}
337 
338 	u8	*data = new u8 [size];
339 	if (!data)
340 		return false;
341 
342 	memcpy(data, MMU.fw.data, size);
343 
344 	shift1 = ((header.shift_amounts >> 0) & 0x07);
345 	shift2 = ((header.shift_amounts >> 3) & 0x07);
346 	shift3 = ((header.shift_amounts >> 6) & 0x07);
347 	shift4 = ((header.shift_amounts >> 9) & 0x07);
348 
349 	// todo - add support for 512Kb
350 	part1addr = (header.part1_rom_boot9_addr << (2 + shift1));
351 	part1ram = (0x02800000 - (header.part1_ram_boot9_addr << (2+shift2)));
352 	part2addr = (header.part2_rom_boot7_addr << (2+shift3));
353 	part2ram = (0x03810000 - (header.part2_ram_boot7_addr << (2+shift4)));
354 	part3addr = (header.part3_rom_gui9_addr << 3);
355 	part4addr = (header.part4_rom_wifi7_addr << 3);
356 	part5addr = (header.part5_data_gfx_addr << 3);
357 
358 	ARM9bootAddr = part1ram;
359 	ARM7bootAddr = part2ram;
360 
361 	enc.init(header.fw_identifier, 1, 0xC);
362 
363 #if 0
364 	enc.applyKeycode((u32*)&data[0x18]);
365 #else
366 	// fix touch coords
367 	data[0x18] = 0x00;
368 	data[0x19] = 0x00;
369 	data[0x1A] = 0x00;
370 	data[0x1B] = 0x00;
371 
372 	data[0x1C] = 0x00;
373 	data[0x1D] = 0xFF;
374 	data[0x1E] = 0x00;
375 	data[0x1F] = 0x00;
376 #endif
377 
378 	enc.init(header.fw_identifier, 2, 0xC);
379 
380 	size9 = decrypt(data + part1addr, tmp_data9);
381 	if (!tmp_data9)
382 	{
383 		delete [] data; data = NULL;
384 		return false;
385 	}
386 
387 	size7 = decrypt(data + part2addr, tmp_data7);
388 	if (!tmp_data7)
389 	{
390 		delete [] tmp_data9;
391 		delete [] data; data = NULL;
392 		return false;
393 	}
394 
395 	u16 crc16_mine = getBootCodeCRC16();
396 
397 	if (crc16_mine != header.part12_boot_crc16)
398 	{
399 #ifdef DEBUG
400 		INFO("Firmware: ERROR: the boot code CRC16 (0x%04X) doesn't match the value in the firmware header (0x%04X)", crc16_mine, header.part12_boot_crc16);
401 #endif
402 		delete [] tmp_data9;
403 		delete [] tmp_data7;
404 		delete [] data; data = NULL;
405 		return false;
406 	}
407 
408 	// Copy firmware boot codes to their respective locations
409 	src = 0;
410 	for(u32 i = 0; i < (size9 >> 2); i++)
411 	{
412 		_MMU_write32<ARMCPU_ARM9>(part1ram, T1ReadLong(tmp_data9, src));
413 		src += 4; part1ram += 4;
414 	}
415 
416 	src = 0;
417 	for(u32 i = 0; i < (size7 >> 2); i++)
418 	{
419 		_MMU_write32<ARMCPU_ARM7>(part2ram, T1ReadLong(tmp_data7, src));
420 		src += 4; part2ram += 4;
421 	}
422 	delete [] tmp_data7;
423 	delete [] tmp_data9;
424 
425 	patched = false;
426 	if (data[0x17C] != 0xFF)
427 		patched = true;
428 
429 #ifdef DEBUG
430 	INFO("Firmware:\n");
431 	INFO("- path: %s\n", CommonSettings.Firmware);
432 	INFO("- size: %i bytes (%i Mbit)\n", size, size/1024/8);
433 	INFO("- CRC : 0x%04X\n", header.part12_boot_crc16);
434 	INFO("- header: \n");
435 	INFO("   * size firmware %i\n", ((header.shift_amounts >> 12) & 0xF) * 128 * 1024);
436 	INFO("   * ARM9 boot code address:     0x%08X\n", part1addr);
437 	INFO("   * ARM9 boot code RAM address: 0x%08X\n", ARM9bootAddr);
438 	INFO("   * ARM9 unpacked size:         0x%08X (%i) bytes\n", size9, size9);
439 	INFO("   * ARM9 GUI code address:      0x%08X\n", part3addr);
440 	INFO("\n");
441 	INFO("   * ARM7 boot code address:     0x%08X\n", part2addr);
442 	INFO("   * ARM7 boot code RAM address: 0x%08X\n", ARM7bootAddr);
443 	INFO("   * ARM7 WiFi code address:     0x%08X\n", part4addr);
444 	INFO("   * ARM7 unpacked size:         0x%08X (%i) bytes\n", size7, size7);
445 	INFO("\n");
446 	INFO("   * Data/GFX address:           0x%08X\n", part5addr);
447 #endif
448 
449 	if (patched)
450 	{
451 		u32 patch_offset = 0x3FC80;
452 		if (data[0x17C] > 1)
453 			patch_offset = 0x3F680;
454 
455 		memcpy(&header, data + patch_offset, sizeof(header));
456 
457 		shift1 = ((header.shift_amounts >> 0) & 0x07);
458 		shift2 = ((header.shift_amounts >> 3) & 0x07);
459 		shift3 = ((header.shift_amounts >> 6) & 0x07);
460 		shift4 = ((header.shift_amounts >> 9) & 0x07);
461 
462 		// todo - add support for 512Kb
463 		part1addr = (header.part1_rom_boot9_addr << (2 + shift1));
464 		part1ram = (0x02800000 - (header.part1_ram_boot9_addr << (2+shift2)));
465 		part2addr = (header.part2_rom_boot7_addr << (2+shift3));
466 		part2ram = (0x03810000 - (header.part2_ram_boot7_addr << (2+shift4)));
467 
468 		ARM9bootAddr = part1ram;
469 		ARM7bootAddr = part2ram;
470 
471 		size9 = decompress(data + part1addr, tmp_data9);
472 		if (!tmp_data9)
473 		{
474 			delete [] data;
475 			return false;
476 		}
477 
478 		size7 = decompress(data + part2addr, tmp_data7);
479 		if (!tmp_data7)
480 		{
481 			delete [] tmp_data9;
482 			delete [] data;
483 			return false;
484 		};
485 		// Copy firmware boot codes to their respective locations
486 		src = 0;
487 		for(u32 i = 0; i < (size9 >> 2); i++)
488 		{
489 			_MMU_write32<ARMCPU_ARM9>(part1ram, T1ReadLong(tmp_data9, src));
490 			src += 4; part1ram += 4;
491 		}
492 
493 		src = 0;
494 		for(u32 i = 0; i < (size7 >> 2); i++)
495 		{
496 			_MMU_write32<ARMCPU_ARM7>(part2ram, T1ReadLong(tmp_data7, src));
497 			src += 4; part2ram += 4;
498 		}
499 		delete [] tmp_data7;
500 		delete [] tmp_data9;
501 
502 #ifdef DEBUG
503 		INFO("\nFlashme:\n");
504 		INFO("- header: \n");
505 		INFO("   * ARM9 boot code address:     0x%08X\n", part1addr);
506 		INFO("   * ARM9 boot code RAM address: 0x%08X\n", ARM9bootAddr);
507 		INFO("   * ARM9 unpacked size:         0x%08X (%i) bytes\n", size9, size9);
508 		INFO("\n");
509 		INFO("   * ARM7 boot code address:     0x%08X\n", part2addr);
510 		INFO("   * ARM7 boot code RAM address: 0x%08X\n", ARM7bootAddr);
511 		INFO("   * ARM7 unpacked size:         0x%08X (%i) bytes\n", size7, size7);
512 #endif
513 	}
514 
515 	memcpy(MMU.fw.data, data, size);
516 	MMU.fw.fp = NULL;
517 
518 	delete [] data; data = NULL;
519 	return true;
520 }
521 
loadSettings()522 bool CFIRMWARE::loadSettings()
523 {
524 	if (!CommonSettings.UseExtFirmware) return false;
525 	if (!CommonSettings.UseExtFirmwareSettings) return false;
526 
527 	FILE *fp = fopen(MMU.fw.userfile, "rb");
528 	if (fp)
529 	{
530 		fseek(fp, 0, SEEK_END);
531 		if (ftell(fp) == DFC_FILE_SIZE)
532 		{
533 			fseek(fp, 0, SEEK_SET);
534 			u8 *usr = new u8[SETTINGS_SIZE];
535 			if (usr)
536 			{
537 				if (fread(usr, 1, DFC_ID_SIZE, fp) == DFC_ID_SIZE)
538 				{
539 					if (memcmp(usr, DFC_ID_CODE, DFC_ID_SIZE) == 0)
540 					{
541 						if (fread(usr, 1, SETTINGS_SIZE, fp) == SETTINGS_SIZE)
542 						{
543 							memcpy(&MMU.fw.data[userDataAddr], usr, USER_SETTINGS_SIZE);
544 							memcpy(&MMU.fw.data[userDataAddr + 0x100], usr, USER_SETTINGS_SIZE);
545 							memcpy(&MMU.fw.data[WIFI_SETTINGS_OFF], usr + USER_SETTINGS_SIZE, WIFI_SETTINGS_SIZE);
546 							memcpy(&MMU.fw.data[WIFI_AP_SETTINGS_OFF], usr + USER_SETTINGS_SIZE + WIFI_SETTINGS_SIZE, WIFI_AP_SETTINGS_SIZE);
547 							printf("Loaded user settings from %s\n", MMU.fw.userfile);
548 						}
549 					}
550 				}
551 				delete [] usr;
552 				usr = NULL;
553 			}
554 		}
555 		else
556 			printf("Failed loading firmware config from %s (wrong file size)\n", MMU.fw.userfile);
557 
558 		fclose(fp);
559 	}
560 
561 	return false;
562 }
563 
saveSettings()564 bool CFIRMWARE::saveSettings()
565 {
566 	if (!CommonSettings.UseExtFirmware) return false;
567 	if (!CommonSettings.UseExtFirmwareSettings) return false;
568 
569 	u8 *data = &MMU.fw.data[userDataAddr];
570 	u8 counter0 = data[0x070];
571 	u8 counter1 = data[0x170];
572 
573 	if (counter1 == ((counter0 + 1) & 0x7F))
574 	{
575 		// copy User Settings 1 to User Settings 0 area
576 		memcpy(data, data + 0x100, 0x100);
577 	}
578 	else
579 	{
580 		// copy User Settings 0 to User Settings 1 area
581 		memcpy(data + 0x100, data, 0x100);
582 	}
583 
584 	printf("Firmware: saving config");
585 	FILE *fp = fopen(MMU.fw.userfile, "wb");
586 	if (fp)
587 	{
588 		u8 *usr = new u8[DFC_FILE_SIZE];
589 		if (usr)
590 		{
591 			memcpy(usr, DFC_ID_CODE, DFC_ID_SIZE);
592 			memcpy(usr + DFC_ID_SIZE, data, USER_SETTINGS_SIZE);
593 			memcpy(usr + DFC_ID_SIZE + USER_SETTINGS_SIZE, &MMU.fw.data[WIFI_SETTINGS_OFF], WIFI_SETTINGS_SIZE);
594 			memcpy(usr + DFC_ID_SIZE + USER_SETTINGS_SIZE + WIFI_SETTINGS_SIZE, &MMU.fw.data[WIFI_AP_SETTINGS_OFF], WIFI_AP_SETTINGS_SIZE);
595 			if (fwrite(usr, 1, DFC_FILE_SIZE, fp) == DFC_FILE_SIZE)
596 				printf(" - done\n");
597 			else
598 				printf(" - failed\n");
599 
600 			delete [] usr;
601 		}
602 		fclose(fp);
603 	}
604 	else
605 		printf(" - failed\n");
606 
607 	return true;
608 }
609 
GetExternalFilePath()610 std::string CFIRMWARE::GetExternalFilePath()
611 {
612 	std::string fwPath = CommonSettings.Firmware;
613 	std::string fwFileName = Path::GetFileNameFromPathWithoutExt(fwPath);
614 	char configPath[PATH_MAX_LENGTH] = {0};
615 	path.getpath(path.BATTERY, configPath);
616 	if (configPath[strlen(configPath)-1] == DIRECTORY_DELIMITER_CHAR)
617 			configPath[strlen(configPath)-1] = 0;
618 	std::string finalPath = std::string(configPath) + DIRECTORY_DELIMITER_CHAR + fwFileName + FILE_EXT_DELIMITER_CHAR + FW_CONFIG_FILE_EXT;
619 
620 	return finalPath;
621 }
622 
getTouchCalibrate()623 void *CFIRMWARE::getTouchCalibrate()
624 {
625 	static TSCalInfo cal = {0};
626 
627 	if (!successLoad || !CommonSettings.UseExtFirmware || !successLoad)
628 	{
629 		cal.adc.x1 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x58) & 0x1FFF;
630 		cal.adc.y1 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x5A) & 0x1FFF;
631 		cal.scr.x1 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x5C);
632 		cal.scr.y1 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x5D);
633 		cal.adc.x2 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x5E) & 0x1FFF;
634 		cal.adc.y2 = _MMU_read16<ARMCPU_ARM7>(0x027FFC80 + 0x60) & 0x1FFF;
635 		cal.scr.x2 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x62);
636 		cal.scr.y2 = _MMU_read08<ARMCPU_ARM7>(0x027FFC80 + 0x63);
637 	}
638 	else
639 	{
640 		cal.adc.x1 = T1ReadWord(MMU.fw.data, userDataAddr + 0x58) & 0x1FFF;
641 		cal.adc.y1 = T1ReadWord(MMU.fw.data, userDataAddr + 0x5A) & 0x1FFF;
642 		cal.scr.x1 = T1ReadByte(MMU.fw.data, userDataAddr + 0x5C);
643 		cal.scr.y1 = T1ReadByte(MMU.fw.data, userDataAddr + 0x5D);
644 		cal.adc.x2 = T1ReadWord(MMU.fw.data, userDataAddr + 0x5E) & 0x1FFF;
645 		cal.adc.y2 = T1ReadWord(MMU.fw.data, userDataAddr + 0x60) & 0x1FFF;
646 		cal.scr.x2 = T1ReadByte(MMU.fw.data, userDataAddr + 0x62);
647 		cal.scr.y2 = T1ReadByte(MMU.fw.data, userDataAddr + 0x63);
648 	}
649 
650 	cal.adc.width	= (cal.adc.x2 - cal.adc.x1);
651 	cal.adc.height	= (cal.adc.y2 - cal.adc.y1);
652 	cal.scr.width	= (cal.scr.x2 - cal.scr.x1);
653 	cal.scr.height	= (cal.scr.y2 - cal.scr.y1);
654 
655 	return (void*)&cal;
656 }
657 
658 //=====================================================================================================
659 static u32
calc_CRC16(u32 start,const u8 * data,int count)660 calc_CRC16( u32 start, const u8 *data, int count) {
661 	int i,j;
662 	u32 crc = start & 0xffff;
663 	const u16 val[8] = { 0xC0C1,0xC181,0xC301,0xC601,0xCC01,0xD801,0xF001,0xA001 };
664 	for(i = 0; i < count; i++)
665 	{
666 		crc = crc ^ data[i];
667 
668 		for(j = 0; j < 8; j++) {
669 			int do_bit = 0;
670 
671 			if ( crc & 0x1)
672 				do_bit = 1;
673 
674 			crc = crc >> 1;
675 
676 			if ( do_bit) {
677 				crc = crc ^ (val[j] << (7-j));
678 			}
679 		}
680 	}
681 	return crc;
682 }
683 
copy_firmware_user_data(u8 * dest_buffer,const u8 * fw_data)684 int copy_firmware_user_data( u8 *dest_buffer, const u8 *fw_data)
685 {
686 	/*
687 	* Determine which of the two user settings in the firmware is the current
688 	* and valid one and then copy this into the destination buffer.
689 	*
690 	* The current setting will have a greater count.
691 	* Settings are only valid if its CRC16 is correct.
692 	*/
693 	int user1_valid = 0;
694 	int user2_valid = 0;
695 	u32 user_settings_offset;
696 	u32 fw_crc;
697 	u32 crc;
698 	int copy_good = 0;
699 
700 	user_settings_offset = fw_data[0x20];
701 	user_settings_offset |= fw_data[0x21] << 8;
702 	user_settings_offset <<= 3;
703 
704 	if ( user_settings_offset <= 0x3FE00) {
705 		s32 copy_settings_offset = -1;
706 
707 		crc = calc_CRC16( 0xffff, &fw_data[user_settings_offset],
708 			NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT);
709 		fw_crc = fw_data[user_settings_offset + 0x72];
710 		fw_crc |= fw_data[user_settings_offset + 0x73] << 8;
711 		if ( crc == fw_crc) {
712 			user1_valid = 1;
713 		}
714 
715 		crc = calc_CRC16( 0xffff, &fw_data[user_settings_offset + 0x100],
716 			NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT);
717 		fw_crc = fw_data[user_settings_offset + 0x100 + 0x72];
718 		fw_crc |= fw_data[user_settings_offset + 0x100 + 0x73] << 8;
719 		if ( crc == fw_crc) {
720 			user2_valid = 1;
721 		}
722 
723 		if ( user1_valid) {
724 			if ( user2_valid) {
725 				u16 count1, count2;
726 
727 				count1 = fw_data[user_settings_offset + 0x70];
728 				count1 |= fw_data[user_settings_offset + 0x71] << 8;
729 
730 				count2 = fw_data[user_settings_offset + 0x100 + 0x70];
731 				count2 |= fw_data[user_settings_offset + 0x100 + 0x71] << 8;
732 
733 				if ( count2 > count1) {
734 					copy_settings_offset = user_settings_offset + 0x100;
735 				}
736 				else {
737 					copy_settings_offset = user_settings_offset;
738 				}
739 			}
740 			else {
741 				copy_settings_offset = user_settings_offset;
742 			}
743 		}
744 		else if ( user2_valid) {
745 			/* copy the second user settings */
746 			copy_settings_offset = user_settings_offset + 0x100;
747 		}
748 
749 		if ( copy_settings_offset > 0) {
750 			memcpy( dest_buffer, &fw_data[copy_settings_offset],
751 				NDS_FW_USER_SETTINGS_MEM_BYTE_COUNT);
752 			copy_good = 1;
753 		}
754 	}
755 
756 	return copy_good;
757 }
758 
fill_user_data_area(struct NDS_fw_config_data * user_settings,u8 * data,int count)759 static void fill_user_data_area( struct NDS_fw_config_data *user_settings,u8 *data, int count)
760 {
761 	u32 crc;
762 	int i;
763 	u8 *ts_cal_data_area;
764 
765 	memset( data, 0, 0x100);
766 
767 	// version
768 	data[0x00] = 5;
769 	data[0x01] = 0;
770 
771 	// colour
772 	data[0x02] = user_settings->fav_colour;
773 
774 	// birthday month and day
775 	data[0x03] = user_settings->birth_month;
776 	data[0x04] = user_settings->birth_day;
777 
778 	//nickname and length
779 	for ( i = 0; i < MAX_FW_NICKNAME_LENGTH; i++) {
780 		data[0x06 + (i * 2)] = user_settings->nickname[i] & 0xff;
781 		data[0x06 + (i * 2) + 1] = (user_settings->nickname[i] >> 8) & 0xff;
782 	}
783 
784 	data[0x1a] = user_settings->nickname_len;
785 
786 	//Message
787 	for ( i = 0; i < MAX_FW_MESSAGE_LENGTH; i++) {
788 		data[0x1c + (i * 2)] = user_settings->message[i] & 0xff;
789 		data[0x1c + (i * 2) + 1] = (user_settings->message[i] >> 8) & 0xff;
790 	}
791 
792 	data[0x50] = user_settings->message_len;
793 
794 	//touch screen calibration
795 	ts_cal_data_area = &data[0x58];
796 	for ( i = 0; i < 2; i++) {
797 		// ADC x y
798 		*ts_cal_data_area++ = user_settings->touch_cal[i].adc_x & 0xff;
799 		*ts_cal_data_area++ = (user_settings->touch_cal[i].adc_x >> 8) & 0xff;
800 		*ts_cal_data_area++ = user_settings->touch_cal[i].adc_y & 0xff;
801 		*ts_cal_data_area++ = (user_settings->touch_cal[i].adc_y >> 8) & 0xff;
802 
803 		//screen x y
804 		*ts_cal_data_area++ = user_settings->touch_cal[i].screen_x;
805 		*ts_cal_data_area++ = user_settings->touch_cal[i].screen_y;
806 	}
807 
808 	//language and flags
809 	data[0x64] = user_settings->language;
810 	data[0x65] = 0xfc;
811 
812 	//update count and crc
813 	data[0x70] = count & 0xff;
814 	data[0x71] = (count >> 8) & 0xff;
815 
816 	crc = calc_CRC16( 0xffff, data, 0x70);
817 	data[0x72] = crc & 0xff;
818 	data[0x73] = (crc >> 8) & 0xff;
819 
820 	memset( &data[0x74], 0xff, 0x100 - 0x74);
821 }
822 
823 // creates an firmware flash image, which contains all needed info to initiate a wifi connection
NDS_CreateDummyFirmware(NDS_fw_config_data * user_settings)824 int NDS_CreateDummyFirmware(NDS_fw_config_data *user_settings)
825 {
826 	//Create the firmware header
827 
828 	memset( MMU.fw.data, 0, 0x40000);
829 
830 	//firmware identifier
831 	MMU.fw.data[0x8] = 'M';
832 	MMU.fw.data[0x8 + 1] = 'A';
833 	MMU.fw.data[0x8 + 2] = 'C';
834 	MMU.fw.data[0x8 + 3] = 'P';
835 
836 	// DS type
837 	if ( user_settings->ds_type == NDS_CONSOLE_TYPE_DSI)
838 		MMU.fw.data[0x1d] = 0xFF;
839 	else
840 		MMU.fw.data[0x1d] = user_settings->ds_type;
841 
842 	//User Settings offset 0x3fe00 / 8
843 	MMU.fw.data[0x20] = 0xc0;
844 	MMU.fw.data[0x21] = 0x7f;
845 
846 
847 	//User settings (at 0x3FE00 and 0x3FF00)
848 
849 	fill_user_data_area( user_settings, &MMU.fw.data[ 0x3FE00], 0);
850 	fill_user_data_area( user_settings, &MMU.fw.data[ 0x3FF00], 1);
851 
852 	// Wifi config length
853 	MMU.fw.data[0x2C] = 0x38;
854 	MMU.fw.data[0x2D] = 0x01;
855 
856 	MMU.fw.data[0x2E] = 0x00;
857 
858 	//Wifi version
859 	MMU.fw.data[0x2F] = 0x00;
860 
861 	//MAC address
862 	memcpy((MMU.fw.data + 0x36), FW_Mac, sizeof(FW_Mac));
863 
864 	//Enabled channels
865 	MMU.fw.data[0x3C] = 0xFE;
866 	MMU.fw.data[0x3D] = 0x3F;
867 
868 	MMU.fw.data[0x3E] = 0xFF;
869 	MMU.fw.data[0x3F] = 0xFF;
870 
871 	//RF related
872 	MMU.fw.data[0x40] = 0x02;
873 	MMU.fw.data[0x41] = 0x18;
874 	MMU.fw.data[0x42] = 0x0C;
875 
876 	MMU.fw.data[0x43] = 0x01;
877 
878 	//Wifi I/O init values
879 	memcpy((MMU.fw.data + 0x44), FW_WIFIInit, sizeof(FW_WIFIInit));
880 
881 	//Wifi BB init values
882 	memcpy((MMU.fw.data + 0x64), FW_BBInit, sizeof(FW_BBInit));
883 
884 	//Wifi RF init values
885 	memcpy((MMU.fw.data + 0xCE), FW_RFInit, sizeof(FW_RFInit));
886 
887 	//Wifi channel-related init values
888 	memcpy((MMU.fw.data + 0xF2), FW_RFChannel, sizeof(FW_RFChannel));
889 	memcpy((MMU.fw.data + 0x146), FW_BBChannel, sizeof(FW_BBChannel));
890 	memset((MMU.fw.data + 0x154), 0x10, 0xE);
891 
892 	//WFC profiles
893 	memcpy((MMU.fw.data + 0x3FA40), &FW_WFCProfile1, sizeof(FW_WFCProfile));
894 	memcpy((MMU.fw.data + 0x3FB40), &FW_WFCProfile2, sizeof(FW_WFCProfile));
895 	memcpy((MMU.fw.data + 0x3FC40), &FW_WFCProfile3, sizeof(FW_WFCProfile));
896 	(*(u16*)(MMU.fw.data + 0x3FAFE)) = (u16)calc_CRC16(0, (MMU.fw.data + 0x3FA00), 0xFE);
897 	(*(u16*)(MMU.fw.data + 0x3FBFE)) = (u16)calc_CRC16(0, (MMU.fw.data + 0x3FB00), 0xFE);
898 	(*(u16*)(MMU.fw.data + 0x3FCFE)) = (u16)calc_CRC16(0, (MMU.fw.data + 0x3FC00), 0xFE);
899 
900 
901 	MMU.fw.data[0x162] = 0x19;
902 	memset((MMU.fw.data + 0x163), 0xFF, 0x9D);
903 
904 	//Wifi settings CRC16
905 	(*(u16*)(MMU.fw.data + 0x2A)) = calc_CRC16(0, (MMU.fw.data + 0x2C), 0x138);
906 
907 	if (&CommonSettings.fw_config != user_settings)
908 		memcpy(&CommonSettings.fw_config, user_settings, sizeof(NDS_fw_config_data));
909 
910 	return TRUE ;
911 }
912 
NDS_FillDefaultFirmwareConfigData(NDS_fw_config_data * fw_config)913 void NDS_FillDefaultFirmwareConfigData(NDS_fw_config_data *fw_config) {
914 	const char *default_nickname = "DeSmuME";
915 	const char *default_message = "DeSmuME makes you happy!";
916 	int i;
917 	int str_length;
918 
919 	memset( fw_config, 0, sizeof(NDS_fw_config_data));
920 	fw_config->ds_type = NDS_CONSOLE_TYPE_FAT;
921 
922 	fw_config->fav_colour = 7;
923 
924 	fw_config->birth_day = 23;
925 	fw_config->birth_month = 6;
926 
927 	str_length = strlen( default_nickname);
928 	for ( i = 0; i < str_length; i++) {
929 		fw_config->nickname[i] = default_nickname[i];
930 	}
931 	fw_config->nickname_len = str_length;
932 
933 	str_length = strlen( default_message);
934 	for ( i = 0; i < str_length; i++) {
935 		fw_config->message[i] = default_message[i];
936 	}
937 	fw_config->message_len = str_length;
938 
939 	//default to English
940 	fw_config->language = 1;
941 
942 	// default touchscreen calibration
943 
944 	//ANCIENT DESMUME VALUES
945 	fw_config->touch_cal[0].adc_x = 0x200;
946 	fw_config->touch_cal[0].adc_y = 0x200;
947 	fw_config->touch_cal[0].screen_x = 0x20 + 1; // calibration screen coords are 1-based,
948 	fw_config->touch_cal[0].screen_y = 0x20 + 1; // either that or NDS_getADCTouchPosX/Y are wrong.
949 	//VALUES FROM NOCASH
950 	//fw_config->touch_cal[0].adc_x = 0x02DF;
951 	//fw_config->touch_cal[0].adc_y = 0x032C;
952 	//fw_config->touch_cal[0].screen_x = 0x20;
953 	//fw_config->touch_cal[0].screen_y = 0x20;
954 
955 	//ANCIENT DESMUME VALUES
956 	fw_config->touch_cal[1].adc_x = 0xe00;
957 	fw_config->touch_cal[1].adc_y = 0x800;
958 	fw_config->touch_cal[1].screen_x = 0xe0 + 1;
959 	fw_config->touch_cal[1].screen_y = 0x80 + 1;
960 	//VALUES FROM NOCASH
961 	//fw_config->touch_cal[1].adc_x = 0x0D3B;
962 	//fw_config->touch_cal[1].adc_y = 0x0CE7;
963 	//fw_config->touch_cal[1].screen_x = 0xE0;
964 	//fw_config->touch_cal[1].screen_y = 0xA0;
965 }
966 
NDS_PatchFirmwareMAC()967 void NDS_PatchFirmwareMAC()
968 {
969 	memcpy((MMU.fw.data + 0x36), FW_Mac, sizeof(FW_Mac));
970 	(*(u16*)(MMU.fw.data + 0x2A)) = calc_CRC16(0, (MMU.fw.data + 0x2C), 0x138);
971 }
972 
973 //=========================
974 //- firmware SPI chip interface -
975 //the original intention was for this code to have similarity to the AUXSPI backup memory devices.
976 //however, that got overgrown, and this stuff stayed pretty simple.
977 //perhaps it can be re-defined in terms of a simpler AUXSPI device after the AUXSPI devices are re-designed.
978 
979 #define FW_CMD_READ             0x03
980 #define FW_CMD_WRITEDISABLE     0x04
981 #define FW_CMD_READSTATUS       0x05
982 #define FW_CMD_WRITEENABLE      0x06
983 #define FW_CMD_PAGEWRITE        0x0A
984 #define FW_CMD_READ_ID			0x9F
985 
fw_reset_com(fw_memory_chip * mc)986 void fw_reset_com(fw_memory_chip *mc)
987 {
988 	if(mc->com == FW_CMD_PAGEWRITE)
989 	{
990 		if (mc->fp)
991 		{
992 			fseek(mc->fp, 0, SEEK_SET);
993 			fwrite(mc->data, mc->size, 1, mc->fp);
994 		}
995 
996 		if (mc->isFirmware && CommonSettings.UseExtFirmware && CommonSettings.UseExtFirmwareSettings && firmware)
997 		{
998 			firmware->saveSettings();
999 		}
1000 		mc->write_enable = FALSE;
1001 	}
1002 
1003 	mc->com = 0;
1004 }
1005 
fw_transfer(fw_memory_chip * mc,u8 data)1006 u8 fw_transfer(fw_memory_chip *mc, u8 data)
1007 {
1008 	if(mc->com == FW_CMD_READ || mc->com == FW_CMD_PAGEWRITE) /* check if we are in a command that needs 3 bytes address */
1009 	{
1010 		if(mc->addr_shift > 0)   /* if we got a complete address */
1011 		{
1012 			mc->addr_shift--;
1013 			mc->addr |= data << (mc->addr_shift * 8); /* argument is a byte of address */
1014 		}
1015 		else    /* if we have received 3 bytes of address, proceed command */
1016 		{
1017 			switch(mc->com)
1018 			{
1019 				case FW_CMD_READ:
1020 					if(mc->addr < mc->size)  /* check if we can read */
1021 					{
1022 						data = mc->data[mc->addr];       /* return byte */
1023 						mc->addr++;      /* then increment address */
1024 					}
1025 					break;
1026 
1027 				case FW_CMD_PAGEWRITE:
1028 					if(mc->addr < mc->size)
1029 					{
1030 						mc->data[mc->addr] = data;       /* write byte */
1031 						mc->addr++;
1032 					}
1033 					break;
1034 			}
1035 
1036 		}
1037 	}
1038 	else if(mc->com == FW_CMD_READ_ID)
1039 	{
1040 		switch(mc->addr)
1041 		{
1042 		//here is an ID string measured from an old ds fat: 62 16 00 (0x62=sanyo)
1043 		//but we chose to use an ST from martin's ds fat string so programs might have a clue as to the firmware size:
1044 		//20 40 12
1045 		case 0:
1046 			data = 0x20;
1047 			mc->addr=1;
1048 			break;
1049 		case 1:
1050 			data = 0x40; //according to gbatek this is the device ID for the flash on someone's ds fat
1051 			mc->addr=2;
1052 			break;
1053 		case 2:
1054 			data = 0x12;
1055 			mc->addr = 0;
1056 			break;
1057 		}
1058 	}
1059 	else if(mc->com == FW_CMD_READSTATUS)
1060 	{
1061 		return (mc->write_enable ? 0x02 : 0x00);
1062 	}
1063 	else	//finally, check if it's a new command
1064 	{
1065 		switch(data)
1066 		{
1067 			case 0: break;	//nothing
1068 
1069 			case FW_CMD_READ_ID:
1070 				mc->addr = 0;
1071 				mc->com = FW_CMD_READ_ID;
1072 				break;
1073 
1074 			case FW_CMD_READ:    //read command
1075 				mc->addr = 0;
1076 				mc->addr_shift = 3;
1077 				mc->com = FW_CMD_READ;
1078 				break;
1079 
1080 			case FW_CMD_WRITEENABLE:     //enable writing
1081 				if(mc->writeable_buffer) { mc->write_enable = TRUE; }
1082 				break;
1083 
1084 			case FW_CMD_WRITEDISABLE:    //disable writing
1085 				mc->write_enable = FALSE;
1086 				break;
1087 
1088 			case FW_CMD_PAGEWRITE:       //write command
1089 				if(mc->write_enable)
1090 				{
1091 					mc->addr = 0;
1092 					mc->addr_shift = 3;
1093 					mc->com = FW_CMD_PAGEWRITE;
1094 				}
1095 				else { data = 0; }
1096 				break;
1097 
1098 			case FW_CMD_READSTATUS:  //status register command
1099 				mc->com = FW_CMD_READSTATUS;
1100 				break;
1101 
1102 			default:
1103 				printf("Unhandled FW command: %02X\n", data);
1104 				break;
1105 		}
1106 	}
1107 
1108 	return data;
1109 }
1110 
1111 
mc_init(fw_memory_chip * mc,int type)1112 void mc_init(fw_memory_chip *mc, int type)
1113 {
1114 	mc->com = 0;
1115 	mc->addr = 0;
1116 	mc->addr_shift = 0;
1117 	mc->data = NULL;
1118 	mc->size = 0;
1119 	mc->write_enable = FALSE;
1120 	mc->writeable_buffer = FALSE;
1121 	mc->type = type;
1122 
1123 	switch(mc->type)
1124 	{
1125 	case MC_TYPE_EEPROM1:
1126 		mc->addr_size = 1;
1127 		break;
1128 	case MC_TYPE_EEPROM2:
1129 	case MC_TYPE_FRAM:
1130 		mc->addr_size = 2;
1131 		break;
1132 	case MC_TYPE_FLASH:
1133 		mc->addr_size = 3;
1134 		break;
1135 	default: break;
1136 	}
1137 }
1138 
mc_alloc(fw_memory_chip * mc,u32 size)1139 u8 *mc_alloc(fw_memory_chip *mc, u32 size)
1140 {
1141 	u8 *buffer = NULL;
1142 	buffer = new u8[size];
1143 	if(!buffer) { return NULL; }
1144 	memset(buffer,0,size);
1145 
1146 	if (mc->data) delete [] mc->data;
1147 	mc->data = buffer;
1148 	mc->size = size;
1149 	mc->writeable_buffer = TRUE;
1150 
1151 	return buffer;
1152 }
1153 
mc_free(fw_memory_chip * mc)1154 void mc_free(fw_memory_chip *mc)
1155 {
1156     if(mc->data) delete[] mc->data;
1157     mc_init(mc, 0);
1158 }
1159