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