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