Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/nyx/nyx_gui/frontend/fe_emummc_tools.c
1476 views
1
/*
2
* Copyright (c) 2018 naehrwert
3
* Copyright (c) 2018 Rajko Stojadinovic
4
* Copyright (c) 2018-2024 CTCaer
5
*
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms and conditions of the GNU General Public License,
8
* version 2, as published by the Free Software Foundation.
9
*
10
* This program is distributed in the hope it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
* more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
//! fix the dram stuff and the pop ups
20
21
#include <string.h>
22
#include <stdlib.h>
23
24
#include <bdk.h>
25
26
#include "gui.h"
27
#include "fe_emummc_tools.h"
28
#include "../config.h"
29
#include <libs/fatfs/diskio.h>
30
#include <libs/fatfs/ff.h>
31
32
#define OUT_FILENAME_SZ 128
33
#define NAND_PATROL_SECTOR 0xC20
34
#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.
35
36
extern hekate_config h_cfg;
37
extern volatile boot_cfg_t *b_cfg;
38
39
void load_emummc_cfg(emummc_cfg_t *emu_info)
40
{
41
memset(emu_info, 0, sizeof(emummc_cfg_t));
42
43
// Parse emuMMC configuration.
44
LIST_INIT(ini_sections);
45
if (!ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
46
return;
47
48
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
49
{
50
if (!strcmp(ini_sec->name, "emummc"))
51
{
52
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
53
{
54
if (!strcmp("enabled", kv->key))
55
emu_info->enabled = atoi(kv->val);
56
else if (!strcmp("sector", kv->key))
57
emu_info->sector = strtol(kv->val, NULL, 16);
58
else if (!strcmp("id", kv->key))
59
emu_info->id = strtol(kv->val, NULL, 16);
60
else if (!strcmp("path", kv->key))
61
{
62
emu_info->path = (char *)malloc(strlen(kv->val) + 1);
63
strcpy(emu_info->path, kv->val);
64
}
65
else if (!strcmp("nintendo_path", kv->key))
66
{
67
emu_info->nintendo_path = (char *)malloc(strlen(kv->val) + 1);
68
strcpy(emu_info->nintendo_path, kv->val);
69
}
70
}
71
72
break;
73
}
74
}
75
76
ini_free(&ini_sections);
77
}
78
79
void save_emummc_cfg(u32 part_idx, u32 sector_start, const char *path)
80
{
81
sd_mount();
82
83
char lbuf[16];
84
FIL fp;
85
86
if (f_open(&fp, "emuMMC/emummc.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
87
return;
88
89
// Add config entry.
90
f_puts("[emummc]\nenabled=", &fp);
91
if (part_idx && sector_start)
92
{
93
itoa(part_idx, lbuf, 10);
94
f_puts(lbuf, &fp);
95
}
96
else if (path)
97
f_puts("1", &fp);
98
else
99
f_puts("0", &fp);
100
101
if (!sector_start)
102
f_puts("\nsector=0x0", &fp);
103
else
104
{
105
f_puts("\nsector=0x", &fp);
106
itoa(sector_start, lbuf, 16);
107
f_puts(lbuf, &fp);
108
}
109
if (path)
110
{
111
f_puts("\npath=", &fp);
112
f_puts(path, &fp);
113
}
114
115
// Get ID from path.
116
u32 id_from_path = 0;
117
if (path && strlen(path) >= 4)
118
memcpy(&id_from_path, path + strlen(path) - 4, 4);
119
f_puts("\nid=0x", &fp);
120
itoa(id_from_path, lbuf, 16);
121
f_puts(lbuf, &fp);
122
123
f_puts("\nnintendo_path=", &fp);
124
if (path)
125
{
126
f_puts(path, &fp);
127
f_puts("/Nintendo\n", &fp);
128
}
129
else
130
f_puts("\n", &fp);
131
132
f_close(&fp);
133
}
134
135
void update_emummc_base_folder(char *outFilename, u32 sdPathLen, u32 currPartIdx)
136
{
137
if (currPartIdx < 10)
138
{
139
outFilename[sdPathLen] = '0';
140
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
141
}
142
else
143
itoa(currPartIdx, &outFilename[sdPathLen], 10);
144
}
145
146
static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_storage_t *storage, const emmc_part_t *part)
147
{
148
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
149
static const u32 SECTORS_TO_MIB_COEFF = 11;
150
151
u32 multipartSplitSize = 0xFE000000;
152
u32 totalSectors = part->lba_end - part->lba_start + 1;
153
u32 currPartIdx = 0;
154
u32 numSplitParts = 0;
155
int res = 0;
156
char *outFilename = sd_path;
157
u32 sdPathLen = strlen(sd_path);
158
159
s_printf(gui->txt_buf, "#96FF00 SD Card free space:# %d MiB\n#96FF00 Total size:# %d MiB\n\n",
160
(u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF),
161
totalSectors >> SECTORS_TO_MIB_COEFF);
162
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
163
manual_system_maintenance(true);
164
165
lv_bar_set_value(gui->bar, 0);
166
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 0%");
167
manual_system_maintenance(true);
168
169
// Check if the USER partition or the RAW eMMC fits the sd card free space.
170
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
171
{
172
s_printf(gui->txt_buf, "\n#FFDD00 Not enough free space for file based emuMMC!#\n");
173
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
174
manual_system_maintenance(true);
175
176
return 0;
177
}
178
179
// Check if filesystem is FAT32 or the free space is smaller and dump in parts.
180
if (totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE))
181
{
182
u32 multipartSplitSectors = multipartSplitSize / EMMC_BLOCKSIZE;
183
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
184
185
// Get first part filename.
186
update_emummc_base_folder(outFilename, sdPathLen, 0);
187
}
188
189
FIL fp;
190
s_printf(gui->txt_buf, "#96FF00 Filepath:#\n%s\n#96FF00 Filename:# #FF8000 %s#",
191
gui->base_path, outFilename + strlen(gui->base_path));
192
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
193
manual_system_maintenance(true);
194
195
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
196
if (res)
197
{
198
s_printf(gui->txt_buf, "\n#FF0000 Error (%d) while creating#\n#FFDD00 %s#\n", res, outFilename);
199
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
200
manual_system_maintenance(true);
201
202
return 0;
203
}
204
205
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
206
207
u32 lba_curr = part->lba_start;
208
u32 bytesWritten = 0;
209
u32 prevPct = 200;
210
int retryCount = 0;
211
DWORD *clmt = NULL;
212
213
u64 totalSize = (u64)((u64)totalSectors << 9);
214
if (totalSize <= FAT32_FILESIZE_LIMIT)
215
clmt = f_expand_cltbl(&fp, SZ_4M, totalSize);
216
else
217
clmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize));
218
219
u32 num = 0;
220
u32 pct = 0;
221
222
lv_obj_set_opa_scale(gui->bar, LV_OPA_COVER);
223
lv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER);
224
while (totalSectors > 0)
225
{
226
if (numSplitParts != 0 && bytesWritten >= multipartSplitSize)
227
{
228
f_close(&fp);
229
free(clmt);
230
memset(&fp, 0, sizeof(fp));
231
currPartIdx++;
232
233
update_emummc_base_folder(outFilename, sdPathLen, currPartIdx);
234
235
// Create next part.
236
s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path));
237
lv_label_cut_text(gui->label_info, strlen(lv_label_get_text(gui->label_info)) - 3, 3);
238
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
239
manual_system_maintenance(true);
240
241
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
242
if (res)
243
{
244
s_printf(gui->txt_buf, "\n#FF0000 Error (%d) while creating#\n#FFDD00 %s#\n", res, outFilename);
245
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
246
manual_system_maintenance(true);
247
248
return 0;
249
}
250
251
bytesWritten = 0;
252
253
totalSize = (u64)((u64)totalSectors << 9);
254
clmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize));
255
}
256
257
// Check for cancellation combo.
258
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
259
{
260
s_printf(gui->txt_buf, "\n#FFDD00 The emuMMC was cancelled!#\n");
261
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
262
manual_system_maintenance(true);
263
264
f_close(&fp);
265
free(clmt);
266
f_unlink(outFilename);
267
268
msleep(1000);
269
270
return 0;
271
}
272
273
retryCount = 0;
274
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
275
276
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
277
{
278
s_printf(gui->txt_buf,
279
"\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n"
280
"#FFDD00 from eMMC (try %d). #",
281
num, lba_curr, ++retryCount);
282
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
283
manual_system_maintenance(true);
284
285
msleep(150);
286
if (retryCount >= 3)
287
{
288
s_printf(gui->txt_buf, "#FF0000 Aborting...#\nPlease try again...\n");
289
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
290
manual_system_maintenance(true);
291
292
f_close(&fp);
293
free(clmt);
294
f_unlink(outFilename);
295
296
return 0;
297
}
298
else
299
{
300
s_printf(gui->txt_buf, "#FFDD00 Retrying...#");
301
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
302
manual_system_maintenance(true);
303
}
304
}
305
306
manual_system_maintenance(false);
307
308
res = f_write_fast(&fp, buf, EMMC_BLOCKSIZE * num);
309
310
manual_system_maintenance(false);
311
312
if (res)
313
{
314
s_printf(gui->txt_buf, "\n#FF0000 Fatal error (%d) when writing to SD Card#\nPlease try again...\n", res);
315
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
316
manual_system_maintenance(true);
317
318
f_close(&fp);
319
free(clmt);
320
f_unlink(outFilename);
321
322
return 0;
323
}
324
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
325
if (pct != prevPct)
326
{
327
lv_bar_set_value(gui->bar, pct);
328
s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct);
329
lv_label_set_text(gui->label_pct, gui->txt_buf);
330
manual_system_maintenance(true);
331
332
prevPct = pct;
333
}
334
335
lba_curr += num;
336
totalSectors -= num;
337
bytesWritten += num * EMMC_BLOCKSIZE;
338
339
// Force a flush after a lot of data if not splitting.
340
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
341
{
342
f_sync(&fp);
343
bytesWritten = 0;
344
}
345
346
manual_system_maintenance(false);
347
}
348
lv_bar_set_value(gui->bar, 100);
349
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%");
350
manual_system_maintenance(true);
351
352
// Operation ended successfully.
353
f_close(&fp);
354
free(clmt);
355
356
return 1;
357
}
358
359
void dump_emummc_file(emmc_tool_gui_t *gui)
360
{
361
int res = 0;
362
int base_len = 0;
363
u32 timer = 0;
364
365
char *txt_buf = (char *)malloc(SZ_16K);
366
gui->base_path = (char *)malloc(OUT_FILENAME_SZ);
367
gui->txt_buf = txt_buf;
368
369
txt_buf[0] = 0;
370
lv_label_set_text(gui->label_log, txt_buf);
371
372
manual_system_maintenance(true);
373
374
if (!sd_mount())
375
{
376
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init SD!#");
377
goto out;
378
}
379
380
lv_label_set_text(gui->label_info, "Checking for available free space...");
381
manual_system_maintenance(true);
382
383
// Get SD Card free space for file based emuMMC.
384
f_getfree("", &sd_fs.free_clst, NULL);
385
386
if (!emmc_initialize(false))
387
{
388
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
389
goto out;
390
}
391
392
int i = 0;
393
char sdPath[OUT_FILENAME_SZ];
394
// Create Restore folders, if they do not exist.
395
f_mkdir("emuMMC");
396
strcpy(sdPath, "emuMMC/SD");
397
base_len = strlen(sdPath);
398
399
for (int j = 0; j < 100; j++)
400
{
401
update_emummc_base_folder(sdPath, base_len, j);
402
if (f_stat(sdPath, NULL) == FR_NO_FILE)
403
break;
404
}
405
406
f_mkdir(sdPath);
407
strcat(sdPath, "/eMMC");
408
f_mkdir(sdPath);
409
strcat(sdPath, "/");
410
strcpy(gui->base_path, sdPath);
411
412
timer = get_tmr_s();
413
const u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB.
414
415
emmc_part_t bootPart;
416
memset(&bootPart, 0, sizeof(bootPart));
417
bootPart.lba_start = 0;
418
bootPart.lba_end = BOOT_PART_SECTORS - 1;
419
420
for (i = 0; i < 2; i++)
421
{
422
strcpy(bootPart.name, "BOOT");
423
bootPart.name[4] = (u8)('0' + i);
424
bootPart.name[5] = 0;
425
426
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
427
i, bootPart.name, bootPart.lba_start, bootPart.lba_end);
428
lv_label_set_text(gui->label_info, txt_buf);
429
s_printf(txt_buf, "%02d: %s... ", i, bootPart.name);
430
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
431
manual_system_maintenance(true);
432
433
emmc_set_partition(i + 1);
434
435
strcat(sdPath, bootPart.name);
436
res = _dump_emummc_file_part(gui, sdPath, &emmc_storage, &bootPart);
437
438
if (!res)
439
{
440
s_printf(txt_buf, "#FFDD00 Failed!#\n");
441
goto out_failed;
442
}
443
else
444
s_printf(txt_buf, "Done!\n");
445
446
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
447
manual_system_maintenance(true);
448
449
strcpy(sdPath, gui->base_path);
450
}
451
452
// Get GP partition size dynamically.
453
emmc_set_partition(EMMC_GPP);
454
455
// Get GP partition size dynamically.
456
const u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt;
457
458
emmc_part_t rawPart;
459
memset(&rawPart, 0, sizeof(rawPart));
460
rawPart.lba_start = 0;
461
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
462
strcpy(rawPart.name, "GPP");
463
464
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
465
i, rawPart.name, rawPart.lba_start, rawPart.lba_end);
466
lv_label_set_text(gui->label_info, txt_buf);
467
s_printf(txt_buf, "%02d: %s... ", i, rawPart.name);
468
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
469
manual_system_maintenance(true);
470
471
res = _dump_emummc_file_part(gui, sdPath, &emmc_storage, &rawPart);
472
473
if (!res)
474
s_printf(txt_buf, "#FFDD00 Failed!#\n");
475
else
476
s_printf(txt_buf, "Done!\n");
477
478
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
479
manual_system_maintenance(true);
480
481
out_failed:
482
timer = get_tmr_s() - timer;
483
emmc_end();
484
485
if (res)
486
{
487
s_printf(txt_buf, "Time taken: %dm %ds.\nFinished!", timer / 60, timer % 60);
488
gui->base_path[strlen(gui->base_path) - 5] = '\0';
489
strcpy(sdPath, gui->base_path);
490
strcat(sdPath, "file_based");
491
FIL fp;
492
f_open(&fp, sdPath, FA_CREATE_ALWAYS | FA_WRITE);
493
f_close(&fp);
494
495
gui->base_path[strlen(gui->base_path) - 1] = 0;
496
save_emummc_cfg(0, 0, gui->base_path);
497
}
498
else
499
s_printf(txt_buf, "Time taken: %dm %ds.", timer / 60, timer % 60);
500
501
lv_label_set_text(gui->label_finish, txt_buf);
502
503
out:
504
free(txt_buf);
505
free(gui->base_path);
506
sd_unmount();
507
}
508
509
static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part_idx, u32 sd_part_off, emmc_part_t *part, u32 resized_count)
510
{
511
u32 num = 0;
512
u32 pct = 0;
513
u32 prevPct = 200;
514
int retryCount = 0;
515
u32 sd_sector_off = sd_part_off + (0x2000 * active_part);
516
u32 lba_curr = part->lba_start;
517
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
518
519
s_printf(gui->txt_buf, "\n\n\n");
520
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
521
manual_system_maintenance(true);
522
523
lv_bar_set_value(gui->bar, 0);
524
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 0%");
525
manual_system_maintenance(true);
526
527
s_printf(gui->txt_buf, "#96FF00 Base folder:#\n%s\n#96FF00 Partition offset:# #FF8000 0x%08X#",
528
gui->base_path, sd_part_off);
529
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
530
manual_system_maintenance(true);
531
532
lv_obj_set_opa_scale(gui->bar, LV_OPA_COVER);
533
lv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER);
534
535
u32 user_offset = 0;
536
537
if (resized_count)
538
{
539
// Get USER partition info.
540
LIST_INIT(gpt_parsed);
541
emmc_gpt_parse(&gpt_parsed);
542
emmc_part_t *user_part = emmc_part_find(&gpt_parsed, "USER");
543
if (!user_part)
544
{
545
s_printf(gui->txt_buf, "\n#FFDD00 USER partition not found!#\n");
546
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
547
manual_system_maintenance(true);
548
549
return 0;
550
}
551
552
user_offset = user_part->lba_start;
553
part->lba_end = user_offset - 1;
554
emmc_gpt_free(&gpt_parsed);
555
}
556
557
u32 totalSectors = part->lba_end - part->lba_start + 1;
558
while (totalSectors > 0)
559
{
560
// Check for cancellation combo.
561
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
562
{
563
s_printf(gui->txt_buf, "\n#FFDD00 The emuMMC was cancelled!#\n");
564
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
565
manual_system_maintenance(true);
566
567
msleep(1000);
568
569
return 0;
570
}
571
572
retryCount = 0;
573
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
574
575
// Read data from eMMC.
576
while (!sdmmc_storage_read(&emmc_storage, lba_curr, num, buf))
577
{
578
s_printf(gui->txt_buf,
579
"\n#FFDD00 Error reading %d blocks @LBA %08X,#\n"
580
"#FFDD00 from eMMC (try %d). #",
581
num, lba_curr, ++retryCount);
582
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
583
manual_system_maintenance(true);
584
585
msleep(150);
586
if (retryCount >= 3)
587
{
588
s_printf(gui->txt_buf, "#FF0000 Aborting...#\nPlease try again...\n");
589
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
590
manual_system_maintenance(true);
591
592
return 0;
593
}
594
else
595
{
596
s_printf(gui->txt_buf, "#FFDD00 Retrying...#\n");
597
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
598
manual_system_maintenance(true);
599
}
600
}
601
602
manual_system_maintenance(false);
603
604
// Write data to SD card.
605
retryCount = 0;
606
while (!sdmmc_storage_write(&sd_storage, sd_sector_off + lba_curr, num, buf))
607
{
608
s_printf(gui->txt_buf,
609
"\n#FFDD00 Error writing %d blocks @LBA %08X,#\n"
610
"#FFDD00 to SD (try %d). #",
611
num, lba_curr, ++retryCount);
612
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
613
manual_system_maintenance(true);
614
615
msleep(150);
616
if (retryCount >= 3)
617
{
618
s_printf(gui->txt_buf, "#FF0000 Aborting...#\nPlease try again...\n");
619
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
620
manual_system_maintenance(true);
621
622
return 0;
623
}
624
else
625
{
626
s_printf(gui->txt_buf, "#FFDD00 Retrying...#\n");
627
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
628
manual_system_maintenance(true);
629
}
630
}
631
632
manual_system_maintenance(false);
633
634
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
635
if (pct != prevPct)
636
{
637
lv_bar_set_value(gui->bar, pct);
638
s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct);
639
lv_label_set_text(gui->label_pct, gui->txt_buf);
640
manual_system_maintenance(true);
641
642
prevPct = pct;
643
}
644
645
lba_curr += num;
646
totalSectors -= num;
647
}
648
lv_bar_set_value(gui->bar, 100);
649
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%");
650
manual_system_maintenance(true);
651
652
// Set partition type to emuMMC (0xE0).
653
if (active_part == 2)
654
{
655
mbr_t mbr;
656
sdmmc_storage_read(&sd_storage, 0, 1, &mbr);
657
mbr.partitions[part_idx].type = 0xE0;
658
sdmmc_storage_write(&sd_storage, 0, 1, &mbr);
659
}
660
661
if (resized_count)
662
{
663
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, "Done!\n");
664
665
// Calculate USER size and set it for FatFS.
666
u32 user_sectors = resized_count - user_offset - 33;
667
user_sectors = ALIGN_DOWN(user_sectors, 0x20); // Align down to cluster size.
668
disk_set_info(DRIVE_EMU, SET_SECTOR_COUNT, &user_sectors);
669
670
// Initialize BIS for emuMMC. BIS keys should be already in place.
671
emmc_part_t user_part = {0};
672
user_part.lba_start = user_offset;
673
user_part.lba_end = user_offset + user_sectors - 1;
674
strcpy(user_part.name, "USER");
675
nx_emmc_bis_init(&user_part, true, sd_sector_off);
676
677
s_printf(gui->txt_buf, "Formatting USER... \n");
678
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
679
manual_system_maintenance(true);
680
681
// Format USER partition.
682
u8 *buff = malloc(SZ_4M);
683
int mkfs_error = f_mkfs("emu:", FM_FAT32 | FM_SFD | FM_PRF2, 16384, buff, SZ_4M);
684
free(buff);
685
686
// Mount sd card back.
687
sd_mount();
688
689
if (mkfs_error)
690
{
691
s_printf(gui->txt_buf, "#FF0000 Failed (%d)!#\nPlease try again...\n", mkfs_error);
692
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
693
694
return 0;
695
}
696
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, "Done!\n");
697
698
// Flush BIS cache, deinit, clear BIS keys slots and reinstate SBK.
699
nx_emmc_bis_end();
700
hos_bis_keys_clear();
701
702
s_printf(gui->txt_buf, "Writing new GPT... ");
703
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
704
manual_system_maintenance(true);
705
706
// Read MBR, GPT and backup GPT.
707
mbr_t mbr;
708
gpt_t *gpt = zalloc(sizeof(gpt_t));
709
gpt_header_t gpt_hdr_backup;
710
sdmmc_storage_read(&emmc_storage, 0, 1, &mbr);
711
sdmmc_storage_read(&emmc_storage, 1, sizeof(gpt_t) >> 9, gpt);
712
sdmmc_storage_read(&emmc_storage, gpt->header.alt_lba, 1, &gpt_hdr_backup);
713
714
// Find USER partition.
715
u32 gpt_entry_idx = 0;
716
for (gpt_entry_idx = 0; gpt_entry_idx < gpt->header.num_part_ents; gpt_entry_idx++)
717
if (!memcmp(gpt->entries[gpt_entry_idx].name, (char[]) { 'U', 0, 'S', 0, 'E', 0, 'R', 0 }, 8))
718
break;
719
720
if (gpt_entry_idx >= gpt->header.num_part_ents)
721
{
722
s_printf(gui->txt_buf, "\n#FF0000 No USER partition...#\nPlease try again...\n");
723
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
724
free(gpt);
725
726
return 0;
727
}
728
729
// Set new emuMMC size and USER size.
730
mbr.partitions[0].size_sct = resized_count;
731
gpt->entries[gpt_entry_idx].lba_end = user_part.lba_end;
732
733
// Update Main GPT.
734
gpt->header.alt_lba = resized_count - 1;
735
gpt->header.last_use_lba = resized_count - 34;
736
gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents);
737
gpt->header.crc32 = 0; // Set to 0 for calculation.
738
gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);
739
740
// Update Backup GPT.
741
gpt_hdr_backup.my_lba = resized_count - 1;
742
gpt_hdr_backup.part_ent_lba = resized_count - 33;
743
gpt_hdr_backup.part_ents_crc32 = gpt->header.part_ents_crc32;
744
gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.
745
gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);
746
747
// Write main GPT.
748
sdmmc_storage_write(&sd_storage, sd_sector_off + gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt);
749
750
// Write backup GPT partition table.
751
sdmmc_storage_write(&sd_storage, sd_sector_off + gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries);
752
753
// Write backup GPT header.
754
sdmmc_storage_write(&sd_storage, sd_sector_off + gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);
755
756
// Write MBR.
757
sdmmc_storage_write(&sd_storage, sd_sector_off, 1, &mbr);
758
759
// Clear nand patrol.
760
memset(buf, 0, EMMC_BLOCKSIZE);
761
sdmmc_storage_write(&sd_storage, sd_part_off + NAND_PATROL_SECTOR, 1, buf);
762
763
free(gpt);
764
}
765
766
return 1;
767
}
768
769
static int _emummc_raw_derive_bis_keys(emmc_tool_gui_t *gui, u32 resized_count)
770
{
771
if (!resized_count)
772
return 1;
773
774
bool error = false;
775
776
char *txt_buf = (char *)malloc(SZ_16K);
777
txt_buf[0] = 0;
778
779
// Generate BIS keys.
780
hos_bis_keygen();
781
782
u8 *cal0_buff = malloc(SZ_64K);
783
784
// Read and decrypt CAL0 for validation of working BIS keys.
785
emmc_set_partition(EMMC_GPP);
786
LIST_INIT(gpt);
787
emmc_gpt_parse(&gpt);
788
emmc_part_t *cal0_part = emmc_part_find(&gpt, "PRODINFO"); // check if null
789
nx_emmc_bis_init(cal0_part, false, 0);
790
nx_emmc_bis_read(0, 0x40, cal0_buff);
791
nx_emmc_bis_end();
792
emmc_gpt_free(&gpt);
793
794
nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buff;
795
796
// Check keys validity.
797
if (memcmp(&cal0->magic, "CAL0", 4))
798
{
799
// Clear EKS keys.
800
hos_eks_clear(HOS_KB_VERSION_MAX);
801
802
strcpy(txt_buf, "#FFDD00 BIS keys validation failed!#\n");
803
error = true;
804
}
805
806
free(cal0_buff);
807
808
if (error)
809
{
810
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
811
lv_obj_set_style(dark_bg, &mbox_darken);
812
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
813
814
static const char * mbox_btn_map[] = { "\251", "\222Close", "\251", "" };
815
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
816
lv_mbox_set_recolor_text(mbox, true);
817
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);
818
819
lv_mbox_set_text(mbox, "#C7EA46 BIS Keys Generation#");
820
821
lv_obj_t * lb_desc = lv_label_create(mbox, NULL);
822
lv_label_set_long_mode(lb_desc, LV_LABEL_LONG_BREAK);
823
lv_label_set_recolor(lb_desc, true);
824
lv_label_set_style(lb_desc, &monospace_text);
825
lv_obj_set_width(lb_desc, LV_HOR_RES / 9 * 4);
826
827
lv_label_set_text(lb_desc, txt_buf);
828
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
829
830
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
831
lv_obj_set_top(mbox, true);
832
833
free(txt_buf);
834
835
return 0;
836
}
837
838
free(txt_buf);
839
840
return 1;
841
}
842
843
void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 resized_count)
844
{
845
int res = 0;
846
u32 timer = 0;
847
848
char *txt_buf = (char *)malloc(SZ_16K);
849
gui->base_path = (char *)malloc(OUT_FILENAME_SZ);
850
gui->txt_buf = txt_buf;
851
852
txt_buf[0] = 0;
853
lv_label_set_text(gui->label_log, txt_buf);
854
855
manual_system_maintenance(true);
856
857
if (!sd_mount())
858
{
859
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init SD!#");
860
goto out;
861
}
862
863
if (!emmc_initialize(false))
864
{
865
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
866
goto out;
867
}
868
869
if (!_emummc_raw_derive_bis_keys(gui, resized_count))
870
{
871
s_printf(gui->txt_buf, "#FFDD00 For formatting USER partition,#\n#FFDD00 BIS keys are needed!#\n");
872
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
873
emmc_end();
874
goto out;
875
}
876
877
int i = 0;
878
char sdPath[OUT_FILENAME_SZ];
879
// Create Restore folders, if they do not exist.
880
f_mkdir("emuMMC");
881
s_printf(sdPath, "emuMMC/RAW%d", part_idx);
882
f_mkdir(sdPath);
883
strcat(sdPath, "/");
884
strcpy(gui->base_path, sdPath);
885
886
timer = get_tmr_s();
887
const u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB.
888
889
emmc_part_t bootPart;
890
memset(&bootPart, 0, sizeof(bootPart));
891
bootPart.lba_start = 0;
892
bootPart.lba_end = BOOT_PART_SECTORS - 1;
893
894
// Clear partition start.
895
memset((u8 *)MIXD_BUF_ALIGNED, 0, SZ_16M);
896
sdmmc_storage_write(&sd_storage, sector_start - 0x8000, 0x8000, (u8 *)MIXD_BUF_ALIGNED);
897
898
for (i = 0; i < 2; i++)
899
{
900
strcpy(bootPart.name, "BOOT");
901
bootPart.name[4] = (u8)('0' + i);
902
bootPart.name[5] = 0;
903
904
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
905
i, bootPart.name, bootPart.lba_start, bootPart.lba_end);
906
lv_label_set_text(gui->label_info, txt_buf);
907
s_printf(txt_buf, "%02d: %s... ", i, bootPart.name);
908
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
909
manual_system_maintenance(true);
910
911
emmc_set_partition(i + 1);
912
913
strcat(sdPath, bootPart.name);
914
res = _dump_emummc_raw_part(gui, i, part_idx, sector_start, &bootPart, 0);
915
916
if (!res)
917
{
918
s_printf(txt_buf, "#FFDD00 Failed!#\n");
919
goto out_failed;
920
}
921
else
922
s_printf(txt_buf, "Done!\n");
923
924
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
925
manual_system_maintenance(true);
926
927
strcpy(sdPath, gui->base_path);
928
}
929
930
emmc_set_partition(EMMC_GPP);
931
932
// Get GP partition size dynamically.
933
const u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt;
934
935
emmc_part_t rawPart;
936
memset(&rawPart, 0, sizeof(rawPart));
937
rawPart.lba_start = 0;
938
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
939
strcpy(rawPart.name, "GPP");
940
{
941
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
942
i, rawPart.name, rawPart.lba_start, rawPart.lba_end);
943
lv_label_set_text(gui->label_info, txt_buf);
944
s_printf(txt_buf, "%02d: %s... ", i, rawPart.name);
945
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
946
manual_system_maintenance(true);
947
948
res = _dump_emummc_raw_part(gui, 2, part_idx, sector_start, &rawPart, resized_count);
949
950
if (!res)
951
s_printf(txt_buf, "#FFDD00 Failed!#\n");
952
else
953
s_printf(txt_buf, "Done!\n");
954
955
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
956
manual_system_maintenance(true);
957
}
958
959
out_failed:
960
timer = get_tmr_s() - timer;
961
emmc_end();
962
963
if (res)
964
{
965
s_printf(txt_buf, "Time taken: %dm %ds.\nFinished!", timer / 60, timer % 60);
966
strcpy(sdPath, gui->base_path);
967
strcat(sdPath, "raw_based");
968
FIL fp;
969
f_open(&fp, sdPath, FA_CREATE_ALWAYS | FA_WRITE);
970
f_write(&fp, &sector_start, 4, NULL);
971
f_close(&fp);
972
973
gui->base_path[strlen(gui->base_path) - 1] = 0;
974
save_emummc_cfg(part_idx, sector_start, gui->base_path);
975
}
976
else
977
s_printf(txt_buf, "Time taken: %dm %ds.", timer / 60, timer % 60);
978
979
lv_label_set_text(gui->label_finish, txt_buf);
980
981
out:
982
free(txt_buf);
983
free(gui->base_path);
984
sd_unmount();
985
}
986
987