Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/nyx/nyx_gui/frontend/gui_tools_partition_manager.c
2598 views
1
/*
2
* Copyright (c) 2019-2026 CTCaer
3
*
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms and conditions of the GNU General Public License,
6
* version 2, as published by the Free Software Foundation.
7
*
8
* This program is distributed in the hope it will be useful, but WITHOUT
9
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11
* more details.
12
*
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15
*/
16
17
#include <stdlib.h>
18
19
#include <bdk.h>
20
21
#include "gui.h"
22
#include "gui_tools.h"
23
#include "fe_emummc_tools.h"
24
#include "gui_tools_partition_manager.h"
25
#include "../hos/hos.h"
26
#include <libs/fatfs/diskio.h>
27
#include <libs/lvgl/lvgl.h>
28
29
#define SECTORS_PER_GB 0x200000
30
31
#define AU_ALIGN_SECTORS 0x8000 // 16MB.
32
#define AU_ALIGN_BYTES (AU_ALIGN_SECTORS * SD_BLOCKSIZE)
33
34
#define HOS_USER_SECTOR 0x53C000
35
#define HOS_FAT_MIN_SIZE_MB 2048
36
#define HOS_USER_MIN_SIZE_MB 1024
37
38
#define EMU_SLIDER_MIN 0
39
#define EMU_SLIDER_MAX 44 // 24 GB. Always an even number.
40
#define EMU_SLIDER_1X_MAX (EMU_SLIDER_MAX / 2)
41
#define EMU_SLIDER_1X_FULL EMU_SLIDER_1X_MAX
42
#define EMU_SLIDER_2X_MIN (EMU_SLIDER_1X_MAX + 1)
43
#define EMU_SLIDER_2X_FULL EMU_SLIDER_MAX
44
#define EMU_SLIDER_OFFSET 3 // Min 4GB.
45
#define EMU_RSVD_MB (4 + 4 + 16 + 8) // BOOT0 + BOOT1 + 16MB offset + 8MB alignment.
46
47
#define EMU_32GB_FULL 29856 // Actual: 29820 MB.
48
#define EMU_64GB_FULL 59680 // Actual: 59640 MB.
49
50
#define AND_SYS_SIZE_MB 6144 // 6 GB. Fits both Legacy (4912MB) and Dynamic (6144MB) partition schemes.
51
52
extern volatile boot_cfg_t *b_cfg;
53
extern volatile nyx_storage_t *nyx_str;
54
55
typedef struct _partition_ctxt_t
56
{
57
bool emmc;
58
sdmmc_storage_t *storage;
59
60
u32 total_sct;
61
u32 alignment;
62
u32 emmc_size_mb;
63
int backup_possible;
64
65
s32 hos_min_size;
66
67
s32 hos_size;
68
u32 emu_size;
69
u32 l4t_size;
70
u32 and_size;
71
72
bool emu_double;
73
bool emmc_is_64gb;
74
75
bool and_dynamic;
76
77
mbr_t mbr_old;
78
79
lv_obj_t *bar_hos;
80
lv_obj_t *bar_emu;
81
lv_obj_t *bar_l4t;
82
lv_obj_t *bar_and;
83
84
lv_obj_t *sep_emu;
85
lv_obj_t *sep_l4t;
86
lv_obj_t *sep_and;
87
88
lv_obj_t *slider_bar_hos;
89
90
lv_obj_t *cont_lbl;
91
92
lv_obj_t *lbl_hos;
93
lv_obj_t *lbl_emu;
94
lv_obj_t *lbl_l4t;
95
lv_obj_t *lbl_and;
96
97
lv_obj_t *partition_button;
98
} partition_ctxt_t;
99
100
typedef struct _l4t_flasher_ctxt_t
101
{
102
u32 offset_sct;
103
u32 image_size_sct;
104
} l4t_flasher_ctxt_t;
105
106
partition_ctxt_t part_info;
107
l4t_flasher_ctxt_t l4t_flash_ctxt;
108
109
lv_obj_t *btn_flash_l4t;
110
lv_obj_t *btn_flash_android;
111
112
static FRESULT _copy_file(const char *src, const char *dst, const char *path)
113
{
114
FIL fp_src;
115
FIL fp_dst;
116
FRESULT res;
117
118
// Open file for reading.
119
f_chdrive(src);
120
res = f_open(&fp_src, path, FA_READ);
121
if (res != FR_OK)
122
return res;
123
124
u32 file_bytes_left = f_size(&fp_src);
125
126
// Open file for writing.
127
f_chdrive(dst);
128
f_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE);
129
f_lseek(&fp_dst, f_size(&fp_src));
130
f_lseek(&fp_dst, 0);
131
132
while (file_bytes_left)
133
{
134
u32 chunk_size = MIN(file_bytes_left, SZ_4M); // 4MB chunks.
135
file_bytes_left -= chunk_size;
136
137
// Copy file to buffer.
138
f_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);
139
140
// Write file to disk.
141
f_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);
142
}
143
144
f_close(&fp_dst);
145
f_chdrive(src);
146
f_close(&fp_src);
147
148
return FR_OK;
149
}
150
151
static int _stat_and_copy_files(const char *src, const char *dst, char *path, u32 *total_files, u32 *total_size, lv_obj_t **labels)
152
{
153
FRESULT res;
154
DIR dir;
155
u32 dirLength = 0;
156
static FILINFO fno;
157
158
f_chdrive(src);
159
160
// Open directory.
161
res = f_opendir(&dir, path);
162
if (res != FR_OK)
163
return res;
164
165
if (labels)
166
lv_label_set_text(labels[0], path);
167
168
dirLength = strlen(path);
169
170
// Hard limit path to 1024 characters. Do not result to error.
171
if (dirLength > 1024)
172
goto out;
173
174
for (;;)
175
{
176
// Clear file path.
177
path[dirLength] = 0;
178
179
// Read a directory item.
180
res = f_readdir(&dir, &fno);
181
182
// Break on error or end of dir.
183
if (res != FR_OK || fno.fname[0] == 0)
184
break;
185
186
// Set new directory or file.
187
memcpy(&path[dirLength], "/", 1);
188
strcpy(&path[dirLength + 1], fno.fname);
189
190
if (labels)
191
{
192
lv_label_set_text(labels[1], fno.fname);
193
manual_system_maintenance(true);
194
}
195
196
// Copy file to destination disk.
197
if (!(fno.fattrib & AM_DIR))
198
{
199
u64 file_size = fno.fsize > RAMDISK_CLUSTER_SZ ? fno.fsize : RAMDISK_CLUSTER_SZ;
200
201
// Check for FAT32 or total overflow.
202
if ((file_size + *total_size) > 0xFFFFFFFFu)
203
{
204
// Set size to > 1GB, skip next folders and return.
205
*total_size = SZ_2G;
206
res = -1;
207
break;
208
}
209
210
*total_size += file_size;
211
*total_files += 1;
212
213
// Create a copy to destination.
214
if (dst)
215
{
216
FIL fp_src;
217
FIL fp_dst;
218
u32 file_bytes_left = fno.fsize;
219
220
// Open file for writing.
221
f_chdrive(dst);
222
f_open(&fp_dst, path, FA_CREATE_ALWAYS | FA_WRITE);
223
f_lseek(&fp_dst, fno.fsize);
224
f_lseek(&fp_dst, 0);
225
226
// Open file for reading.
227
f_chdrive(src);
228
f_open(&fp_src, path, FA_READ);
229
230
while (file_bytes_left)
231
{
232
u32 chunk_size = MIN(file_bytes_left, SZ_4M); // 4MB chunks.
233
file_bytes_left -= chunk_size;
234
235
// Copy file to buffer.
236
f_read(&fp_src, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);
237
manual_system_maintenance(true);
238
239
// Write file to disk.
240
f_write(&fp_dst, (void *)SDXC_BUF_ALIGNED, chunk_size, NULL);
241
}
242
243
// Finalize copied file.
244
f_close(&fp_dst);
245
f_chdrive(dst);
246
f_chmod(path, fno.fattrib, 0xFF);
247
248
f_chdrive(src);
249
f_close(&fp_src);
250
}
251
252
// If total is > 1.2GB exit.
253
if (*total_size > (RAM_DISK_SZ - SZ_16M)) // Account for alignment.
254
{
255
// Skip next folders and return.
256
res = -1;
257
break;
258
}
259
}
260
else // It's a directory.
261
{
262
if (!memcmp("System Volume Information", fno.fname, 25))
263
continue;
264
265
// Create folder to destination.
266
if (dst)
267
{
268
f_chdrive(dst);
269
f_mkdir(path);
270
f_chmod(path, fno.fattrib, 0xFF);
271
}
272
273
// Enter the directory.
274
res = _stat_and_copy_files(src, dst, path, total_files, total_size, labels);
275
if (res != FR_OK)
276
break;
277
278
if (labels)
279
{
280
// Clear folder path.
281
path[dirLength] = 0;
282
lv_label_set_text(labels[0], path);
283
}
284
}
285
}
286
287
out:
288
f_closedir(&dir);
289
290
return res;
291
}
292
293
static void _create_gpt_partition(gpt_t *gpt, u8 *gpt_idx, u32 *curr_part_lba, u32 size_lba, const char *name, int name_size)
294
{
295
static const u8 linux_part_guid[] = { 0xAF, 0x3D, 0xC6, 0x0F, 0x83, 0x84, 0x72, 0x47, 0x8E, 0x79, 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 };
296
297
// Reset partition.
298
memset(&gpt->entries[*gpt_idx], 0, sizeof(gpt_entry_t));
299
300
// Create GPT partition.
301
memcpy(gpt->entries[*gpt_idx].type_guid, linux_part_guid, 16);
302
303
// Set randomly created GUID.
304
u8 random_number[SE_RNG_BLOCK_SIZE];
305
se_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);
306
memcpy(gpt->entries[*gpt_idx].part_guid, random_number, SE_RNG_BLOCK_SIZE);
307
308
// Set partition start and end.
309
gpt->entries[*gpt_idx].lba_start = *curr_part_lba;
310
gpt->entries[*gpt_idx].lba_end = *curr_part_lba + size_lba - 1;
311
312
// Set name.
313
u16 name_utf16[36] = {0};
314
u32 name_lenth = strlen(name);
315
for (u32 i = 0; i < name_lenth; i++)
316
name_utf16[i] = name[i];
317
memcpy(gpt->entries[*gpt_idx].name, name_utf16, name_lenth * sizeof(u16));
318
319
// Wipe the first 1MB to sanitize it as raw-empty partition.
320
sdmmc_storage_write(part_info.storage, *curr_part_lba, 0x800, (void *)SDMMC_UPPER_BUFFER);
321
322
// Prepare for next.
323
(*curr_part_lba) += size_lba;
324
(*gpt_idx)++;
325
}
326
327
static void _sd_prepare_and_flash_mbr_gpt()
328
{
329
mbr_t mbr;
330
u8 random_number[SE_RNG_BLOCK_SIZE];
331
332
// Read current MBR.
333
sdmmc_storage_read(&sd_storage, 0, 1, &mbr);
334
335
// Copy over metadata if they exist.
336
if (*(u32 *)&part_info.mbr_old.bootstrap[0x80])
337
memcpy(&mbr.bootstrap[0x80], &part_info.mbr_old.bootstrap[0x80], 64);
338
if (*(u32 *)&part_info.mbr_old.bootstrap[0xE0])
339
memcpy(&mbr.bootstrap[0xE0], &part_info.mbr_old.bootstrap[0xE0], 208);
340
341
// Clear the first 16MB.
342
memset((void *)SDMMC_UPPER_BUFFER, 0, AU_ALIGN_BYTES);
343
sdmmc_storage_write(&sd_storage, 0, AU_ALIGN_SECTORS, (void *)SDMMC_UPPER_BUFFER);
344
345
// Set disk signature.
346
se_rng_pseudo(random_number, sizeof(u32));
347
memcpy(&mbr.signature, random_number, sizeof(u32));
348
349
// FAT partition as first.
350
u8 mbr_idx = 1;
351
352
// Apply L4T Linux second to MBR if no Android.
353
if (part_info.l4t_size && !part_info.and_size)
354
{
355
mbr.partitions[mbr_idx].type = 0x83; // Linux system partition.
356
mbr.partitions[mbr_idx].start_sct = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11);
357
mbr.partitions[mbr_idx].size_sct = part_info.l4t_size << 11;
358
sdmmc_storage_write(&sd_storage, mbr.partitions[mbr_idx].start_sct, 0x800, (void *)SDMMC_UPPER_BUFFER); // Clear the first 1MB.
359
mbr_idx++;
360
}
361
362
// emuMMC goes second or third. Next to L4T if no Android.
363
if (part_info.emu_size)
364
{
365
mbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition.
366
mbr.partitions[mbr_idx].start_sct = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11);
367
368
if (!part_info.emu_double)
369
mbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 11) - 0x800; // Reserve 1MB.
370
else
371
{
372
mbr.partitions[mbr_idx].size_sct = part_info.emu_size << 10;
373
mbr_idx++;
374
375
// 2nd emuMMC.
376
mbr.partitions[mbr_idx].type = 0xE0; // emuMMC partition.
377
mbr.partitions[mbr_idx].start_sct = mbr.partitions[mbr_idx - 1].start_sct + (part_info.emu_size << 10);
378
mbr.partitions[mbr_idx].size_sct = (part_info.emu_size << 10) - 0x800; // Reserve 1MB.
379
}
380
mbr_idx++;
381
}
382
383
if (part_info.and_size)
384
{
385
gpt_t *gpt = zalloc(sizeof(gpt_t));
386
gpt_header_t gpt_hdr_backup = { 0 };
387
388
// Set GPT protective partition in MBR.
389
mbr.partitions[mbr_idx].type = 0xEE;
390
mbr.partitions[mbr_idx].start_sct = 1;
391
mbr.partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1;
392
mbr_idx++;
393
394
// Set GPT header.
395
memcpy(&gpt->header.signature, "EFI PART", 8);
396
gpt->header.revision = 0x10000;
397
gpt->header.size = 92;
398
gpt->header.my_lba = 1;
399
gpt->header.alt_lba = sd_storage.sec_cnt - 1;
400
gpt->header.first_use_lba = (sizeof(mbr_t) + sizeof(gpt_t)) >> 9;
401
gpt->header.last_use_lba = sd_storage.sec_cnt - 0x800 - 1; // sd_storage.sec_cnt - 33 is start of backup gpt partition entries.
402
se_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);
403
memcpy(gpt->header.disk_guid, random_number, 10);
404
memcpy(gpt->header.disk_guid + 10, "NYXGPT", 6);
405
gpt->header.part_ent_lba = 2;
406
gpt->header.part_ent_size = 128;
407
408
// Set FAT GPT partition manually.
409
const u8 basic_part_guid[] = { 0xA2, 0xA0, 0xD0, 0xEB, 0xE5, 0xB9, 0x33, 0x44, 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 };
410
memcpy(gpt->entries[0].type_guid, basic_part_guid, 16);
411
se_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);
412
memcpy(gpt->entries[0].part_guid, random_number, SE_RNG_BLOCK_SIZE);
413
414
// Clear non-standard Windows MBR attributes. bit4: Read only, bit5: Shadow copy, bit6: Hidden, bit7: No drive letter.
415
gpt->entries[0].part_guid[7] = 0;
416
417
gpt->entries[0].lba_start = mbr.partitions[0].start_sct;
418
gpt->entries[0].lba_end = mbr.partitions[0].start_sct + mbr.partitions[0].size_sct - 1;
419
memcpy(gpt->entries[0].name, (u16[]) { 'h', 'o', 's', '_', 'd', 'a', 't', 'a' }, 16);
420
421
// Set the rest of GPT partitions.
422
u8 gpt_idx = 1;
423
u32 curr_part_lba = AU_ALIGN_SECTORS + ((u32)part_info.hos_size << 11);
424
425
// L4T partition.
426
if (part_info.l4t_size)
427
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, part_info.l4t_size << 11, "l4t", 6);
428
429
if (part_info.and_dynamic)
430
{
431
// Android Linux Kernel partition. 64MB.
432
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "boot", 8);
433
434
// Android Recovery partition. 64MB.
435
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "recovery", 16);
436
437
// Android Device Tree Reference partition. 1MB.
438
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, "dtb", 6);
439
440
// Android Misc partition. 3MB.
441
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, "misc", 8);
442
443
// Android Cache partition. 60MB.
444
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1E000, "cache", 10);
445
446
// Android Super dynamic partition. 5952MB.
447
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0xBA0000, "super", 10);
448
449
// Android Userdata partition.
450
u32 uda_size = (part_info.and_size << 11) - 0xC00000; // Subtract the other partitions (6144MB).
451
if (!part_info.emu_size)
452
uda_size -= 0x800; // Reserve 1MB.
453
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, "userdata", 16);
454
}
455
else
456
{
457
// Android Vendor partition. 1GB
458
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x200000, "vendor", 12);
459
460
// Android System partition. 3GB.
461
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x600000, "APP", 6);
462
463
// Android Linux Kernel partition. 32MB.
464
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x10000, "LNX", 6);
465
466
// Android Recovery partition. 64MB.
467
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "SOS", 6);
468
469
// Android Device Tree Reference partition. 1MB.
470
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, "DTB", 6);
471
472
// Android Encryption partition. 16MB.
473
// Note: 16MB size is for aligning UDA. If any other tiny partition must be added, it should split the MDA one.
474
sdmmc_storage_write(&sd_storage, curr_part_lba, 0x8000, (void *)SDMMC_UPPER_BUFFER); // Clear the whole of it.
475
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x8000, "MDA", 6);
476
477
// Android Cache partition. 700MB.
478
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x15E000, "CAC", 6);
479
480
// Android Misc partition. 3MB.
481
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, "MSC", 6);
482
483
// Android Userdata partition.
484
u32 uda_size = (part_info.and_size << 11) - 0x998000; // Subtract the other partitions (4912MB).
485
if (!part_info.emu_size)
486
uda_size -= 0x800; // Reserve 1MB.
487
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, "UDA", 6);
488
}
489
490
// Handle emuMMC partitions manually.
491
if (part_info.emu_size)
492
{
493
// Set 1st emuMMC.
494
u8 emu_part_guid[] = { 0x00, 0x7E, 0xCA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 'e', 'm', 'u', 'M', 'M', 'C' };
495
memcpy(gpt->entries[gpt_idx].type_guid, emu_part_guid, 16);
496
se_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);
497
memcpy(gpt->entries[gpt_idx].part_guid, random_number, SE_RNG_BLOCK_SIZE);
498
gpt->entries[gpt_idx].lba_start = curr_part_lba;
499
if (!part_info.emu_double)
500
gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 11) - 0x800 - 1; // Reserve 1MB.
501
else
502
gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 1;
503
memcpy(gpt->entries[gpt_idx].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c' }, 12);
504
gpt_idx++;
505
506
// Set 2nd emuMMC.
507
if (part_info.emu_double)
508
{
509
curr_part_lba += (part_info.emu_size << 10);
510
memcpy(gpt->entries[gpt_idx].type_guid, emu_part_guid, 16);
511
se_rng_pseudo(random_number, SE_RNG_BLOCK_SIZE);
512
memcpy(gpt->entries[gpt_idx].part_guid, random_number, SE_RNG_BLOCK_SIZE);
513
gpt->entries[gpt_idx].lba_start = curr_part_lba;
514
gpt->entries[gpt_idx].lba_end = curr_part_lba + (part_info.emu_size << 10) - 0x800 - 1; // Reserve 1MB.
515
memcpy(gpt->entries[gpt_idx].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c', '2' }, 14);
516
gpt_idx++;
517
}
518
}
519
520
// Set final GPT header parameters.
521
gpt->header.num_part_ents = gpt_idx;
522
gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents);
523
gpt->header.crc32 = 0; // Set to 0 for calculation.
524
gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);
525
526
// Set final backup GPT header parameters.
527
memcpy(&gpt_hdr_backup, &gpt->header, sizeof(gpt_header_t));
528
gpt_hdr_backup.my_lba = sd_storage.sec_cnt - 1;
529
gpt_hdr_backup.alt_lba = 1;
530
gpt_hdr_backup.part_ent_lba = sd_storage.sec_cnt - 33;
531
gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.
532
gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);
533
534
// Write main GPT.
535
sdmmc_storage_write(&sd_storage, gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt);
536
537
// Write backup GPT partition table.
538
sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries);
539
540
// Write backup GPT header.
541
sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);
542
543
free(gpt);
544
}
545
546
// Write MBR.
547
sdmmc_storage_write(&sd_storage, 0, 1, &mbr);
548
}
549
550
static int _emmc_prepare_and_flash_mbr_gpt()
551
{
552
gpt_t *gpt = zalloc(sizeof(gpt_t));
553
gpt_header_t gpt_hdr_backup = { 0 };
554
555
// Read main GPT.
556
sdmmc_storage_read(&emmc_storage, 1, sizeof(gpt_t) >> 9, gpt);
557
558
// Set GPT header.
559
gpt->header.alt_lba = emmc_storage.sec_cnt - 1;
560
gpt->header.last_use_lba = emmc_storage.sec_cnt - 0x800 - 1; // emmc_storage.sec_cnt - 33 is start of backup gpt partition entries.
561
562
// Calculate HOS USER partition
563
u32 part_rsvd_size = (part_info.l4t_size << 11) + (part_info.and_size << 11);
564
part_rsvd_size += part_rsvd_size ? part_info.alignment : 0x800; // Only reserve 1MB if no extra partitions.
565
u32 hos_user_size = emmc_storage.sec_cnt - HOS_USER_SECTOR - part_rsvd_size;
566
567
// Get HOS USER partition index.
568
LIST_INIT(gpt_emmc);
569
emmc_gpt_parse(&gpt_emmc);
570
emmc_part_t *user_part = emmc_part_find(&gpt_emmc, "USER");
571
if (!user_part)
572
{
573
emmc_gpt_free(&gpt_emmc);
574
free(gpt);
575
576
return 1;
577
}
578
u8 gpt_idx = user_part->index;
579
emmc_gpt_free(&gpt_emmc);
580
581
// HOS USER partition.
582
u32 curr_part_lba = gpt->entries[gpt_idx].lba_start;
583
gpt->entries[gpt_idx].lba_end = curr_part_lba + hos_user_size - 1;
584
585
curr_part_lba += hos_user_size;
586
gpt_idx++;
587
588
// L4T partition.
589
if (part_info.l4t_size)
590
{
591
u32 l4t_size = part_info.l4t_size << 11;
592
if (!part_info.and_size)
593
l4t_size -= 0x800; // Reserve 1MB.
594
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, l4t_size, "l4t", 6);
595
}
596
597
if (part_info.and_size && part_info.and_dynamic)
598
{
599
// Android Linux Kernel partition. 64MB.
600
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "boot", 8);
601
602
// Android Recovery partition. 64MB.
603
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "recovery", 16);
604
605
// Android Device Tree Reference partition. 1MB.
606
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, "dtb", 6);
607
608
// Android Misc partition. 3MB.
609
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, "misc", 8);
610
611
// Android Cache partition. 60MB.
612
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1E000, "cache", 10);
613
614
// Android Super dynamic partition. 5952MB.
615
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0xBA0000, "super", 10);
616
617
// Android Userdata partition.
618
u32 uda_size = (part_info.and_size << 11) - 0xC00000; // Subtract the other partitions (6144MB).
619
uda_size -= 0x800; // Reserve 1MB.
620
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, "userdata", 16);
621
}
622
else if (part_info.and_size)
623
{
624
// Android Vendor partition. 1GB
625
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x200000, "vendor", 12);
626
627
// Android System partition. 3GB.
628
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x600000, "APP", 6);
629
630
// Android Linux Kernel partition. 32MB.
631
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x10000, "LNX", 6);
632
633
// Android Recovery partition. 64MB.
634
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x20000, "SOS", 6);
635
636
// Android Device Tree Reference partition. 1MB.
637
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x800, "DTB", 6);
638
639
// Android Encryption partition. 16MB.
640
// Note: 16MB size is for aligning UDA. If any other tiny partition must be added, it should split the MDA one.
641
sdmmc_storage_write(&emmc_storage, curr_part_lba, 0x8000, (void *)SDMMC_UPPER_BUFFER); // Clear the whole of it.
642
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x8000, "MDA", 6);
643
644
// Android Cache partition. 700MB.
645
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x15E000, "CAC", 6);
646
647
// Android Misc partition. 3MB.
648
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, 0x1800, "MSC", 6);
649
650
// Android Userdata partition.
651
u32 uda_size = (part_info.and_size << 11) - 0x998000; // Subtract the other partitions (4912MB).
652
uda_size -= 0x800; // Reserve 1MB.
653
_create_gpt_partition(gpt, &gpt_idx, &curr_part_lba, uda_size, "UDA", 6);
654
}
655
656
// Clear the rest of GPT partition table.
657
for (u32 i = gpt_idx; i < 128; i++)
658
memset(&gpt->entries[i], 0, sizeof(gpt_entry_t));
659
660
// Set final GPT header parameters.
661
gpt->header.num_part_ents = gpt_idx;
662
gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, sizeof(gpt_entry_t) * gpt->header.num_part_ents);
663
gpt->header.crc32 = 0; // Set to 0 for calculation.
664
gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);
665
666
// Set final backup GPT header parameters.
667
memcpy(&gpt_hdr_backup, &gpt->header, sizeof(gpt_header_t));
668
gpt_hdr_backup.my_lba = emmc_storage.sec_cnt - 1;
669
gpt_hdr_backup.alt_lba = 1;
670
gpt_hdr_backup.part_ent_lba = emmc_storage.sec_cnt - 33;
671
gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.
672
gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);
673
674
// Write main GPT.
675
sdmmc_storage_write(&emmc_storage, gpt->header.my_lba, sizeof(gpt_t) >> 9, gpt);
676
677
// Write backup GPT partition table.
678
sdmmc_storage_write(&emmc_storage, gpt_hdr_backup.part_ent_lba, ((sizeof(gpt_entry_t) * 128) >> 9), gpt->entries);
679
680
// Write backup GPT header.
681
sdmmc_storage_write(&emmc_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);
682
683
// Clear nand patrol.
684
u8 *buf = (u8 *)gpt;
685
memset(buf, 0, EMMC_BLOCKSIZE);
686
emmc_set_partition(EMMC_BOOT0);
687
sdmmc_storage_write(&emmc_storage, NAND_PATROL_SECTOR, 1, buf);
688
emmc_set_partition(EMMC_GPP);
689
690
free(gpt);
691
692
return 0;
693
}
694
695
static lv_res_t _action_part_manager_ums_sd(lv_obj_t *btn)
696
{
697
action_ums_sd(NULL);
698
699
// Close and reopen partition manager.
700
lv_action_t close_btn_action = lv_btn_get_action(close_btn, LV_BTN_ACTION_CLICK);
701
close_btn_action(close_btn);
702
lv_obj_del(ums_mbox);
703
create_window_sd_partition_manager(NULL);
704
705
return LV_RES_INV;
706
}
707
708
static lv_res_t _action_delete_linux_installer_files(lv_obj_t * btns, const char * txt)
709
{
710
711
int btn_idx = lv_btnm_get_pressed(btns);
712
713
// Delete parent mbox.
714
mbox_action(btns, txt);
715
716
// Flash Linux.
717
if (!btn_idx)
718
{
719
char path[128];
720
721
sd_mount();
722
723
strcpy(path, "switchroot/install/l4t.");
724
725
// Delete all l4t.xx files.
726
u32 idx = 0;
727
while (true)
728
{
729
if (idx < 10)
730
{
731
path[23] = '0';
732
itoa(idx, &path[23 + 1], 10);
733
}
734
else
735
itoa(idx, &path[23], 10);
736
737
if (!f_stat(path, NULL))
738
{
739
f_unlink(path);
740
}
741
else
742
break;
743
744
idx++;
745
}
746
747
sd_unmount();
748
}
749
750
return LV_RES_INV;
751
}
752
753
static lv_res_t _action_flash_linux_data(lv_obj_t * btns, const char * txt)
754
{
755
int btn_idx = lv_btnm_get_pressed(btns);
756
757
// Delete parent mbox.
758
mbox_action(btns, txt);
759
760
bool succeeded = false;
761
762
if (btn_idx)
763
return LV_RES_INV;
764
765
// Flash Linux.
766
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
767
lv_obj_set_style(dark_bg, &mbox_darken);
768
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
769
770
static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
771
static const char *mbox_btn_map2[] = { "\223Delete Installation Files", "\221OK", "" };
772
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
773
lv_mbox_set_recolor_text(mbox, true);
774
lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);
775
776
lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#");
777
778
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
779
lv_label_set_recolor(lbl_status, true);
780
lv_label_set_text(lbl_status, "#C7EA46 Status:# Flashing Linux...");
781
782
// Create container to keep content inside.
783
lv_obj_t *h1 = lv_cont_create(mbox, NULL);
784
lv_cont_set_fit(h1, true, true);
785
lv_cont_set_style(h1, &lv_style_transp_tight);
786
787
lv_obj_t *bar = lv_bar_create(h1, NULL);
788
lv_obj_set_size(bar, LV_DPI * 30 / 10, LV_DPI / 5);
789
lv_bar_set_range(bar, 0, 100);
790
lv_bar_set_value(bar, 0);
791
792
lv_obj_t *label_pct = lv_label_create(h1, NULL);
793
lv_label_set_recolor(label_pct, true);
794
lv_label_set_text(label_pct, " "SYMBOL_DOT" 0%");
795
lv_label_set_style(label_pct, lv_theme_get_current()->label.prim);
796
lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);
797
798
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
799
lv_obj_set_top(mbox, true);
800
801
sd_mount();
802
if (part_info.emmc)
803
emmc_initialize(false);
804
805
int res = 0;
806
char *path = malloc(1024);
807
char *txt_buf = malloc(SZ_4K);
808
strcpy(path, "switchroot/install/l4t.00");
809
u32 path_len = strlen(path) - 2;
810
811
FIL fp;
812
813
res = f_open(&fp, path, FA_READ);
814
if (res)
815
{
816
lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to open 1st part!");
817
818
goto exit;
819
}
820
821
u64 fileSize = (u64)f_size(&fp);
822
823
u32 num = 0;
824
u32 pct = 0;
825
u32 lba_curr = 0;
826
u32 bytesWritten = 0;
827
u32 currPartIdx = 0;
828
u32 prevPct = 200;
829
int retryCount = 0;
830
u32 total_size_sct = l4t_flash_ctxt.image_size_sct;
831
832
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
833
DWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0);
834
835
// Start flashing L4T.
836
while (total_size_sct > 0)
837
{
838
// 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.
839
if (bytesWritten >= fileSize)
840
{
841
// If we have more bytes written then close the file pointer and increase the part index we are using
842
f_close(&fp);
843
free(clmt);
844
memset(&fp, 0, sizeof(fp));
845
currPartIdx++;
846
847
if (currPartIdx < 10)
848
{
849
path[path_len] = '0';
850
itoa(currPartIdx, &path[path_len + 1], 10);
851
}
852
else
853
itoa(currPartIdx, &path[path_len], 10);
854
855
// Try to open the next file part
856
res = f_open(&fp, path, FA_READ);
857
if (res)
858
{
859
s_printf(txt_buf, "#FFDD00 Error:# Failed to open part %d#", currPartIdx);
860
lv_label_set_text(lbl_status, txt_buf);
861
manual_system_maintenance(true);
862
863
goto exit;
864
}
865
fileSize = (u64)f_size(&fp);
866
bytesWritten = 0;
867
clmt = f_expand_cltbl(&fp, SZ_4M, 0);
868
}
869
870
retryCount = 0;
871
num = MIN(total_size_sct, 8192);
872
873
// Read next data block from SD.
874
res = f_read_fast(&fp, buf, num << 9);
875
manual_system_maintenance(false);
876
877
if (res)
878
{
879
lv_label_set_text(lbl_status, "#FFDD00 Error:# Reading from SD!");
880
manual_system_maintenance(true);
881
882
f_close(&fp);
883
free(clmt);
884
goto exit;
885
}
886
887
// Write data block to L4T partition.
888
res = !sdmmc_storage_write(part_info.storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);
889
890
manual_system_maintenance(false);
891
892
// If failed, retry 3 more times.
893
while (res)
894
{
895
msleep(150);
896
manual_system_maintenance(true);
897
898
if (retryCount >= 3)
899
{
900
lv_label_set_text(lbl_status, "#FFDD00 Error:# Writing to SD!");
901
manual_system_maintenance(true);
902
903
f_close(&fp);
904
free(clmt);
905
goto exit;
906
}
907
908
res = !sdmmc_storage_write(part_info.storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);
909
manual_system_maintenance(false);
910
}
911
912
// Update completion percentage.
913
pct = (u64)((u64)lba_curr * 100u) / (u64)l4t_flash_ctxt.image_size_sct;
914
if (pct != prevPct)
915
{
916
lv_bar_set_value(bar, pct);
917
s_printf(txt_buf, " #DDDDDD "SYMBOL_DOT"# %d%%", pct);
918
lv_label_set_text(label_pct, txt_buf);
919
manual_system_maintenance(true);
920
prevPct = pct;
921
}
922
923
lba_curr += num;
924
total_size_sct -= num;
925
bytesWritten += num * EMMC_BLOCKSIZE;
926
}
927
lv_bar_set_value(bar, 100);
928
lv_label_set_text(label_pct, " "SYMBOL_DOT" 100%");
929
manual_system_maintenance(true);
930
931
// Restore operation ended successfully.
932
f_close(&fp);
933
free(clmt);
934
935
succeeded = true;
936
937
exit:
938
free(path);
939
free(txt_buf);
940
941
if (!succeeded)
942
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
943
else
944
lv_mbox_add_btns(mbox, mbox_btn_map2, _action_delete_linux_installer_files);
945
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
946
947
sd_unmount();
948
if (part_info.emmc)
949
emmc_end();
950
951
return LV_RES_INV;
952
}
953
954
static u32 _get_available_l4t_partition()
955
{
956
mbr_t mbr = { 0 };
957
gpt_t *gpt = zalloc(sizeof(gpt_t));
958
959
memset(&l4t_flash_ctxt, 0, sizeof(l4t_flasher_ctxt_t));
960
961
// Read MBR.
962
sdmmc_storage_read(part_info.storage, 0, 1, &mbr);
963
964
// Read main GPT.
965
sdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);
966
967
// Search for a suitable partition.
968
u32 size_sct = 0;
969
if (!memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)
970
{
971
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
972
{
973
if (!memcmp(gpt->entries[i].name, (u16[]) { 'l', '4', 't' }, 6))
974
{
975
l4t_flash_ctxt.offset_sct = gpt->entries[i].lba_start;
976
size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;
977
break;
978
}
979
}
980
}
981
else
982
{
983
for (u32 i = 1; i < 4; i++)
984
{
985
if (mbr.partitions[i].type == 0x83)
986
{
987
l4t_flash_ctxt.offset_sct = mbr.partitions[i].start_sct;
988
size_sct = mbr.partitions[i].size_sct;
989
break;
990
}
991
}
992
}
993
994
free(gpt);
995
996
return size_sct;
997
}
998
999
static int _get_available_android_partition()
1000
{
1001
gpt_t *gpt = zalloc(sizeof(gpt_t));
1002
1003
// Read main GPT.
1004
sdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);
1005
1006
// Check if GPT.
1007
if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)
1008
goto out;
1009
1010
// Find kernel partition.
1011
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
1012
{
1013
if (gpt->entries[i].lba_start)
1014
{
1015
int found = !memcmp(gpt->entries[i].name, (u16[]) { 'b', 'o', 'o', 't' }, 8) ? 2 : 0;
1016
found |= !memcmp(gpt->entries[i].name, (u16[]) { 'L', 'N', 'X' }, 6) ? 1 : 0;
1017
1018
if (found)
1019
{
1020
free(gpt);
1021
1022
return found;
1023
}
1024
}
1025
}
1026
1027
out:
1028
free(gpt);
1029
1030
return false;
1031
}
1032
1033
static lv_res_t _action_check_flash_linux(lv_obj_t *btn)
1034
{
1035
FILINFO fno;
1036
char path[128];
1037
1038
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
1039
lv_obj_set_style(dark_bg, &mbox_darken);
1040
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
1041
1042
static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
1043
static const char *mbox_btn_map2[] = { "\222Continue", "\222Cancel", "" };
1044
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
1045
lv_mbox_set_recolor_text(mbox, true);
1046
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
1047
1048
lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#");
1049
1050
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
1051
lv_label_set_recolor(lbl_status, true);
1052
lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions...");
1053
1054
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1055
lv_obj_set_top(mbox, true);
1056
1057
manual_system_maintenance(true);
1058
1059
sd_mount();
1060
if (part_info.emmc)
1061
emmc_initialize(false);
1062
1063
// Check if L4T image exists.
1064
strcpy(path, "switchroot/install/l4t.00");
1065
if (f_stat(path, NULL))
1066
{
1067
lv_label_set_text(lbl_status, "#FFDD00 Error:# Installation files not found!");
1068
goto error;
1069
}
1070
1071
// Find an applicable partition for L4T.
1072
u32 size_sct = _get_available_l4t_partition();
1073
if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)
1074
{
1075
lv_label_set_text(lbl_status, "#FFDD00 Error:# No partition found!");
1076
goto error;
1077
}
1078
1079
u32 idx = 0;
1080
path[23] = 0;
1081
1082
// Validate L4T images and consolidate their info.
1083
while (true)
1084
{
1085
if (idx < 10)
1086
{
1087
path[23] = '0';
1088
itoa(idx, &path[23 + 1], 10);
1089
}
1090
else
1091
itoa(idx, &path[23], 10);
1092
1093
// Check for alignment.
1094
if (f_stat(path, &fno))
1095
break;
1096
1097
// Check if current part is unaligned.
1098
if ((u64)fno.fsize % SZ_4M)
1099
{
1100
// Get next part filename.
1101
idx++;
1102
if (idx < 10)
1103
{
1104
path[23] = '0';
1105
itoa(idx, &path[23 + 1], 10);
1106
}
1107
else
1108
itoa(idx, &path[23], 10);
1109
1110
// If it exists, unaligned size for current part is not permitted.
1111
if (!f_stat(path, NULL)) // NULL: Don't override current part fs info.
1112
{
1113
lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is not aligned to 4 MiB!");
1114
goto error;
1115
}
1116
1117
// Last part. Align size to LBA (SD_BLOCKSIZE).
1118
fno.fsize = ALIGN((u64)fno.fsize, SD_BLOCKSIZE);
1119
idx--;
1120
}
1121
l4t_flash_ctxt.image_size_sct += (u64)fno.fsize >> 9;
1122
1123
idx++;
1124
}
1125
1126
// Check if image size is bigger than the partition available.
1127
if (l4t_flash_ctxt.image_size_sct > size_sct)
1128
{
1129
lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is bigger than the partition!");
1130
goto error;
1131
}
1132
1133
char *txt_buf = malloc(SZ_4K);
1134
s_printf(txt_buf,
1135
"#C7EA46 Status:# Found installation files and partition.\n"
1136
"#00DDFF Offset:# %08x, #00DDFF Size:# %X, #00DDFF Image size:# %d MiB\n"
1137
"\nDo you want to continue?", l4t_flash_ctxt.offset_sct, size_sct, l4t_flash_ctxt.image_size_sct >> 11);
1138
lv_label_set_text(lbl_status, txt_buf);
1139
free(txt_buf);
1140
lv_mbox_add_btns(mbox, mbox_btn_map2, _action_flash_linux_data);
1141
goto exit;
1142
1143
error:
1144
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
1145
1146
exit:
1147
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1148
1149
sd_unmount();
1150
if (part_info.emmc)
1151
emmc_end();
1152
1153
return LV_RES_OK;
1154
}
1155
1156
static lv_res_t _action_reboot_recovery(lv_obj_t * btns, const char * txt)
1157
{
1158
int btn_idx = lv_btnm_get_pressed(btns);
1159
1160
// Delete parent mbox.
1161
mbox_action(btns, txt);
1162
1163
if (!btn_idx)
1164
{
1165
// Set custom reboot type to Android Recovery.
1166
PMC(APBDEV_PMC_SCRATCH0) |= PMC_SCRATCH0_MODE_RECOVERY;
1167
1168
// Enable hekate boot configuration.
1169
b_cfg->boot_cfg = BOOT_CFG_FROM_ID | BOOT_CFG_AUTOBOOT_EN;
1170
1171
// Set id to Android.
1172
strcpy((char *)b_cfg->id, "SWANDR");
1173
1174
void (*main_ptr)() = (void *)nyx_str->hekate;
1175
1176
// Deinit hardware.
1177
sd_end();
1178
hw_deinit(false);
1179
1180
// Chainload to hekate main.
1181
(*main_ptr)();
1182
}
1183
1184
return LV_RES_INV;
1185
}
1186
1187
static lv_res_t _action_flash_android_data(lv_obj_t * btns, const char * txt)
1188
{
1189
int btn_idx = lv_btnm_get_pressed(btns);
1190
bool boot_recovery = false;
1191
1192
// Delete parent mbox.
1193
mbox_action(btns, txt);
1194
1195
if (btn_idx)
1196
return LV_RES_INV;
1197
1198
// Flash Android components.
1199
char path[128];
1200
gpt_t *gpt = zalloc(sizeof(gpt_t));
1201
char *txt_buf = malloc(SZ_4K);
1202
1203
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
1204
lv_obj_set_style(dark_bg, &mbox_darken);
1205
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
1206
1207
static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
1208
static const char *mbox_btn_map2[] = { "\222Continue", "\222No", "" };
1209
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
1210
lv_mbox_set_recolor_text(mbox, true);
1211
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
1212
1213
lv_mbox_set_text(mbox, "#FF8000 Android Flasher#");
1214
1215
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
1216
lv_label_set_recolor(lbl_status, true);
1217
lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions...");
1218
1219
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1220
lv_obj_set_top(mbox, true);
1221
1222
manual_system_maintenance(true);
1223
1224
sd_mount();
1225
if (part_info.emmc)
1226
emmc_initialize(false);
1227
1228
// Read main GPT.
1229
sdmmc_storage_read(part_info.storage, 1, sizeof(gpt_t) >> 9, gpt);
1230
1231
// Validate GPT header.
1232
if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)
1233
{
1234
lv_label_set_text(lbl_status, "#FFDD00 Error:# No Android GPT was found!");
1235
goto error;
1236
}
1237
1238
u32 offset_sct = 0;
1239
u32 size_sct = 0;
1240
1241
// Check if Kernel image should be flashed.
1242
strcpy(path, "switchroot/install/boot.img");
1243
if (f_stat(path, NULL))
1244
{
1245
s_printf(txt_buf, "#FF8000 Warning:# Kernel image not found!\n");
1246
goto boot_img_not_found;
1247
}
1248
1249
// Find Kernel partition.
1250
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
1251
{
1252
if (!memcmp(gpt->entries[i].name, (u16[]) { 'L', 'N', 'X' }, 6) ||
1253
!memcmp(gpt->entries[i].name, (u16[]) { 'b', 'o', 'o', 't' }, 8))
1254
{
1255
offset_sct = gpt->entries[i].lba_start;
1256
size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;
1257
break;
1258
}
1259
}
1260
1261
// Flash Kernel.
1262
if (offset_sct && size_sct)
1263
{
1264
u32 file_size = 0;
1265
u8 *buf = sd_file_read(path, &file_size);
1266
1267
if (file_size % 0x200)
1268
{
1269
file_size = ALIGN(file_size, 0x200);
1270
u8 *buf_tmp = zalloc(file_size);
1271
memcpy(buf_tmp, buf, file_size);
1272
free(buf);
1273
buf = buf_tmp;
1274
}
1275
1276
if ((file_size >> 9) > size_sct)
1277
s_printf(txt_buf, "#FF8000 Warning:# Kernel image too big!\n");
1278
else
1279
{
1280
sdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);
1281
1282
s_printf(txt_buf, "#C7EA46 Success:# Kernel image flashed!\n");
1283
f_unlink(path);
1284
}
1285
1286
free(buf);
1287
}
1288
else
1289
s_printf(txt_buf, "#FF8000 Warning:# Kernel partition not found!\n");
1290
1291
boot_img_not_found:
1292
lv_label_set_text(lbl_status, txt_buf);
1293
manual_system_maintenance(true);
1294
1295
// Check if Recovery should be flashed.
1296
strcpy(path, "switchroot/install/recovery.img");
1297
if (f_stat(path, NULL))
1298
{
1299
// Not found, try twrp.img instead.
1300
strcpy(path, "switchroot/install/twrp.img");
1301
if (f_stat(path, NULL))
1302
{
1303
strcat(txt_buf, "#FF8000 Warning:# Recovery image not found!\n");
1304
goto recovery_not_found;
1305
}
1306
}
1307
1308
offset_sct = 0;
1309
size_sct = 0;
1310
1311
// Find Recovery partition.
1312
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
1313
{
1314
if (!memcmp(gpt->entries[i].name, (u16[]) { 'S', 'O', 'S' }, 6) ||
1315
!memcmp(gpt->entries[i].name, (u16[]) { 'r', 'e', 'c', 'o', 'v', 'e', 'r', 'y' }, 16))
1316
{
1317
offset_sct = gpt->entries[i].lba_start;
1318
size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;
1319
break;
1320
}
1321
}
1322
1323
// Flash Recovery.
1324
if (offset_sct && size_sct)
1325
{
1326
u32 file_size = 0;
1327
u8 *buf = sd_file_read(path, &file_size);
1328
1329
if (file_size % 0x200)
1330
{
1331
file_size = ALIGN(file_size, 0x200);
1332
u8 *buf_tmp = zalloc(file_size);
1333
memcpy(buf_tmp, buf, file_size);
1334
free(buf);
1335
buf = buf_tmp;
1336
}
1337
1338
if ((file_size >> 9) > size_sct)
1339
strcat(txt_buf, "#FF8000 Warning:# Recovery image too big!\n");
1340
else
1341
{
1342
sdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);
1343
strcat(txt_buf, "#C7EA46 Success:# Recovery image flashed!\n");
1344
f_unlink(path);
1345
}
1346
1347
free(buf);
1348
}
1349
else
1350
strcat(txt_buf, "#FF8000 Warning:# Recovery partition not found!\n");
1351
1352
recovery_not_found:
1353
lv_label_set_text(lbl_status, txt_buf);
1354
manual_system_maintenance(true);
1355
1356
// Check if Device Tree should be flashed.
1357
strcpy(path, "switchroot/install/nx-plat.dtimg");
1358
if (f_stat(path, NULL))
1359
{
1360
strcpy(path, "switchroot/install/tegra210-icosa.dtb");
1361
if (f_stat(path, NULL))
1362
{
1363
strcat(txt_buf, "#FF8000 Warning:# DTB image not found!");
1364
goto dtb_not_found;
1365
}
1366
}
1367
1368
offset_sct = 0;
1369
size_sct = 0;
1370
1371
// Find Device Tree partition.
1372
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
1373
{
1374
if (!memcmp(gpt->entries[i].name, (u16[]) { 'D', 'T', 'B' }, 6) ||
1375
!memcmp(gpt->entries[i].name, (u16[]) { 'd', 't', 'b' }, 6))
1376
{
1377
offset_sct = gpt->entries[i].lba_start;
1378
size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;
1379
break;
1380
}
1381
}
1382
1383
// Flash Device Tree.
1384
if (offset_sct && size_sct)
1385
{
1386
u32 file_size = 0;
1387
u8 *buf = sd_file_read(path, &file_size);
1388
1389
if (file_size % 0x200)
1390
{
1391
file_size = ALIGN(file_size, 0x200);
1392
u8 *buf_tmp = zalloc(file_size);
1393
memcpy(buf_tmp, buf, file_size);
1394
free(buf);
1395
buf = buf_tmp;
1396
}
1397
1398
if ((file_size >> 9) > size_sct)
1399
strcat(txt_buf, "#FF8000 Warning:# DTB image too big!");
1400
else
1401
{
1402
sdmmc_storage_write(part_info.storage, offset_sct, file_size >> 9, buf);
1403
strcat(txt_buf, "#C7EA46 Success:# DTB image flashed!");
1404
f_unlink(path);
1405
}
1406
1407
free(buf);
1408
}
1409
else
1410
strcat(txt_buf, "#FF8000 Warning:# DTB partition not found!");
1411
1412
dtb_not_found:
1413
lv_label_set_text(lbl_status, txt_buf);
1414
1415
// Check if Recovery is flashed unconditionally.
1416
u8 *rec = malloc(SD_BLOCKSIZE);
1417
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
1418
{
1419
if (!memcmp(gpt->entries[i].name, (u16[]) { 'S', 'O', 'S' }, 6) ||
1420
!memcmp(gpt->entries[i].name, (u16[]) { 'r', 'e', 'c', 'o', 'v', 'e', 'r', 'y' }, 16))
1421
{
1422
sdmmc_storage_read(part_info.storage, gpt->entries[i].lba_start, 1, rec);
1423
if (!memcmp(rec, "ANDROID", 7))
1424
boot_recovery = true;
1425
break;
1426
}
1427
}
1428
free(rec);
1429
1430
error:
1431
if (boot_recovery)
1432
{
1433
// If a Recovery partition was found, ask user if rebooting into it is wanted.
1434
strcat(txt_buf,"\n\nDo you want to reboot into Recovery\nto finish Android installation?");
1435
lv_label_set_text(lbl_status, txt_buf);
1436
lv_mbox_add_btns(mbox, mbox_btn_map2, _action_reboot_recovery);
1437
}
1438
else
1439
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
1440
1441
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1442
1443
free(txt_buf);
1444
free(gpt);
1445
1446
sd_unmount();
1447
if (part_info.emmc)
1448
emmc_end();
1449
1450
return LV_RES_INV;
1451
}
1452
1453
static lv_res_t _action_flash_android(lv_obj_t *btn)
1454
{
1455
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
1456
lv_obj_set_style(dark_bg, &mbox_darken);
1457
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
1458
1459
static const char *mbox_btn_map[] = { "\222Continue", "\222Cancel", "" };
1460
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
1461
lv_mbox_set_recolor_text(mbox, true);
1462
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
1463
1464
lv_mbox_set_text(mbox, "#FF8000 Android Flasher#");
1465
1466
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
1467
lv_label_set_recolor(lbl_status, true);
1468
lv_label_set_text(lbl_status,
1469
"This will flash #C7EA46 Kernel#, #C7EA46 DTB# and #C7EA46 Recovery# if found.\n"
1470
"These will be deleted after a successful flash.\n"
1471
"Do you want to continue?");
1472
1473
lv_mbox_add_btns(mbox, mbox_btn_map, _action_flash_android_data);
1474
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1475
lv_obj_set_top(mbox, true);
1476
1477
return LV_RES_OK;
1478
}
1479
1480
static lv_res_t _action_part_manager_flash_options0(lv_obj_t *btns, const char *txt)
1481
{
1482
int btn_idx = lv_btnm_get_pressed(btns);
1483
1484
switch (btn_idx)
1485
{
1486
case 0:
1487
action_ums_sd(NULL);
1488
lv_obj_del(ums_mbox);
1489
break;
1490
case 1:
1491
_action_check_flash_linux(NULL);
1492
break;
1493
case 2:
1494
_action_flash_android(NULL);
1495
break;
1496
case 3:
1497
mbox_action(btns, txt);
1498
return LV_RES_INV;
1499
}
1500
1501
return LV_RES_OK;
1502
}
1503
1504
static lv_res_t _action_part_manager_flash_options1(lv_obj_t *btns, const char *txt)
1505
{
1506
int btn_idx = lv_btnm_get_pressed(btns);
1507
1508
switch (btn_idx)
1509
{
1510
case 0:
1511
action_ums_sd(NULL);
1512
lv_obj_del(ums_mbox);
1513
break;
1514
case 1:
1515
mbox_action(btns, txt);
1516
_action_check_flash_linux(NULL);
1517
return LV_RES_INV;
1518
case 2:
1519
mbox_action(btns, txt);
1520
return LV_RES_INV;
1521
}
1522
1523
return LV_RES_OK;
1524
}
1525
1526
static lv_res_t _action_part_manager_flash_options2(lv_obj_t *btns, const char *txt)
1527
{
1528
int btn_idx = lv_btnm_get_pressed(btns);
1529
1530
switch (btn_idx)
1531
{
1532
case 0:
1533
action_ums_sd(NULL);
1534
lv_obj_del(ums_mbox);
1535
break;
1536
case 1:
1537
mbox_action(btns, txt);
1538
_action_flash_android(NULL);
1539
return LV_RES_INV;
1540
case 2:
1541
mbox_action(btns, txt);
1542
return LV_RES_INV;
1543
}
1544
1545
return LV_RES_OK;
1546
}
1547
1548
static int _backup_and_restore_files(bool backup, lv_obj_t **labels)
1549
{
1550
const char *src_drv = backup ? "sd:" : "ram:";
1551
const char *dst_drv = backup ? "ram:" : "sd:";
1552
1553
int res = 0;
1554
u32 total_size = 0;
1555
u32 total_files = 0;
1556
char *path = malloc(0x1000);
1557
path[0] = 0; // Set default as root folder.
1558
1559
// Check if Mariko Warmboot Storage exists in source drive.
1560
f_chdrive(src_drv);
1561
bool backup_pld = !part_info.backup_possible && !f_stat("payload.bin", NULL);
1562
1563
if (!part_info.backup_possible)
1564
{
1565
// Change path to hekate/Nyx.
1566
strcpy(path, "bootloader");
1567
1568
// Create hekate/Nyx/MWS folders in destination drive.
1569
f_chdrive(dst_drv);
1570
f_mkdir("bootloader");
1571
}
1572
1573
// Copy all or hekate/Nyx files.
1574
res = _stat_and_copy_files(src_drv, dst_drv, path, &total_files, &total_size, labels);
1575
1576
// If incomplete backup mode, copy MWS and payload.bin also.
1577
if (!res)
1578
{
1579
if (!res && backup_pld)
1580
{
1581
strcpy(path, "payload.bin");
1582
res = _copy_file(src_drv, dst_drv, path);
1583
}
1584
}
1585
1586
free(path);
1587
1588
return res;
1589
}
1590
1591
static lv_res_t _sd_create_mbox_start_partitioning()
1592
{
1593
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
1594
lv_obj_set_style(dark_bg, &mbox_darken);
1595
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
1596
1597
static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
1598
static const char *mbox_btn_map1[] = { "\222SD UMS", "\222Flash Linux", "\222Flash Android", "\221OK", "" };
1599
static const char *mbox_btn_map2[] = { "\222SD UMS", "\222Flash Linux", "\221OK", "" };
1600
static const char *mbox_btn_map3[] = { "\222SD UMS", "\222Flash Android", "\221OK", "" };
1601
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
1602
lv_mbox_set_recolor_text(mbox, true);
1603
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
1604
1605
lv_mbox_set_text(mbox, "#FF8000 SD Partition Manager#");
1606
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1607
lv_obj_set_top(mbox, true);
1608
1609
bool buttons_set = false;
1610
1611
// Use safety wait if backup is not possible.
1612
char *txt_buf = malloc(SZ_4K);
1613
strcpy(txt_buf, "#FF8000 SD Partition Manager#\n\nSafety wait ends in ");
1614
lv_mbox_set_text(mbox, txt_buf);
1615
1616
u32 seconds = 5;
1617
u32 text_idx = strlen(txt_buf);
1618
while (seconds)
1619
{
1620
s_printf(txt_buf + text_idx, "%d seconds...", seconds);
1621
lv_mbox_set_text(mbox, txt_buf);
1622
manual_system_maintenance(true);
1623
msleep(1000);
1624
seconds--;
1625
}
1626
1627
lv_mbox_set_text(mbox,
1628
"#FF8000 SD Partition Manager#\n\n"
1629
"#FFDD00 Warning: Do you really want to continue?!#\n\n"
1630
"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");
1631
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1632
manual_system_maintenance(true);
1633
1634
free(txt_buf);
1635
1636
if (!(btn_wait() & BTN_POWER))
1637
goto exit;
1638
1639
// Start partitioning.
1640
lv_mbox_set_text(mbox, "#FF8000 SD Partition Manager#");
1641
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1642
manual_system_maintenance(true);
1643
1644
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
1645
lv_label_set_recolor(lbl_status, true);
1646
1647
lv_obj_t *lbl_paths[2];
1648
1649
// Create backup/restore paths labels.
1650
lbl_paths[0] = lv_label_create(mbox, NULL);
1651
lv_label_set_text(lbl_paths[0], "/");
1652
lv_label_set_long_mode(lbl_paths[0], LV_LABEL_LONG_DOT);
1653
lv_cont_set_fit(lbl_paths[0], false, true);
1654
lv_obj_set_width(lbl_paths[0], (LV_HOR_RES / 9 * 6) - LV_DPI / 2);
1655
lv_label_set_align(lbl_paths[0], LV_LABEL_ALIGN_CENTER);
1656
lbl_paths[1] = lv_label_create(mbox, NULL);
1657
lv_label_set_text(lbl_paths[1], " ");
1658
lv_label_set_long_mode(lbl_paths[1], LV_LABEL_LONG_DOT);
1659
lv_cont_set_fit(lbl_paths[1], false, true);
1660
lv_obj_set_width(lbl_paths[1], (LV_HOR_RES / 9 * 6) - LV_DPI / 2);
1661
lv_label_set_align(lbl_paths[1], LV_LABEL_ALIGN_CENTER);
1662
1663
sd_mount();
1664
1665
FATFS ram_fs;
1666
1667
// Read current MBR.
1668
sdmmc_storage_read(part_info.storage, 0, 1, &part_info.mbr_old);
1669
1670
lv_label_set_text(lbl_status, "#00DDFF Status:# Initializing Ramdisk...");
1671
lv_label_set_text(lbl_paths[0], "Please wait...");
1672
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1673
manual_system_maintenance(true);
1674
1675
// Initialize RAM disk.
1676
if (ram_disk_init(&ram_fs, RAM_DISK_SZ))
1677
{
1678
lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to initialize Ramdisk!");
1679
goto error;
1680
}
1681
1682
lv_label_set_text(lbl_status, "#00DDFF Status:# Backing up files...");
1683
manual_system_maintenance(true);
1684
1685
// Do full or hekate/Nyx backup.
1686
if (_backup_and_restore_files(true, lbl_paths))
1687
{
1688
if (part_info.backup_possible)
1689
lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!");
1690
else
1691
lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to back up files!\nBootloader folder exceeds 1.2GB or corrupt!");
1692
1693
goto error;
1694
}
1695
1696
f_unmount("sd:"); // Unmount SD card.
1697
1698
lv_label_set_text(lbl_status, "#00DDFF Status:# Formatting FAT32 partition...");
1699
lv_label_set_text(lbl_paths[0], "Please wait...");
1700
lv_label_set_text(lbl_paths[1], " ");
1701
manual_system_maintenance(true);
1702
1703
// Set reserved size.
1704
u32 part_rsvd_size = (part_info.emu_size << 11) + (part_info.l4t_size << 11) + (part_info.and_size << 11);
1705
part_rsvd_size += part_rsvd_size ? part_info.alignment : 0; // Do not reserve alignment space if no extra partitions.
1706
disk_set_info(DRIVE_SD, SET_SECTOR_COUNT, &part_rsvd_size);
1707
u8 *buf = malloc(SZ_4M);
1708
1709
// Set cluster size to 64KB and try to format.
1710
u32 cluster_size = 65536;
1711
u32 mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);
1712
1713
if (!mkfs_error)
1714
goto mkfs_no_error;
1715
1716
// Retry formatting by halving cluster size, until one succeeds.
1717
while (cluster_size > 4096)
1718
{
1719
cluster_size /= 2;
1720
mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);
1721
1722
if (!mkfs_error)
1723
break;
1724
}
1725
1726
if (mkfs_error)
1727
{
1728
// Failed to format.
1729
s_printf((char *)buf, "#FFDD00 Error:# Failed to format disk (%d)!\n\n"
1730
"Remove the SD card and check that is OK.\nIf not, format it, reinsert it and\npress #FF8000 POWER#!", mkfs_error);
1731
1732
lv_label_set_text(lbl_status, (char *)buf);
1733
lv_label_set_text(lbl_paths[0], " ");
1734
manual_system_maintenance(true);
1735
1736
sd_end();
1737
1738
while (!(btn_wait() & BTN_POWER));
1739
1740
sd_mount();
1741
1742
lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files...");
1743
manual_system_maintenance(true);
1744
1745
// Restore backed up files back to SD.
1746
if (_backup_and_restore_files(false, lbl_paths))
1747
{
1748
// Failed to restore files. Try again once more.
1749
if (_backup_and_restore_files(false, lbl_paths))
1750
{
1751
lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!");
1752
free(buf);
1753
goto error;
1754
}
1755
}
1756
1757
lv_label_set_text(lbl_status, "#00DDFF Status:# Restored files but the operation failed!");
1758
f_unmount("ram:");
1759
free(buf);
1760
goto error;
1761
}
1762
1763
mkfs_no_error:
1764
free(buf);
1765
1766
// Remount sd card as it was unmounted from formatting it.
1767
f_mount(&sd_fs, "sd:", 1); // Mount SD card.
1768
1769
lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files...");
1770
manual_system_maintenance(true);
1771
1772
// Restore backed up files back to SD.
1773
if (_backup_and_restore_files(false, lbl_paths))
1774
{
1775
// Failed to restore files. Try again once more.
1776
if (_backup_and_restore_files(false, lbl_paths))
1777
{
1778
lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!");
1779
goto error;
1780
}
1781
}
1782
1783
// Unmount ramdisk.
1784
f_unmount("ram:");
1785
f_chdrive("sd:");
1786
1787
// Set Volume label.
1788
f_setlabel("0:SWITCH SD");
1789
1790
lv_label_set_text(lbl_status, "#00DDFF Status:# Flashing partition table...");
1791
lv_label_set_text(lbl_paths[0], "Please wait...");
1792
lv_label_set_text(lbl_paths[1], " ");
1793
manual_system_maintenance(true);
1794
1795
// Prepare MBR and GPT header and partition entries and flash them.
1796
_sd_prepare_and_flash_mbr_gpt();
1797
1798
// Enable/Disable buttons depending on partition layout.
1799
if (part_info.l4t_size)
1800
{
1801
lv_obj_set_click(btn_flash_l4t, true);
1802
lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_REL);
1803
}
1804
else
1805
{
1806
lv_obj_set_click(btn_flash_l4t, false);
1807
lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);
1808
}
1809
1810
// Enable/Disable buttons depending on partition layout.
1811
if (part_info.and_size)
1812
{
1813
lv_obj_set_click(btn_flash_android, true);
1814
lv_btn_set_state(btn_flash_android, LV_BTN_STATE_REL);
1815
}
1816
else
1817
{
1818
lv_obj_set_click(btn_flash_android, false);
1819
lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);
1820
}
1821
1822
sd_unmount();
1823
lv_label_set_text(lbl_status, "#00DDFF Status:# Done!");
1824
manual_system_maintenance(true);
1825
1826
// Set buttons depending on what user chose to create.
1827
if (part_info.l4t_size && part_info.and_size)
1828
lv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0);
1829
else if (part_info.l4t_size)
1830
lv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1);
1831
else if (part_info.and_size)
1832
lv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2);
1833
1834
if (part_info.l4t_size || part_info.and_size)
1835
buttons_set = true;
1836
1837
goto out;
1838
1839
error:
1840
f_chdrive("sd:");
1841
1842
out:
1843
lv_obj_del(lbl_paths[0]);
1844
lv_obj_del(lbl_paths[1]);
1845
exit:
1846
if (!buttons_set)
1847
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
1848
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1849
lv_obj_set_top(mbox, true);
1850
1851
// Disable partitioning button.
1852
if (part_info.partition_button)
1853
lv_btn_set_state(part_info.partition_button, LV_BTN_STATE_INA);
1854
1855
return LV_RES_OK;
1856
}
1857
1858
static lv_res_t _emmc_create_mbox_start_partitioning()
1859
{
1860
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
1861
lv_obj_set_style(dark_bg, &mbox_darken);
1862
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
1863
1864
static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
1865
static const char *mbox_btn_map1[] = { "\222Flash Linux", "\222Flash Android", "\221OK", "" };
1866
static const char *mbox_btn_map2[] = { "\222Flash Linux", "\221OK", "" };
1867
static const char *mbox_btn_map3[] = { "\222Flash Android", "\221OK", "" };
1868
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
1869
lv_mbox_set_recolor_text(mbox, true);
1870
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
1871
1872
lv_mbox_set_text(mbox, "#FF8000 eMMC Partition Manager#");
1873
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1874
lv_obj_set_top(mbox, true);
1875
1876
bool buttons_set = false;
1877
1878
// Use safety wait if backup is not possible.
1879
char *txt_buf = malloc(SZ_4K);
1880
strcpy(txt_buf, "#FF8000 eMMC Partition Manager#\n\nSafety wait ends in ");
1881
lv_mbox_set_text(mbox, txt_buf);
1882
1883
u32 seconds = 5;
1884
u32 text_idx = strlen(txt_buf);
1885
while (seconds)
1886
{
1887
s_printf(txt_buf + text_idx, "%d seconds...", seconds);
1888
lv_mbox_set_text(mbox, txt_buf);
1889
manual_system_maintenance(true);
1890
msleep(1000);
1891
seconds--;
1892
}
1893
1894
lv_mbox_set_text(mbox,
1895
"#FF8000 eMMC Partition Manager#\n\n"
1896
"#FFDD00 Warning: Do you really want to continue?!#\n\n"
1897
"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");
1898
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1899
manual_system_maintenance(true);
1900
1901
if (!(btn_wait() & BTN_POWER))
1902
goto exit;
1903
1904
// Start partitioning.
1905
lv_mbox_set_text(mbox, "#FF8000 eMMC Partition Manager#");
1906
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1907
manual_system_maintenance(true);
1908
1909
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
1910
lv_label_set_recolor(lbl_status, true);
1911
1912
lv_obj_t *lbl_extra = lv_label_create(mbox, NULL);
1913
lv_label_set_long_mode(lbl_extra, LV_LABEL_LONG_DOT);
1914
lv_cont_set_fit(lbl_extra, false, true);
1915
lv_obj_set_width(lbl_extra, (LV_HOR_RES / 9 * 6) - LV_DPI / 2);
1916
lv_label_set_align(lbl_extra, LV_LABEL_ALIGN_CENTER);
1917
1918
lv_label_set_text(lbl_status, "#00DDFF Status:# Initializing...");
1919
lv_label_set_text(lbl_extra, "Please wait...");
1920
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
1921
manual_system_maintenance(true);
1922
1923
if (!emmc_initialize(false))
1924
{
1925
lv_label_set_text(lbl_extra, "#FFDD00 Failed to init eMMC!#");
1926
goto exit;
1927
}
1928
1929
emmc_set_partition(EMMC_GPP);
1930
1931
if (!emummc_raw_derive_bis_keys())
1932
{
1933
lv_label_set_text(lbl_extra, "#FFDD00 For formatting USER partition,#\n#FFDD00 BIS keys are needed!#");
1934
emmc_end();
1935
goto exit;
1936
}
1937
1938
lv_label_set_text(lbl_status, "#00DDFF Status:# Flashing partition table...");
1939
lv_label_set_text(lbl_extra, "Please wait...");
1940
manual_system_maintenance(true);
1941
1942
// Prepare MBR and GPT header and partition entries and flash them.
1943
if (_emmc_prepare_and_flash_mbr_gpt())
1944
goto no_hos_user_part;
1945
1946
lv_label_set_text(lbl_status, "#00DDFF Status:# Formatting USER partition...");
1947
lv_label_set_text(lbl_extra, "Please wait...");
1948
manual_system_maintenance(true);
1949
1950
// Get USER partition and configure BIS and FatFS.
1951
LIST_INIT(gpt);
1952
emmc_gpt_parse(&gpt);
1953
emmc_part_t *user_part = emmc_part_find(&gpt, "USER");
1954
1955
if (!user_part)
1956
{
1957
no_hos_user_part:
1958
s_printf(txt_buf, "#FF0000 HOS USER partition doesn't exist!#\nRestore HOS backup first...");
1959
lv_label_set_text(lbl_extra, txt_buf);
1960
1961
emmc_gpt_free(&gpt);
1962
emmc_end();
1963
1964
goto exit;
1965
}
1966
1967
// Initialize BIS for eMMC. BIS keys should be already in place.
1968
nx_emmc_bis_init(user_part, true, 0);
1969
1970
// Set BIS size for FatFS.
1971
u32 user_sectors = user_part->lba_end - user_part->lba_start + 1;
1972
disk_set_info(DRIVE_BIS, SET_SECTOR_COUNT, &user_sectors);
1973
1974
// Enable writing.
1975
bool allow_writes = true;
1976
disk_set_info(DRIVE_BIS, SET_WRITE_PROTECT, &allow_writes);
1977
1978
// Format USER partition as FAT32 with 16KB cluster and PRF2SAFE.
1979
u8 *buff = malloc(SZ_4M);
1980
int mkfs_error = f_mkfs("bis:", FM_FAT32 | FM_SFD | FM_PRF2, 16384, buff, SZ_4M);
1981
1982
if (mkfs_error)
1983
{
1984
s_printf(txt_buf, "#FF0000 Failed (%d)!#\nPlease try again...\n", mkfs_error);
1985
lv_label_set_text(lbl_extra, txt_buf);
1986
1987
free(buff);
1988
emmc_end();
1989
1990
goto exit;
1991
}
1992
1993
// Disable writes to BIS.
1994
allow_writes = false;
1995
disk_set_info(DRIVE_BIS, SET_WRITE_PROTECT, &allow_writes);
1996
1997
// Flush BIS cache, deinit, clear BIS keys slots and reinstate SBK.
1998
nx_emmc_bis_end();
1999
hos_bis_keys_clear();
2000
emmc_gpt_free(&gpt);
2001
emmc_end();
2002
2003
// Enable/Disable buttons depending on partition layout.
2004
if (part_info.l4t_size)
2005
{
2006
lv_obj_set_click(btn_flash_l4t, true);
2007
lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_REL);
2008
}
2009
else
2010
{
2011
lv_obj_set_click(btn_flash_l4t, false);
2012
lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);
2013
}
2014
2015
// Enable/Disable buttons depending on partition layout.
2016
if (part_info.and_size)
2017
{
2018
lv_obj_set_click(btn_flash_android, true);
2019
lv_btn_set_state(btn_flash_android, LV_BTN_STATE_REL);
2020
}
2021
else
2022
{
2023
lv_obj_set_click(btn_flash_android, false);
2024
lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);
2025
}
2026
2027
lv_label_set_text(lbl_status, "#00DDFF Status:# Done!");
2028
manual_system_maintenance(true);
2029
2030
// Set buttons depending on what user chose to create.
2031
if (part_info.l4t_size && part_info.and_size)
2032
lv_mbox_add_btns(mbox, mbox_btn_map1, _action_part_manager_flash_options0);
2033
else if (part_info.l4t_size)
2034
lv_mbox_add_btns(mbox, mbox_btn_map2, _action_part_manager_flash_options1);
2035
else if (part_info.and_size)
2036
lv_mbox_add_btns(mbox, mbox_btn_map3, _action_part_manager_flash_options2);
2037
2038
if (part_info.l4t_size || part_info.and_size)
2039
buttons_set = true;
2040
2041
lv_obj_del(lbl_extra);
2042
2043
exit:
2044
free(txt_buf);
2045
2046
if (!buttons_set)
2047
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
2048
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
2049
lv_obj_set_top(mbox, true);
2050
2051
// Disable partitioning button.
2052
if (part_info.partition_button)
2053
lv_btn_set_state(part_info.partition_button, LV_BTN_STATE_INA);
2054
2055
return LV_RES_OK;
2056
}
2057
2058
static lv_res_t _create_mbox_partitioning_option0(lv_obj_t *btns, const char *txt)
2059
{
2060
int btn_idx = lv_btnm_get_pressed(btns);
2061
2062
switch (btn_idx)
2063
{
2064
case 0:
2065
action_ums_sd(NULL);
2066
return LV_RES_OK;
2067
case 1:
2068
mbox_action(btns, txt);
2069
_sd_create_mbox_start_partitioning();
2070
break;
2071
case 2:
2072
mbox_action(btns, txt);
2073
break;
2074
}
2075
2076
return LV_RES_INV;
2077
}
2078
2079
static lv_res_t _create_mbox_partitioning_option1(lv_obj_t *btns, const char *txt)
2080
{
2081
int btn_idx = lv_btnm_get_pressed(btns);
2082
2083
mbox_action(btns, txt);
2084
2085
if (!btn_idx)
2086
{
2087
mbox_action(btns, txt);
2088
if (!part_info.emmc)
2089
_sd_create_mbox_start_partitioning();
2090
else
2091
_emmc_create_mbox_start_partitioning();
2092
return LV_RES_INV;
2093
}
2094
2095
return LV_RES_OK;
2096
}
2097
2098
static lv_res_t _create_mbox_partitioning_warn()
2099
{
2100
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
2101
lv_obj_set_style(dark_bg, &mbox_darken);
2102
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
2103
2104
static const char *mbox_btn_map[] = { "\222SD UMS", "\222Start", "\222Cancel", "" };
2105
static const char *mbox_btn_map2[] = { "\222Start", "\222Cancel", "" };
2106
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
2107
lv_mbox_set_recolor_text(mbox, true);
2108
2109
char *txt_buf = malloc(SZ_4K);
2110
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
2111
lv_mbox_set_text(mbox, "#FF8000 Partition Manager#");
2112
2113
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
2114
lv_label_set_recolor(lbl_status, true);
2115
2116
if (!part_info.emmc)
2117
{
2118
s_printf(txt_buf, "#FFDD00 Warning: This will partition the SD Card!#\n\n");
2119
2120
if (part_info.backup_possible)
2121
{
2122
strcat(txt_buf, "#C7EA46 Your files will be backed up and restored!#\n"
2123
"#FFDD00 Any other partition will be wiped!#");
2124
}
2125
else
2126
{
2127
strcat(txt_buf, "#FFDD00 Your files will be wiped!#\n"
2128
"#FFDD00 Any other partition will be also wiped!#\n"
2129
"#FFDD00 Use USB UMS to copy them over!#");
2130
}
2131
2132
lv_label_set_text(lbl_status, txt_buf);
2133
2134
if (part_info.backup_possible)
2135
lv_mbox_add_btns(mbox, mbox_btn_map2, _create_mbox_partitioning_option1);
2136
else
2137
lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_option0);
2138
}
2139
else
2140
{
2141
s_printf(txt_buf, "#FFDD00 Warning: This will partition the eMMC!#\n\n"
2142
"#FFDD00 The USER partition will also be formatted!#");
2143
lv_label_set_text(lbl_status, txt_buf);
2144
lv_mbox_add_btns(mbox, mbox_btn_map2, _create_mbox_partitioning_option1);
2145
}
2146
2147
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
2148
lv_obj_set_top(mbox, true);
2149
2150
free(txt_buf);
2151
2152
return LV_RES_OK;
2153
}
2154
2155
static lv_res_t _create_mbox_partitioning_android(lv_obj_t *btns, const char *txt)
2156
{
2157
int btn_idx = lv_btnm_get_pressed(btns);
2158
2159
mbox_action(btns, txt);
2160
2161
part_info.and_dynamic = !btn_idx;
2162
_create_mbox_partitioning_warn();
2163
2164
return LV_RES_INV;
2165
}
2166
2167
static lv_res_t _create_mbox_partitioning_andr_part()
2168
{
2169
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
2170
lv_obj_set_style(dark_bg, &mbox_darken);
2171
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
2172
2173
static const char *mbox_btn_map[] = { "\222Dynamic", "\222Legacy", "" };
2174
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
2175
lv_mbox_set_recolor_text(mbox, true);
2176
2177
lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);
2178
lv_mbox_set_text(mbox, "#FF8000 Android Partitioning#");
2179
2180
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
2181
lv_label_set_recolor(lbl_status, true);
2182
2183
lv_label_set_text(lbl_status,
2184
"Please select a partition scheme:\n\n"
2185
"#C7EA46 Dynamic:# Android 13+\n"
2186
"#C7EA46 Legacy:# Android 10-11\n");
2187
2188
lv_mbox_add_btns(mbox, mbox_btn_map, _create_mbox_partitioning_android);
2189
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
2190
lv_obj_set_top(mbox, true);
2191
2192
return LV_RES_OK;
2193
}
2194
2195
static lv_res_t _create_mbox_partitioning_next(lv_obj_t *btn) {
2196
if (part_info.and_size)
2197
return _create_mbox_partitioning_andr_part();
2198
else
2199
return _create_mbox_partitioning_warn();
2200
}
2201
2202
static void _update_partition_bar()
2203
{
2204
lv_obj_t *h1 = lv_obj_get_parent(part_info.bar_hos);
2205
2206
// Set widths based on max bar width.
2207
u32 total_size = (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB;
2208
u32 bar_hos_size = lv_obj_get_width(h1) * (part_info.hos_size >> 10) / total_size;
2209
u32 bar_emu_size = lv_obj_get_width(h1) * (part_info.emu_size >> 10) / total_size;
2210
u32 bar_l4t_size = lv_obj_get_width(h1) * (part_info.l4t_size >> 10) / total_size;
2211
u32 bar_and_size = lv_obj_get_width(h1) * (part_info.and_size >> 10) / total_size;
2212
2213
// Update bar widths.
2214
lv_obj_set_width(part_info.bar_hos, bar_hos_size);
2215
lv_obj_set_width(part_info.bar_emu, bar_emu_size);
2216
lv_obj_set_width(part_info.bar_l4t, bar_l4t_size);
2217
lv_obj_set_width(part_info.bar_and, bar_and_size);
2218
2219
// Re-align bars.
2220
lv_obj_realign(part_info.bar_emu);
2221
lv_obj_realign(part_info.bar_l4t);
2222
lv_obj_realign(part_info.bar_and);
2223
2224
// Set emuMMC blending separator sizes and realign.
2225
lv_obj_set_width(part_info.sep_emu, bar_emu_size ? 8 : 0);
2226
lv_obj_realign(part_info.sep_emu);
2227
2228
// Set L4T blending separator sizes and realign.
2229
lv_obj_set_width(part_info.sep_l4t, bar_l4t_size ? 8 : 0);
2230
lv_obj_realign(part_info.sep_l4t);
2231
2232
// Set Android blending separator sizes and realign.
2233
lv_obj_set_width(part_info.sep_and, bar_and_size ? 8 : 0);
2234
lv_obj_realign(part_info.sep_and);
2235
2236
// Re-align size labels.
2237
lv_obj_realign(part_info.lbl_hos);
2238
lv_obj_realign(part_info.lbl_emu);
2239
lv_obj_realign(part_info.lbl_l4t);
2240
lv_obj_realign(part_info.lbl_and);
2241
lv_obj_align(part_info.cont_lbl, part_info.bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 11 - LV_DPI / 2, LV_DPI * 9 / 23);
2242
}
2243
2244
static lv_res_t _action_slider_emu(lv_obj_t *slider)
2245
{
2246
u32 size;
2247
char lbl_text[64];
2248
bool prev_emu_double = part_info.emu_double;
2249
int slide_val = lv_slider_get_value(slider);
2250
u32 max_emmc_size = !part_info.emmc_is_64gb ? EMU_32GB_FULL : EMU_64GB_FULL;
2251
2252
part_info.emu_double = false;
2253
2254
// Check that eMMC exists.
2255
if (!part_info.emmc_size_mb)
2256
{
2257
lv_slider_set_value(slider, 0);
2258
return LV_RES_OK;
2259
}
2260
2261
// In case of upgraded eMMC, do not allow FULL sizes. Max size is always bigger than official eMMCs.
2262
if (max_emmc_size < part_info.emmc_size_mb)
2263
{
2264
if (slide_val == EMU_SLIDER_1X_FULL)
2265
{
2266
if (prev_emu_double)
2267
slide_val--;
2268
else
2269
slide_val++;
2270
lv_slider_set_value(slider, slide_val);
2271
}
2272
else if (slide_val == EMU_SLIDER_2X_FULL)
2273
{
2274
slide_val--;
2275
lv_slider_set_value(slider, slide_val);
2276
}
2277
}
2278
2279
size = (slide_val > EMU_SLIDER_1X_MAX ? (slide_val - EMU_SLIDER_1X_MAX) : slide_val) + EMU_SLIDER_OFFSET;
2280
size *= 1024; // Convert to GB.
2281
size += EMU_RSVD_MB; // Add reserved size.
2282
2283
if (slide_val == EMU_SLIDER_MIN)
2284
size = 0; // Reset if 0.
2285
else if (slide_val >= EMU_SLIDER_2X_MIN)
2286
{
2287
size *= 2;
2288
part_info.emu_double = true;
2289
}
2290
2291
// Handle special cases. 2nd value is for 64GB Aula. Values already include reserved space.
2292
if (slide_val == EMU_SLIDER_1X_FULL)
2293
size = max_emmc_size;
2294
else if (slide_val == EMU_SLIDER_2X_FULL)
2295
size = 2 * max_emmc_size;
2296
2297
// Sanitize sizes based on new HOS size.
2298
s32 hos_size = (part_info.total_sct >> 11) - 16 - size - part_info.l4t_size - part_info.and_size;
2299
if (hos_size > part_info.hos_min_size)
2300
{
2301
part_info.emu_size = size;
2302
part_info.hos_size = hos_size;
2303
2304
s_printf(lbl_text, "#96FF00 %4d GiB#", hos_size >> 10);
2305
lv_label_set_text(part_info.lbl_hos, lbl_text);
2306
lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);
2307
2308
if (!part_info.emu_double)
2309
{
2310
if (slide_val != EMU_SLIDER_1X_FULL)
2311
s_printf(lbl_text, "#FF3C28 %4d GiB#", size >> 10);
2312
else
2313
s_printf(lbl_text, "#FF3C28 %d FULL#", size >> 10);
2314
}
2315
else
2316
s_printf(lbl_text, "#FFDD00 2x##FF3C28 %d GiB#", size >> 11);
2317
lv_label_set_text(part_info.lbl_emu, lbl_text);
2318
}
2319
else
2320
{
2321
u32 emu_size = part_info.emu_size;
2322
2323
if (emu_size == max_emmc_size)
2324
emu_size = EMU_SLIDER_1X_FULL;
2325
else if (emu_size == 2 * max_emmc_size)
2326
emu_size = EMU_SLIDER_2X_FULL;
2327
else if (emu_size)
2328
{
2329
if (prev_emu_double)
2330
emu_size /= 2;
2331
emu_size -= EMU_RSVD_MB;
2332
emu_size /= 1024;
2333
emu_size -= EMU_SLIDER_OFFSET;
2334
2335
if (prev_emu_double)
2336
emu_size += EMU_SLIDER_2X_MIN;
2337
}
2338
2339
int new_slider_val = emu_size;
2340
part_info.emu_double = prev_emu_double ? true : false;
2341
2342
lv_slider_set_value(slider, new_slider_val);
2343
}
2344
2345
_update_partition_bar();
2346
2347
return LV_RES_OK;
2348
}
2349
2350
static lv_res_t _action_slider_l4t(lv_obj_t *slider)
2351
{
2352
char lbl_text[64];
2353
2354
u32 size = (u32)lv_slider_get_value(slider) << 10;
2355
if (size < 4096)
2356
size = 0;
2357
else if (size < 8192)
2358
size = 8192;
2359
2360
s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - size - part_info.and_size;
2361
2362
// Sanitize sizes based on new HOS size.
2363
if (hos_size > part_info.hos_min_size)
2364
{
2365
if (size <= 8192)
2366
lv_slider_set_value(slider, size >> 10);
2367
}
2368
else
2369
{
2370
size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - 2048;
2371
hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.and_size - size;
2372
if (hos_size < part_info.hos_min_size || size < 8192)
2373
{
2374
lv_slider_set_value(slider, part_info.l4t_size >> 10);
2375
goto out;
2376
}
2377
lv_slider_set_value(slider, size >> 10);
2378
}
2379
2380
part_info.l4t_size = size;
2381
part_info.hos_size = hos_size;
2382
2383
s_printf(lbl_text, "#96FF00 %4d GiB#", hos_size >> 10);
2384
lv_label_set_text(part_info.lbl_hos, lbl_text);
2385
lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);
2386
s_printf(lbl_text, "#00DDFF %4d GiB#", size >> 10);
2387
lv_label_set_text(part_info.lbl_l4t, lbl_text);
2388
2389
_update_partition_bar();
2390
2391
out:
2392
return LV_RES_OK;
2393
}
2394
2395
static lv_res_t _action_slider_and(lv_obj_t *slider)
2396
{
2397
char lbl_text[64];
2398
2399
u32 user_size = (u32)lv_slider_get_value(slider) << 10;
2400
if (user_size < 2048)
2401
user_size = 0;
2402
else if (user_size < 4096)
2403
user_size = 4096;
2404
2405
u32 and_size = user_size ? (user_size + AND_SYS_SIZE_MB) : 0;
2406
s32 hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size;
2407
2408
// Sanitize sizes based on new HOS size.
2409
if (hos_size > part_info.hos_min_size)
2410
{
2411
if (user_size <= 4096)
2412
lv_slider_set_value(slider, user_size >> 10);
2413
}
2414
else
2415
{
2416
and_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - 2048;
2417
hos_size = (part_info.total_sct >> 11) - 16 - part_info.emu_size - part_info.l4t_size - and_size;
2418
if (hos_size < part_info.hos_min_size || and_size < 8192)
2419
{
2420
lv_slider_set_value(slider, part_info.and_size >> 10);
2421
goto out;
2422
}
2423
user_size = and_size - AND_SYS_SIZE_MB;
2424
lv_slider_set_value(slider, user_size >> 10);
2425
}
2426
2427
part_info.and_size = and_size;
2428
part_info.hos_size = hos_size;
2429
2430
s_printf(lbl_text, "#96FF00 %4d GiB#", hos_size >> 10);
2431
lv_label_set_text(part_info.lbl_hos, lbl_text);
2432
lv_bar_set_value(part_info.slider_bar_hos, hos_size >> 10);
2433
s_printf(lbl_text, "#FF8000 %4d GiB#", user_size >> 10);
2434
lv_label_set_text(part_info.lbl_and, lbl_text);
2435
2436
_update_partition_bar();
2437
2438
out:
2439
return LV_RES_OK;
2440
}
2441
2442
static lv_res_t _mbox_check_files_total_size_option(lv_obj_t *btns, const char *txt)
2443
{
2444
// If "don't backup" button was pressed, disable backup/restore of files.
2445
if (!lv_btnm_get_pressed(btns))
2446
part_info.backup_possible = false;
2447
2448
mbox_action(btns, txt);
2449
2450
return LV_RES_INV;
2451
}
2452
2453
static void _create_mbox_check_files_total_size()
2454
{
2455
static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind;
2456
static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg;
2457
2458
// Set HOS bar style.
2459
lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic);
2460
bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00);
2461
bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color;
2462
2463
// Set emuMMC bar style.
2464
lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic);
2465
bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28);
2466
bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color;
2467
2468
// Set L4T bar style.
2469
lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic);
2470
bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);
2471
bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;
2472
2473
// Set GPT bar style.
2474
lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);
2475
bar_and_ind.body.main_color = LV_COLOR_HEX(0xC000FF);
2476
bar_and_ind.body.grad_color = bar_and_ind.body.main_color;
2477
2478
// Set separator styles.
2479
lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont);
2480
sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28);
2481
sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color;
2482
sep_emu_bg.body.radius = 0;
2483
lv_style_copy(&sep_l4t_bg, &sep_emu_bg);
2484
sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);
2485
sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;
2486
lv_style_copy(&sep_and_bg, &sep_emu_bg);
2487
sep_and_bg.body.main_color = LV_COLOR_HEX(0xC000FF);
2488
sep_and_bg.body.grad_color = sep_and_bg.body.main_color;
2489
2490
char *txt_buf = malloc(SZ_8K);
2491
2492
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
2493
lv_obj_set_style(dark_bg, &mbox_darken);
2494
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
2495
2496
static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
2497
static const char *mbox_btn_map2[] = { "\222Don't Backup", "\222OK", "" };
2498
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
2499
lv_mbox_set_recolor_text(mbox, true);
2500
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
2501
2502
lv_mbox_set_text(mbox, "Analyzing SD card usage. This might take a while...");
2503
2504
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
2505
lv_obj_set_top(mbox, true);
2506
manual_system_maintenance(true);
2507
2508
char *path = malloc(0x1000);
2509
u32 total_files = 0;
2510
u32 total_size = 0;
2511
path[0] = 0;
2512
2513
// Check total size of files.
2514
int res = _stat_and_copy_files("sd:", NULL, path, &total_files, &total_size, NULL);
2515
2516
// Not more than 1.2GB.
2517
part_info.backup_possible = !res && !(total_size > (RAM_DISK_SZ - SZ_16M)); // Account for alignment.
2518
2519
if (part_info.backup_possible)
2520
{
2521
s_printf(txt_buf,
2522
"#96FF00 The SD Card files will be backed up automatically!#\n"
2523
"#FFDD00 Any other partition will be wiped!#\n"
2524
"#00DDFF Total files:# %d, #00DDFF Total size:# %d MiB", total_files, total_size >> 20);
2525
lv_mbox_set_text(mbox, txt_buf);
2526
}
2527
else
2528
{
2529
lv_mbox_set_text(mbox,
2530
"#FFDD00 The SD Card cannot be backed up automatically!#\n"
2531
"#FFDD00 Any other partition will be also wiped!#\n\n"
2532
"You will be asked to back up your files later via UMS.");
2533
}
2534
2535
// Create container to keep content inside.
2536
lv_obj_t *h1 = lv_cont_create(mbox, NULL);
2537
lv_cont_set_fit(h1, false, true);
2538
lv_cont_set_style(h1, &lv_style_transp_tight);
2539
lv_obj_set_width(h1, lv_obj_get_width(mbox) - LV_DPI * 3);
2540
2541
lv_obj_t *lbl_part = lv_label_create(h1, NULL);
2542
lv_label_set_recolor(lbl_part, true);
2543
lv_label_set_text(lbl_part, "#00DDFF Current MBR partition layout:#");
2544
2545
// Read current MBR.
2546
mbr_t mbr = { 0 };
2547
sdmmc_storage_read(&sd_storage, 0, 1, &mbr);
2548
2549
// Calculate MBR partitions size.
2550
total_size = (sd_storage.sec_cnt - AU_ALIGN_SECTORS) / SECTORS_PER_GB;
2551
u32 bar_hos_size = lv_obj_get_width(h1) * (mbr.partitions[0].size_sct / SECTORS_PER_GB) / total_size;
2552
u32 bar_emu_size = 0;
2553
for (u32 i = 1; i < 4; i++)
2554
if (mbr.partitions[i].type == 0xE0)
2555
bar_emu_size += mbr.partitions[i].size_sct;
2556
bar_emu_size = lv_obj_get_width(h1) * (bar_emu_size / SECTORS_PER_GB) / total_size;
2557
2558
u32 bar_l4t_size = 0;
2559
for (u32 i = 1; i < 4; i++)
2560
if (mbr.partitions[i].type == 0x83)
2561
bar_l4t_size += mbr.partitions[i].size_sct;
2562
bar_l4t_size = lv_obj_get_width(h1) * (bar_l4t_size / SECTORS_PER_GB) / total_size;
2563
2564
u32 bar_and_size = lv_obj_get_width(h1) - bar_hos_size - bar_emu_size - bar_l4t_size;
2565
2566
// Create HOS bar.
2567
lv_obj_t *bar_mbr_hos = lv_bar_create(h1, NULL);
2568
lv_obj_set_size(bar_mbr_hos, bar_hos_size, LV_DPI / 3);
2569
lv_bar_set_range(bar_mbr_hos, 0, 1);
2570
lv_bar_set_value(bar_mbr_hos, 1);
2571
lv_bar_set_style(bar_mbr_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind);
2572
lv_obj_align(bar_mbr_hos, lbl_part, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6);
2573
2574
// Create emuMMC bar.
2575
lv_obj_t *bar_mbr_emu = lv_bar_create(h1, bar_mbr_hos);
2576
lv_obj_set_size(bar_mbr_emu, bar_emu_size, LV_DPI / 3);
2577
lv_bar_set_style(bar_mbr_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind);
2578
lv_obj_align(bar_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
2579
2580
// Create L4T bar.
2581
lv_obj_t *bar_mbr_l4t = lv_bar_create(h1, bar_mbr_hos);
2582
lv_obj_set_size(bar_mbr_l4t, bar_l4t_size, LV_DPI / 3);
2583
lv_bar_set_style(bar_mbr_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind);
2584
lv_obj_align(bar_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
2585
2586
// Create GPT bar.
2587
lv_obj_t *bar_mbr_gpt = lv_bar_create(h1, bar_mbr_hos);
2588
lv_obj_set_size(bar_mbr_gpt, bar_and_size > 1 ? bar_and_size : 0, LV_DPI / 3);
2589
lv_bar_set_style(bar_mbr_gpt, LV_BAR_STYLE_INDIC, &bar_and_ind);
2590
lv_obj_align(bar_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
2591
2592
// Create emuMMC separator.
2593
lv_obj_t *sep_mbr_emu = lv_cont_create(h1, NULL);
2594
lv_obj_set_size(sep_mbr_emu, bar_emu_size ? 8 : 0, LV_DPI / 3);
2595
lv_obj_set_style(sep_mbr_emu, &sep_emu_bg);
2596
lv_obj_align(sep_mbr_emu, bar_mbr_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);
2597
2598
// Create L4T separator.
2599
lv_obj_t *sep_mbr_l4t = lv_cont_create(h1, sep_mbr_emu);
2600
lv_obj_set_size(sep_mbr_l4t, bar_l4t_size ? 8 : 0, LV_DPI / 3);
2601
lv_obj_set_style(sep_mbr_l4t, &sep_l4t_bg);
2602
lv_obj_align(sep_mbr_l4t, bar_mbr_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);
2603
2604
// Create GPT separator.
2605
lv_obj_t *sep_mbr_gpt = lv_cont_create(h1, sep_mbr_emu);
2606
lv_obj_set_size(sep_mbr_gpt, bar_and_size ? (bar_and_size > 1 ? 8 : 0) : 0, LV_DPI / 3);
2607
lv_obj_set_style(sep_mbr_gpt, &sep_and_bg);
2608
lv_obj_align(sep_mbr_gpt, bar_mbr_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);
2609
2610
// Print partition table info.
2611
s_printf(txt_buf,
2612
"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"
2613
"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"
2614
"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"
2615
"Partition 3 - Type: %02x, Start: %08x, Size: %08x",
2616
mbr.partitions[0].type, mbr.partitions[0].start_sct, mbr.partitions[0].size_sct,
2617
mbr.partitions[1].type, mbr.partitions[1].start_sct, mbr.partitions[1].size_sct,
2618
mbr.partitions[2].type, mbr.partitions[2].start_sct, mbr.partitions[2].size_sct,
2619
mbr.partitions[3].type, mbr.partitions[3].start_sct, mbr.partitions[3].size_sct);
2620
2621
lv_obj_t *lbl_table = lv_label_create(h1, NULL);
2622
lv_label_set_style(lbl_table, &monospace_text);
2623
lv_label_set_text(lbl_table, txt_buf);
2624
lv_obj_align(lbl_table, h1, LV_ALIGN_IN_TOP_MID, 0, LV_DPI);
2625
2626
if (!part_info.backup_possible)
2627
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
2628
else
2629
lv_mbox_add_btns(mbox, mbox_btn_map2, _mbox_check_files_total_size_option);
2630
2631
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
2632
2633
free(txt_buf);
2634
free(path);
2635
}
2636
2637
static lv_res_t _action_fix_mbr_gpt(lv_obj_t *btn)
2638
{
2639
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
2640
lv_obj_set_style(dark_bg, &mbox_darken);
2641
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
2642
2643
static const char *mbox_btn_map[] = { "\251", "\222OK", "\251", "" };
2644
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
2645
lv_mbox_set_recolor_text(mbox, true);
2646
2647
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
2648
lv_mbox_set_text(mbox, "#FF8000 Fix Hybrid MBR#");
2649
2650
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
2651
lv_label_set_recolor(lbl_status, true);
2652
2653
mbr_t mbr[2] = { 0 };
2654
gpt_t *gpt = zalloc(sizeof(gpt_t));
2655
gpt_header_t gpt_hdr_backup = { 0 };
2656
2657
bool has_mbr_attributes = false;
2658
bool hybrid_mbr_changed = false;
2659
bool gpt_partition_exists = false;
2660
int gpt_oob_empty_part_no = 0;
2661
int gpt_emummc_migrate_no = 0;
2662
2663
// Try to init sd card. No need for valid MBR.
2664
if (!sd_mount() && !sd_get_card_initialized())
2665
{
2666
lv_label_set_text(lbl_status, "#FFDD00 Failed to init SD!#");
2667
goto out;
2668
}
2669
2670
sdmmc_storage_read(&sd_storage, 0, 1, &mbr[0]);
2671
sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt);
2672
2673
memcpy(&mbr[1], &mbr[0], sizeof(mbr_t));
2674
2675
sd_unmount();
2676
2677
// Check for secret MBR attributes.
2678
if (gpt->entries[0].part_guid[7])
2679
has_mbr_attributes = true;
2680
2681
// Check if there's a GPT Protective partition.
2682
for (u32 i = 0; i < 4; i++)
2683
{
2684
if (mbr[0].partitions[i].type == 0xEE)
2685
gpt_partition_exists = true;
2686
}
2687
2688
// Check if GPT is valid.
2689
if (!gpt_partition_exists || memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)
2690
{
2691
lv_label_set_text(lbl_status, "#FFDD00 Warning:# No valid GPT was found!");
2692
2693
gpt_partition_exists = false;
2694
2695
if (has_mbr_attributes)
2696
goto check_changes;
2697
else
2698
goto out;
2699
}
2700
2701
sdmmc_storage_read(&sd_storage, gpt->header.alt_lba, 1, &gpt_hdr_backup);
2702
2703
// Parse GPT.
2704
LIST_INIT(gpt_parsed);
2705
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
2706
{
2707
// Check if partition is out of bounds or empty.
2708
if ( gpt->entries[i].lba_start < gpt->header.first_use_lba ||
2709
gpt->entries[i].lba_start >= gpt->entries[i].lba_end ||
2710
!gpt->entries[i].lba_end)
2711
{
2712
gpt_oob_empty_part_no++;
2713
continue;
2714
}
2715
2716
emmc_part_t *part = (emmc_part_t *)zalloc(sizeof(emmc_part_t));
2717
2718
part->index = i;
2719
part->lba_start = gpt->entries[i].lba_start;
2720
part->lba_end = gpt->entries[i].lba_end;
2721
2722
// ASCII conversion. Copy only the LSByte of the UTF-16LE name.
2723
for (u32 j = 0; j < 36; j++)
2724
part->name[j] = gpt->entries[i].name[j];
2725
part->name[35] = 0;
2726
2727
list_append(&gpt_parsed, &part->link);
2728
}
2729
2730
// Set FAT and emuMMC partitions.
2731
u32 mbr_idx = 1;
2732
bool found_hos_data = false;
2733
u32 emummc_mbr_part_idx[2] = {0};
2734
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt_parsed, link)
2735
{
2736
// FatFS simple GPT found a fat partition, set it.
2737
if (sd_fs.part_type && !part->index)
2738
{
2739
mbr[1].partitions[0].type = sd_fs.fs_type == FS_EXFAT ? 0x7 : 0xC;
2740
mbr[1].partitions[0].start_sct = part->lba_start;
2741
mbr[1].partitions[0].size_sct = part->lba_end - part->lba_start + 1;
2742
}
2743
2744
// FatFS simple GPT didn't find a fat partition as the first one.
2745
if (!sd_fs.part_type && !found_hos_data && !strcmp(part->name, "hos_data"))
2746
{
2747
mbr[1].partitions[0].type = 0xC;
2748
mbr[1].partitions[0].start_sct = part->lba_start;
2749
mbr[1].partitions[0].size_sct = part->lba_end - part->lba_start + 1;
2750
found_hos_data = true;
2751
}
2752
2753
// Set up to max 2 emuMMC partitions.
2754
if (!strcmp(part->name, "emummc") || !strcmp(part->name, "emummc2"))
2755
{
2756
mbr[1].partitions[mbr_idx].type = 0xE0;
2757
mbr[1].partitions[mbr_idx].start_sct = part->lba_start;
2758
mbr[1].partitions[mbr_idx].size_sct = part->lba_end - part->lba_start + 1;
2759
if (!strcmp(part->name, "emummc"))
2760
emummc_mbr_part_idx[0] = mbr_idx;
2761
else
2762
emummc_mbr_part_idx[1] = mbr_idx;
2763
mbr_idx++;
2764
}
2765
2766
// Total reached last slot.
2767
if (mbr_idx >= 3)
2768
break;
2769
}
2770
2771
emmc_gpt_free(&gpt_parsed);
2772
2773
// Set GPT protective partition.
2774
mbr[1].partitions[mbr_idx].type = 0xEE;
2775
mbr[1].partitions[mbr_idx].start_sct = 1;
2776
mbr[1].partitions[mbr_idx].size_sct = sd_storage.sec_cnt - 1;
2777
2778
// Check for differences.
2779
for (u32 i = 1; i < 4; i++)
2780
{
2781
if ((mbr[0].partitions[i].type != mbr[1].partitions[i].type) ||
2782
(mbr[0].partitions[i].start_sct != mbr[1].partitions[i].start_sct) ||
2783
(mbr[0].partitions[i].size_sct != mbr[1].partitions[i].size_sct))
2784
{
2785
// Check if original MBR already has an emuMMC and use it as source of truth.
2786
if (mbr[0].partitions[i].type == 0xE0)
2787
{
2788
memcpy(&mbr[1].partitions[i], &mbr[0].partitions[i], sizeof(mbr_part_t));
2789
gpt_emummc_migrate_no++;
2790
continue;
2791
}
2792
else
2793
hybrid_mbr_changed = true;
2794
break;
2795
}
2796
}
2797
2798
check_changes:
2799
if (!hybrid_mbr_changed && !has_mbr_attributes && !gpt_emummc_migrate_no)
2800
{
2801
lv_label_set_text(lbl_status, "#96FF00 Warning:# The Hybrid MBR needs no change!#");
2802
goto out;
2803
}
2804
2805
char *txt_buf = malloc(SZ_16K);
2806
2807
if (hybrid_mbr_changed)
2808
{
2809
// Current MBR info.
2810
s_printf(txt_buf, "#00DDFF Current MBR Layout:#\n");
2811
s_printf(txt_buf + strlen(txt_buf),
2812
"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"
2813
"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"
2814
"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"
2815
"Partition 3 - Type: %02x, Start: %08x, Size: %08x\n\n",
2816
mbr[0].partitions[0].type, mbr[0].partitions[0].start_sct, mbr[0].partitions[0].size_sct,
2817
mbr[0].partitions[1].type, mbr[0].partitions[1].start_sct, mbr[0].partitions[1].size_sct,
2818
mbr[0].partitions[2].type, mbr[0].partitions[2].start_sct, mbr[0].partitions[2].size_sct,
2819
mbr[0].partitions[3].type, mbr[0].partitions[3].start_sct, mbr[0].partitions[3].size_sct);
2820
2821
// New MBR info.
2822
s_printf(txt_buf + strlen(txt_buf), "#00DDFF New MBR Layout:#\n");
2823
s_printf(txt_buf + strlen(txt_buf),
2824
"Partition 0 - Type: %02x, Start: %08x, Size: %08x\n"
2825
"Partition 1 - Type: %02x, Start: %08x, Size: %08x\n"
2826
"Partition 2 - Type: %02x, Start: %08x, Size: %08x\n"
2827
"Partition 3 - Type: %02x, Start: %08x, Size: %08x",
2828
mbr[1].partitions[0].type, mbr[1].partitions[0].start_sct, mbr[1].partitions[0].size_sct,
2829
mbr[1].partitions[1].type, mbr[1].partitions[1].start_sct, mbr[1].partitions[1].size_sct,
2830
mbr[1].partitions[2].type, mbr[1].partitions[2].start_sct, mbr[1].partitions[2].size_sct,
2831
mbr[1].partitions[3].type, mbr[1].partitions[3].start_sct, mbr[1].partitions[3].size_sct);
2832
}
2833
else if (has_mbr_attributes || gpt_emummc_migrate_no || gpt_oob_empty_part_no)
2834
{
2835
s_printf(txt_buf, "#00DDFF The following need to be corrected:#\n");
2836
if (has_mbr_attributes)
2837
s_printf(txt_buf + strlen(txt_buf), "- MBR attributes\n");
2838
if (gpt_emummc_migrate_no)
2839
s_printf(txt_buf + strlen(txt_buf), "- emuMMC GPT Partition address and size\n");
2840
if (gpt_oob_empty_part_no)
2841
s_printf(txt_buf + strlen(txt_buf), "- GPT OOB/Empty Partitions (removal)\n");
2842
}
2843
2844
lv_label_set_text(lbl_status, txt_buf);
2845
lv_label_set_style(lbl_status, &monospace_text);
2846
2847
free(txt_buf);
2848
2849
lbl_status = lv_label_create(mbox, NULL);
2850
lv_label_set_recolor(lbl_status, true);
2851
lv_label_set_align(lbl_status, LV_LABEL_ALIGN_CENTER);
2852
2853
lv_label_set_text(lbl_status,
2854
"#FF8000 Warning: Do you really want to continue?!#\n\n"
2855
"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.");
2856
2857
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
2858
lv_obj_set_top(mbox, true);
2859
2860
manual_system_maintenance(true);
2861
2862
if (btn_wait() & BTN_POWER)
2863
{
2864
bool has_gpt_changes = false;
2865
2866
sd_mount();
2867
2868
// Write MBR.
2869
if (hybrid_mbr_changed)
2870
sdmmc_storage_write(&sd_storage, 0, 1, &mbr[1]);
2871
2872
// Fix MBR secret attributes.
2873
if (has_mbr_attributes)
2874
{
2875
// Clear secret attributes.
2876
gpt->entries[0].part_guid[7] = 0;
2877
has_gpt_changes = gpt_partition_exists;
2878
2879
if (!has_gpt_changes)
2880
{
2881
// Only write the relevant sector if the only change is MBR attributes.
2882
sdmmc_storage_write(&sd_storage, 2, 1, &gpt->entries[0]);
2883
}
2884
}
2885
2886
if (gpt_emummc_migrate_no)
2887
{
2888
u32 emu_idx = 0;
2889
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
2890
{
2891
if (!memcmp(gpt->entries[i].name, (u16[]) { 'e', 'm', 'u', 'm', 'm', 'c' }, 12))
2892
{
2893
u32 idx = emummc_mbr_part_idx[emu_idx];
2894
gpt->entries[i].lba_start = mbr[0].partitions[idx].start_sct;
2895
gpt->entries[i].lba_end = mbr[0].partitions[idx].start_sct + mbr[0].partitions[idx].size_sct - 1;
2896
gpt_emummc_migrate_no--;
2897
emu_idx++;
2898
2899
has_gpt_changes = true;
2900
}
2901
2902
if (i > 126 || !gpt_emummc_migrate_no)
2903
break;
2904
}
2905
}
2906
2907
if (gpt_oob_empty_part_no)
2908
{
2909
u32 part_idx = 0;
2910
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
2911
{
2912
if ( gpt->entries[i].lba_start < gpt->header.first_use_lba ||
2913
gpt->entries[i].lba_start >= gpt->entries[i].lba_end ||
2914
!gpt->entries[i].lba_end)
2915
{
2916
continue;
2917
}
2918
2919
if (part_idx != i)
2920
memcpy(&gpt->entries[part_idx], &gpt->entries[i], sizeof(gpt_entry_t));
2921
part_idx++;
2922
}
2923
gpt->header.num_part_ents -= gpt_oob_empty_part_no;
2924
has_gpt_changes = true;
2925
}
2926
2927
if (has_gpt_changes)
2928
{
2929
// Fix GPT CRC32s.
2930
u32 entries_size = sizeof(gpt_entry_t) * gpt->header.num_part_ents;
2931
gpt->header.part_ents_crc32 = crc32_calc(0, (const u8 *)gpt->entries, entries_size);
2932
gpt->header.crc32 = 0; // Set to 0 for calculation.
2933
gpt->header.crc32 = crc32_calc(0, (const u8 *)&gpt->header, gpt->header.size);
2934
2935
gpt_hdr_backup.part_ents_crc32 = gpt->header.part_ents_crc32;
2936
gpt_hdr_backup.crc32 = 0; // Set to 0 for calculation.
2937
gpt_hdr_backup.crc32 = crc32_calc(0, (const u8 *)&gpt_hdr_backup, gpt_hdr_backup.size);
2938
2939
// Write main GPT.
2940
u32 aligned_entries_size = ALIGN(entries_size, SD_BLOCKSIZE);
2941
sdmmc_storage_write(&sd_storage, gpt->header.my_lba, (sizeof(gpt_header_t) + aligned_entries_size) >> 9, gpt);
2942
2943
// Write backup GPT partition table.
2944
sdmmc_storage_write(&sd_storage, gpt_hdr_backup.part_ent_lba, aligned_entries_size >> 9, gpt->entries);
2945
2946
// Write backup GPT header.
2947
sdmmc_storage_write(&sd_storage, gpt_hdr_backup.my_lba, 1, &gpt_hdr_backup);
2948
}
2949
2950
sd_unmount();
2951
2952
lv_label_set_text(lbl_status, "#96FF00 The new Hybrid MBR was written successfully!#");
2953
}
2954
else
2955
lv_label_set_text(lbl_status, "#FFDD00 Warning: The Hybrid MBR Fix was canceled!#");
2956
2957
out:
2958
free(gpt);
2959
2960
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
2961
2962
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
2963
lv_obj_set_top(mbox, true);
2964
2965
return LV_RES_OK;
2966
}
2967
2968
lv_res_t create_window_partition_manager(bool emmc)
2969
{
2970
lv_obj_t *win;
2971
2972
if (!emmc)
2973
{
2974
win = nyx_create_standard_window(SYMBOL_SD" SD Partition Manager");
2975
lv_win_add_btn(win, NULL, SYMBOL_MODULES_ALT" Fix Hybrid MBR/GPT", _action_fix_mbr_gpt);
2976
}
2977
else
2978
win = nyx_create_standard_window(SYMBOL_CHIP" eMMC Partition Manager");
2979
2980
static lv_style_t bar_hos_bg, bar_emu_bg, bar_l4t_bg, bar_and_bg;
2981
static lv_style_t bar_hos_ind, bar_emu_ind, bar_l4t_ind, bar_and_ind;
2982
static lv_style_t bar_emu_btn, bar_l4t_btn, bar_and_btn;
2983
static lv_style_t sep_emu_bg, sep_l4t_bg, sep_and_bg;
2984
2985
// Set HOS bar styles.
2986
lv_style_copy(&bar_hos_bg, lv_theme_get_current()->bar.bg);
2987
bar_hos_bg.body.main_color = LV_COLOR_HEX(0x4A8000);
2988
bar_hos_bg.body.grad_color = bar_hos_bg.body.main_color;
2989
lv_style_copy(&bar_hos_ind, lv_theme_get_current()->bar.indic);
2990
bar_hos_ind.body.main_color = LV_COLOR_HEX(0x96FF00);
2991
bar_hos_ind.body.grad_color = bar_hos_ind.body.main_color;
2992
2993
// Set eMUMMC bar styles.
2994
lv_style_copy(&bar_emu_bg, lv_theme_get_current()->bar.bg);
2995
bar_emu_bg.body.main_color = LV_COLOR_HEX(0x940F00);
2996
bar_emu_bg.body.grad_color = bar_emu_bg.body.main_color;
2997
lv_style_copy(&bar_emu_ind, lv_theme_get_current()->bar.indic);
2998
bar_emu_ind.body.main_color = LV_COLOR_HEX(0xFF3C28);
2999
bar_emu_ind.body.grad_color = bar_emu_ind.body.main_color;
3000
lv_style_copy(&bar_emu_btn, lv_theme_get_current()->slider.knob);
3001
bar_emu_btn.body.main_color = LV_COLOR_HEX(0xB31200);
3002
bar_emu_btn.body.grad_color = bar_emu_btn.body.main_color;
3003
lv_style_copy(&sep_emu_bg, lv_theme_get_current()->cont);
3004
sep_emu_bg.body.main_color = LV_COLOR_HEX(0xFF3C28);
3005
sep_emu_bg.body.grad_color = sep_emu_bg.body.main_color;
3006
sep_emu_bg.body.radius = 0;
3007
3008
// Set L4T bar styles.
3009
lv_style_copy(&bar_l4t_bg, lv_theme_get_current()->bar.bg);
3010
bar_l4t_bg.body.main_color = LV_COLOR_HEX(0x006E80);
3011
bar_l4t_bg.body.grad_color = bar_l4t_bg.body.main_color;
3012
lv_style_copy(&bar_l4t_ind, lv_theme_get_current()->bar.indic);
3013
bar_l4t_ind.body.main_color = LV_COLOR_HEX(0x00DDFF);
3014
bar_l4t_ind.body.grad_color = bar_l4t_ind.body.main_color;
3015
lv_style_copy(&bar_l4t_btn, lv_theme_get_current()->slider.knob);
3016
bar_l4t_btn.body.main_color = LV_COLOR_HEX(0x00B1CC);
3017
bar_l4t_btn.body.grad_color = bar_l4t_btn.body.main_color;
3018
lv_style_copy(&sep_l4t_bg, &sep_emu_bg);
3019
sep_l4t_bg.body.main_color = LV_COLOR_HEX(0x00DDFF);
3020
sep_l4t_bg.body.grad_color = sep_l4t_bg.body.main_color;
3021
3022
// Set Android bar styles.
3023
lv_style_copy(&bar_and_bg, lv_theme_get_current()->bar.bg);
3024
bar_and_bg.body.main_color = LV_COLOR_HEX(0x804000);
3025
bar_and_bg.body.grad_color = bar_and_bg.body.main_color;
3026
lv_style_copy(&bar_and_ind, lv_theme_get_current()->bar.indic);
3027
bar_and_ind.body.main_color = LV_COLOR_HEX(0xFF8000);
3028
bar_and_ind.body.grad_color = bar_and_ind.body.main_color;
3029
lv_style_copy(&bar_and_btn, lv_theme_get_current()->slider.knob);
3030
bar_and_btn.body.main_color = LV_COLOR_HEX(0xCC6600);
3031
bar_and_btn.body.grad_color = bar_and_btn.body.main_color;
3032
lv_style_copy(&sep_and_bg, &sep_emu_bg);
3033
sep_and_bg.body.main_color = LV_COLOR_HEX(0xFF8000);
3034
sep_and_bg.body.grad_color = sep_and_bg.body.main_color;
3035
3036
lv_obj_t *sep = lv_label_create(win, NULL);
3037
lv_label_set_static_text(sep, "");
3038
lv_obj_align(sep, NULL, LV_ALIGN_IN_TOP_MID, 0, 0);
3039
3040
// Create container to keep content inside.
3041
lv_obj_t *h1 = lv_cont_create(win, NULL);
3042
lv_obj_set_size(h1, LV_HOR_RES - (LV_DPI * 8 / 10), LV_VER_RES - LV_DPI);
3043
3044
u32 emmc_size = 0;
3045
if (!emmc)
3046
{
3047
if (!sd_mount())
3048
{
3049
lv_obj_t *lbl = lv_label_create(h1, NULL);
3050
lv_label_set_recolor(lbl, true);
3051
lv_label_set_text(lbl, "#FFDD00 Failed to init SD!#");
3052
return LV_RES_OK;
3053
}
3054
3055
if (emmc_initialize(false))
3056
{
3057
emmc_set_partition(EMMC_GPP);
3058
emmc_size = emmc_storage.sec_cnt >> 11;
3059
emmc_end();
3060
}
3061
}
3062
else
3063
{
3064
if (!emmc_initialize(false))
3065
{
3066
lv_obj_t *lbl = lv_label_create(h1, NULL);
3067
lv_label_set_recolor(lbl, true);
3068
lv_label_set_text(lbl, "#FFDD00 Failed to init eMMC!#");
3069
return LV_RES_OK;
3070
}
3071
emmc_set_partition(EMMC_GPP);
3072
}
3073
3074
memset(&part_info, 0, sizeof(partition_ctxt_t));
3075
if (!emmc)
3076
_create_mbox_check_files_total_size();
3077
3078
char *txt_buf = malloc(SZ_8K);
3079
3080
part_info.emmc = emmc;
3081
part_info.storage = !emmc ? &sd_storage : &emmc_storage;
3082
part_info.total_sct = part_info.storage->sec_cnt;
3083
if (emmc)
3084
part_info.total_sct -= HOS_USER_SECTOR; // Reserved HOS partitions.
3085
3086
// Align down total size to ensure alignment of all partitions after HOS one.
3087
part_info.alignment = part_info.total_sct - ALIGN_DOWN(part_info.total_sct, AU_ALIGN_SECTORS);
3088
part_info.total_sct -= part_info.alignment;
3089
3090
u32 extra_sct = AU_ALIGN_SECTORS + 0x400000; // Reserved 16MB alignment for FAT partition + 2GB.
3091
3092
// Set initial HOS partition size, so the correct cluster size can be selected.
3093
part_info.hos_size = (part_info.total_sct >> 11) - 16; // Important if there's no slider change.
3094
3095
// Check if eMMC should be 64GB (Aula).
3096
part_info.emmc_is_64gb = fuse_read_hw_type() == FUSE_NX_HW_TYPE_AULA;
3097
3098
// Set actual eMMC size.
3099
part_info.emmc_size_mb = emmc_size;
3100
3101
// Set HOS FAT or USER minimum size.
3102
part_info.hos_min_size = !emmc? HOS_FAT_MIN_SIZE_MB : HOS_USER_MIN_SIZE_MB;
3103
3104
// Read current MBR.
3105
mbr_t mbr = { 0 };
3106
sdmmc_storage_read(part_info.storage, 0, 1, &mbr);
3107
3108
u32 bar_hos_size = lv_obj_get_width(h1);
3109
u32 bar_emu_size = 0;
3110
u32 bar_l4t_size = 0;
3111
u32 bar_and_size = 0;
3112
3113
lv_obj_t *lbl = lv_label_create(h1, NULL);
3114
lv_label_set_recolor(lbl, true);
3115
lv_label_set_text(lbl, "Choose #FFDD00 new# partition layout:");
3116
3117
// Create disk layout blocks.
3118
// HOS partition block.
3119
lv_obj_t *bar_hos = lv_bar_create(h1, NULL);
3120
lv_obj_set_size(bar_hos, bar_hos_size, LV_DPI / 2);
3121
lv_bar_set_range(bar_hos, 0, 1);
3122
lv_bar_set_value(bar_hos, 1);
3123
lv_bar_set_style(bar_hos, LV_BAR_STYLE_INDIC, &bar_hos_ind);
3124
lv_obj_align(bar_hos, lbl, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6);
3125
part_info.bar_hos = bar_hos;
3126
3127
// emuMMC partition block.
3128
lv_obj_t *bar_emu = lv_bar_create(h1, bar_hos);
3129
lv_obj_set_size(bar_emu, bar_emu_size, LV_DPI / 2);
3130
lv_bar_set_style(bar_emu, LV_BAR_STYLE_INDIC, &bar_emu_ind);
3131
lv_obj_align(bar_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
3132
part_info.bar_emu = bar_emu;
3133
3134
// L4T partition block.
3135
lv_obj_t *bar_l4t = lv_bar_create(h1, bar_hos);
3136
lv_obj_set_size(bar_l4t, bar_l4t_size, LV_DPI / 2);
3137
lv_bar_set_style(bar_l4t, LV_BAR_STYLE_INDIC, &bar_l4t_ind);
3138
lv_obj_align(bar_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
3139
part_info.bar_l4t = bar_l4t;
3140
3141
// Android partition block.
3142
lv_obj_t *bar_and = lv_bar_create(h1, bar_hos);
3143
lv_obj_set_size(bar_and, bar_and_size, LV_DPI / 2);
3144
lv_bar_set_style(bar_and, LV_BAR_STYLE_INDIC, &bar_and_ind);
3145
lv_obj_align(bar_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
3146
part_info.bar_and = bar_and;
3147
3148
// HOS partition block.
3149
lv_obj_t *sep_emu = lv_cont_create(h1, NULL);
3150
lv_cont_set_fit(sep_emu, false, false);
3151
lv_obj_set_size(sep_emu, 0, LV_DPI / 2); // 8.
3152
lv_obj_set_style(sep_emu, &sep_emu_bg);
3153
lv_obj_align(sep_emu, bar_hos, LV_ALIGN_OUT_RIGHT_MID, -4, 0);
3154
part_info.sep_emu = sep_emu;
3155
3156
// Create disk layout blending separators.
3157
lv_obj_t *sep_l4t = lv_cont_create(h1, sep_emu);
3158
lv_obj_set_style(sep_l4t, &sep_l4t_bg);
3159
lv_obj_align(sep_l4t, bar_emu, LV_ALIGN_OUT_RIGHT_MID, -4, 0);
3160
part_info.sep_l4t = sep_l4t;
3161
3162
lv_obj_t *sep_and = lv_cont_create(h1, sep_emu);
3163
lv_obj_set_style(sep_and, &sep_and_bg);
3164
lv_obj_align(sep_and, bar_l4t, LV_ALIGN_OUT_RIGHT_MID, -4, 0);
3165
part_info.sep_and = sep_and;
3166
3167
// Create slider type labels.
3168
lv_obj_t *cont_lbl_hos = lv_cont_create(h1, NULL);
3169
lv_cont_set_fit(cont_lbl_hos, false, true);
3170
lv_obj_set_width(cont_lbl_hos, LV_DPI * 17 / 7);
3171
lv_obj_t *lbl_hos = lv_label_create(cont_lbl_hos, NULL);
3172
lv_label_set_recolor(lbl_hos, true);
3173
lv_label_set_static_text(lbl_hos, !emmc ? "#96FF00 "SYMBOL_DOT" HOS (FAT32):#" :
3174
"#96FF00 "SYMBOL_DOT" eMMC (USER):#");
3175
lv_obj_align(lbl_hos, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
3176
3177
lv_obj_t *lbl_emu = lbl_hos;
3178
if (!emmc)
3179
{
3180
lbl_emu = lv_label_create(h1, lbl_hos);
3181
lv_label_set_static_text(lbl_emu, "#FF3C28 "SYMBOL_DOT" emuMMC (RAW):#");
3182
lv_obj_align(lbl_emu, lbl_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
3183
}
3184
3185
lv_obj_t *lbl_l4t = lv_label_create(h1, lbl_hos);
3186
lv_label_set_static_text(lbl_l4t, "#00DDFF "SYMBOL_DOT" Linux (EXT4):#");
3187
lv_obj_align(lbl_l4t, lbl_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
3188
3189
lv_obj_t *lbl_and = lv_label_create(h1, lbl_hos);
3190
lv_label_set_static_text(lbl_and, "#FF8000 "SYMBOL_DOT" Android (USER):#");
3191
lv_obj_align(lbl_and, lbl_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
3192
3193
// Create HOS size slider. Non-interactive.
3194
lv_obj_t *slider_bar_hos = lv_bar_create(h1, NULL);
3195
lv_obj_set_size(slider_bar_hos, LV_DPI * 7, LV_DPI * 3 / 17);
3196
lv_bar_set_range(slider_bar_hos, 0, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB);
3197
lv_bar_set_value(slider_bar_hos, (part_info.total_sct - AU_ALIGN_SECTORS) / SECTORS_PER_GB);
3198
lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_BG, &bar_hos_bg);
3199
lv_bar_set_style(slider_bar_hos, LV_SLIDER_STYLE_INDIC, &bar_hos_ind);
3200
lv_obj_align(slider_bar_hos, cont_lbl_hos, LV_ALIGN_OUT_RIGHT_MID, LV_DPI, 0);
3201
part_info.slider_bar_hos = slider_bar_hos;
3202
3203
lv_obj_t *slider_emu = slider_bar_hos;
3204
if (!emmc)
3205
{
3206
// Create emuMMC size slider.
3207
slider_emu = lv_slider_create(h1, NULL);
3208
lv_obj_set_size(slider_emu, LV_DPI * 7, LV_DPI / 3);
3209
lv_slider_set_range(slider_emu, EMU_SLIDER_MIN, EMU_SLIDER_MAX);
3210
lv_slider_set_value(slider_emu, EMU_SLIDER_MIN);
3211
lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_BG, &bar_emu_bg);
3212
lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_INDIC, &bar_emu_ind);
3213
lv_slider_set_style(slider_emu, LV_SLIDER_STYLE_KNOB, &bar_emu_btn);
3214
lv_obj_align(slider_emu, slider_bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 + 5);
3215
lv_slider_set_action(slider_emu, _action_slider_emu);
3216
}
3217
3218
// Create L4T size slider.
3219
lv_obj_t *slider_l4t = lv_slider_create(h1, NULL);
3220
lv_obj_set_size(slider_l4t, LV_DPI * 7, LV_DPI / 3);
3221
lv_slider_set_range(slider_l4t, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB);
3222
lv_slider_set_value(slider_l4t, 0);
3223
lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_BG, &bar_l4t_bg);
3224
lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_INDIC, &bar_l4t_ind);
3225
lv_slider_set_style(slider_l4t, LV_SLIDER_STYLE_KNOB, &bar_l4t_btn);
3226
lv_obj_align(slider_l4t, slider_emu, LV_ALIGN_OUT_BOTTOM_LEFT, 0, !emmc ? (LV_DPI / 3 - 3) : (LV_DPI / 3 + 5));
3227
lv_slider_set_action(slider_l4t, _action_slider_l4t);
3228
3229
// Create Android size slider.
3230
lv_obj_t *slider_and = lv_slider_create(h1, NULL);
3231
lv_obj_set_size(slider_and, LV_DPI * 7, LV_DPI / 3);
3232
lv_slider_set_range(slider_and, 0, (part_info.total_sct - extra_sct) / SECTORS_PER_GB - (AND_SYS_SIZE_MB / 1024)); // Subtract android reserved size.
3233
lv_slider_set_value(slider_and, 0);
3234
lv_slider_set_style(slider_and, LV_SLIDER_STYLE_BG, &bar_and_bg);
3235
lv_slider_set_style(slider_and, LV_SLIDER_STYLE_INDIC, &bar_and_ind);
3236
lv_slider_set_style(slider_and, LV_SLIDER_STYLE_KNOB, &bar_and_btn);
3237
lv_obj_align(slider_and, slider_l4t, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3 - 3);
3238
lv_slider_set_action(slider_and, _action_slider_and);
3239
3240
// Create container for the labels.
3241
lv_obj_t *cont_lbl = lv_cont_create(h1, NULL);
3242
lv_cont_set_fit(cont_lbl, false, true);
3243
lv_obj_set_width(cont_lbl, LV_DPI * 3 / 2);
3244
part_info.cont_lbl = cont_lbl;
3245
3246
// Create HOS size label.
3247
lv_obj_t *lbl_sl_hos = lv_label_create(cont_lbl, NULL);
3248
lv_label_set_recolor(lbl_sl_hos, true);
3249
lv_label_set_align(lbl_sl_hos, LV_LABEL_ALIGN_RIGHT);
3250
s_printf(txt_buf, "#96FF00 %4d GiB#", (part_info.total_sct - AU_ALIGN_SECTORS) >> 11 >> 10);
3251
lv_label_set_text(lbl_sl_hos, txt_buf);
3252
lv_obj_align(lbl_sl_hos, cont_lbl, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
3253
part_info.lbl_hos = lbl_sl_hos;
3254
3255
// Create emuMMC size label.
3256
part_info.lbl_emu = lbl_sl_hos;
3257
if (!emmc)
3258
{
3259
lv_obj_t *lbl_sl_emu = lv_label_create(cont_lbl, lbl_sl_hos);
3260
lv_label_set_text(lbl_sl_emu, "#FF3C28 0 GiB#");
3261
lv_obj_align(lbl_sl_emu, lbl_sl_hos, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);
3262
part_info.lbl_emu = lbl_sl_emu;
3263
}
3264
3265
// Create L4T size label.
3266
lv_obj_t *lbl_sl_l4t = lv_label_create(cont_lbl, lbl_sl_hos);
3267
lv_label_set_text(lbl_sl_l4t, "#00DDFF 0 GiB#");
3268
lv_obj_align(lbl_sl_l4t, part_info.lbl_emu, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);
3269
part_info.lbl_l4t = lbl_sl_l4t;
3270
3271
// Create Android size label.
3272
lv_obj_t *lbl_sl_and = lv_label_create(cont_lbl, lbl_sl_hos);
3273
lv_label_set_text(lbl_sl_and, "#FF8000 0 GiB#");
3274
lv_obj_align(lbl_sl_and, lbl_sl_l4t, LV_ALIGN_OUT_BOTTOM_RIGHT, 0, LV_DPI / 3);
3275
part_info.lbl_and = lbl_sl_and;
3276
3277
lv_obj_align(cont_lbl, bar_hos, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI * 11 - LV_DPI / 2, LV_DPI * 9 / 23);
3278
3279
// Set partition manager notes.
3280
lv_obj_t *lbl_notes = lv_label_create(h1, NULL);
3281
lv_label_set_recolor(lbl_notes, true);
3282
lv_label_set_style(lbl_notes, &hint_small_style);
3283
if (!emmc)
3284
{
3285
lv_label_set_static_text(lbl_notes,
3286
"Note 1: Only up to #C7EA46 1.2GB# can be backed up. If more, you will be asked to back them manually at the next step.\n"
3287
"Note 2: Resized emuMMC formats the USER partition. A save data manager can be used to move them over.\n"
3288
"Note 3: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# will flash files if suitable partitions and installer files are found.\n");
3289
lv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6 * 2);
3290
}
3291
else
3292
{
3293
lv_label_set_static_text(lbl_notes,
3294
"Note 1: Any partition existing after the selected ones gets removed from the table.\n"
3295
"Note 2: The HOS USER partition gets formatted. A save data manager can be used to move them over.\n"
3296
"Note 3: The #C7EA46 Flash Linux# and #C7EA46 Flash Android# will flash files if suitable partitions and installer files are found.\n");
3297
lv_obj_align(lbl_notes, lbl_and, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 6 * 4);
3298
}
3299
3300
lv_obj_t *btn1 = NULL;
3301
lv_obj_t *label_btn = NULL;
3302
if (!emmc)
3303
{
3304
// Create UMS button.
3305
btn1 = lv_btn_create(h1, NULL);
3306
lv_obj_t *label_btn = lv_label_create(btn1, NULL);
3307
lv_btn_set_fit(btn1, true, true);
3308
lv_label_set_static_text(label_btn, SYMBOL_USB" SD UMS");
3309
lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5);
3310
lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _action_part_manager_ums_sd);
3311
}
3312
3313
// Create Flash Linux button.
3314
btn_flash_l4t = lv_btn_create(h1, NULL);
3315
label_btn = lv_label_create(btn_flash_l4t, NULL);
3316
lv_btn_set_fit(btn_flash_l4t, true, true);
3317
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Linux");
3318
if (!emmc)
3319
lv_obj_align(btn_flash_l4t, btn1, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);
3320
else
3321
lv_obj_align(btn_flash_l4t, h1, LV_ALIGN_IN_TOP_LEFT, 0, LV_DPI * 5);
3322
lv_btn_set_action(btn_flash_l4t, LV_BTN_ACTION_CLICK, _action_check_flash_linux);
3323
3324
// Disable Flash Linux button if partition not found.
3325
u32 size_sct = _get_available_l4t_partition();
3326
if (!l4t_flash_ctxt.offset_sct || size_sct < 0x800000)
3327
{
3328
lv_obj_set_click(btn_flash_l4t, false);
3329
lv_btn_set_state(btn_flash_l4t, LV_BTN_STATE_INA);
3330
}
3331
3332
int part_type_and = _get_available_android_partition();
3333
3334
// Create Flash Android button.
3335
btn_flash_android = lv_btn_create(h1, NULL);
3336
label_btn = lv_label_create(btn_flash_android, NULL);
3337
lv_btn_set_fit(btn_flash_android, true, true);
3338
switch (part_type_and)
3339
{
3340
case 0: // Disable Flash Android button if partition not found.
3341
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android");
3342
lv_obj_set_click(btn_flash_android, false);
3343
lv_btn_set_state(btn_flash_android, LV_BTN_STATE_INA);
3344
break;
3345
case 1: // Android 10/11.
3346
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 10/11");
3347
break;
3348
case 2: // Android 13+
3349
lv_label_set_static_text(label_btn, SYMBOL_DOWNLOAD" Flash Android 13+");
3350
break;
3351
}
3352
lv_obj_align(btn_flash_android, btn_flash_l4t, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 3, 0);
3353
lv_btn_set_action(btn_flash_android, LV_BTN_ACTION_CLICK, _action_flash_android);
3354
3355
// Create next step button.
3356
btn1 = lv_btn_create(h1, NULL);
3357
label_btn = lv_label_create(btn1, NULL);
3358
lv_btn_set_fit(btn1, true, true);
3359
lv_label_set_static_text(label_btn, SYMBOL_SD" Next Step");
3360
lv_obj_align(btn1, h1, LV_ALIGN_IN_TOP_RIGHT, 0, LV_DPI * 5);
3361
lv_btn_set_action(btn1, LV_BTN_ACTION_CLICK, _create_mbox_partitioning_next);
3362
part_info.partition_button = btn1;
3363
3364
free(txt_buf);
3365
3366
if (!emmc)
3367
sd_unmount();
3368
else
3369
emmc_end();
3370
3371
return LV_RES_OK;
3372
}
3373
3374
lv_res_t create_window_sd_partition_manager(lv_obj_t *btn) { return create_window_partition_manager(false); }
3375
lv_res_t create_window_emmc_partition_manager(lv_obj_t *btn) { return create_window_partition_manager(true); }
3376
3377