Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/nyx/nyx_gui/frontend/fe_emmc_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_emmc_tools.h"
28
#include "fe_emummc_tools.h"
29
#include "../config.h"
30
#include <libs/fatfs/ff.h>
31
32
#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.
33
#define OUT_FILENAME_SZ 128
34
#define HASH_FILENAME_SZ (OUT_FILENAME_SZ + 11) // 11 == strlen(".sha256sums")
35
36
extern nyx_config n_cfg;
37
38
extern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
39
40
static void _get_valid_partition(u32 *sector_start, u32 *sector_size, u32 *part_idx, bool backup)
41
{
42
sd_mount();
43
mbr_t *mbr = (mbr_t *)zalloc(sizeof(mbr_t));
44
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
45
46
*part_idx = 0;
47
int i = 0;
48
u32 curr_part_size = 0;
49
// Find first partition with emuMMC GPP.
50
for (i = 1; i < 4; i++)
51
{
52
curr_part_size = mbr->partitions[i].size_sct;
53
*sector_start = mbr->partitions[i].start_sct;
54
u8 type = mbr->partitions[i].type;
55
u32 sector_size_safe = backup ? 0x400000 : (*sector_size) + 0x8000; // 2GB min safe size for backup.
56
if ((curr_part_size >= sector_size_safe) && (*sector_start) && type != 0x83 && (!backup || type == 0xE0))
57
{
58
if (backup)
59
{
60
u8 gpt_check[SD_BLOCKSIZE] = { 0 };
61
sdmmc_storage_read(&sd_storage, (*sector_start) + 0xC001, 1, gpt_check);
62
if (!memcmp(gpt_check, "EFI PART", 8))
63
{
64
*sector_size = curr_part_size;
65
*sector_start = (*sector_start) + 0x8000;
66
break;
67
}
68
sdmmc_storage_read(&sd_storage, (*sector_start) + 0x4001, 1, gpt_check);
69
if (!memcmp(gpt_check, "EFI PART", 8))
70
{
71
*sector_size = curr_part_size;
72
break;
73
}
74
}
75
else
76
break;
77
}
78
}
79
free(mbr);
80
81
if (i < 4)
82
*part_idx = i;
83
else
84
{
85
*sector_start = 0;
86
*sector_size = 0;
87
*part_idx = 0;
88
}
89
90
// Get emuMMC GPP size.
91
if (backup && *part_idx && *sector_size)
92
{
93
gpt_t *gpt = (gpt_t *)zalloc(sizeof(gpt_t));
94
sdmmc_storage_read(&sd_storage, (*sector_start) + 0x4001, 1, gpt);
95
96
u32 new_size = gpt->header.alt_lba + 1;
97
if (*sector_size > new_size)
98
*sector_size = new_size;
99
else
100
*sector_size = 0;
101
102
free(gpt);
103
}
104
else if (!backup && *part_idx)
105
*sector_start = (*sector_start) + 0x8000;
106
}
107
108
static lv_obj_t *create_mbox_text(const char *text, bool button_ok)
109
{
110
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
111
lv_obj_set_style(dark_bg, &mbox_darken);
112
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
113
114
static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
115
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
116
lv_mbox_set_recolor_text(mbox, true);
117
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
118
119
lv_mbox_set_text(mbox, text);
120
if (button_ok)
121
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
122
123
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
124
lv_obj_set_top(mbox, true);
125
126
return dark_bg;
127
}
128
129
static void _update_filename(char *outFilename, u32 sdPathLen, u32 currPartIdx)
130
{
131
if (currPartIdx < 10)
132
{
133
outFilename[sdPathLen] = '0';
134
itoa(currPartIdx, &outFilename[sdPathLen + 1], 10);
135
}
136
else
137
itoa(currPartIdx, &outFilename[sdPathLen], 10);
138
}
139
140
static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32 lba_curr, const char *outFilename, const emmc_part_t *part)
141
{
142
FIL fp;
143
FIL hashFp;
144
u8 sparseShouldVerify = 4;
145
u32 prevPct = 200;
146
u32 sdFileSector = 0;
147
int res = 0;
148
static const char hexa[] = "0123456789abcdef";
149
DWORD *clmt = NULL;
150
151
u8 hashEm[SE_SHA_256_SIZE];
152
u8 hashSd[SE_SHA_256_SIZE];
153
154
if (f_open(&fp, outFilename, FA_READ) == FR_OK)
155
{
156
if (n_cfg.verification == 3)
157
{
158
char hashFilename[HASH_FILENAME_SZ];
159
strncpy(hashFilename, outFilename, OUT_FILENAME_SZ - 1);
160
strcat(hashFilename, ".sha256sums");
161
162
res = f_open(&hashFp, hashFilename, FA_CREATE_ALWAYS | FA_WRITE);
163
if (res)
164
{
165
f_close(&fp);
166
167
s_printf(gui->txt_buf,
168
"\n#FF0000 Hash file could not be written (error %d)!#\n"
169
"#FF0000 Aborting..#\n", res);
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
char chunkSizeAscii[10];
177
itoa(NUM_SECTORS_PER_ITER * EMMC_BLOCKSIZE, chunkSizeAscii, 10);
178
chunkSizeAscii[9] = '\0';
179
180
f_puts("# chunksize: ", &hashFp);
181
f_puts(chunkSizeAscii, &hashFp);
182
f_puts("\n", &hashFp);
183
}
184
185
u32 totalSectorsVer = (u32)((u64)f_size(&fp) >> (u64)9);
186
187
u8 *bufEm = (u8 *)EMMC_BUF_ALIGNED;
188
u8 *bufSd = (u8 *)SDXC_BUF_ALIGNED;
189
190
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
191
lv_bar_set_value(gui->bar, pct);
192
lv_bar_set_style(gui->bar, LV_BAR_STYLE_BG, gui->bar_teal_bg);
193
lv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, gui->bar_teal_ind);
194
s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct);
195
lv_label_set_text(gui->label_pct, gui->txt_buf);
196
manual_system_maintenance(true);
197
198
clmt = f_expand_cltbl(&fp, SZ_4M, 0);
199
200
u32 num = 0;
201
while (totalSectorsVer > 0)
202
{
203
num = MIN(totalSectorsVer, NUM_SECTORS_PER_ITER);
204
205
// Check every time or every 4.
206
// Every 4 protects from fake sd, sector corruption and frequent I/O corruption.
207
// Full provides all that, plus protection from extremely rare I/O corruption.
208
if ((n_cfg.verification >= 2) || !(sparseShouldVerify % 4))
209
{
210
if (!sdmmc_storage_read(storage, lba_curr, num, bufEm))
211
{
212
s_printf(gui->txt_buf,
213
"\n#FF0000 Failed to read %d blocks (@LBA %08X),#\n"
214
"#FF0000 from eMMC! Verification failed..#\n",
215
num, lba_curr);
216
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
217
manual_system_maintenance(true);
218
219
free(clmt);
220
f_close(&fp);
221
if (n_cfg.verification == 3)
222
f_close(&hashFp);
223
224
return 1;
225
}
226
manual_system_maintenance(false);
227
se_calc_sha256(hashEm, NULL, bufEm, num << 9, 0, SHA_INIT_HASH, false);
228
229
f_lseek(&fp, (u64)sdFileSector << (u64)9);
230
if (f_read_fast(&fp, bufSd, num << 9))
231
{
232
s_printf(gui->txt_buf,
233
"\n#FF0000 Failed to read %d blocks (@LBA %08X),#\n"
234
"#FF0000 from SD card! Verification failed..#\n",
235
num, lba_curr);
236
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
237
manual_system_maintenance(true);
238
239
free(clmt);
240
f_close(&fp);
241
if (n_cfg.verification == 3)
242
f_close(&hashFp);
243
244
return 1;
245
}
246
manual_system_maintenance(false);
247
se_calc_sha256_finalize(hashEm, NULL);
248
se_calc_sha256_oneshot(hashSd, bufSd, num << 9);
249
res = memcmp(hashEm, hashSd, SE_SHA_256_SIZE / 2);
250
251
if (res)
252
{
253
s_printf(gui->txt_buf,
254
"\n#FF0000 SD & eMMC data (@LBA %08X) do not match!#\n"
255
"\n#FF0000 Verification failed..#\n",
256
lba_curr);
257
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
258
manual_system_maintenance(true);
259
260
free(clmt);
261
f_close(&fp);
262
if (n_cfg.verification == 3)
263
f_close(&hashFp);
264
265
return 1;
266
}
267
268
if (n_cfg.verification == 3)
269
{
270
// Transform computed hash to readable hexadecimal
271
char hashStr[SE_SHA_256_SIZE * 2 + 1];
272
char *hashStrPtr = hashStr;
273
for (int i = 0; i < SE_SHA_256_SIZE; i++)
274
{
275
*(hashStrPtr++) = hexa[hashSd[i] >> 4];
276
*(hashStrPtr++) = hexa[hashSd[i] & 0x0F];
277
}
278
hashStr[SE_SHA_256_SIZE * 2] = '\0';
279
280
f_puts(hashStr, &hashFp);
281
f_puts("\n", &hashFp);
282
}
283
}
284
285
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
286
if (pct != prevPct)
287
{
288
lv_bar_set_value(gui->bar, pct);
289
s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct);
290
lv_label_set_text(gui->label_pct, gui->txt_buf);
291
manual_system_maintenance(true);
292
prevPct = pct;
293
}
294
295
manual_system_maintenance(false);
296
297
lba_curr += num;
298
totalSectorsVer -= num;
299
sdFileSector += num;
300
sparseShouldVerify++;
301
302
// Check for cancellation combo.
303
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
304
{
305
s_printf(gui->txt_buf, "#FFDD00 Verification was cancelled!#\n");
306
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
307
manual_system_maintenance(true);
308
309
msleep(1000);
310
311
free(clmt);
312
f_close(&fp);
313
f_close(&hashFp);
314
315
return 0;
316
}
317
}
318
free(clmt);
319
f_close(&fp);
320
f_close(&hashFp);
321
322
lv_bar_set_value(gui->bar, pct);
323
s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct);
324
lv_label_set_text(gui->label_pct, gui->txt_buf);
325
manual_system_maintenance(true);
326
327
return 0;
328
}
329
else
330
{
331
s_printf(gui->txt_buf, "\n#FFDD00 File not found or could not be loaded!#\n#FFDD00 Verification failed..#\n");
332
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
333
manual_system_maintenance(true);
334
335
return 1;
336
}
337
}
338
339
bool partial_sd_full_unmount = false;
340
341
static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part, sdmmc_storage_t *storage, emmc_part_t *part)
342
{
343
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
344
static const u32 SECTORS_TO_MIB_COEFF = 11;
345
346
partial_sd_full_unmount = false;
347
348
u32 multipartSplitSize = (1u << 31);
349
u32 lba_end = part->lba_end;
350
u32 totalSectors = part->lba_end - part->lba_start + 1;
351
u32 currPartIdx = 0;
352
u32 numSplitParts = 0;
353
u32 maxSplitParts = 0;
354
bool isSmallSdCard = false;
355
bool partialDumpInProgress = false;
356
int res = 0;
357
char *outFilename = sd_path;
358
u32 sdPathLen = strlen(sd_path);
359
360
u32 sector_start = 0, part_idx = 0;
361
u32 sector_size = totalSectors;
362
u32 sd_sector_off = 0;
363
364
FIL partialIdxFp;
365
char partialIdxFilename[12];
366
strcpy(partialIdxFilename, "partial.idx");
367
368
if (gui->raw_emummc)
369
{
370
_get_valid_partition(&sector_start, &sector_size, &part_idx, true);
371
if (!part_idx || !sector_size)
372
{
373
s_printf(gui->txt_buf, "\n#FFDD00 Failed to find a partition...#\n");
374
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
375
manual_system_maintenance(true);
376
377
return 0;
378
}
379
sd_sector_off = sector_start + (0x2000 * active_part);
380
if (active_part == 2)
381
{
382
// Set new total sectors and lba end sector for percentage calculations.
383
totalSectors = sector_size;
384
lba_end = sector_size + part->lba_start - 1;
385
}
386
}
387
388
s_printf(gui->txt_buf, "#96FF00 SD Card free space:# %d MiB\n#96FF00 Total backup size:# %d MiB\n\n",
389
(u32)(sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF),
390
totalSectors >> SECTORS_TO_MIB_COEFF);
391
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
392
manual_system_maintenance(true);
393
394
lv_bar_set_value(gui->bar, 0);
395
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 0%");
396
lv_bar_set_style(gui->bar, LV_BAR_STYLE_BG, lv_theme_get_current()->bar.bg);
397
lv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, gui->bar_white_ind);
398
manual_system_maintenance(true);
399
400
// 1GB parts for sd cards 8GB and less.
401
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
402
multipartSplitSize = (1u << 30);
403
// Maximum parts fitting the free space available.
404
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / EMMC_BLOCKSIZE);
405
406
// Check if the USER partition or the RAW eMMC fits the sd card free space.
407
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
408
{
409
isSmallSdCard = true;
410
411
s_printf(gui->txt_buf, "\n#FFBA00 Free space is smaller than backup size.#\n");
412
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
413
manual_system_maintenance(true);
414
415
if (!maxSplitParts)
416
{
417
s_printf(gui->txt_buf, "#FFDD00 Not enough free space for Partial Backup!#\n");
418
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
419
manual_system_maintenance(true);
420
421
return 0;
422
}
423
}
424
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
425
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE))
426
{
427
s_printf(gui->txt_buf, "\n#AEFD14 Partial Backup in progress. Continuing...#\n");
428
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
429
manual_system_maintenance(true);
430
431
partialDumpInProgress = true;
432
// Force partial dumping, even if the card is larger.
433
isSmallSdCard = true;
434
435
f_read(&partialIdxFp, &currPartIdx, 4, NULL);
436
f_close(&partialIdxFp);
437
438
if (!maxSplitParts)
439
{
440
s_printf(gui->txt_buf, "\n#FFDD00 Not enough free space for Partial Backup!#\n");
441
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
442
manual_system_maintenance(true);
443
444
return 0;
445
}
446
447
// Increase maxSplitParts to accommodate previously backed up parts.
448
maxSplitParts += currPartIdx;
449
}
450
else if (isSmallSdCard)
451
{
452
s_printf(gui->txt_buf, "\n#FFBA00 Partial Backup enabled (%d MiB parts)...#\n", multipartSplitSize >> 20);
453
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
454
manual_system_maintenance(true);
455
}
456
457
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
458
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE)) || isSmallSdCard)
459
{
460
u32 multipartSplitSectors = multipartSplitSize / EMMC_BLOCKSIZE;
461
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
462
463
outFilename[sdPathLen++] = '.';
464
465
// Continue from where we left, if Partial Backup in progress.
466
_update_filename(outFilename, sdPathLen, partialDumpInProgress ? currPartIdx : 0);
467
}
468
469
FIL fp;
470
if (!f_open(&fp, outFilename, FA_READ))
471
{
472
f_close(&fp);
473
474
lv_obj_t *warn_mbox_bg = create_mbox_text(
475
"#FFDD00 An existing backup has been detected!#\n\n"
476
"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.", false);
477
manual_system_maintenance(true);
478
479
if (!(btn_wait() & BTN_POWER))
480
{
481
lv_obj_del(warn_mbox_bg);
482
return 0;
483
}
484
lv_obj_del(warn_mbox_bg);
485
}
486
487
s_printf(gui->txt_buf, "#96FF00 Filepath:#\n%s\n#96FF00 Filename:# #FF8000 %s#",
488
gui->base_path, outFilename + strlen(gui->base_path));
489
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
490
manual_system_maintenance(true);
491
492
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
493
if (res)
494
{
495
s_printf(gui->txt_buf, "\n#FF0000 Error (%d) while creating#\n#FFDD00 %s#\n", res, outFilename);
496
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
497
manual_system_maintenance(true);
498
499
return 0;
500
}
501
502
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
503
504
u32 lba_curr = part->lba_start;
505
u32 lbaStartPart = part->lba_start;
506
u32 bytesWritten = 0;
507
u32 prevPct = 200;
508
int retryCount = 0;
509
DWORD *clmt = NULL;
510
511
// Continue from where we left, if Partial Backup in progress.
512
if (partialDumpInProgress)
513
{
514
lba_curr += currPartIdx * (multipartSplitSize / EMMC_BLOCKSIZE);
515
totalSectors -= currPartIdx * (multipartSplitSize / EMMC_BLOCKSIZE);
516
lbaStartPart = lba_curr; // Update the start LBA for verification.
517
}
518
u64 totalSize = (u64)((u64)totalSectors << 9);
519
if (!isSmallSdCard && (sd_fs.fs_type == FS_EXFAT || totalSize <= FAT32_FILESIZE_LIMIT))
520
clmt = f_expand_cltbl(&fp, SZ_4M, totalSize);
521
else
522
clmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize));
523
524
u32 num = 0;
525
u32 pct = 0;
526
527
lv_obj_set_opa_scale(gui->bar, LV_OPA_COVER);
528
lv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER);
529
while (totalSectors > 0)
530
{
531
if (numSplitParts != 0 && bytesWritten >= multipartSplitSize)
532
{
533
f_close(&fp);
534
free(clmt);
535
memset(&fp, 0, sizeof(fp));
536
currPartIdx++;
537
538
if (n_cfg.verification && !gui->raw_emummc)
539
{
540
// Verify part.
541
if (_dump_emmc_verify(gui, storage, lbaStartPart, outFilename, part))
542
{
543
s_printf(gui->txt_buf, "#FFDD00 Please try again...#\n");
544
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
545
manual_system_maintenance(true);
546
547
return 0;
548
}
549
lv_bar_set_style(gui->bar, LV_BAR_STYLE_BG, lv_theme_get_current()->bar.bg);
550
lv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, gui->bar_white_ind);
551
}
552
553
_update_filename(outFilename, sdPathLen, currPartIdx);
554
555
// Always create partial.idx before next part, in case a fatal error occurs.
556
if (isSmallSdCard)
557
{
558
// Create partial backup index file.
559
if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
560
{
561
f_write(&partialIdxFp, &currPartIdx, 4, NULL);
562
f_close(&partialIdxFp);
563
}
564
else
565
{
566
s_printf(gui->txt_buf, "\n#FF0000 Error creating partial.idx file!#\n");
567
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
568
manual_system_maintenance(true);
569
570
return 0;
571
}
572
573
// More parts to backup that do not currently fit the sd card free space or fatal error.
574
if (currPartIdx >= maxSplitParts)
575
{
576
create_mbox_text(
577
"#96FF00 Partial Backup in progress!#\n\n"
578
"#96FF00 1.# Press OK to unmount SD Card.\n"
579
"#96FF00 2.# Remove SD Card and move files to free space.\n"
580
"#FFDD00 Don\'t move the partial.idx file!#\n"
581
"#96FF00 3.# Re-insert SD Card.\n"
582
"#96FF00 4.# Select the SAME option again to continue.", true);
583
584
partial_sd_full_unmount = true;
585
586
return 1;
587
}
588
}
589
590
// Create next part.
591
s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path));
592
lv_label_cut_text(gui->label_info,
593
strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1,
594
strlen(outFilename + strlen(gui->base_path)) + 1);
595
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
596
manual_system_maintenance(true);
597
lbaStartPart = lba_curr;
598
res = f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE);
599
if (res)
600
{
601
s_printf(gui->txt_buf, "\n#FF0000 Error (%d) while creating#\n#FFDD00 %s#\n", res, outFilename);
602
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
603
manual_system_maintenance(true);
604
605
return 0;
606
}
607
608
bytesWritten = 0;
609
610
totalSize = (u64)((u64)totalSectors << 9);
611
clmt = f_expand_cltbl(&fp, SZ_4M, MIN(totalSize, multipartSplitSize));
612
}
613
614
retryCount = 0;
615
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
616
617
int res_read;
618
if (!gui->raw_emummc)
619
res_read = !sdmmc_storage_read(storage, lba_curr, num, buf);
620
else
621
res_read = !sdmmc_storage_read(&sd_storage, lba_curr + sd_sector_off, num, buf);
622
623
while (res_read)
624
{
625
if (!gui->raw_emummc)
626
{
627
s_printf(gui->txt_buf,
628
"\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n"
629
"#FFDD00 from eMMC (try %d). #",
630
num, lba_curr, ++retryCount);
631
}
632
else
633
{
634
s_printf(gui->txt_buf,
635
"\n#FFDD00 Error reading %d blocks @ LBA %08X,#\n"
636
"#FFDD00 from emuMMC @ %08X (try %d). #",
637
num, lba_curr + sd_sector_off, lba_curr, ++retryCount);
638
}
639
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
640
manual_system_maintenance(true);
641
642
msleep(150);
643
if (retryCount >= 3)
644
{
645
s_printf(gui->txt_buf, "#FF0000 Aborting...#\nPlease try again...\n");
646
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
647
manual_system_maintenance(true);
648
649
f_close(&fp);
650
free(clmt);
651
f_unlink(outFilename);
652
653
return 0;
654
}
655
else
656
{
657
s_printf(gui->txt_buf, "#FFDD00 Retrying...#\n");
658
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
659
manual_system_maintenance(true);
660
}
661
}
662
manual_system_maintenance(false);
663
664
res = f_write_fast(&fp, buf, EMMC_BLOCKSIZE * num);
665
666
if (res)
667
{
668
s_printf(gui->txt_buf, "\n#FF0000 Fatal error (%d) when writing to SD Card#\nPlease try again...\n", res);
669
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
670
manual_system_maintenance(true);
671
672
f_close(&fp);
673
free(clmt);
674
f_unlink(outFilename);
675
676
return 0;
677
}
678
679
manual_system_maintenance(false);
680
681
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(lba_end - part->lba_start);
682
if (pct != prevPct)
683
{
684
lv_bar_set_value(gui->bar, pct);
685
s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct);
686
lv_label_set_text(gui->label_pct, gui->txt_buf);
687
manual_system_maintenance(true);
688
689
prevPct = pct;
690
}
691
692
lba_curr += num;
693
totalSectors -= num;
694
bytesWritten += num * EMMC_BLOCKSIZE;
695
696
// Force a flush after a lot of data if not splitting.
697
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
698
{
699
f_sync(&fp);
700
bytesWritten = 0;
701
}
702
703
// Check for cancellation combo.
704
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
705
{
706
s_printf(gui->txt_buf, "\n#FFDD00 The backup was cancelled!#\n");
707
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
708
manual_system_maintenance(true);
709
710
msleep(1500);
711
712
f_close(&fp);
713
free(clmt);
714
f_unlink(outFilename);
715
716
return 0;
717
}
718
}
719
lv_bar_set_value(gui->bar, 100);
720
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%");
721
manual_system_maintenance(true);
722
723
// Backup operation ended successfully.
724
f_close(&fp);
725
free(clmt);
726
727
if (n_cfg.verification && !gui->raw_emummc)
728
{
729
// Verify last part or single file backup.
730
if (_dump_emmc_verify(gui, storage, lbaStartPart, outFilename, part))
731
{
732
s_printf(gui->txt_buf, "\n#FFDD00 Please try again...#\n");
733
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
734
manual_system_maintenance(true);
735
736
return 0;
737
}
738
lv_bar_set_value(gui->bar, 100);
739
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%");
740
manual_system_maintenance(true);
741
}
742
743
// Remove partial backup index file if no fatal errors occurred.
744
if (isSmallSdCard)
745
{
746
f_unlink(partialIdxFilename);
747
748
create_mbox_text(
749
"#96FF00 Partial Backup done!#\n\n"
750
"You can now join the files if needed\nand get the complete eMMC RAW GPP backup.", true);
751
752
partial_sd_full_unmount = true;
753
}
754
755
return 1;
756
}
757
758
void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui)
759
{
760
int res = 0;
761
u32 timer = 0;
762
763
char *txt_buf = (char *)malloc(SZ_16K);
764
gui->txt_buf = txt_buf;
765
766
txt_buf[0] = 0;
767
lv_label_set_text(gui->label_log, txt_buf);
768
769
lv_label_set_text(gui->label_info, "Checking for available free space...");
770
manual_system_maintenance(true);
771
772
if (!sd_mount())
773
{
774
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init SD!#");
775
goto out;
776
}
777
778
// Get SD Card free space for Partial Backup.
779
f_getfree("", &sd_fs.free_clst, NULL);
780
781
if (!emmc_initialize(false))
782
{
783
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
784
goto out;
785
}
786
787
int i = 0;
788
char sdPath[OUT_FILENAME_SZ];
789
// Create Restore folders, if they do not exist.
790
emmcsn_path_impl(sdPath, "/restore", "", &emmc_storage);
791
emmcsn_path_impl(sdPath, "/restore/emummc", "", &emmc_storage);
792
emmcsn_path_impl(sdPath, "/restore/partitions", "", &emmc_storage);
793
794
// Set folder to backup/{emmc_sn}.
795
emmcsn_path_impl(sdPath, "", "", &emmc_storage);
796
gui->base_path = (char *)malloc(strlen(sdPath) + 1);
797
strcpy(gui->base_path, sdPath);
798
799
timer = get_tmr_s();
800
if (dumpType & PART_BOOT)
801
{
802
const u32 BOOT_PART_SIZE = emmc_storage.ext_csd.boot_mult << 17;
803
const u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB for emuMMC.
804
805
emmc_part_t bootPart;
806
memset(&bootPart, 0, sizeof(bootPart));
807
bootPart.lba_start = 0;
808
if (!gui->raw_emummc)
809
bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;
810
else
811
bootPart.lba_end = BOOT_PART_SECTORS - 1;
812
for (i = 0; i < 2; i++)
813
{
814
strcpy(bootPart.name, "BOOT");
815
bootPart.name[4] = (u8)('0' + i);
816
bootPart.name[5] = 0;
817
818
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
819
i, bootPart.name, bootPart.lba_start, bootPart.lba_end);
820
lv_label_set_text(gui->label_info, txt_buf);
821
s_printf(txt_buf, "%02d: %s... ", i, bootPart.name);
822
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
823
manual_system_maintenance(true);
824
825
emmc_set_partition(i + 1);
826
827
// Set filename to backup/{emmc_sn}/BOOT0/1 or backup/{emmc_sn}/emummc/BOOT0/1.
828
if (!gui->raw_emummc)
829
emmcsn_path_impl(sdPath, "", bootPart.name, &emmc_storage);
830
else
831
emmcsn_path_impl(sdPath, "/emummc", bootPart.name, &emmc_storage);
832
833
res = _dump_emmc_part(gui, sdPath, i, &emmc_storage, &bootPart);
834
835
if (!res)
836
s_printf(txt_buf, "#FFDD00 Failed!#\n");
837
else
838
s_printf(txt_buf, "Done!\n");
839
840
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
841
manual_system_maintenance(true);
842
}
843
}
844
845
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER) || (dumpType & PART_RAW))
846
{
847
emmc_set_partition(EMMC_GPP);
848
849
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER))
850
{
851
emmcsn_path_impl(sdPath, "/partitions", "", &emmc_storage);
852
gui->base_path = (char *)malloc(strlen(sdPath) + 1);
853
strcpy(gui->base_path, sdPath);
854
855
LIST_INIT(gpt);
856
emmc_gpt_parse(&gpt);
857
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
858
{
859
if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER"))
860
continue;
861
if ((dumpType & PART_SYSTEM) == 0 && strcmp(part->name, "USER"))
862
continue;
863
864
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
865
i, part->name, part->lba_start, part->lba_end);
866
lv_label_set_text(gui->label_info, txt_buf);
867
s_printf(txt_buf, "%02d: %s... ", i, part->name);
868
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
869
manual_system_maintenance(true);
870
i++;
871
872
emmcsn_path_impl(sdPath, "/partitions", part->name, &emmc_storage);
873
res = _dump_emmc_part(gui, sdPath, 0, &emmc_storage, part);
874
// If a part failed, don't continue.
875
if (!res)
876
{
877
s_printf(txt_buf, "#FFDD00 Failed!#\n");
878
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
879
break;
880
}
881
else
882
s_printf(txt_buf, "Done!\n");
883
884
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
885
manual_system_maintenance(true);
886
}
887
emmc_gpt_free(&gpt);
888
}
889
890
if (dumpType & PART_RAW)
891
{
892
// Get GP partition size dynamically.
893
const u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt;
894
895
emmc_part_t rawPart;
896
memset(&rawPart, 0, sizeof(rawPart));
897
rawPart.lba_start = 0;
898
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
899
strcpy(rawPart.name, "rawnand.bin");
900
{
901
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
902
i, rawPart.name, rawPart.lba_start, rawPart.lba_end);
903
lv_label_set_text(gui->label_info, txt_buf);
904
s_printf(txt_buf, "%02d: %s... ", i, rawPart.name);
905
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
906
manual_system_maintenance(true);
907
908
i++;
909
910
// Set filename to backup/{emmc_sn}/rawnand.bin or backup/{emmc_sn}/emummc/rawnand.bin.
911
if (!gui->raw_emummc)
912
emmcsn_path_impl(sdPath, "", rawPart.name, &emmc_storage);
913
else
914
emmcsn_path_impl(sdPath, "/emummc", rawPart.name, &emmc_storage);
915
916
res = _dump_emmc_part(gui, sdPath, 2, &emmc_storage, &rawPart);
917
918
if (!res)
919
s_printf(txt_buf, "#FFDD00 Failed!#\n");
920
else
921
s_printf(txt_buf, "Done!\n");
922
923
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
924
manual_system_maintenance(true);
925
}
926
}
927
}
928
929
timer = get_tmr_s() - timer;
930
emmc_end();
931
932
if (res && n_cfg.verification && !gui->raw_emummc)
933
s_printf(txt_buf, "Time taken: %dm %ds.\n#96FF00 Finished and verified!#", timer / 60, timer % 60);
934
else if (res)
935
s_printf(txt_buf, "Time taken: %dm %ds.\nFinished!", timer / 60, timer % 60);
936
else
937
s_printf(txt_buf, "Time taken: %dm %ds.", timer / 60, timer % 60);
938
939
lv_label_set_text(gui->label_finish, txt_buf);
940
941
out:
942
free(txt_buf);
943
free(gui->base_path);
944
if (!partial_sd_full_unmount)
945
sd_unmount();
946
else
947
{
948
partial_sd_full_unmount = false;
949
sd_end();
950
}
951
}
952
953
static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part, sdmmc_storage_t *storage, emmc_part_t *part, bool allow_multi_part)
954
{
955
static const u32 SECTORS_TO_MIB_COEFF = 11;
956
957
u32 lba_end = part->lba_end;
958
u32 totalSectors = part->lba_end - part->lba_start + 1;
959
u32 currPartIdx = 0;
960
u32 numSplitParts = 0;
961
u32 lbaStartPart = part->lba_start;
962
int res = 0;
963
char *outFilename = sd_path;
964
u32 sdPathLen = strlen(sd_path);
965
u64 fileSize = 0;
966
u64 totalCheckFileSize = 0;
967
968
FIL fp;
969
FILINFO fno;
970
971
lv_bar_set_value(gui->bar, 0);
972
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 0%");
973
lv_bar_set_style(gui->bar, LV_BAR_STYLE_BG, lv_theme_get_current()->bar.bg);
974
lv_bar_set_style(gui->bar, LV_BAR_STYLE_INDIC, gui->bar_white_ind);
975
manual_system_maintenance(true);
976
977
bool use_multipart = false;
978
bool check_4MB_aligned = true;
979
980
if (!allow_multi_part)
981
goto multipart_not_allowed;
982
983
// Check to see if there is a combined file and if so then use that.
984
if (f_stat(outFilename, &fno))
985
{
986
// If not, check if there are partial files and the total size matches.
987
s_printf(gui->txt_buf, "\nNo single file, checking for part files...\n");
988
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
989
manual_system_maintenance(true);
990
991
outFilename[sdPathLen++] = '.';
992
993
_update_filename(outFilename, sdPathLen, numSplitParts);
994
995
s_printf(gui->txt_buf, "#96FF00 Filepath:#\n%s\n#96FF00 Filename:# #FF8000 %s#",
996
gui->base_path, outFilename + strlen(gui->base_path));
997
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
998
999
// Stat total size of the part files.
1000
while ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
1001
{
1002
_update_filename(outFilename, sdPathLen, numSplitParts);
1003
1004
s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path));
1005
lv_label_cut_text(gui->label_info,
1006
strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1,
1007
strlen(outFilename + strlen(gui->base_path)) + 1);
1008
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
1009
manual_system_maintenance(true);
1010
1011
if ((u32)((u64)totalCheckFileSize >> (u64)9) > totalSectors)
1012
{
1013
s_printf(gui->txt_buf, "\n#FF8000 Size of SD Card split backup exceeds#\n#FF8000 eMMC's selected part size!#\n#FFDD00 Aborting...#");
1014
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1015
manual_system_maintenance(true);
1016
1017
return 0;
1018
}
1019
else if (f_stat(outFilename, &fno))
1020
{
1021
if (!gui->raw_emummc)
1022
{
1023
s_printf(gui->txt_buf, "\n#FFDD00 Error (%d) file not found#\n#FFDD00 %s.#\n\n", res, outFilename);
1024
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1025
manual_system_maintenance(true);
1026
1027
// Attempt a smaller restore.
1028
if (numSplitParts)
1029
break;
1030
}
1031
else
1032
{
1033
// Set new total sectors and lba end sector for percentage calculations.
1034
totalSectors = (u32)((u64)totalCheckFileSize >> (u64)9);
1035
lba_end = totalSectors + part->lba_start - 1;
1036
}
1037
1038
// Restore folder is empty.
1039
if (!numSplitParts)
1040
{
1041
s_printf(gui->txt_buf, "\n#FFDD00 Restore folder is empty.#\n\n");
1042
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1043
manual_system_maintenance(true);
1044
1045
return 0;
1046
}
1047
}
1048
else
1049
{
1050
totalCheckFileSize += (u64)fno.fsize;
1051
1052
if (check_4MB_aligned && (((u64)fno.fsize) % SZ_4M))
1053
{
1054
s_printf(gui->txt_buf, "\n#FFDD00 The split file must be a#\n#FFDD00 multiple of 4 MiB.#\n#FFDD00 Aborting...#");
1055
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1056
manual_system_maintenance(true);
1057
1058
return 0;
1059
}
1060
1061
check_4MB_aligned = false;
1062
}
1063
1064
numSplitParts++;
1065
}
1066
1067
s_printf(gui->txt_buf, "%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9));
1068
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1069
manual_system_maintenance(true);
1070
1071
if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
1072
{
1073
lv_obj_t *warn_mbox_bg = create_mbox_text(
1074
"#FF8000 Size of SD Card split backup does not match#\n#FF8000 eMMC's selected part size!#\n\n"
1075
"#FFDD00 The backup might be corrupted,#\n#FFDD00 or missing files!#\n#FFDD00 Aborting is suggested!#\n\n"
1076
"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.", false);
1077
manual_system_maintenance(true);
1078
1079
if (!(btn_wait() & BTN_POWER))
1080
{
1081
lv_obj_del(warn_mbox_bg);
1082
s_printf(gui->txt_buf, "\n#FF0000 Size of SD Card split backup does not match#\n#FF0000 eMMC's selected part size!#\n");
1083
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1084
manual_system_maintenance(true);
1085
1086
return 0;
1087
}
1088
lv_obj_del(warn_mbox_bg);
1089
1090
// Set new total sectors and lba end sector for percentage calculations.
1091
totalSectors = (u32)((u64)totalCheckFileSize >> (u64)9);
1092
lba_end = totalSectors + part->lba_start - 1;
1093
}
1094
use_multipart = true;
1095
_update_filename(outFilename, sdPathLen, 0);
1096
}
1097
1098
multipart_not_allowed:
1099
res = f_open(&fp, outFilename, FA_READ);
1100
if (use_multipart)
1101
{
1102
s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path));
1103
lv_label_cut_text(gui->label_info,
1104
strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1,
1105
strlen(outFilename + strlen(gui->base_path)) + 1);
1106
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
1107
manual_system_maintenance(true);
1108
}
1109
else
1110
{
1111
s_printf(gui->txt_buf, "#96FF00 Filepath:#\n%s\n#96FF00 Filename:# #FF8000 %s#",
1112
gui->base_path, outFilename + strlen(gui->base_path));
1113
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
1114
}
1115
manual_system_maintenance(true);
1116
if (res)
1117
{
1118
if (res != FR_NO_FILE)
1119
{
1120
s_printf(gui->txt_buf, "\n#FF0000 Error (%d) while opening file. Continuing...#\n", res);
1121
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1122
manual_system_maintenance(true);
1123
}
1124
else
1125
{
1126
s_printf(gui->txt_buf, "\n#FFDD00 Error (%d) file not found. Continuing...#\n", res);
1127
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1128
manual_system_maintenance(true);
1129
}
1130
1131
return -1;
1132
}
1133
else if (!use_multipart && (((u32)((u64)f_size(&fp) >> (u64)9)) != totalSectors)) // Check total restore size vs emmc size.
1134
{
1135
if (((u32)((u64)f_size(&fp) >> (u64)9)) > totalSectors)
1136
{
1137
s_printf(gui->txt_buf, "\n#FF8000 Size of SD Card backup exceeds#\n#FF8000 eMMC's selected part size!#\n#FFDD00 Aborting...#");
1138
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1139
manual_system_maintenance(true);
1140
1141
f_close(&fp);
1142
1143
return 0;
1144
}
1145
else if (!gui->raw_emummc)
1146
{
1147
lv_obj_t *warn_mbox_bg = create_mbox_text(
1148
"#FF8000 Size of the SD Card backup does not match#\n#FF8000 eMMC's selected part size!#\n\n"
1149
"#FFDD00 The backup might be corrupted!#\n#FFDD00 Aborting is suggested!#\n\n"
1150
"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.", false);
1151
manual_system_maintenance(true);
1152
1153
if (!(btn_wait() & BTN_POWER))
1154
{
1155
lv_obj_del(warn_mbox_bg);
1156
s_printf(gui->txt_buf, "\n#FF0000 Size of the SD Card backup does not match#\n#FF0000 eMMC's selected part size.#\n");
1157
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1158
manual_system_maintenance(true);
1159
1160
f_close(&fp);
1161
1162
return 0;
1163
}
1164
lv_obj_del(warn_mbox_bg);
1165
}
1166
// Set new total sectors and lba end sector for percentage calculations.
1167
totalSectors = (u32)((u64)f_size(&fp) >> (u64)9);
1168
lba_end = totalSectors + part->lba_start - 1;
1169
}
1170
else
1171
{
1172
fileSize = (u64)f_size(&fp);
1173
s_printf(gui->txt_buf, "\nTotal restore size: %d MiB.\n",
1174
(u32)((use_multipart ? (u64)totalCheckFileSize : fileSize) >> (u64)9) >> SECTORS_TO_MIB_COEFF);
1175
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1176
manual_system_maintenance(true);
1177
}
1178
1179
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
1180
1181
u32 lba_curr = part->lba_start;
1182
u32 bytesWritten = 0;
1183
u32 prevPct = 200;
1184
int retryCount = 0;
1185
1186
u32 num = 0;
1187
u32 pct = 0;
1188
1189
DWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0);
1190
1191
u32 sector_start = 0, part_idx = 0;
1192
u32 sector_size = totalSectors;
1193
u32 sd_sector_off = 0;
1194
1195
if (gui->raw_emummc)
1196
{
1197
_get_valid_partition(&sector_start, &sector_size, &part_idx, false);
1198
if (!part_idx || !sector_size)
1199
{
1200
s_printf(gui->txt_buf, "\n#FFDD00 Failed to find a partition...#\n");
1201
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1202
manual_system_maintenance(true);
1203
1204
return 0;
1205
}
1206
sd_sector_off = sector_start + (0x2000 * active_part);
1207
}
1208
1209
lv_obj_set_opa_scale(gui->bar, LV_OPA_COVER);
1210
lv_obj_set_opa_scale(gui->label_pct, LV_OPA_COVER);
1211
while (totalSectors > 0)
1212
{
1213
// If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that.
1214
if (numSplitParts != 0 && bytesWritten >= fileSize)
1215
{
1216
// If we have more bytes written then close the file pointer and increase the part index we are using
1217
f_close(&fp);
1218
free(clmt);
1219
memset(&fp, 0, sizeof(fp));
1220
currPartIdx++;
1221
1222
if (n_cfg.verification && !gui->raw_emummc)
1223
{
1224
// Verify part.
1225
if (_dump_emmc_verify(gui, storage, lbaStartPart, outFilename, part))
1226
{
1227
s_printf(gui->txt_buf, "\n#FFDD00 Please try again...#\n");
1228
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1229
manual_system_maintenance(true);
1230
1231
return 0;
1232
}
1233
}
1234
1235
_update_filename(outFilename, sdPathLen, currPartIdx);
1236
1237
// Read from next part.
1238
s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path));
1239
lv_label_cut_text(gui->label_info,
1240
strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1,
1241
strlen(outFilename + strlen(gui->base_path)) + 1);
1242
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
1243
manual_system_maintenance(true);
1244
1245
lbaStartPart = lba_curr;
1246
1247
// Try to open the next file part
1248
res = f_open(&fp, outFilename, FA_READ);
1249
if (res)
1250
{
1251
s_printf(gui->txt_buf, "\n#FF0000 Error (%d) while opening file#\n#FFDD00 %s!#\n", res, outFilename);
1252
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1253
manual_system_maintenance(true);
1254
1255
return 0;
1256
}
1257
fileSize = (u64)f_size(&fp);
1258
bytesWritten = 0;
1259
clmt = f_expand_cltbl(&fp, SZ_4M, 0);
1260
}
1261
1262
retryCount = 0;
1263
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
1264
1265
res = f_read_fast(&fp, buf, num << 9);
1266
manual_system_maintenance(false);
1267
1268
if (res)
1269
{
1270
s_printf(gui->txt_buf,
1271
"\n#FF0000 Fatal error (%d) when reading from SD!#\n"
1272
"#FF0000 This device may be in an inoperative state!#\n"
1273
"#FFDD00 Please try again now!#\n", res);
1274
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1275
manual_system_maintenance(true);
1276
1277
f_close(&fp);
1278
free(clmt);
1279
return 0;
1280
}
1281
if (!gui->raw_emummc)
1282
res = !sdmmc_storage_write(storage, lba_curr, num, buf);
1283
else
1284
res = !sdmmc_storage_write(&sd_storage, lba_curr + sd_sector_off, num, buf);
1285
1286
manual_system_maintenance(false);
1287
1288
while (res)
1289
{
1290
s_printf(gui->txt_buf,
1291
"\n#FFDD00 Error writing %d blocks @ LBA %08X,#\n"
1292
"#FFDD00 from eMMC (try %d). #",
1293
num, lba_curr, ++retryCount);
1294
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1295
manual_system_maintenance(true);
1296
1297
msleep(150);
1298
if (retryCount >= 3)
1299
{
1300
s_printf(gui->txt_buf, "#FF0000 Aborting...#\n"
1301
"#FF0000 This device may be in an inoperative state!#\n"
1302
"#FFDD00 Please try again now!#\n");
1303
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1304
manual_system_maintenance(true);
1305
1306
f_close(&fp);
1307
free(clmt);
1308
return 0;
1309
}
1310
else
1311
{
1312
s_printf(gui->txt_buf, "#FFDD00 Retrying...#\n");
1313
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1314
manual_system_maintenance(true);
1315
}
1316
if (!gui->raw_emummc)
1317
res = !sdmmc_storage_write(storage, lba_curr, num, buf);
1318
else
1319
res = !sdmmc_storage_write(&sd_storage, lba_curr + sd_sector_off, num, buf);
1320
manual_system_maintenance(false);
1321
}
1322
pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(lba_end - part->lba_start);
1323
if (pct != prevPct)
1324
{
1325
lv_bar_set_value(gui->bar, pct);
1326
s_printf(gui->txt_buf, " "SYMBOL_DOT" %d%%", pct);
1327
lv_label_set_text(gui->label_pct, gui->txt_buf);
1328
manual_system_maintenance(true);
1329
prevPct = pct;
1330
}
1331
1332
lba_curr += num;
1333
totalSectors -= num;
1334
bytesWritten += num * EMMC_BLOCKSIZE;
1335
}
1336
lv_bar_set_value(gui->bar, 100);
1337
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%");
1338
manual_system_maintenance(true);
1339
1340
// Restore operation ended successfully.
1341
f_close(&fp);
1342
free(clmt);
1343
1344
if (n_cfg.verification && !gui->raw_emummc)
1345
{
1346
// Verify restored data.
1347
if (_dump_emmc_verify(gui, storage, lbaStartPart, outFilename, part))
1348
{
1349
s_printf(gui->txt_buf, "#FFDD00 Please try again...#\n");
1350
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
1351
manual_system_maintenance(true);
1352
1353
return 0;
1354
}
1355
lv_bar_set_value(gui->bar, 100);
1356
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%");
1357
manual_system_maintenance(true);
1358
}
1359
1360
if (gui->raw_emummc)
1361
{
1362
char sdPath[OUT_FILENAME_SZ];
1363
// Create Restore folders, if they do not exist.
1364
f_mkdir("emuMMC");
1365
s_printf(sdPath, "emuMMC/RAW%d", part_idx);
1366
f_mkdir(sdPath);
1367
strcat(sdPath, "/raw_based");
1368
FIL fp_raw;
1369
f_open(&fp_raw, sdPath, FA_CREATE_ALWAYS | FA_WRITE);
1370
f_write(&fp_raw, &sector_start, 4, NULL);
1371
f_close(&fp_raw);
1372
1373
s_printf(sdPath, "emuMMC/RAW%d", part_idx);
1374
save_emummc_cfg(part_idx, sector_start, sdPath);
1375
}
1376
1377
return 1;
1378
}
1379
1380
void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui)
1381
{
1382
int res = 0;
1383
u32 timer = 0;
1384
1385
char *txt_buf = (char *)malloc(SZ_16K);
1386
gui->txt_buf = txt_buf;
1387
1388
txt_buf[0] = 0;
1389
lv_label_set_text(gui->label_log, txt_buf);
1390
1391
manual_system_maintenance(true);
1392
1393
s_printf(txt_buf,
1394
"#FFDD00 This may render the device inoperative!#\n\n"
1395
"#FFDD00 Are you really sure?#");
1396
if ((restoreType & PART_BOOT) || (restoreType & PART_GP_ALL))
1397
{
1398
s_printf(txt_buf + strlen(txt_buf),
1399
"\n\nThe mode you selected will only restore\nthe partitions that it can find.\n"
1400
"If it is not found, it will be skipped\nand continue with the next.");
1401
}
1402
1403
u32 orig_msg_len = strlen(txt_buf);
1404
1405
lv_obj_t *warn_mbox_bg = create_mbox_text(txt_buf, false);
1406
lv_obj_t *warn_mbox = lv_obj_get_child(warn_mbox_bg, NULL);
1407
1408
u8 failsafe_wait = 6;
1409
while (failsafe_wait > 0)
1410
{
1411
s_printf(txt_buf + orig_msg_len, "\n\n#888888 Wait... (%ds)#", failsafe_wait);
1412
lv_mbox_set_text(warn_mbox, txt_buf);
1413
msleep(1000);
1414
manual_system_maintenance(true);
1415
failsafe_wait--;
1416
}
1417
1418
s_printf(txt_buf + orig_msg_len, "\n\nPress #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");
1419
lv_mbox_set_text(warn_mbox, txt_buf);
1420
manual_system_maintenance(true);
1421
1422
if (!(btn_wait() & BTN_POWER))
1423
{
1424
lv_label_set_text(gui->label_info, "#FFDD00 Restore operation was aborted!#");
1425
lv_obj_del(warn_mbox_bg);
1426
goto out;
1427
}
1428
lv_obj_del(warn_mbox_bg);
1429
manual_system_maintenance(true);
1430
1431
if (!sd_mount())
1432
{
1433
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init SD!#");
1434
goto out;
1435
}
1436
1437
if (!emmc_initialize(false))
1438
{
1439
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
1440
goto out;
1441
}
1442
1443
int i = 0;
1444
char sdPath[OUT_FILENAME_SZ];
1445
if (!gui->raw_emummc)
1446
emmcsn_path_impl(sdPath, "/restore", "", &emmc_storage);
1447
else
1448
emmcsn_path_impl(sdPath, "/restore/emummc", "", &emmc_storage);
1449
gui->base_path = (char *)malloc(strlen(sdPath) + 1);
1450
strcpy(gui->base_path, sdPath);
1451
1452
timer = get_tmr_s();
1453
if (restoreType & PART_BOOT)
1454
{
1455
const u32 BOOT_PART_SIZE = emmc_storage.ext_csd.boot_mult << 17;
1456
const u32 BOOT_PART_SECTORS = 0x2000; // Force 4 MiB for emuMMC.
1457
1458
emmc_part_t bootPart;
1459
memset(&bootPart, 0, sizeof(bootPart));
1460
bootPart.lba_start = 0;
1461
if (!gui->raw_emummc)
1462
bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;
1463
else
1464
bootPart.lba_end = BOOT_PART_SECTORS - 1;
1465
for (i = 0; i < 2; i++)
1466
{
1467
strcpy(bootPart.name, "BOOT");
1468
bootPart.name[4] = (u8)('0' + i);
1469
bootPart.name[5] = 0;
1470
1471
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n\n\n\n",
1472
i, bootPart.name, bootPart.lba_start, bootPart.lba_end);
1473
lv_label_set_text(gui->label_info, txt_buf);
1474
s_printf(txt_buf, "%02d: %s... ", i, bootPart.name);
1475
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
1476
manual_system_maintenance(true);
1477
1478
emmc_set_partition(i + 1);
1479
1480
if (!gui->raw_emummc)
1481
emmcsn_path_impl(sdPath, "/restore", bootPart.name, &emmc_storage);
1482
else
1483
emmcsn_path_impl(sdPath, "/restore/emummc", bootPart.name, &emmc_storage);
1484
res = _restore_emmc_part(gui, sdPath, i, &emmc_storage, &bootPart, false);
1485
1486
if (!res)
1487
s_printf(txt_buf, "#FFDD00 Failed!#\n");
1488
else if (res > 0)
1489
s_printf(txt_buf, "Done!\n");
1490
1491
if (res >= 0)
1492
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
1493
else
1494
res = 0;
1495
manual_system_maintenance(true);
1496
}
1497
}
1498
1499
if (restoreType & PART_GP_ALL)
1500
{
1501
emmcsn_path_impl(sdPath, "/restore/partitions", "", &emmc_storage);
1502
gui->base_path = (char *)malloc(strlen(sdPath) + 1);
1503
strcpy(gui->base_path, sdPath);
1504
1505
emmc_set_partition(EMMC_GPP);
1506
1507
LIST_INIT(gpt);
1508
emmc_gpt_parse(&gpt);
1509
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
1510
{
1511
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n\n\n\n",
1512
i, part->name, part->lba_start, part->lba_end);
1513
lv_label_set_text(gui->label_info, txt_buf);
1514
s_printf(txt_buf, "%02d: %s... ", i, part->name);
1515
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
1516
manual_system_maintenance(true);
1517
i++;
1518
1519
emmcsn_path_impl(sdPath, "/restore/partitions", part->name, &emmc_storage);
1520
res = _restore_emmc_part(gui, sdPath, 0, &emmc_storage, part, false);
1521
1522
if (!res)
1523
s_printf(txt_buf, "#FFDD00 Failed!#\n");
1524
else if (res > 0)
1525
s_printf(txt_buf, "Done!\n");
1526
1527
if (res >= 0)
1528
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
1529
else
1530
res = 0;
1531
manual_system_maintenance(true);
1532
}
1533
emmc_gpt_free(&gpt);
1534
}
1535
1536
if (restoreType & PART_RAW)
1537
{
1538
// Get GP partition size dynamically.
1539
const u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt;
1540
1541
emmc_part_t rawPart;
1542
memset(&rawPart, 0, sizeof(rawPart));
1543
rawPart.lba_start = 0;
1544
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
1545
strcpy(rawPart.name, "rawnand.bin");
1546
{
1547
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n\n\n\n",
1548
i, rawPart.name, rawPart.lba_start, rawPart.lba_end);
1549
lv_label_set_text(gui->label_info, txt_buf);
1550
s_printf(txt_buf, "%02d: %s... ", i, rawPart.name);
1551
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
1552
manual_system_maintenance(true);
1553
i++;
1554
1555
if (!gui->raw_emummc)
1556
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &emmc_storage);
1557
else
1558
emmcsn_path_impl(sdPath, "/restore/emummc", rawPart.name, &emmc_storage);
1559
res = _restore_emmc_part(gui, sdPath, 2, &emmc_storage, &rawPart, true);
1560
1561
if (!res)
1562
s_printf(txt_buf, "#FFDD00 Failed!#\n");
1563
else if (res > 0)
1564
s_printf(txt_buf, "Done!\n");
1565
1566
if (res >= 0)
1567
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
1568
else
1569
res = 0;
1570
manual_system_maintenance(true);
1571
}
1572
}
1573
1574
timer = get_tmr_s() - timer;
1575
emmc_end();
1576
1577
if (res && n_cfg.verification && !gui->raw_emummc)
1578
s_printf(txt_buf, "Time taken: %dm %ds.\n#96FF00 Finished and verified!#", timer / 60, timer % 60);
1579
else if (res)
1580
s_printf(txt_buf, "Time taken: %dm %ds.\nFinished!", timer / 60, timer % 60);
1581
else
1582
s_printf(txt_buf, "Time taken: %dm %ds.", timer / 60, timer % 60);
1583
1584
lv_label_set_text(gui->label_finish, txt_buf);
1585
1586
out:
1587
free(txt_buf);
1588
free(gui->base_path);
1589
sd_unmount();
1590
}
1591
1592