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