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