mirror of
https://github.com/CTCaer/hekate
synced 2024-12-22 11:21:23 +00:00
hekate/nyx: move emmc ops to bdk and adhere to changes
This commit is contained in:
parent
b08e36a7b0
commit
28167b7304
24 changed files with 176 additions and 576 deletions
5
Makefile
5
Makefile
|
@ -34,7 +34,7 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
bpmp.o ccplex.o clock.o di.o gpio.o i2c.o irq.o mc.o sdram.o \
|
bpmp.o ccplex.o clock.o di.o gpio.o i2c.o irq.o mc.o sdram.o \
|
||||||
pinmux.o pmc.o se.o smmu.o tsec.o uart.o \
|
pinmux.o pmc.o se.o smmu.o tsec.o uart.o \
|
||||||
fuse.o kfuse.o minerva.o \
|
fuse.o kfuse.o minerva.o \
|
||||||
sdmmc.o sdmmc_driver.o sd.o emummc.o nx_emmc.o \
|
sdmmc.o sdmmc_driver.o emmc.o sd.o emummc.o \
|
||||||
bq24193.o max17050.o max7762x.o max77620-rtc.o \
|
bq24193.o max17050.o max7762x.o max77620-rtc.o \
|
||||||
hw_init.o \
|
hw_init.o \
|
||||||
)
|
)
|
||||||
|
@ -65,6 +65,9 @@ FFCFG_INC := '"../$(SOURCEDIR)/libs/fatfs/ffconf.h"'
|
||||||
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DBL_MAGIC=$(IPL_MAGIC)
|
CUSTOMDEFINES := -DIPL_LOAD_ADDR=$(IPL_LOAD_ADDR) -DBL_MAGIC=$(IPL_MAGIC)
|
||||||
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BLVERSION_RSVD)
|
CUSTOMDEFINES += -DBL_VER_MJ=$(BLVERSION_MAJOR) -DBL_VER_MN=$(BLVERSION_MINOR) -DBL_VER_HF=$(BLVERSION_HOTFX) -DBL_RESERVED=$(BLVERSION_RSVD)
|
||||||
CUSTOMDEFINES += -DNYX_VER_MJ=$(NYXVERSION_MAJOR) -DNYX_VER_MN=$(NYXVERSION_MINOR) -DNYX_VER_HF=$(NYXVERSION_HOTFX) -DNYX_RESERVED=$(NYXVERSION_RSVD)
|
CUSTOMDEFINES += -DNYX_VER_MJ=$(NYXVERSION_MAJOR) -DNYX_VER_MN=$(NYXVERSION_MINOR) -DNYX_VER_HF=$(NYXVERSION_HOTFX) -DNYX_RESERVED=$(NYXVERSION_RSVD)
|
||||||
|
|
||||||
|
# BDK defines.
|
||||||
|
CUSTOMDEFINES += -DBDK_EMUMMC_ENABLE
|
||||||
CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC)
|
CUSTOMDEFINES += -DGFX_INC=$(GFX_INC) -DFFCFG_INC=$(FFCFG_INC)
|
||||||
|
|
||||||
#CUSTOMDEFINES += -DDEBUG
|
#CUSTOMDEFINES += -DDEBUG
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 Rajko Stojadinovic
|
* Copyright (c) 2018 Rajko Stojadinovic
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -25,7 +25,6 @@
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include "../gfx/tui.h"
|
#include "../gfx/tui.h"
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.
|
#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.
|
||||||
#define OUT_FILENAME_SZ 128
|
#define OUT_FILENAME_SZ 128
|
||||||
|
@ -180,7 +179,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||||
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
|
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
|
||||||
multipartSplitSize = (1u << 30);
|
multipartSplitSize = (1u << 30);
|
||||||
// Maximum parts fitting the free space available.
|
// Maximum parts fitting the free space available.
|
||||||
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
// Check if the USER partition or the RAW eMMC fits the sd card free space.
|
// Check if the USER partition or the RAW eMMC fits the sd card free space.
|
||||||
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
||||||
|
@ -198,7 +197,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
|
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
|
||||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
|
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE))
|
||||||
{
|
{
|
||||||
gfx_printf("%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
|
gfx_printf("%kFound Partial Backup in progress. Continuing...%k\n\n", 0xFFAEFD14, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
@ -224,9 +223,9 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||||
gfx_printf("%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC);
|
gfx_printf("%kPartial Backup enabled (with %d MiB parts)...%k\n\n", 0xFFFFBA00, multipartSplitSize >> 20, 0xFFCCCCCC);
|
||||||
|
|
||||||
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
|
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
|
||||||
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) || isSmallSdCard)
|
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE)) || isSmallSdCard)
|
||||||
{
|
{
|
||||||
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
|
u32 multipartSplitSectors = multipartSplitSize / EMMC_BLOCKSIZE;
|
||||||
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
||||||
|
|
||||||
outFilename[sdPathLen++] = '.';
|
outFilename[sdPathLen++] = '.';
|
||||||
|
@ -273,8 +272,8 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||||
// Continue from where we left, if Partial Backup in progress.
|
// Continue from where we left, if Partial Backup in progress.
|
||||||
if (partialDumpInProgress)
|
if (partialDumpInProgress)
|
||||||
{
|
{
|
||||||
lba_curr += currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
lba_curr += currPartIdx * (multipartSplitSize / EMMC_BLOCKSIZE);
|
||||||
totalSectors -= currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
totalSectors -= currPartIdx * (multipartSplitSize / EMMC_BLOCKSIZE);
|
||||||
lbaStartPart = lba_curr; // Update the start LBA for verification.
|
lbaStartPart = lba_curr; // Update the start LBA for verification.
|
||||||
}
|
}
|
||||||
u64 totalSize = (u64)((u64)totalSectors << 9);
|
u64 totalSize = (u64)((u64)totalSectors << 9);
|
||||||
|
@ -376,7 +375,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
res = f_write(&fp, buf, EMMC_BLOCKSIZE * num, NULL);
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
|
@ -397,7 +396,7 @@ static int _dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t
|
||||||
|
|
||||||
lba_curr += num;
|
lba_curr += num;
|
||||||
totalSectors -= num;
|
totalSectors -= num;
|
||||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
bytesWritten += num * EMMC_BLOCKSIZE;
|
||||||
|
|
||||||
// Force a flush after a lot of data if not splitting.
|
// Force a flush after a lot of data if not splitting.
|
||||||
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
|
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
|
||||||
|
@ -471,9 +470,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||||
// Get SD Card free space for Partial Backup.
|
// Get SD Card free space for Partial Backup.
|
||||||
f_getfree("", &sd_fs.free_clst, NULL);
|
f_getfree("", &sd_fs.free_clst, NULL);
|
||||||
|
|
||||||
sdmmc_storage_t storage;
|
if (!emmc_initialize(false))
|
||||||
sdmmc_t sdmmc;
|
|
||||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
|
||||||
{
|
{
|
||||||
EPRINTF("Failed to init eMMC.");
|
EPRINTF("Failed to init eMMC.");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -482,18 +479,18 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char sdPath[OUT_FILENAME_SZ];
|
char sdPath[OUT_FILENAME_SZ];
|
||||||
// Create Restore folders, if they do not exist.
|
// Create Restore folders, if they do not exist.
|
||||||
emmcsn_path_impl(sdPath, "/restore", "", &storage);
|
emmcsn_path_impl(sdPath, "/restore", "", &emmc_storage);
|
||||||
emmcsn_path_impl(sdPath, "/restore/partitions", "", &storage);
|
emmcsn_path_impl(sdPath, "/restore/partitions", "", &emmc_storage);
|
||||||
|
|
||||||
timer = get_tmr_s();
|
timer = get_tmr_s();
|
||||||
if (dumpType & PART_BOOT)
|
if (dumpType & PART_BOOT)
|
||||||
{
|
{
|
||||||
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
|
const u32 BOOT_PART_SIZE = emmc_storage.ext_csd.boot_mult << 17;
|
||||||
|
|
||||||
emmc_part_t bootPart;
|
emmc_part_t bootPart;
|
||||||
memset(&bootPart, 0, sizeof(bootPart));
|
memset(&bootPart, 0, sizeof(bootPart));
|
||||||
bootPart.lba_start = 0;
|
bootPart.lba_start = 0;
|
||||||
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
strcpy(bootPart.name, "BOOT");
|
strcpy(bootPart.name, "BOOT");
|
||||||
|
@ -503,21 +500,21 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
||||||
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, i + 1);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "", bootPart.name, &storage);
|
emmcsn_path_impl(sdPath, "", bootPart.name, &emmc_storage);
|
||||||
res = _dump_emmc_part(sdPath, &storage, &bootPart);
|
res = _dump_emmc_part(sdPath, &emmc_storage, &bootPart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER) || (dumpType & PART_RAW))
|
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER) || (dumpType & PART_RAW))
|
||||||
{
|
{
|
||||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_GPP);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
||||||
|
|
||||||
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER))
|
if ((dumpType & PART_SYSTEM) || (dumpType & PART_USER))
|
||||||
{
|
{
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &storage);
|
emmc_gpt_parse(&gpt);
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||||
{
|
{
|
||||||
if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER"))
|
if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER"))
|
||||||
|
@ -528,19 +525,19 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||||
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "/partitions", part->name, &storage);
|
emmcsn_path_impl(sdPath, "/partitions", part->name, &emmc_storage);
|
||||||
res = _dump_emmc_part(sdPath, &storage, part);
|
res = _dump_emmc_part(sdPath, &emmc_storage, part);
|
||||||
// If a part failed, don't continue.
|
// If a part failed, don't continue.
|
||||||
if (!res)
|
if (!res)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dumpType & PART_RAW)
|
if (dumpType & PART_RAW)
|
||||||
{
|
{
|
||||||
// Get GP partition size dynamically.
|
// Get GP partition size dynamically.
|
||||||
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
|
const u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt;
|
||||||
|
|
||||||
emmc_part_t rawPart;
|
emmc_part_t rawPart;
|
||||||
memset(&rawPart, 0, sizeof(rawPart));
|
memset(&rawPart, 0, sizeof(rawPart));
|
||||||
|
@ -551,8 +548,8 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||||
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "", rawPart.name, &storage);
|
emmcsn_path_impl(sdPath, "", rawPart.name, &emmc_storage);
|
||||||
res = _dump_emmc_part(sdPath, &storage, &rawPart);
|
res = _dump_emmc_part(sdPath, &emmc_storage, &rawPart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -560,7 +557,7 @@ static void _dump_emmc_selected(emmcPartType_t dumpType)
|
||||||
gfx_putc('\n');
|
gfx_putc('\n');
|
||||||
timer = get_tmr_s() - timer;
|
timer = get_tmr_s() - timer;
|
||||||
gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
||||||
sdmmc_storage_end(&storage);
|
sdmmc_storage_end(&emmc_storage);
|
||||||
if (res)
|
if (res)
|
||||||
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
@ -724,7 +721,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||||
retryCount = 0;
|
retryCount = 0;
|
||||||
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||||
|
|
||||||
res = f_read(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
res = f_read(&fp, buf, EMMC_BLOCKSIZE * num, NULL);
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
|
@ -760,7 +757,7 @@ static int _restore_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part
|
||||||
|
|
||||||
lba_curr += num;
|
lba_curr += num;
|
||||||
totalSectors -= num;
|
totalSectors -= num;
|
||||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
bytesWritten += num * EMMC_BLOCKSIZE;
|
||||||
}
|
}
|
||||||
tui_pbar(0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
tui_pbar(0, gfx_con.y, 100, 0xFFCCCCCC, 0xFF555555);
|
||||||
|
|
||||||
|
@ -822,9 +819,7 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||||
if (!sd_mount())
|
if (!sd_mount())
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
sdmmc_storage_t storage;
|
if (!emmc_initialize(false))
|
||||||
sdmmc_t sdmmc;
|
|
||||||
if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
|
||||||
{
|
{
|
||||||
EPRINTF("Failed to init eMMC.");
|
EPRINTF("Failed to init eMMC.");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -836,12 +831,12 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||||
timer = get_tmr_s();
|
timer = get_tmr_s();
|
||||||
if (restoreType & PART_BOOT)
|
if (restoreType & PART_BOOT)
|
||||||
{
|
{
|
||||||
const u32 BOOT_PART_SIZE = storage.ext_csd.boot_mult << 17;
|
const u32 BOOT_PART_SIZE = emmc_storage.ext_csd.boot_mult << 17;
|
||||||
|
|
||||||
emmc_part_t bootPart;
|
emmc_part_t bootPart;
|
||||||
memset(&bootPart, 0, sizeof(bootPart));
|
memset(&bootPart, 0, sizeof(bootPart));
|
||||||
bootPart.lba_start = 0;
|
bootPart.lba_start = 0;
|
||||||
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
strcpy(bootPart.name, "BOOT");
|
strcpy(bootPart.name, "BOOT");
|
||||||
|
@ -851,34 +846,34 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i,
|
||||||
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
sdmmc_storage_set_mmc_partition(&storage, i + 1);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, i + 1);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "/restore", bootPart.name, &storage);
|
emmcsn_path_impl(sdPath, "/restore", bootPart.name, &emmc_storage);
|
||||||
res = _restore_emmc_part(sdPath, &storage, &bootPart, false);
|
res = _restore_emmc_part(sdPath, &emmc_storage, &bootPart, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (restoreType & PART_GP_ALL)
|
if (restoreType & PART_GP_ALL)
|
||||||
{
|
{
|
||||||
sdmmc_storage_set_mmc_partition(&storage, EMMC_GPP);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
||||||
|
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &storage);
|
emmc_gpt_parse(&gpt);
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||||
{
|
{
|
||||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||||
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
part->name, part->lba_start, part->lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &storage);
|
emmcsn_path_impl(sdPath, "/restore/partitions/", part->name, &emmc_storage);
|
||||||
res = _restore_emmc_part(sdPath, &storage, part, false);
|
res = _restore_emmc_part(sdPath, &emmc_storage, part, false);
|
||||||
}
|
}
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (restoreType & PART_RAW)
|
if (restoreType & PART_RAW)
|
||||||
{
|
{
|
||||||
// Get GP partition size dynamically.
|
// Get GP partition size dynamically.
|
||||||
const u32 RAW_AREA_NUM_SECTORS = storage.sec_cnt;
|
const u32 RAW_AREA_NUM_SECTORS = emmc_storage.sec_cnt;
|
||||||
|
|
||||||
emmc_part_t rawPart;
|
emmc_part_t rawPart;
|
||||||
memset(&rawPart, 0, sizeof(rawPart));
|
memset(&rawPart, 0, sizeof(rawPart));
|
||||||
|
@ -889,15 +884,15 @@ static void _restore_emmc_selected(emmcPartType_t restoreType)
|
||||||
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
gfx_printf("%k%02d: %s (%07X-%07X)%k\n", 0xFF00DDFF, i++,
|
||||||
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFCCCCCC);
|
||||||
|
|
||||||
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &storage);
|
emmcsn_path_impl(sdPath, "/restore", rawPart.name, &emmc_storage);
|
||||||
res = _restore_emmc_part(sdPath, &storage, &rawPart, true);
|
res = _restore_emmc_part(sdPath, &emmc_storage, &rawPart, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx_putc('\n');
|
gfx_putc('\n');
|
||||||
timer = get_tmr_s() - timer;
|
timer = get_tmr_s() - timer;
|
||||||
gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
gfx_printf("Time taken: %dm %ds.\n", timer / 60, timer % 60);
|
||||||
sdmmc_storage_end(&storage);
|
sdmmc_storage_end(&emmc_storage);
|
||||||
if (res)
|
if (res)
|
||||||
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
gfx_printf("\n%kFinished and verified!%k\nPress any key...\n", 0xFF96FF00, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -25,7 +25,6 @@
|
||||||
#include "../hos/hos.h"
|
#include "../hos/hos.h"
|
||||||
#include "../hos/pkg1.h"
|
#include "../hos/pkg1.h"
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
extern void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
|
||||||
|
@ -123,7 +122,7 @@ void print_mmc_info()
|
||||||
|
|
||||||
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
static const u32 SECTORS_TO_MIB_COEFF = 11;
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
EPRINTF("Failed to init eMMC.");
|
EPRINTF("Failed to init eMMC.");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -226,7 +225,7 @@ void print_mmc_info()
|
||||||
|
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &emmc_storage);
|
emmc_gpt_parse(&gpt);
|
||||||
int gpp_idx = 0;
|
int gpp_idx = 0;
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||||
{
|
{
|
||||||
|
@ -235,7 +234,7 @@ void print_mmc_info()
|
||||||
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end);
|
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end);
|
||||||
gfx_put_small_sep();
|
gfx_put_small_sep();
|
||||||
}
|
}
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
* Copyright (c) 2018 Reisyukaku
|
* Copyright (c) 2018 Reisyukaku
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -28,7 +28,6 @@
|
||||||
#include "../hos/pkg1.h"
|
#include "../hos/pkg1.h"
|
||||||
#include "../hos/pkg2.h"
|
#include "../hos/pkg2.h"
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
extern boot_cfg_t b_cfg;
|
extern boot_cfg_t b_cfg;
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
|
@ -57,7 +56,7 @@ void dump_packages12()
|
||||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
EPRINTF("Failed to init eMMC.");
|
EPRINTF("Failed to init eMMC.");
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
@ -65,7 +64,7 @@ void dump_packages12()
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0);
|
||||||
|
|
||||||
// Read package1.
|
// Read package1.
|
||||||
sdmmc_storage_read(&emmc_storage, 0x100000 / NX_EMMC_BLOCKSIZE, SZ_256K / NX_EMMC_BLOCKSIZE, pkg1);
|
sdmmc_storage_read(&emmc_storage, 0x100000 / EMMC_BLOCKSIZE, SZ_256K / EMMC_BLOCKSIZE, pkg1);
|
||||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||||
if (!pkg1_id)
|
if (!pkg1_id)
|
||||||
{
|
{
|
||||||
|
@ -87,8 +86,8 @@ void dump_packages12()
|
||||||
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
||||||
|
|
||||||
// Read keyblob.
|
// Read keyblob.
|
||||||
u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
u8 *keyblob = (u8 *)calloc(EMMC_BLOCKSIZE, 1);
|
||||||
sdmmc_storage_read(&emmc_storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
|
sdmmc_storage_read(&emmc_storage, 0x180000 / EMMC_BLOCKSIZE + kb, 1, keyblob);
|
||||||
|
|
||||||
// Decrypt.
|
// Decrypt.
|
||||||
hos_keygen(keyblob, kb, &tsec_ctxt, false, false);
|
hos_keygen(keyblob, kb, &tsec_ctxt, false, false);
|
||||||
|
@ -153,23 +152,23 @@ void dump_packages12()
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
||||||
// Parse eMMC GPT.
|
// Parse eMMC GPT.
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &emmc_storage);
|
emmc_gpt_parse(&gpt);
|
||||||
// Find package2 partition.
|
// Find package2 partition.
|
||||||
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
emmc_part_t *pkg2_part = emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
||||||
if (!pkg2_part)
|
if (!pkg2_part)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
// Read in package2 header and get package2 real size.
|
// Read in package2 header and get package2 real size.
|
||||||
u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
u8 *tmp = (u8 *)malloc(EMMC_BLOCKSIZE);
|
||||||
nx_emmc_part_read(&emmc_storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp);
|
emmc_part_read(pkg2_part, 0x4000 / EMMC_BLOCKSIZE, 1, tmp);
|
||||||
u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);
|
u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);
|
||||||
u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];
|
u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];
|
||||||
free(tmp);
|
free(tmp);
|
||||||
// Read in package2.
|
// Read in package2.
|
||||||
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
|
u32 pkg2_size_aligned = ALIGN(pkg2_size, EMMC_BLOCKSIZE);
|
||||||
pkg2 = malloc(pkg2_size_aligned);
|
pkg2 = malloc(pkg2_size_aligned);
|
||||||
nx_emmc_part_read(&emmc_storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE,
|
emmc_part_read(pkg2_part, 0x4000 / EMMC_BLOCKSIZE,
|
||||||
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
|
pkg2_size_aligned / EMMC_BLOCKSIZE, pkg2);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
emmcsn_path_impl(path, "/pkg2", "pkg2_encr.bin", &emmc_storage);
|
emmcsn_path_impl(path, "/pkg2", "pkg2_encr.bin", &emmc_storage);
|
||||||
|
@ -227,7 +226,7 @@ void dump_packages12()
|
||||||
gfx_puts("\nDone. Press any key...\n");
|
gfx_puts("\nDone. Press any key...\n");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
out_free:
|
out_free:
|
||||||
free(pkg1);
|
free(pkg1);
|
||||||
free(secmon);
|
free(secmon);
|
||||||
|
@ -248,7 +247,7 @@ void _toggle_autorcm(bool enable)
|
||||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
EPRINTF("Failed to init eMMC.");
|
EPRINTF("Failed to init eMMC.");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -266,7 +265,7 @@ void _toggle_autorcm(bool enable)
|
||||||
// Iterate BCTs.
|
// Iterate BCTs.
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
sect = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE;
|
sect = (0x200 + (0x4000 * i)) / EMMC_BLOCKSIZE;
|
||||||
sdmmc_storage_read(&emmc_storage, sect, 1, tempbuf);
|
sdmmc_storage_read(&emmc_storage, sect, 1, tempbuf);
|
||||||
|
|
||||||
// Check if 2nd byte of modulus is correct.
|
// Check if 2nd byte of modulus is correct.
|
||||||
|
@ -312,7 +311,7 @@ void menu_autorcm()
|
||||||
// Do a simple check on the main BCT.
|
// Do a simple check on the main BCT.
|
||||||
bool disabled = true;
|
bool disabled = true;
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
EPRINTF("Failed to init eMMC.");
|
EPRINTF("Failed to init eMMC.");
|
||||||
btn_wait();
|
btn_wait();
|
||||||
|
@ -326,7 +325,7 @@ void menu_autorcm()
|
||||||
|
|
||||||
u8 *tempbuf = (u8 *)malloc(0x200);
|
u8 *tempbuf = (u8 *)malloc(0x200);
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0);
|
||||||
sdmmc_storage_read(&emmc_storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
|
sdmmc_storage_read(&emmc_storage, 0x200 / EMMC_BLOCKSIZE, 1, tempbuf);
|
||||||
|
|
||||||
// Check if 2nd byte of modulus is correct.
|
// Check if 2nd byte of modulus is correct.
|
||||||
if (tempbuf[0x11] == mod1)
|
if (tempbuf[0x11] == mod1)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 st4rk
|
* Copyright (c) 2018 st4rk
|
||||||
* Copyright (c) 2018 Ced2911
|
* Copyright (c) 2018 Ced2911
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -27,7 +27,6 @@
|
||||||
#include "secmon_exo.h"
|
#include "secmon_exo.h"
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include "../storage/emummc.h"
|
#include "../storage/emummc.h"
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
|
@ -612,7 +611,7 @@ static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
|
||||||
try_load:
|
try_load:
|
||||||
// Read package1.
|
// Read package1.
|
||||||
emummc_storage_set_mmc_partition(EMMC_BOOT0);
|
emummc_storage_set_mmc_partition(EMMC_BOOT0);
|
||||||
emummc_storage_read(bootloader_offset / NX_EMMC_BLOCKSIZE, PKG1_BOOTLOADER_SIZE / NX_EMMC_BLOCKSIZE, ctxt->pkg1);
|
emummc_storage_read(bootloader_offset / EMMC_BLOCKSIZE, PKG1_BOOTLOADER_SIZE / EMMC_BLOCKSIZE, ctxt->pkg1);
|
||||||
|
|
||||||
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1 + pk1_offset);
|
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1 + pk1_offset);
|
||||||
if (!ctxt->pkg1_id)
|
if (!ctxt->pkg1_id)
|
||||||
|
@ -656,8 +655,8 @@ try_load:
|
||||||
// Read the correct keyblob for older HOS versions.
|
// Read the correct keyblob for older HOS versions.
|
||||||
if (ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
if (ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
|
||||||
{
|
{
|
||||||
ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
ctxt->keyblob = (u8 *)calloc(EMMC_BLOCKSIZE, 1);
|
||||||
emummc_storage_read(PKG1_HOS_KEYBLOBS_OFFSET / NX_EMMC_BLOCKSIZE + ctxt->pkg1_id->kb, 1, ctxt->keyblob);
|
emummc_storage_read(PKG1_HOS_KEYBLOBS_OFFSET / EMMC_BLOCKSIZE + ctxt->pkg1_id->kb, 1, ctxt->keyblob);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -671,34 +670,34 @@ static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
|
||||||
|
|
||||||
// Parse eMMC GPT.
|
// Parse eMMC GPT.
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &emmc_storage);
|
emmc_gpt_parse(&gpt);
|
||||||
DPRINTF("Parsed GPT\n");
|
DPRINTF("Parsed GPT\n");
|
||||||
// Find package2 partition.
|
// Find package2 partition.
|
||||||
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
emmc_part_t *pkg2_part = emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
||||||
if (!pkg2_part)
|
if (!pkg2_part)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
// Read in package2 header and get package2 real size.
|
// Read in package2 header and get package2 real size.
|
||||||
const u32 BCT_SIZE = SZ_16K;
|
const u32 BCT_SIZE = SZ_16K;
|
||||||
bctBuf = (u8 *)malloc(BCT_SIZE);
|
bctBuf = (u8 *)malloc(BCT_SIZE);
|
||||||
nx_emmc_part_read(&emmc_storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE, 1, bctBuf);
|
emmc_part_read(pkg2_part, BCT_SIZE / EMMC_BLOCKSIZE, 1, bctBuf);
|
||||||
u32 *hdr = (u32 *)(bctBuf + 0x100);
|
u32 *hdr = (u32 *)(bctBuf + 0x100);
|
||||||
u32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3];
|
u32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3];
|
||||||
DPRINTF("pkg2 size on emmc is %08X\n", pkg2_size);
|
DPRINTF("pkg2 size on emmc is %08X\n", pkg2_size);
|
||||||
|
|
||||||
// Read in Boot Config.
|
// Read in Boot Config.
|
||||||
memset(bctBuf, 0, BCT_SIZE);
|
memset(bctBuf, 0, BCT_SIZE);
|
||||||
nx_emmc_part_read(&emmc_storage, pkg2_part, 0, BCT_SIZE / NX_EMMC_BLOCKSIZE, bctBuf);
|
emmc_part_read(pkg2_part, 0, BCT_SIZE / EMMC_BLOCKSIZE, bctBuf);
|
||||||
|
|
||||||
// Read in package2.
|
// Read in package2.
|
||||||
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
|
u32 pkg2_size_aligned = ALIGN(pkg2_size, EMMC_BLOCKSIZE);
|
||||||
DPRINTF("pkg2 size aligned is %08X\n", pkg2_size_aligned);
|
DPRINTF("pkg2 size aligned is %08X\n", pkg2_size_aligned);
|
||||||
ctxt->pkg2 = malloc(pkg2_size_aligned);
|
ctxt->pkg2 = malloc(pkg2_size_aligned);
|
||||||
ctxt->pkg2_size = pkg2_size;
|
ctxt->pkg2_size = pkg2_size;
|
||||||
nx_emmc_part_read(&emmc_storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE,
|
emmc_part_read(pkg2_part, BCT_SIZE / EMMC_BLOCKSIZE,
|
||||||
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, ctxt->pkg2);
|
pkg2_size_aligned / EMMC_BLOCKSIZE, ctxt->pkg2);
|
||||||
out:
|
out:
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
|
|
||||||
return bctBuf;
|
return bctBuf;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
* Copyright (c) 2019 Atmosphère-NX
|
* Copyright (c) 2019 Atmosphère-NX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -24,7 +24,6 @@
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
#include "../storage/emummc.h"
|
#include "../storage/emummc.h"
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -30,7 +30,6 @@
|
||||||
#include <libs/compr/blz.h>
|
#include <libs/compr/blz.h>
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
#include "storage/emummc.h"
|
#include "storage/emummc.h"
|
||||||
#include "storage/nx_emmc.h"
|
|
||||||
|
|
||||||
#include "frontend/fe_emmc_tools.h"
|
#include "frontend/fe_emmc_tools.h"
|
||||||
#include "frontend/fe_tools.h"
|
#include "frontend/fe_tools.h"
|
||||||
|
@ -57,7 +56,7 @@ void emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t
|
||||||
|
|
||||||
if (!storage)
|
if (!storage)
|
||||||
{
|
{
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
memcpy(emmcSN, "00000000", 9);
|
memcpy(emmcSN, "00000000", 9);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2021 CTCaer
|
* Copyright (c) 2019-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -22,7 +22,6 @@
|
||||||
#include "emummc.h"
|
#include "emummc.h"
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
emummc_cfg_t emu_cfg = { 0 };
|
emummc_cfg_t emu_cfg = { 0 };
|
||||||
|
@ -139,7 +138,7 @@ int emummc_storage_init_mmc()
|
||||||
emu_cfg.active_part = 0;
|
emu_cfg.active_part = 0;
|
||||||
|
|
||||||
// Always init eMMC even when in emuMMC. eMMC is needed from the emuMMC driver anyway.
|
// Always init eMMC even when in emuMMC. eMMC is needed from the emuMMC driver anyway.
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018 naehrwert
|
|
||||||
* Copyright (c) 2019-2021 CTCaer
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <bdk.h>
|
|
||||||
|
|
||||||
#include "nx_emmc.h"
|
|
||||||
#include "emummc.h"
|
|
||||||
|
|
||||||
sdmmc_t emmc_sdmmc;
|
|
||||||
sdmmc_storage_t emmc_storage;
|
|
||||||
FATFS emmc_fs;
|
|
||||||
|
|
||||||
void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
|
|
||||||
{
|
|
||||||
gpt_t *gpt_buf = (gpt_t *)calloc(NX_GPT_NUM_BLOCKS, NX_EMMC_BLOCKSIZE);
|
|
||||||
|
|
||||||
emummc_storage_read(NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, gpt_buf);
|
|
||||||
|
|
||||||
// Check if no GPT or more than max allowed entries.
|
|
||||||
if (memcmp(&gpt_buf->header.signature, "EFI PART", 8) || gpt_buf->header.num_part_ents > 128)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < gpt_buf->header.num_part_ents; i++)
|
|
||||||
{
|
|
||||||
emmc_part_t *part = (emmc_part_t *)calloc(sizeof(emmc_part_t), 1);
|
|
||||||
|
|
||||||
if (gpt_buf->entries[i].lba_start < gpt_buf->header.first_use_lba)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
part->index = i;
|
|
||||||
part->lba_start = gpt_buf->entries[i].lba_start;
|
|
||||||
part->lba_end = gpt_buf->entries[i].lba_end;
|
|
||||||
part->attrs = gpt_buf->entries[i].attrs;
|
|
||||||
|
|
||||||
// ASCII conversion. Copy only the LSByte of the UTF-16LE name.
|
|
||||||
for (u32 j = 0; j < 36; j++)
|
|
||||||
part->name[j] = gpt_buf->entries[i].name[j];
|
|
||||||
part->name[35] = 0;
|
|
||||||
|
|
||||||
list_append(gpt, &part->link);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
free(gpt_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nx_emmc_gpt_free(link_t *gpt)
|
|
||||||
{
|
|
||||||
LIST_FOREACH_SAFE(iter, gpt)
|
|
||||||
free(CONTAINER_OF(iter, emmc_part_t, link));
|
|
||||||
}
|
|
||||||
|
|
||||||
emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name)
|
|
||||||
{
|
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link)
|
|
||||||
if (!strcmp(part->name, name))
|
|
||||||
return part;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
|
|
||||||
{
|
|
||||||
// The last LBA is inclusive.
|
|
||||||
if (part->lba_start + sector_off > part->lba_end)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return emummc_storage_read(part->lba_start + sector_off, num_sectors, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
|
|
||||||
{
|
|
||||||
// The last LBA is inclusive.
|
|
||||||
if (part->lba_start + sector_off > part->lba_end)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return emummc_storage_write(part->lba_start + sector_off, num_sectors, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1)
|
|
||||||
{
|
|
||||||
if (fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD)
|
|
||||||
{
|
|
||||||
*mod0 = 0xF7;
|
|
||||||
*mod1 = 0x86;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*mod0 = 0x37;
|
|
||||||
*mod1 = 0x84;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018 naehrwert
|
|
||||||
* Copyright (c) 2019-2020 CTCaer
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _NX_EMMC_H_
|
|
||||||
#define _NX_EMMC_H_
|
|
||||||
|
|
||||||
#include <bdk.h>
|
|
||||||
|
|
||||||
#include <libs/fatfs/ff.h>
|
|
||||||
|
|
||||||
#define NX_GPT_FIRST_LBA 1
|
|
||||||
#define NX_GPT_NUM_BLOCKS 33
|
|
||||||
#define NX_EMMC_BLOCKSIZE 512
|
|
||||||
|
|
||||||
typedef struct _emmc_part_t
|
|
||||||
{
|
|
||||||
u32 index;
|
|
||||||
u32 lba_start;
|
|
||||||
u32 lba_end;
|
|
||||||
u64 attrs;
|
|
||||||
char name[37];
|
|
||||||
link_t link;
|
|
||||||
} emmc_part_t;
|
|
||||||
|
|
||||||
extern sdmmc_t emmc_sdmmc;
|
|
||||||
extern sdmmc_storage_t emmc_storage;
|
|
||||||
extern FATFS emmc_fs;
|
|
||||||
|
|
||||||
void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage);
|
|
||||||
void nx_emmc_gpt_free(link_t *gpt);
|
|
||||||
emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name);
|
|
||||||
int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);
|
|
||||||
int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);
|
|
||||||
|
|
||||||
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -36,7 +36,7 @@ OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
bpmp.o ccplex.o clock.o di.o gpio.o i2c.o irq.o pinmux.o pmc.o se.o smmu.o tsec.o uart.o \
|
bpmp.o ccplex.o clock.o di.o gpio.o i2c.o irq.o pinmux.o pmc.o se.o smmu.o tsec.o uart.o \
|
||||||
fuse.o kfuse.o \
|
fuse.o kfuse.o \
|
||||||
mc.o sdram.o minerva.o ramdisk.o \
|
mc.o sdram.o minerva.o ramdisk.o \
|
||||||
sdmmc.o sdmmc_driver.o sd.o nx_emmc.o nx_emmc_bis.o \
|
sdmmc.o sdmmc_driver.o emmc.o sd.o nx_emmc_bis.o \
|
||||||
bm92t36.o bq24193.o max17050.o max7762x.o max77620-rtc.o regulator_5v.o \
|
bm92t36.o bq24193.o max17050.o max7762x.o max77620-rtc.o regulator_5v.o \
|
||||||
touch.o joycon.o tmp451.o fan.o \
|
touch.o joycon.o tmp451.o fan.o \
|
||||||
usbd.o xusbd.o usb_descriptors.o usb_gadget_ums.o usb_gadget_hid.o \
|
usbd.o xusbd.o usb_descriptors.o usb_gadget_ums.o usb_gadget_hid.o \
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 Rajko Stojadinovic
|
* Copyright (c) 2018 Rajko Stojadinovic
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -28,7 +28,6 @@
|
||||||
#include "fe_emummc_tools.h"
|
#include "fe_emummc_tools.h"
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.
|
#define NUM_SECTORS_PER_ITER 8192 // 4MB Cache.
|
||||||
#define OUT_FILENAME_SZ 128
|
#define OUT_FILENAME_SZ 128
|
||||||
|
@ -175,7 +174,7 @@ static int _dump_emmc_verify(emmc_tool_gui_t *gui, sdmmc_storage_t *storage, u32
|
||||||
}
|
}
|
||||||
|
|
||||||
char chunkSizeAscii[10];
|
char chunkSizeAscii[10];
|
||||||
itoa(NUM_SECTORS_PER_ITER * NX_EMMC_BLOCKSIZE, chunkSizeAscii, 10);
|
itoa(NUM_SECTORS_PER_ITER * EMMC_BLOCKSIZE, chunkSizeAscii, 10);
|
||||||
chunkSizeAscii[9] = '\0';
|
chunkSizeAscii[9] = '\0';
|
||||||
|
|
||||||
f_puts("# chunksize: ", &hashFp);
|
f_puts("# chunksize: ", &hashFp);
|
||||||
|
@ -402,7 +401,7 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part,
|
||||||
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
|
if ((sd_storage.csd.capacity >> (20 - sd_storage.csd.read_blkbits)) <= 8192)
|
||||||
multipartSplitSize = (1u << 30);
|
multipartSplitSize = (1u << 30);
|
||||||
// Maximum parts fitting the free space available.
|
// Maximum parts fitting the free space available.
|
||||||
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (multipartSplitSize / EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
// Check if the USER partition or the RAW eMMC fits the sd card free space.
|
// Check if the USER partition or the RAW eMMC fits the sd card free space.
|
||||||
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
||||||
|
@ -423,7 +422,7 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
|
// Check if we are continuing a previous raw eMMC or USER partition backup in progress.
|
||||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
|
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK && totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE))
|
||||||
{
|
{
|
||||||
s_printf(gui->txt_buf, "\n#AEFD14 Partial Backup in progress. Continuing...#\n");
|
s_printf(gui->txt_buf, "\n#AEFD14 Partial Backup in progress. Continuing...#\n");
|
||||||
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
|
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
|
||||||
|
@ -456,9 +455,9 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
|
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
|
||||||
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE)) || isSmallSdCard)
|
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE)) || isSmallSdCard)
|
||||||
{
|
{
|
||||||
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
|
u32 multipartSplitSectors = multipartSplitSize / EMMC_BLOCKSIZE;
|
||||||
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
||||||
|
|
||||||
outFilename[sdPathLen++] = '.';
|
outFilename[sdPathLen++] = '.';
|
||||||
|
@ -512,8 +511,8 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part,
|
||||||
// Continue from where we left, if Partial Backup in progress.
|
// Continue from where we left, if Partial Backup in progress.
|
||||||
if (partialDumpInProgress)
|
if (partialDumpInProgress)
|
||||||
{
|
{
|
||||||
lba_curr += currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
lba_curr += currPartIdx * (multipartSplitSize / EMMC_BLOCKSIZE);
|
||||||
totalSectors -= currPartIdx * (multipartSplitSize / NX_EMMC_BLOCKSIZE);
|
totalSectors -= currPartIdx * (multipartSplitSize / EMMC_BLOCKSIZE);
|
||||||
lbaStartPart = lba_curr; // Update the start LBA for verification.
|
lbaStartPart = lba_curr; // Update the start LBA for verification.
|
||||||
}
|
}
|
||||||
u64 totalSize = (u64)((u64)totalSectors << 9);
|
u64 totalSize = (u64)((u64)totalSectors << 9);
|
||||||
|
@ -652,7 +651,7 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part,
|
||||||
}
|
}
|
||||||
manual_system_maintenance(false);
|
manual_system_maintenance(false);
|
||||||
|
|
||||||
res = f_write_fast(&fp, buf, NX_EMMC_BLOCKSIZE * num);
|
res = f_write_fast(&fp, buf, EMMC_BLOCKSIZE * num);
|
||||||
|
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
|
@ -682,7 +681,7 @@ static int _dump_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_part,
|
||||||
|
|
||||||
lba_curr += num;
|
lba_curr += num;
|
||||||
totalSectors -= num;
|
totalSectors -= num;
|
||||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
bytesWritten += num * EMMC_BLOCKSIZE;
|
||||||
|
|
||||||
// Force a flush after a lot of data if not splitting.
|
// Force a flush after a lot of data if not splitting.
|
||||||
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
|
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
|
||||||
|
@ -769,7 +768,7 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui)
|
||||||
// Get SD Card free space for Partial Backup.
|
// Get SD Card free space for Partial Backup.
|
||||||
f_getfree("", &sd_fs.free_clst, NULL);
|
f_getfree("", &sd_fs.free_clst, NULL);
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -792,7 +791,7 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui)
|
||||||
emmc_part_t bootPart;
|
emmc_part_t bootPart;
|
||||||
memset(&bootPart, 0, sizeof(bootPart));
|
memset(&bootPart, 0, sizeof(bootPart));
|
||||||
bootPart.lba_start = 0;
|
bootPart.lba_start = 0;
|
||||||
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
strcpy(bootPart.name, "BOOT");
|
strcpy(bootPart.name, "BOOT");
|
||||||
|
@ -832,7 +831,7 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui)
|
||||||
strcpy(gui->base_path, sdPath);
|
strcpy(gui->base_path, sdPath);
|
||||||
|
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &emmc_storage);
|
emmc_gpt_parse(&gpt);
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||||
{
|
{
|
||||||
if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER"))
|
if ((dumpType & PART_USER) == 0 && !strcmp(part->name, "USER"))
|
||||||
|
@ -863,7 +862,7 @@ void dump_emmc_selected(emmcPartType_t dumpType, emmc_tool_gui_t *gui)
|
||||||
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
|
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
|
||||||
manual_system_maintenance(true);
|
manual_system_maintenance(true);
|
||||||
}
|
}
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dumpType & PART_RAW)
|
if (dumpType & PART_RAW)
|
||||||
|
@ -1304,7 +1303,7 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa
|
||||||
|
|
||||||
lba_curr += num;
|
lba_curr += num;
|
||||||
totalSectors -= num;
|
totalSectors -= num;
|
||||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
bytesWritten += num * EMMC_BLOCKSIZE;
|
||||||
}
|
}
|
||||||
lv_bar_set_value(gui->bar, 100);
|
lv_bar_set_value(gui->bar, 100);
|
||||||
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%");
|
lv_label_set_text(gui->label_pct, " "SYMBOL_DOT" 100%");
|
||||||
|
@ -1407,7 +1406,7 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1428,7 +1427,7 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui)
|
||||||
emmc_part_t bootPart;
|
emmc_part_t bootPart;
|
||||||
memset(&bootPart, 0, sizeof(bootPart));
|
memset(&bootPart, 0, sizeof(bootPart));
|
||||||
bootPart.lba_start = 0;
|
bootPart.lba_start = 0;
|
||||||
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
strcpy(bootPart.name, "BOOT");
|
strcpy(bootPart.name, "BOOT");
|
||||||
|
@ -1466,7 +1465,7 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui)
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
||||||
|
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &emmc_storage);
|
emmc_gpt_parse(&gpt);
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||||
{
|
{
|
||||||
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n\n\n\n",
|
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n\n\n\n",
|
||||||
|
@ -1488,7 +1487,7 @@ void restore_emmc_selected(emmcPartType_t restoreType, emmc_tool_gui_t *gui)
|
||||||
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
|
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
|
||||||
manual_system_maintenance(true);
|
manual_system_maintenance(true);
|
||||||
}
|
}
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (restoreType & PART_RAW)
|
if (restoreType & PART_RAW)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 Rajko Stojadinovic
|
* Copyright (c) 2018 Rajko Stojadinovic
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -28,7 +28,6 @@
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include <libs/fatfs/diskio.h>
|
#include <libs/fatfs/diskio.h>
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
#include "../storage/nx_emmc_bis.h"
|
#include "../storage/nx_emmc_bis.h"
|
||||||
|
|
||||||
#define OUT_FILENAME_SZ 128
|
#define OUT_FILENAME_SZ 128
|
||||||
|
@ -169,9 +168,9 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
|
// Check if filesystem is FAT32 or the free space is smaller and backup in parts.
|
||||||
if (totalSectors > (FAT32_FILESIZE_LIMIT / NX_EMMC_BLOCKSIZE))
|
if (totalSectors > (FAT32_FILESIZE_LIMIT / EMMC_BLOCKSIZE))
|
||||||
{
|
{
|
||||||
u32 multipartSplitSectors = multipartSplitSize / NX_EMMC_BLOCKSIZE;
|
u32 multipartSplitSectors = multipartSplitSize / EMMC_BLOCKSIZE;
|
||||||
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
numSplitParts = (totalSectors + multipartSplitSectors - 1) / multipartSplitSectors;
|
||||||
|
|
||||||
// Continue from where we left, if Partial Backup in progress.
|
// Continue from where we left, if Partial Backup in progress.
|
||||||
|
@ -296,7 +295,7 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto
|
||||||
|
|
||||||
manual_system_maintenance(false);
|
manual_system_maintenance(false);
|
||||||
|
|
||||||
res = f_write_fast(&fp, buf, NX_EMMC_BLOCKSIZE * num);
|
res = f_write_fast(&fp, buf, EMMC_BLOCKSIZE * num);
|
||||||
|
|
||||||
manual_system_maintenance(false);
|
manual_system_maintenance(false);
|
||||||
|
|
||||||
|
@ -325,7 +324,7 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto
|
||||||
|
|
||||||
lba_curr += num;
|
lba_curr += num;
|
||||||
totalSectors -= num;
|
totalSectors -= num;
|
||||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
bytesWritten += num * EMMC_BLOCKSIZE;
|
||||||
|
|
||||||
// Force a flush after a lot of data if not splitting.
|
// Force a flush after a lot of data if not splitting.
|
||||||
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
|
if (numSplitParts == 0 && bytesWritten >= multipartSplitSize)
|
||||||
|
@ -374,7 +373,7 @@ void dump_emummc_file(emmc_tool_gui_t *gui)
|
||||||
// Get SD Card free space for Partial Backup.
|
// Get SD Card free space for Partial Backup.
|
||||||
f_getfree("", &sd_fs.free_clst, NULL);
|
f_getfree("", &sd_fs.free_clst, NULL);
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -406,7 +405,7 @@ void dump_emummc_file(emmc_tool_gui_t *gui)
|
||||||
emmc_part_t bootPart;
|
emmc_part_t bootPart;
|
||||||
memset(&bootPart, 0, sizeof(bootPart));
|
memset(&bootPart, 0, sizeof(bootPart));
|
||||||
bootPart.lba_start = 0;
|
bootPart.lba_start = 0;
|
||||||
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
strcpy(bootPart.name, "BOOT");
|
strcpy(bootPart.name, "BOOT");
|
||||||
|
@ -497,7 +496,7 @@ out:
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part_idx, u32 sd_part_off, sdmmc_storage_t *storage, emmc_part_t *part, u32 resized_count)
|
static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part_idx, u32 sd_part_off, emmc_part_t *part, u32 resized_count)
|
||||||
{
|
{
|
||||||
u32 num = 0;
|
u32 num = 0;
|
||||||
u32 pct = 0;
|
u32 pct = 0;
|
||||||
|
@ -529,8 +528,8 @@ static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part
|
||||||
{
|
{
|
||||||
// Get USER partition info.
|
// Get USER partition info.
|
||||||
LIST_INIT(gpt_parsed);
|
LIST_INIT(gpt_parsed);
|
||||||
nx_emmc_gpt_parse(&gpt_parsed, storage);
|
emmc_gpt_parse(&gpt_parsed);
|
||||||
emmc_part_t *user_part = nx_emmc_part_find(&gpt_parsed, "USER");
|
emmc_part_t *user_part = emmc_part_find(&gpt_parsed, "USER");
|
||||||
if (!user_part)
|
if (!user_part)
|
||||||
{
|
{
|
||||||
s_printf(gui->txt_buf, "\n#FFDD00 USER partition not found!#\n");
|
s_printf(gui->txt_buf, "\n#FFDD00 USER partition not found!#\n");
|
||||||
|
@ -542,7 +541,7 @@ static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part
|
||||||
|
|
||||||
user_offset = user_part->lba_start;
|
user_offset = user_part->lba_start;
|
||||||
part->lba_end = user_offset - 1;
|
part->lba_end = user_offset - 1;
|
||||||
nx_emmc_gpt_free(&gpt_parsed);
|
emmc_gpt_free(&gpt_parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
||||||
|
@ -564,7 +563,7 @@ static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part
|
||||||
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||||
|
|
||||||
// Read data from eMMC.
|
// Read data from eMMC.
|
||||||
while (!sdmmc_storage_read(storage, lba_curr, num, buf))
|
while (!sdmmc_storage_read(&emmc_storage, lba_curr, num, buf))
|
||||||
{
|
{
|
||||||
s_printf(gui->txt_buf,
|
s_printf(gui->txt_buf,
|
||||||
"\n#FFDD00 Error reading %d blocks @LBA %08X,#\n"
|
"\n#FFDD00 Error reading %d blocks @LBA %08X,#\n"
|
||||||
|
@ -697,9 +696,9 @@ static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part
|
||||||
mbr_t mbr;
|
mbr_t mbr;
|
||||||
gpt_t *gpt = calloc(1, sizeof(gpt_t));
|
gpt_t *gpt = calloc(1, sizeof(gpt_t));
|
||||||
gpt_header_t gpt_hdr_backup;
|
gpt_header_t gpt_hdr_backup;
|
||||||
sdmmc_storage_read(storage, 0, 1, &mbr);
|
sdmmc_storage_read(&emmc_storage, 0, 1, &mbr);
|
||||||
sdmmc_storage_read(storage, 1, sizeof(gpt_t) >> 9, gpt);
|
sdmmc_storage_read(&emmc_storage, 1, sizeof(gpt_t) >> 9, gpt);
|
||||||
sdmmc_storage_read(storage, gpt->header.alt_lba, 1, &gpt_hdr_backup);
|
sdmmc_storage_read(&emmc_storage, gpt->header.alt_lba, 1, &gpt_hdr_backup);
|
||||||
|
|
||||||
// Find USER partition.
|
// Find USER partition.
|
||||||
u32 gpt_entry_idx = 0;
|
u32 gpt_entry_idx = 0;
|
||||||
|
@ -747,7 +746,7 @@ static int _dump_emummc_raw_part(emmc_tool_gui_t *gui, int active_part, int part
|
||||||
sdmmc_storage_write(&sd_storage, sd_sector_off, 1, &mbr);
|
sdmmc_storage_write(&sd_storage, sd_sector_off, 1, &mbr);
|
||||||
|
|
||||||
// Clear nand patrol.
|
// Clear nand patrol.
|
||||||
memset(buf, 0, NX_EMMC_BLOCKSIZE);
|
memset(buf, 0, EMMC_BLOCKSIZE);
|
||||||
sdmmc_storage_write(&sd_storage, sd_part_off + NAND_PATROL_SECTOR, 1, buf);
|
sdmmc_storage_write(&sd_storage, sd_part_off + NAND_PATROL_SECTOR, 1, buf);
|
||||||
|
|
||||||
free(gpt);
|
free(gpt);
|
||||||
|
@ -774,12 +773,12 @@ static int _emummc_raw_derive_bis_keys(emmc_tool_gui_t *gui, u32 resized_count)
|
||||||
// Read and decrypt CAL0 for validation of working BIS keys.
|
// Read and decrypt CAL0 for validation of working BIS keys.
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &emmc_storage);
|
emmc_gpt_parse(&gpt);
|
||||||
emmc_part_t *cal0_part = nx_emmc_part_find(&gpt, "PRODINFO"); // check if null
|
emmc_part_t *cal0_part = emmc_part_find(&gpt, "PRODINFO"); // check if null
|
||||||
nx_emmc_bis_init(cal0_part, false, 0);
|
nx_emmc_bis_init(cal0_part, false, 0);
|
||||||
nx_emmc_bis_read(0, 0x40, cal0_buf);
|
nx_emmc_bis_read(0, 0x40, cal0_buf);
|
||||||
nx_emmc_bis_end();
|
nx_emmc_bis_end();
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
|
|
||||||
nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buf;
|
nx_emmc_cal0_t *cal0 = (nx_emmc_cal0_t *)cal0_buf;
|
||||||
|
|
||||||
|
@ -850,7 +849,7 @@ void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 r
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
lv_label_set_text(gui->label_info, "#FFDD00 Failed to init eMMC!#");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -879,7 +878,7 @@ void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 r
|
||||||
emmc_part_t bootPart;
|
emmc_part_t bootPart;
|
||||||
memset(&bootPart, 0, sizeof(bootPart));
|
memset(&bootPart, 0, sizeof(bootPart));
|
||||||
bootPart.lba_start = 0;
|
bootPart.lba_start = 0;
|
||||||
bootPart.lba_end = (BOOT_PART_SIZE / NX_EMMC_BLOCKSIZE) - 1;
|
bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;
|
||||||
|
|
||||||
// Clear partition start.
|
// Clear partition start.
|
||||||
memset((u8 *)MIXD_BUF_ALIGNED, 0, SZ_16M);
|
memset((u8 *)MIXD_BUF_ALIGNED, 0, SZ_16M);
|
||||||
|
@ -901,7 +900,7 @@ void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 r
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, i + 1);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, i + 1);
|
||||||
|
|
||||||
strcat(sdPath, bootPart.name);
|
strcat(sdPath, bootPart.name);
|
||||||
res = _dump_emummc_raw_part(gui, i, part_idx, sector_start, &emmc_storage, &bootPart, 0);
|
res = _dump_emummc_raw_part(gui, i, part_idx, sector_start, &bootPart, 0);
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
|
@ -935,7 +934,7 @@ void dump_emummc_raw(emmc_tool_gui_t *gui, int part_idx, u32 sector_start, u32 r
|
||||||
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
|
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
|
||||||
manual_system_maintenance(true);
|
manual_system_maintenance(true);
|
||||||
|
|
||||||
res = _dump_emummc_raw_part(gui, 2, part_idx, sector_start, &emmc_storage, &rawPart, resized_count);
|
res = _dump_emummc_raw_part(gui, 2, part_idx, sector_start, &rawPart, resized_count);
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
s_printf(txt_buf, "#FFDD00 Failed!#\n");
|
s_printf(txt_buf, "#FFDD00 Failed!#\n");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2021 CTCaer
|
* Copyright (c) 2019-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -218,7 +218,7 @@ static void _create_mbox_emummc_raw()
|
||||||
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
|
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
|
|
||||||
sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
emmc_initialize(false);
|
||||||
|
|
||||||
u32 emmc_size_safe = emmc_storage.sec_cnt + 0xC000; // eMMC GPP size + BOOT0/1.
|
u32 emmc_size_safe = emmc_storage.sec_cnt + 0xC000; // eMMC GPP size + BOOT0/1.
|
||||||
|
|
||||||
|
@ -769,7 +769,7 @@ static lv_res_t _create_mbox_emummc_migrate(lv_obj_t *btn)
|
||||||
sd_mount();
|
sd_mount();
|
||||||
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
|
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
|
||||||
|
|
||||||
sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
emmc_initialize(false);
|
||||||
|
|
||||||
em_raw = false;
|
em_raw = false;
|
||||||
em_file = false;
|
em_file = false;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
@ -262,7 +262,7 @@ static lv_res_t _create_mbox_cal0(lv_obj_t *btn)
|
||||||
sd_mount();
|
sd_mount();
|
||||||
|
|
||||||
// Init eMMC.
|
// Init eMMC.
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
|
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
|
||||||
|
|
||||||
|
@ -278,12 +278,12 @@ static lv_res_t _create_mbox_cal0(lv_obj_t *btn)
|
||||||
// Read and decrypt CAL0.
|
// Read and decrypt CAL0.
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &emmc_storage);
|
emmc_gpt_parse(&gpt);
|
||||||
emmc_part_t *cal0_part = nx_emmc_part_find(&gpt, "PRODINFO"); // check if null
|
emmc_part_t *cal0_part = emmc_part_find(&gpt, "PRODINFO"); // check if null
|
||||||
nx_emmc_bis_init(cal0_part, false, 0);
|
nx_emmc_bis_init(cal0_part, false, 0);
|
||||||
nx_emmc_bis_read(0, 0x40, cal0_buf);
|
nx_emmc_bis_read(0, 0x40, cal0_buf);
|
||||||
nx_emmc_bis_end();
|
nx_emmc_bis_end();
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
|
|
||||||
// Clear BIS keys slots.
|
// Clear BIS keys slots.
|
||||||
hos_bis_keys_clear();
|
hos_bis_keys_clear();
|
||||||
|
@ -1123,7 +1123,7 @@ static lv_res_t _create_mbox_emmc_sandisk_report(lv_obj_t * btn)
|
||||||
lv_obj_align(lb_desc2, lb_desc, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);
|
lv_obj_align(lb_desc2, lb_desc, LV_ALIGN_OUT_RIGHT_TOP, 0, 0);
|
||||||
|
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
|
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
|
||||||
|
|
||||||
|
@ -1321,7 +1321,7 @@ static lv_res_t _create_mbox_benchmark(bool sd_bench)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
storage = &emmc_storage;
|
storage = &emmc_storage;
|
||||||
res = !sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
res = !emmc_initialize(false);
|
||||||
if (!res)
|
if (!res)
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
||||||
}
|
}
|
||||||
|
@ -1553,7 +1553,7 @@ static lv_res_t _create_window_emmc_info_status(lv_obj_t *btn)
|
||||||
txt_buf[0] = '\n';
|
txt_buf[0] = '\n';
|
||||||
txt_buf[1] = 0;
|
txt_buf[1] = 0;
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
|
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
|
||||||
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
|
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
|
||||||
|
@ -1711,7 +1711,7 @@ static lv_res_t _create_window_emmc_info_status(lv_obj_t *btn)
|
||||||
|
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &emmc_storage);
|
emmc_gpt_parse(&gpt);
|
||||||
|
|
||||||
u32 idx = 0;
|
u32 idx = 0;
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||||
|
@ -1741,7 +1741,7 @@ static lv_res_t _create_window_emmc_info_status(lv_obj_t *btn)
|
||||||
if (!idx)
|
if (!idx)
|
||||||
strcat(txt_buf, "#FFDD00 Partition table is empty!#");
|
strcat(txt_buf, "#FFDD00 Partition table is empty!#");
|
||||||
|
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
|
|
||||||
lv_label_set_text(lb_desc2, txt_buf);
|
lv_label_set_text(lb_desc2, txt_buf);
|
||||||
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
|
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -29,7 +29,6 @@
|
||||||
#include "../hos/pkg2.h"
|
#include "../hos/pkg2.h"
|
||||||
#include "../hos/hos.h"
|
#include "../hos/hos.h"
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
extern volatile boot_cfg_t *b_cfg;
|
extern volatile boot_cfg_t *b_cfg;
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
|
@ -64,11 +63,11 @@ bool get_autorcm_status(bool toggle)
|
||||||
if (h_cfg.t210b01)
|
if (h_cfg.t210b01)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
|
emmc_initialize(false);
|
||||||
|
|
||||||
u8 *tempbuf = (u8 *)malloc(0x200);
|
u8 *tempbuf = (u8 *)malloc(0x200);
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_BOOT0);
|
||||||
sdmmc_storage_read(&emmc_storage, 0x200 / NX_EMMC_BLOCKSIZE, 1, tempbuf);
|
sdmmc_storage_read(&emmc_storage, 0x200 / EMMC_BLOCKSIZE, 1, tempbuf);
|
||||||
|
|
||||||
// Get the correct RSA modulus byte masks.
|
// Get the correct RSA modulus byte masks.
|
||||||
nx_emmc_get_autorcm_masks(&corr_mod0, &mod1);
|
nx_emmc_get_autorcm_masks(&corr_mod0, &mod1);
|
||||||
|
@ -86,7 +85,7 @@ bool get_autorcm_status(bool toggle)
|
||||||
// Iterate BCTs.
|
// Iterate BCTs.
|
||||||
for (u32 i = 0; i < 4; i++)
|
for (u32 i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
sector = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE; // 0x4000 bct + 0x200 offset.
|
sector = (0x200 + (0x4000 * i)) / EMMC_BLOCKSIZE; // 0x4000 bct + 0x200 offset.
|
||||||
sdmmc_storage_read(&emmc_storage, sector, 1, tempbuf);
|
sdmmc_storage_read(&emmc_storage, sector, 1, tempbuf);
|
||||||
|
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
|
@ -104,7 +103,7 @@ bool get_autorcm_status(bool toggle)
|
||||||
// Iterate BCTs.
|
// Iterate BCTs.
|
||||||
for (u32 i = 0; i < 4; i++)
|
for (u32 i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
sector = (0x200 + (0x4000 * i)) / NX_EMMC_BLOCKSIZE; // 0x4000 bct + 0x200 offset.
|
sector = (0x200 + (0x4000 * i)) / EMMC_BLOCKSIZE; // 0x4000 bct + 0x200 offset.
|
||||||
sdmmc_storage_read(&emmc_storage, sector, 1, tempbuf);
|
sdmmc_storage_read(&emmc_storage, sector, 1, tempbuf);
|
||||||
|
|
||||||
// Check if 2nd byte of modulus is correct.
|
// Check if 2nd byte of modulus is correct.
|
||||||
|
@ -1104,7 +1103,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||||
|
|
||||||
char *txt_buf = (char *)malloc(SZ_16K);
|
char *txt_buf = (char *)malloc(SZ_16K);
|
||||||
|
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
{
|
{
|
||||||
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
|
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
|
||||||
|
|
||||||
|
@ -1120,7 +1119,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||||
|
|
||||||
char *build_date = malloc(32);
|
char *build_date = malloc(32);
|
||||||
u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header.
|
u32 pk1_offset = h_cfg.t210b01 ? sizeof(bl_hdr_t210b01_t) : 0; // Skip T210B01 OEM header.
|
||||||
sdmmc_storage_read(&emmc_storage, BOOTLOADER_MAIN_OFFSET / NX_EMMC_BLOCKSIZE, BOOTLOADER_SIZE / NX_EMMC_BLOCKSIZE, pkg1);
|
sdmmc_storage_read(&emmc_storage, BOOTLOADER_MAIN_OFFSET / EMMC_BLOCKSIZE, BOOTLOADER_SIZE / EMMC_BLOCKSIZE, pkg1);
|
||||||
|
|
||||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1 + pk1_offset, build_date);
|
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1 + pk1_offset, build_date);
|
||||||
|
|
||||||
|
@ -1159,8 +1158,8 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||||
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
tsec_ctxt.secmon_base = pkg1_id->secmon_base;
|
||||||
|
|
||||||
// Read keyblob.
|
// Read keyblob.
|
||||||
u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
|
u8 *keyblob = (u8 *)calloc(EMMC_BLOCKSIZE, 1);
|
||||||
sdmmc_storage_read(&emmc_storage, HOS_KEYBLOBS_OFFSET / NX_EMMC_BLOCKSIZE + kb, 1, keyblob);
|
sdmmc_storage_read(&emmc_storage, HOS_KEYBLOBS_OFFSET / EMMC_BLOCKSIZE + kb, 1, keyblob);
|
||||||
|
|
||||||
// Decrypt.
|
// Decrypt.
|
||||||
hos_keygen(keyblob, kb, &tsec_ctxt);
|
hos_keygen(keyblob, kb, &tsec_ctxt);
|
||||||
|
@ -1256,23 +1255,23 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||||
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
|
||||||
// Parse eMMC GPT.
|
// Parse eMMC GPT.
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &emmc_storage);
|
emmc_gpt_parse(&gpt);
|
||||||
// Find package2 partition.
|
// Find package2 partition.
|
||||||
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
emmc_part_t *pkg2_part = emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
|
||||||
if (!pkg2_part)
|
if (!pkg2_part)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
// Read in package2 header and get package2 real size.
|
// Read in package2 header and get package2 real size.
|
||||||
u8 *tmp = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
u8 *tmp = (u8 *)malloc(EMMC_BLOCKSIZE);
|
||||||
nx_emmc_part_read(&emmc_storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE, 1, tmp);
|
emmc_part_read(pkg2_part, 0x4000 / EMMC_BLOCKSIZE, 1, tmp);
|
||||||
u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);
|
u32 *hdr_pkg2_raw = (u32 *)(tmp + 0x100);
|
||||||
u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];
|
u32 pkg2_size = hdr_pkg2_raw[0] ^ hdr_pkg2_raw[2] ^ hdr_pkg2_raw[3];
|
||||||
free(tmp);
|
free(tmp);
|
||||||
// Read in package2.
|
// Read in package2.
|
||||||
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
|
u32 pkg2_size_aligned = ALIGN(pkg2_size, EMMC_BLOCKSIZE);
|
||||||
pkg2 = malloc(pkg2_size_aligned);
|
pkg2 = malloc(pkg2_size_aligned);
|
||||||
nx_emmc_part_read(&emmc_storage, pkg2_part, 0x4000 / NX_EMMC_BLOCKSIZE,
|
emmc_part_read(pkg2_part, 0x4000 / EMMC_BLOCKSIZE,
|
||||||
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, pkg2);
|
pkg2_size_aligned / EMMC_BLOCKSIZE, pkg2);
|
||||||
|
|
||||||
// Dump encrypted package2.
|
// Dump encrypted package2.
|
||||||
emmcsn_path_impl(path, "/pkg2", "pkg2_encr.bin", &emmc_storage);
|
emmcsn_path_impl(path, "/pkg2", "pkg2_encr.bin", &emmc_storage);
|
||||||
|
@ -1384,7 +1383,7 @@ static lv_res_t _create_window_dump_pk12_tool(lv_obj_t *btn)
|
||||||
free(kip_buffer);
|
free(kip_buffer);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
nx_emmc_gpt_free(&gpt);
|
emmc_gpt_free(&gpt);
|
||||||
out_free:
|
out_free:
|
||||||
free(pkg1);
|
free(pkg1);
|
||||||
free(secmon);
|
free(secmon);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2021 CTCaer
|
* Copyright (c) 2019-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -23,7 +23,6 @@
|
||||||
#include "gui_tools_partition_manager.h"
|
#include "gui_tools_partition_manager.h"
|
||||||
#include <libs/fatfs/diskio.h>
|
#include <libs/fatfs/diskio.h>
|
||||||
#include <libs/lvgl/lvgl.h>
|
#include <libs/lvgl/lvgl.h>
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
extern volatile boot_cfg_t *b_cfg;
|
extern volatile boot_cfg_t *b_cfg;
|
||||||
extern volatile nyx_storage_t *nyx_str;
|
extern volatile nyx_storage_t *nyx_str;
|
||||||
|
@ -693,7 +692,7 @@ static lv_res_t _action_flash_linux_data(lv_obj_t * btns, const char * txt)
|
||||||
|
|
||||||
lba_curr += num;
|
lba_curr += num;
|
||||||
total_size_sct -= num;
|
total_size_sct -= num;
|
||||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
bytesWritten += num * EMMC_BLOCKSIZE;
|
||||||
}
|
}
|
||||||
lv_bar_set_value(bar, 100);
|
lv_bar_set_value(bar, 100);
|
||||||
lv_label_set_text(label_pct, " "SYMBOL_DOT" 100%");
|
lv_label_set_text(label_pct, " "SYMBOL_DOT" 100%");
|
||||||
|
@ -2110,7 +2109,7 @@ static lv_res_t _action_fix_mbr(lv_obj_t *btn)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
nx_emmc_gpt_free(&gpt_parsed);
|
emmc_gpt_free(&gpt_parsed);
|
||||||
|
|
||||||
// Set GPT protective partition.
|
// Set GPT protective partition.
|
||||||
mbr[1].partitions[mbr_idx].type = 0xEE;
|
mbr[1].partitions[mbr_idx].type = 0xEE;
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
|
|
||||||
#include "hos.h"
|
#include "hos.h"
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018-2021 CTCaer
|
* Copyright (c) 2018-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "hos/hos.h"
|
#include "hos/hos.h"
|
||||||
#include "storage/nx_emmc.h"
|
|
||||||
#include <ianos/ianos.h>
|
#include <ianos/ianos.h>
|
||||||
#include <libs/compr/blz.h>
|
#include <libs/compr/blz.h>
|
||||||
#include <libs/fatfs/ff.h>
|
#include <libs/fatfs/ff.h>
|
||||||
|
@ -59,7 +58,7 @@ char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_
|
||||||
// Get actual eMMC S/N.
|
// Get actual eMMC S/N.
|
||||||
if (!storage)
|
if (!storage)
|
||||||
{
|
{
|
||||||
if (!sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400))
|
if (!emmc_initialize(false))
|
||||||
strcpy(emmc_sn, "00000000");
|
strcpy(emmc_sn, "00000000");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,104 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018 naehrwert
|
|
||||||
* Copyright (c) 2019-2020 CTCaer
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <bdk.h>
|
|
||||||
|
|
||||||
#include "nx_emmc.h"
|
|
||||||
|
|
||||||
sdmmc_t emmc_sdmmc;
|
|
||||||
sdmmc_storage_t emmc_storage;
|
|
||||||
FATFS emmc_fs;
|
|
||||||
|
|
||||||
void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
|
|
||||||
{
|
|
||||||
gpt_t *gpt_buf = (gpt_t *)calloc(NX_GPT_NUM_BLOCKS, NX_EMMC_BLOCKSIZE);
|
|
||||||
|
|
||||||
sdmmc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, gpt_buf);
|
|
||||||
|
|
||||||
// Check if no GPT or more than max allowed entries.
|
|
||||||
if (memcmp(&gpt_buf->header.signature, "EFI PART", 8) || gpt_buf->header.num_part_ents > 128)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < gpt_buf->header.num_part_ents; i++)
|
|
||||||
{
|
|
||||||
emmc_part_t *part = (emmc_part_t *)calloc(sizeof(emmc_part_t), 1);
|
|
||||||
|
|
||||||
if (gpt_buf->entries[i].lba_start < gpt_buf->header.first_use_lba)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
part->index = i;
|
|
||||||
part->lba_start = gpt_buf->entries[i].lba_start;
|
|
||||||
part->lba_end = gpt_buf->entries[i].lba_end;
|
|
||||||
part->attrs = gpt_buf->entries[i].attrs;
|
|
||||||
|
|
||||||
// ASCII conversion. Copy only the LSByte of the UTF-16LE name.
|
|
||||||
for (u32 j = 0; j < 36; j++)
|
|
||||||
part->name[j] = gpt_buf->entries[i].name[j];
|
|
||||||
part->name[35] = 0;
|
|
||||||
|
|
||||||
list_append(gpt, &part->link);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
free(gpt_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nx_emmc_gpt_free(link_t *gpt)
|
|
||||||
{
|
|
||||||
LIST_FOREACH_SAFE(iter, gpt)
|
|
||||||
free(CONTAINER_OF(iter, emmc_part_t, link));
|
|
||||||
}
|
|
||||||
|
|
||||||
emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name)
|
|
||||||
{
|
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link)
|
|
||||||
if (!strcmp(part->name, name))
|
|
||||||
return part;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
|
|
||||||
{
|
|
||||||
// The last LBA is inclusive.
|
|
||||||
if (part->lba_start + sector_off > part->lba_end)
|
|
||||||
return 0;
|
|
||||||
return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
|
|
||||||
{
|
|
||||||
// The last LBA is inclusive.
|
|
||||||
if (part->lba_start + sector_off > part->lba_end)
|
|
||||||
return 0;
|
|
||||||
return sdmmc_storage_write(storage, part->lba_start + sector_off, num_sectors, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1)
|
|
||||||
{
|
|
||||||
if (fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD)
|
|
||||||
{
|
|
||||||
*mod0 = 0xF7;
|
|
||||||
*mod1 = 0x86;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*mod0 = 0x37;
|
|
||||||
*mod1 = 0x84;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018 naehrwert
|
|
||||||
* Copyright (c) 2019-2020 CTCaer
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms and conditions of the GNU General Public License,
|
|
||||||
* version 2, as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _NX_EMMC_H_
|
|
||||||
#define _NX_EMMC_H_
|
|
||||||
|
|
||||||
#include <bdk.h>
|
|
||||||
|
|
||||||
#include <libs/fatfs/ff.h>
|
|
||||||
|
|
||||||
#define NX_GPT_FIRST_LBA 1
|
|
||||||
#define NX_GPT_NUM_BLOCKS 33
|
|
||||||
#define NX_EMMC_BLOCKSIZE 512
|
|
||||||
|
|
||||||
typedef struct _emmc_part_t
|
|
||||||
{
|
|
||||||
u32 index;
|
|
||||||
u32 lba_start;
|
|
||||||
u32 lba_end;
|
|
||||||
u64 attrs;
|
|
||||||
char name[37];
|
|
||||||
link_t link;
|
|
||||||
} emmc_part_t;
|
|
||||||
|
|
||||||
extern sdmmc_t emmc_sdmmc;
|
|
||||||
extern sdmmc_storage_t emmc_storage;
|
|
||||||
extern FATFS emmc_fs;
|
|
||||||
|
|
||||||
void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage);
|
|
||||||
void nx_emmc_gpt_free(link_t *gpt);
|
|
||||||
emmc_part_t *nx_emmc_part_find(link_t *gpt, const char *name);
|
|
||||||
int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);
|
|
||||||
int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);
|
|
||||||
|
|
||||||
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -2,7 +2,7 @@
|
||||||
* eMMC BIS driver for Nintendo Switch
|
* eMMC BIS driver for Nintendo Switch
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2020 shchmue
|
* Copyright (c) 2019-2020 shchmue
|
||||||
* Copyright (c) 2019-2021 CTCaer
|
* Copyright (c) 2019-2022 CTCaer
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
@ -21,8 +21,6 @@
|
||||||
|
|
||||||
#include <bdk.h>
|
#include <bdk.h>
|
||||||
|
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
#define BIS_CLUSTER_SECTORS 32
|
#define BIS_CLUSTER_SECTORS 32
|
||||||
#define BIS_CLUSTER_SIZE 16384
|
#define BIS_CLUSTER_SIZE 16384
|
||||||
#define BIS_CACHE_MAX_ENTRIES 16384
|
#define BIS_CACHE_MAX_ENTRIES 16384
|
||||||
|
@ -52,74 +50,6 @@ static emmc_part_t *system_part = NULL;
|
||||||
static u32 *cache_lookup_tbl = (u32 *)NX_BIS_LOOKUP_ADDR;
|
static u32 *cache_lookup_tbl = (u32 *)NX_BIS_LOOKUP_ADDR;
|
||||||
static bis_cache_t *bis_cache = (bis_cache_t *)NX_BIS_CACHE_ADDR;
|
static bis_cache_t *bis_cache = (bis_cache_t *)NX_BIS_CACHE_ADDR;
|
||||||
|
|
||||||
static void _gf256_mul_x_le(void *block)
|
|
||||||
{
|
|
||||||
u32 *pdata = (u32 *)block;
|
|
||||||
u32 carry = 0;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
u32 b = pdata[i];
|
|
||||||
pdata[i] = (b << 1) | carry;
|
|
||||||
carry = b >> 31;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (carry)
|
|
||||||
pdata[0x0] ^= 0x87;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _nx_aes_xts_crypt_sec(u32 tweak_ks, u32 crypt_ks, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 sec_size)
|
|
||||||
{
|
|
||||||
u32 *pdst = (u32 *)dst;
|
|
||||||
u32 *psrc = (u32 *)src;
|
|
||||||
u32 *ptweak = (u32 *)tweak;
|
|
||||||
|
|
||||||
if (regen_tweak)
|
|
||||||
{
|
|
||||||
for (int i = 0xF; i >= 0; i--)
|
|
||||||
{
|
|
||||||
tweak[i] = sec & 0xFF;
|
|
||||||
sec >>= 8;
|
|
||||||
}
|
|
||||||
if (!se_aes_crypt_block_ecb(tweak_ks, ENCRYPT, tweak, tweak))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tweak_exp allows us to use a saved tweak to reduce _gf256_mul_x_le calls.
|
|
||||||
for (u32 i = 0; i < (tweak_exp << 5); i++)
|
|
||||||
_gf256_mul_x_le(tweak);
|
|
||||||
|
|
||||||
u8 orig_tweak[SE_KEY_128_SIZE] __attribute__((aligned(4)));
|
|
||||||
memcpy(orig_tweak, tweak, SE_KEY_128_SIZE);
|
|
||||||
|
|
||||||
// We are assuming a 16 sector aligned size in this implementation.
|
|
||||||
for (u32 i = 0; i < (sec_size >> 4); i++)
|
|
||||||
{
|
|
||||||
for (u32 j = 0; j < 4; j++)
|
|
||||||
pdst[j] = psrc[j] ^ ptweak[j];
|
|
||||||
|
|
||||||
_gf256_mul_x_le(tweak);
|
|
||||||
psrc += 4;
|
|
||||||
pdst += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!se_aes_crypt_ecb(crypt_ks, enc, dst, sec_size, dst, sec_size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
pdst = (u32 *)dst;
|
|
||||||
ptweak = (u32 *)orig_tweak;
|
|
||||||
for (u32 i = 0; i < (sec_size >> 4); i++)
|
|
||||||
{
|
|
||||||
for (u32 j = 0; j < 4; j++)
|
|
||||||
pdst[j] = pdst[j] ^ ptweak[j];
|
|
||||||
|
|
||||||
_gf256_mul_x_le(orig_tweak);
|
|
||||||
pdst += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush)
|
static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush)
|
||||||
{
|
{
|
||||||
if (!system_part)
|
if (!system_part)
|
||||||
|
@ -137,7 +67,7 @@ static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush
|
||||||
if (is_cached)
|
if (is_cached)
|
||||||
{
|
{
|
||||||
if (buff)
|
if (buff)
|
||||||
memcpy(bis_cache->clusters[lookup_idx].data + sector_in_cluster * NX_EMMC_BLOCKSIZE, buff, count * NX_EMMC_BLOCKSIZE);
|
memcpy(bis_cache->clusters[lookup_idx].data + sector_in_cluster * EMMC_BLOCKSIZE, buff, count * EMMC_BLOCKSIZE);
|
||||||
else
|
else
|
||||||
buff = bis_cache->clusters[lookup_idx].data;
|
buff = bis_cache->clusters[lookup_idx].data;
|
||||||
if (!bis_cache->clusters[lookup_idx].dirty)
|
if (!bis_cache->clusters[lookup_idx].dirty)
|
||||||
|
@ -154,12 +84,12 @@ static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt cluster.
|
// Encrypt cluster.
|
||||||
if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 1, tweak, true, sector_in_cluster, cluster, bis_cache->dma_buff, buff, count * NX_EMMC_BLOCKSIZE))
|
if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, ENCRYPT, cluster, tweak, true, sector_in_cluster, bis_cache->dma_buff, buff, count * EMMC_BLOCKSIZE))
|
||||||
return 1; // Encryption error.
|
return 1; // Encryption error.
|
||||||
|
|
||||||
// If not reading from cache, do a regular read and decrypt.
|
// If not reading from cache, do a regular read and decrypt.
|
||||||
if (!emu_offset)
|
if (!emu_offset)
|
||||||
res = nx_emmc_part_write(&emmc_storage, system_part, sector, count, bis_cache->dma_buff);
|
res = emmc_part_write(system_part, sector, count, bis_cache->dma_buff);
|
||||||
else
|
else
|
||||||
res = sdmmc_storage_write(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
res = sdmmc_storage_write(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||||
if (!res)
|
if (!res)
|
||||||
|
@ -219,7 +149,7 @@ static int nx_emmc_bis_read_block_normal(u32 sector, u32 count, void *buff)
|
||||||
|
|
||||||
// If not reading from cache, do a regular read and decrypt.
|
// If not reading from cache, do a regular read and decrypt.
|
||||||
if (!emu_offset)
|
if (!emu_offset)
|
||||||
res = nx_emmc_part_read(&emmc_storage, system_part, sector, count, bis_cache->dma_buff);
|
res = emmc_part_read(system_part, sector, count, bis_cache->dma_buff);
|
||||||
else
|
else
|
||||||
res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
|
||||||
if (!res)
|
if (!res)
|
||||||
|
@ -240,7 +170,7 @@ static int nx_emmc_bis_read_block_normal(u32 sector, u32 count, void *buff)
|
||||||
tweak_exp = sector_in_cluster;
|
tweak_exp = sector_in_cluster;
|
||||||
|
|
||||||
// Maximum one cluster (1 XTS crypto block 16KB).
|
// Maximum one cluster (1 XTS crypto block 16KB).
|
||||||
if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, tweak, regen_tweak, tweak_exp, prev_cluster, buff, bis_cache->dma_buff, count * NX_EMMC_BLOCKSIZE))
|
if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, DECRYPT, prev_cluster, tweak, regen_tweak, tweak_exp, buff, bis_cache->dma_buff, count * EMMC_BLOCKSIZE))
|
||||||
return 1; // R/W error.
|
return 1; // R/W error.
|
||||||
|
|
||||||
prev_sector = sector + count - 1;
|
prev_sector = sector + count - 1;
|
||||||
|
@ -260,7 +190,7 @@ static int nx_emmc_bis_read_block_cached(u32 sector, u32 count, void *buff)
|
||||||
// Read from cached cluster.
|
// Read from cached cluster.
|
||||||
if (lookup_idx != (u32)BIS_CACHE_LOOKUP_TBL_EMPTY_ENTRY)
|
if (lookup_idx != (u32)BIS_CACHE_LOOKUP_TBL_EMPTY_ENTRY)
|
||||||
{
|
{
|
||||||
memcpy(buff, bis_cache->clusters[lookup_idx].data + sector_in_cluster * NX_EMMC_BLOCKSIZE, count * NX_EMMC_BLOCKSIZE);
|
memcpy(buff, bis_cache->clusters[lookup_idx].data + sector_in_cluster * EMMC_BLOCKSIZE, count * EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
return 0; // Success.
|
return 0; // Success.
|
||||||
}
|
}
|
||||||
|
@ -276,19 +206,19 @@ static int nx_emmc_bis_read_block_cached(u32 sector, u32 count, void *buff)
|
||||||
|
|
||||||
// Read the whole cluster the sector resides in.
|
// Read the whole cluster the sector resides in.
|
||||||
if (!emu_offset)
|
if (!emu_offset)
|
||||||
res = nx_emmc_part_read(&emmc_storage, system_part, cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
res = emmc_part_read(system_part, cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
||||||
else
|
else
|
||||||
res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
|
||||||
if (!res)
|
if (!res)
|
||||||
return 1; // R/W error.
|
return 1; // R/W error.
|
||||||
|
|
||||||
// Decrypt cluster.
|
// Decrypt cluster.
|
||||||
if (!_nx_aes_xts_crypt_sec(ks_tweak, ks_crypt, 0, cache_tweak, true, 0, cluster, bis_cache->dma_buff, bis_cache->dma_buff, BIS_CLUSTER_SIZE))
|
if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, DECRYPT, cluster, cache_tweak, true, 0, bis_cache->dma_buff, bis_cache->dma_buff, BIS_CLUSTER_SIZE))
|
||||||
return 1; // Decryption error.
|
return 1; // Decryption error.
|
||||||
|
|
||||||
// Copy to cluster cache.
|
// Copy to cluster cache.
|
||||||
memcpy(bis_cache->clusters[bis_cache->top_idx].data, bis_cache->dma_buff, BIS_CLUSTER_SIZE);
|
memcpy(bis_cache->clusters[bis_cache->top_idx].data, bis_cache->dma_buff, BIS_CLUSTER_SIZE);
|
||||||
memcpy(buff, bis_cache->dma_buff + sector_in_cluster * NX_EMMC_BLOCKSIZE, count * NX_EMMC_BLOCKSIZE);
|
memcpy(buff, bis_cache->dma_buff + sector_in_cluster * EMMC_BLOCKSIZE, count * EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
// Increment cache count.
|
// Increment cache count.
|
||||||
bis_cache->top_idx++;
|
bis_cache->top_idx++;
|
||||||
|
@ -320,7 +250,7 @@ int nx_emmc_bis_read(u32 sector, u32 count, void *buff)
|
||||||
|
|
||||||
count -= sct_cnt;
|
count -= sct_cnt;
|
||||||
curr_sct += sct_cnt;
|
curr_sct += sct_cnt;
|
||||||
buf += sct_cnt * NX_EMMC_BLOCKSIZE;
|
buf += sct_cnt * EMMC_BLOCKSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -339,7 +269,7 @@ int nx_emmc_bis_write(u32 sector, u32 count, void *buff)
|
||||||
|
|
||||||
count -= sct_cnt;
|
count -= sct_cnt;
|
||||||
curr_sct += sct_cnt;
|
curr_sct += sct_cnt;
|
||||||
buf += sct_cnt * NX_EMMC_BLOCKSIZE;
|
buf += sct_cnt * EMMC_BLOCKSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -20,8 +20,6 @@
|
||||||
|
|
||||||
#include <bdk.h>
|
#include <bdk.h>
|
||||||
|
|
||||||
#include "../storage/nx_emmc.h"
|
|
||||||
|
|
||||||
typedef struct _nx_emmc_cal0_spk_t
|
typedef struct _nx_emmc_cal0_spk_t
|
||||||
{
|
{
|
||||||
u16 unk0;
|
u16 unk0;
|
||||||
|
|
Loading…
Reference in a new issue