Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
267f02c2f6 |
2
Makefile
2
Makefile
@@ -44,7 +44,7 @@ OBJS = $(addprefix $(BUILD)/, \
|
||||
OBJS += $(addprefix $(BUILD)/, diskio.o ff.o ffunicode.o)
|
||||
|
||||
ARCH := -march=armv4t -mtune=arm7tdmi -mthumb -mthumb-interwork
|
||||
CFLAGS = $(ARCH) -Os -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11# -Wall
|
||||
CFLAGS = $(ARCH) -O2 -nostdlib -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-inline -std=gnu11# -Wall
|
||||
LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
@@ -200,7 +200,7 @@
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
#define FF_FS_NOFSINFO 1
|
||||
#define FF_FS_NOFSINFO 0
|
||||
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||
/ option, and f_getfree() function at first time after volume mount will force
|
||||
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||
@@ -224,7 +224,7 @@
|
||||
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
|
||||
|
||||
|
||||
#define FF_FS_EXFAT 1
|
||||
#define FF_FS_EXFAT 0
|
||||
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
|
||||
/ When enable exFAT, also LFN needs to be enabled.
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
227
ipl/hos.c
227
ipl/hos.c
@@ -59,13 +59,6 @@ static const u8 ckey_keyseed[0x10] =
|
||||
static const u8 key8_keyseed[] =
|
||||
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
|
||||
|
||||
static const u8 new_masterkey_seed[0x10] =
|
||||
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
|
||||
|
||||
static const u8 new_per_console_key[0x10] =
|
||||
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
|
||||
|
||||
|
||||
static void _se_lock()
|
||||
{
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
@@ -93,8 +86,8 @@ static void _se_lock()
|
||||
gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
|
||||
}
|
||||
|
||||
// <-- key derivation algorithm
|
||||
static int keygen(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||
//Key derivation for < 4.0.0
|
||||
static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||
{
|
||||
u8 *tmp = (u8 *)malloc(0x10);
|
||||
|
||||
@@ -104,143 +97,47 @@ static int keygen(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||
//Get TSEC key.
|
||||
if (tsec_query(tmp, 1, tsec_fw) < 0)
|
||||
return 0;
|
||||
|
||||
se_aes_key_set(13, tmp, 0x10);
|
||||
|
||||
//Derive keyblob key from TSEC+SBK.
|
||||
memcpy(tmp, keyblob_keyseeds[kb], 0x10);
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||
se_aes_unwrap_key(13, 14, tmp);
|
||||
se_aes_key_clear(14);
|
||||
|
||||
//TODO: verify keyblob CMAC.
|
||||
//se_aes_unwrap_key(11, 13, cmac_keyseed);
|
||||
//se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0);
|
||||
//if (!memcmp(keyblob, tmp, 0x10))
|
||||
// return 0;
|
||||
|
||||
switch(kb) {
|
||||
// 1.0.0~2.0.0 FW
|
||||
case 0: {
|
||||
//Decrypt keyblob and set keyslots.
|
||||
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10);
|
||||
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
||||
|
||||
//Derive keyblob key from TSEC+SBK.
|
||||
memcpy(tmp, keyblob_keyseeds[kb], 0x10);
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||
se_aes_unwrap_key(13, 14, tmp);
|
||||
se_aes_key_clear(14);
|
||||
//TODO: for some reason SE likes to hang if we don't execute an operation here.
|
||||
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||
se_aes_crypt_block_ecb(12, 0, tmp, tmp);
|
||||
|
||||
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10);
|
||||
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
||||
//Generate retail master key.
|
||||
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||
se_aes_unwrap_key(12, 12, tmp);
|
||||
|
||||
//TODO: for some reason SE likes to hang if we don't execute an operation here.
|
||||
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||
se_aes_crypt_block_ecb(12, 0, tmp, tmp);
|
||||
memcpy(tmp, key8_keyseed, 0x10);
|
||||
se_key_acc_ctrl(8, 0x15);
|
||||
se_aes_unwrap_key(8, 12, tmp);
|
||||
|
||||
//Generate retail master key.
|
||||
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||
se_aes_unwrap_key(12, 12, tmp);
|
||||
//Generate console specific key.
|
||||
memcpy(tmp, ckey_keyseed, 0x10);
|
||||
se_aes_unwrap_key(13, 13, tmp);
|
||||
|
||||
//Generate console specific key.
|
||||
memcpy(tmp, ckey_keyseed, 0x10);
|
||||
se_aes_unwrap_key(13, 13, tmp);
|
||||
se_key_acc_ctrl(12, 0xFF);
|
||||
se_key_acc_ctrl(13, 0xFF);
|
||||
|
||||
memcpy(tmp, key8_keyseed, 0x10);
|
||||
se_key_acc_ctrl(8, 0x15);
|
||||
se_aes_unwrap_key(8, 12, tmp);
|
||||
|
||||
se_key_acc_ctrl(12, 0xFF);
|
||||
se_key_acc_ctrl(13, 0xFF);
|
||||
}
|
||||
break;
|
||||
// 3.0.0~3.0.1 FW
|
||||
case 1:
|
||||
case 2: {
|
||||
|
||||
// keyslot 10
|
||||
memcpy(tmp, keyblob_keyseeds[0], 0x10);
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||
se_aes_unwrap_key(10, 14, tmp);
|
||||
|
||||
// keyslot 13
|
||||
memcpy(tmp, keyblob_keyseeds[kb], 0x10);
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||
se_aes_unwrap_key(13, 14, tmp);
|
||||
|
||||
se_aes_key_clear(14);
|
||||
se_aes_key_clear(15);
|
||||
|
||||
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10);
|
||||
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
||||
|
||||
//TODO: for some reason SE likes to hang if we don't execute an operation here.
|
||||
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||
se_aes_crypt_block_ecb(12, 0, tmp, tmp);
|
||||
|
||||
//Generate retail master key.
|
||||
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||
se_aes_unwrap_key(12, 12, tmp);
|
||||
|
||||
//Generate console specific key.
|
||||
memcpy(tmp, ckey_keyseed, 0x10);
|
||||
se_aes_unwrap_key(13, 10, tmp);
|
||||
se_aes_key_clear(10);
|
||||
|
||||
memcpy(tmp, key8_keyseed, 0x10);
|
||||
se_key_acc_ctrl(8, 0x15);
|
||||
se_aes_unwrap_key(8, 12, tmp);
|
||||
|
||||
se_key_acc_ctrl(12, 0xFF);
|
||||
se_key_acc_ctrl(13, 0xFF);
|
||||
}
|
||||
break;
|
||||
|
||||
// 4.0.0~5.0.1 FW
|
||||
case 3:
|
||||
case 4: {
|
||||
se_key_acc_ctrl(14, 0x15);
|
||||
se_key_acc_ctrl(15, 0x15);
|
||||
|
||||
// keyslot 15
|
||||
memcpy(tmp, keyblob_keyseeds[0], 0x10);
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||
se_aes_unwrap_key(15, 14, tmp);
|
||||
|
||||
// keyslot 13
|
||||
memcpy(tmp, keyblob_keyseeds[kb], 0x10);
|
||||
se_aes_crypt_block_ecb(13, 0, tmp, tmp);
|
||||
se_aes_unwrap_key(13, 14, tmp);
|
||||
|
||||
se_aes_key_clear(14);
|
||||
|
||||
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10);
|
||||
se_aes_key_set(12, keyblob + 0x20, 0x10);
|
||||
|
||||
//TODO: for some reason SE likes to hang if we don't execute an operation here.
|
||||
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||
se_aes_crypt_block_ecb(12, 0, tmp, tmp);
|
||||
|
||||
// keyslot 14
|
||||
memcpy(tmp, new_masterkey_seed, 0x10);
|
||||
se_aes_unwrap_key(14, 12, tmp);
|
||||
|
||||
// keyslot 12
|
||||
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||
se_aes_unwrap_key(12, 12, tmp);
|
||||
|
||||
// keyslot 13
|
||||
memcpy(tmp, new_per_console_key, 0x10);
|
||||
se_aes_unwrap_key(13, 15, tmp);
|
||||
|
||||
// keyslot 15
|
||||
memcpy(tmp, ckey_keyseed, 0x10);
|
||||
se_aes_unwrap_key(15, 13, tmp);
|
||||
|
||||
se_key_acc_ctrl(12, 0xFF);
|
||||
se_key_acc_ctrl(15, 0xFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
|
||||
typedef struct _launch_ctxt_t
|
||||
{
|
||||
void *keyblob;
|
||||
@@ -428,12 +325,12 @@ int hos_launch(ini_sec_t *cfg)
|
||||
return 0;
|
||||
|
||||
//XXX: remove this once we support 3+.
|
||||
//if (ctxt.pkg1_id->kb > 0)
|
||||
// return 0;
|
||||
if (ctxt.pkg1_id->kb > 0)
|
||||
return 0;
|
||||
|
||||
DPRINTF("loaded pkg1 and keyblob\n");
|
||||
//Generate keys.
|
||||
keygen(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off);
|
||||
_keygen_1(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off);
|
||||
DPRINTF("generated keys\n");
|
||||
//Decrypt and unpack package1 if we require parts of it.
|
||||
if (!ctxt.warmboot || !ctxt.secmon)
|
||||
@@ -450,57 +347,41 @@ DPRINTF("decrypted and unpacked pkg1\n");
|
||||
//Set warmboot address in PMC.
|
||||
PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000;
|
||||
//Replace 'SecureMonitor' if requested.
|
||||
if (ctxt.secmon) {
|
||||
if (ctxt.secmon)
|
||||
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Else we patch it to allow for an unsigned package2.
|
||||
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
|
||||
if (secmon_patchset != NULL) {
|
||||
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
|
||||
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
|
||||
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
|
||||
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
|
||||
}
|
||||
DPRINTF("loaded warmboot.bin and secmon\n");
|
||||
|
||||
DPRINTF("loaded warmboot.bin and secmon\n");
|
||||
|
||||
//Read package2.
|
||||
if (!_read_emmc_pkg2(&ctxt))
|
||||
return 0;
|
||||
//Read package2.
|
||||
if (!_read_emmc_pkg2(&ctxt))
|
||||
return 0;
|
||||
DPRINTF("read pkg2\n");
|
||||
//Decrypt package2 and parse KIP1 blobs in INI1 section.
|
||||
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
|
||||
|
||||
DPRINTF("read pkg2\n");
|
||||
//Decrypt package2 and parse KIP1 blobs in INI1 section.
|
||||
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
|
||||
|
||||
LIST_INIT(kip1_info);
|
||||
pkg2_parse_kips(&kip1_info, pkg2_hdr);
|
||||
|
||||
DPRINTF("parsed ini1\n");
|
||||
|
||||
//Use the kernel included in package2 in case we didn't load one already.
|
||||
if (!ctxt.kernel)
|
||||
{
|
||||
ctxt.kernel = pkg2_hdr->data;
|
||||
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
|
||||
}
|
||||
|
||||
//Merge extra KIP1s into loaded ones.
|
||||
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
|
||||
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
|
||||
|
||||
//Rebuild and encrypt package2.
|
||||
pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info);
|
||||
DPRINTF("rebuilt pkg2\n");
|
||||
} else {
|
||||
//Read package2.
|
||||
if (!_read_emmc_pkg2(&ctxt))
|
||||
return 0;
|
||||
|
||||
DPRINTF("read pkg2\n");
|
||||
memcpy((void *)0xA9800000, ctxt.pkg2, ctxt.pkg2_size);
|
||||
}
|
||||
LIST_INIT(kip1_info);
|
||||
pkg2_parse_kips(&kip1_info, pkg2_hdr);
|
||||
DPRINTF("parsed ini1\n");
|
||||
//Use the kernel included in package2 in case we didn't load one already.
|
||||
if (!ctxt.kernel)
|
||||
{
|
||||
ctxt.kernel = pkg2_hdr->data;
|
||||
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
|
||||
}
|
||||
|
||||
//Merge extra KIP1s into loaded ones.
|
||||
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
|
||||
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
|
||||
|
||||
//Rebuild and encrypt package2.
|
||||
pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info);
|
||||
DPRINTF("rebuilt pkg2\n");
|
||||
//Clear 'BootConfig'.
|
||||
memset((void *)0x4003D000, 0, 0x3000);
|
||||
|
||||
|
||||
658
ipl/main.c
658
ipl/main.c
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <alloca.h>
|
||||
|
||||
#include "clock.h"
|
||||
#include "uart.h"
|
||||
@@ -171,10 +169,6 @@ void config_se_brom()
|
||||
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
|
||||
//Lock SSK (although it's not set and unused anyways).
|
||||
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E;
|
||||
// Clear the boot reason to avoid problems later
|
||||
PMC(APBDEV_PMC_SCRATCH200) = 0x0;
|
||||
PMC(APBDEV_PMC_RST_STATUS_0) = 0x0;
|
||||
PMC(APBDEV_PMC_SCRATCH49_0) = 0x0;
|
||||
}
|
||||
|
||||
void config_hw()
|
||||
@@ -386,247 +380,40 @@ void *sd_file_read(char *path)
|
||||
|
||||
int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
{
|
||||
static const u32 FAT32_FILESIZE_LIMIT = 0xFFFFFFFF;
|
||||
static const u32 MULTIPART_SPLIT_SIZE = (1u << 31);
|
||||
static const u32 SECTORS_TO_MB_COEFF = 0x800;
|
||||
|
||||
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
||||
u32 currPartIdx = 0;
|
||||
u32 numSplitParts = 0;
|
||||
u32 maxSplitParts = 0;
|
||||
int isSmallSdCard = 0;
|
||||
int partialDumpInProgress = 0;
|
||||
int res = 0;
|
||||
int ignoreWriteErrors = 0;
|
||||
char* outFilename = sd_path;
|
||||
u32 sdPathLen = strlen(sd_path);
|
||||
|
||||
FIL partialIdxFp;
|
||||
char partialIdxFilename[12];
|
||||
memcpy(partialIdxFilename, "partial.idx", 11);
|
||||
partialIdxFilename[11] = 0;
|
||||
|
||||
gfx_printf(&gfx_con, "SD Card free space: %dMB, Total dump size %dMB\n",
|
||||
sd_fs.free_clst * sd_fs.csize / SECTORS_TO_MB_COEFF,
|
||||
totalSectors / SECTORS_TO_MB_COEFF);
|
||||
|
||||
// Check if the USER partition or the RAW eMMC fits the sd card free space
|
||||
if (totalSectors > (sd_fs.free_clst * sd_fs.csize))
|
||||
{
|
||||
isSmallSdCard = 1;
|
||||
|
||||
gfx_printf(&gfx_con, "%kSD card free space is smaller than dump total size.%k\n", 0xFF00BAFF, 0xFFFFFFFF);
|
||||
|
||||
maxSplitParts = (sd_fs.free_clst * sd_fs.csize) / (MULTIPART_SPLIT_SIZE / 512);
|
||||
|
||||
if (!maxSplitParts)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kNot enough free space for partial dumping.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Check if we continueing a previous raw eMMC dump in progress.
|
||||
if (isSmallSdCard)
|
||||
{
|
||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_READ) == FR_OK)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFound partial dump in progress. Continuing...%k\n", 0xFF14FDAE, 0xFFFFFFFF);
|
||||
|
||||
partialDumpInProgress = 1;
|
||||
|
||||
f_read(&partialIdxFp, &currPartIdx, 4, NULL);
|
||||
f_close(&partialIdxFp);
|
||||
|
||||
// Increase maxSplitParts to accommodate previously dumped parts
|
||||
maxSplitParts += currPartIdx;
|
||||
}
|
||||
else
|
||||
gfx_printf(&gfx_con, "%kContinuing with partial dumping...%k\n", 0xFF00BAFF, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
// Check if filesystem is FAT32 or the free space is smaller and dump in parts
|
||||
if (((sd_fs.fs_type != FS_EXFAT) || isSmallSdCard) && totalSectors > (FAT32_FILESIZE_LIMIT/NX_EMMC_BLOCKSIZE))
|
||||
{
|
||||
static const u32 MULTIPART_SPLIT_SECTORS = MULTIPART_SPLIT_SIZE/NX_EMMC_BLOCKSIZE;
|
||||
numSplitParts = (totalSectors+MULTIPART_SPLIT_SECTORS-1)/MULTIPART_SPLIT_SECTORS;
|
||||
|
||||
outFilename = alloca(sdPathLen+4);
|
||||
memcpy(outFilename, sd_path, sdPathLen);
|
||||
outFilename[sdPathLen++] = '.';
|
||||
|
||||
if (!partialDumpInProgress)
|
||||
{
|
||||
outFilename[sdPathLen] = '0';
|
||||
if (numSplitParts >= 10)
|
||||
{
|
||||
outFilename[sdPathLen+1] = '0';
|
||||
outFilename[sdPathLen+2] = 0;
|
||||
}
|
||||
else
|
||||
outFilename[sdPathLen+1] = 0;
|
||||
}
|
||||
// Continue from where we left, if partial dump in proggress.
|
||||
else
|
||||
{
|
||||
if (numSplitParts >= 10 && currPartIdx < 10)
|
||||
{
|
||||
outFilename[sdPathLen] = '0';
|
||||
itoa(currPartIdx, &outFilename[sdPathLen+1], 10);
|
||||
}
|
||||
else
|
||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
||||
}
|
||||
}
|
||||
|
||||
FIL fp;
|
||||
if (f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
|
||||
if (f_open(&fp, sd_path, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
|
||||
return 0;
|
||||
|
||||
static const u32 NUM_SECTORS_PER_ITER = 512;
|
||||
u8 *buf = (u8 *)malloc(NX_EMMC_BLOCKSIZE * NUM_SECTORS_PER_ITER);
|
||||
u8 *buf = (u8 *)malloc(NX_EMMC_BLOCKSIZE * 512);
|
||||
|
||||
u32 total = part->lba_end - part->lba_start + 1;
|
||||
u32 lba_curr = part->lba_start;
|
||||
u32 bytesWritten = 0;
|
||||
u32 prevPct = 200;
|
||||
int retryCount = 0;
|
||||
|
||||
// Continue from where we left, if partial dump in proggress.
|
||||
if (partialDumpInProgress)
|
||||
while(total > 0)
|
||||
{
|
||||
lba_curr += currPartIdx * (MULTIPART_SPLIT_SIZE / NX_EMMC_BLOCKSIZE);
|
||||
totalSectors -= currPartIdx * (MULTIPART_SPLIT_SIZE / NX_EMMC_BLOCKSIZE);
|
||||
}
|
||||
u32 num = MIN(total, 512);
|
||||
|
||||
while(totalSectors > 0)
|
||||
{
|
||||
if (numSplitParts != 0 && bytesWritten >= MULTIPART_SPLIT_SIZE)
|
||||
if(!sdmmc_storage_read(storage, lba_curr, num, buf))
|
||||
{
|
||||
f_close(&fp);
|
||||
memset(&fp, 0, sizeof(fp));
|
||||
currPartIdx++;
|
||||
|
||||
if (numSplitParts >= 10 && currPartIdx < 10)
|
||||
{
|
||||
outFilename[sdPathLen] = '0';
|
||||
itoa(currPartIdx, &outFilename[sdPathLen+1], 10);
|
||||
}
|
||||
else
|
||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
||||
|
||||
// More parts to dump that do not currently fit the sd card free space
|
||||
if ((isSmallSdCard && currPartIdx >= maxSplitParts) || (res && !ignoreWriteErrors))
|
||||
{
|
||||
// Create partial dump index file
|
||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
|
||||
{
|
||||
f_write(&partialIdxFp, &currPartIdx, 4, NULL);
|
||||
f_close(&partialIdxFp);
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k\nError creating partial.idx file.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
if (res && !ignoreWriteErrors)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k\nPress any key and try again.%k\n",
|
||||
0xFF0000FF, 0xFFFFFFFF);
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
gfx_puts(&gfx_con, "\n1. Press any key and Power off Switch from the main menu.\n\
|
||||
2. Move the files from SD card to free space.\n \
|
||||
Don\'t move the partial.idx file!\n\
|
||||
3. Unplug and re-plug USB while pressing Vol+.\n\
|
||||
4. Run hekate - ipl again and press Dump RAW eMMC or eMMC USER to continue");
|
||||
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (f_open(&fp, outFilename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
|
||||
{
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
bytesWritten = 0;
|
||||
gfx_printf(&gfx_con, "%kError reading %d blocks @ LBA %08X%k\n",
|
||||
0xFF0000FF, num, lba_curr, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
|
||||
retryCount = 0;
|
||||
u32 num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||
while(!sdmmc_storage_read(storage, lba_curr, num, buf))
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kError reading %d blocks @ LBA %08X from eMMC (try %d)%k\n",
|
||||
0xFF0000FF, num, lba_curr, ++retryCount, 0xFFFFFFFF);
|
||||
|
||||
sleep(500000);
|
||||
if (retryCount >= 10)
|
||||
goto out;
|
||||
}
|
||||
res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||
if (res && !ignoreWriteErrors)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFatal error %d when writing to SD Card%k\n\
|
||||
Press VOL to abort and try again\nPress POWER to ignore errors (will produce a corrupt dump)",
|
||||
0xFF0000FF, res, 0xFFFFFFFF);
|
||||
u32 btn = btn_wait();
|
||||
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
bytesWritten = MULTIPART_SPLIT_SIZE - num * NX_EMMC_BLOCKSIZE;
|
||||
currPartIdx--;
|
||||
}
|
||||
else
|
||||
{
|
||||
ignoreWriteErrors = 1;
|
||||
}
|
||||
}
|
||||
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
{
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct);
|
||||
prevPct = pct;
|
||||
}
|
||||
f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||
u32 pct = ((lba_curr - part->lba_start) * 100) / (part->lba_end - part->lba_start);
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, pct);
|
||||
|
||||
lba_curr += num;
|
||||
totalSectors -= num;
|
||||
bytesWritten += num * NX_EMMC_BLOCKSIZE;
|
||||
|
||||
//force a flush after a lot of data if not splitting
|
||||
if (numSplitParts == 0 && bytesWritten >= MULTIPART_SPLIT_SIZE)
|
||||
{
|
||||
f_sync(&fp);
|
||||
bytesWritten = 0;
|
||||
}
|
||||
total -= num;
|
||||
}
|
||||
tui_pbar(&gfx_con, 0, gfx_con.y, 100);
|
||||
|
||||
out:;
|
||||
free(buf);
|
||||
f_close(&fp);
|
||||
// Partial dump done. Remove partial dump index file.
|
||||
if(partialDumpInProgress)
|
||||
{
|
||||
f_unlink(partialIdxFilename);
|
||||
gfx_printf(&gfx_con, "\n\nYou can now join the files and get the complete raw eMMC dump.\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DUMP_BOOT = 1,
|
||||
DUMP_SYSTEM = 2,
|
||||
DUMP_USER = 4,
|
||||
DUMP_RAW = 8
|
||||
} dumpType_t;
|
||||
|
||||
static void dump_emmc_selected(dumpType_t dumpType)
|
||||
void dump_emmc()
|
||||
{
|
||||
gfx_clear(&gfx_ctxt, 0xFF000000);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
@@ -636,11 +423,53 @@ static void dump_emmc_selected(dumpType_t dumpType)
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if(!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
gfx_puts(&gfx_con, "Checking for available free space...\n");
|
||||
// Get SD Card free space for partial dumping
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
int i = 0;
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%02d: %s (%08X-%08X)\n", i++,
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
|
||||
//XXX: skip these for now.
|
||||
if (//!strcmp(part->name, "SYSTEM") ||
|
||||
!strcmp(part->name, "USER"))
|
||||
{
|
||||
gfx_puts(&gfx_con, "Skipped.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
}
|
||||
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
out:;
|
||||
sleep(100000);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void dump_boot0_emmc()
|
||||
{
|
||||
emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t));
|
||||
gfx_clear(&gfx_ctxt, 0xFF000000);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
@@ -650,85 +479,295 @@ static void dump_emmc_selected(dumpType_t dumpType)
|
||||
gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
|
||||
int i = 0;
|
||||
if (dumpType & DUMP_BOOT)
|
||||
{
|
||||
static const u32 BOOT_PART_SIZE = 0x400000;
|
||||
//LIST_INIT(gpt);
|
||||
//nx_emmc_gpt_parse(&gpt, &storage);
|
||||
|
||||
emmc_part_t bootPart;
|
||||
memset(&bootPart, 0, sizeof(bootPart));
|
||||
bootPart.lba_start = 0;
|
||||
bootPart.lba_end = (BOOT_PART_SIZE/NX_EMMC_BLOCKSIZE)-1;
|
||||
for (i=0; i<2; i++)
|
||||
{
|
||||
memcpy(bootPart.name, "BOOT", 4);
|
||||
bootPart.name[4] = (u8)('0' + i);
|
||||
bootPart.name[5] = 0;
|
||||
part->name[0] = 0x62;
|
||||
part->name[1] = 0x6f;
|
||||
part->name[2] = 0x6f;
|
||||
part->name[3] = 0x74;
|
||||
part->name[4] = 0x5f;
|
||||
part->name[6] = 0x0;
|
||||
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%08X-%08X)%k\n", 0xFFFFDD00, i,
|
||||
bootPart.name, bootPart.lba_start, bootPart.lba_end, 0xFFFFFFFF);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, i+1);
|
||||
dump_emmc_part(bootPart.name, &storage, &bootPart);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
if ((dumpType & DUMP_SYSTEM) || (dumpType & DUMP_USER) || (dumpType & DUMP_RAW))
|
||||
{
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
|
||||
if ((dumpType & DUMP_SYSTEM) || (dumpType & DUMP_USER))
|
||||
{
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
if ((dumpType & DUMP_USER) == 0 && !strcmp(part->name, "USER"))
|
||||
continue;
|
||||
if ((dumpType & DUMP_SYSTEM) == 0 && strcmp(part->name, "USER"))
|
||||
continue;
|
||||
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%08X-%08X)%k\n", 0xFFFFDD00, i++,
|
||||
part->name, part->lba_start, part->lba_end, 0xFFFFFFFF);
|
||||
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (dumpType & DUMP_RAW)
|
||||
{
|
||||
static const u32 RAW_AREA_NUM_SECTORS = 0x3A3E000;
|
||||
|
||||
emmc_part_t rawPart;
|
||||
memset(&rawPart, 0, sizeof(rawPart));
|
||||
rawPart.lba_start = 0;
|
||||
rawPart.lba_end = RAW_AREA_NUM_SECTORS-1;
|
||||
strcpy(rawPart.name, "rawnand.bin");
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k%02d: %s (%08X-%08X)%k\n", 0xFFFFDD00, i++,
|
||||
rawPart.name, rawPart.lba_start, rawPart.lba_end, 0xFFFFFFFF);
|
||||
|
||||
dump_emmc_part(rawPart.name, &storage, &rawPart);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
part->name[5] = 0x30;
|
||||
part->lba_start = 0x0000;
|
||||
part->lba_end = 0x1FFF;
|
||||
gfx_printf(&gfx_con, "%s (%08X-%08X)\n",
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
out:;
|
||||
sleep(100000);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void dump_boot1_emmc()
|
||||
{
|
||||
emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t));
|
||||
gfx_clear(&gfx_ctxt, 0xFF000000);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if(!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, 2);
|
||||
|
||||
//LIST_INIT(gpt);
|
||||
//nx_emmc_gpt_parse(&gpt, &storage);
|
||||
|
||||
part->name[0] = 0x62;
|
||||
part->name[1] = 0x6f;
|
||||
part->name[2] = 0x6f;
|
||||
part->name[3] = 0x74;
|
||||
part->name[4] = 0x5f;
|
||||
part->name[6] = 0x0;
|
||||
|
||||
part->name[5] = 0x31;
|
||||
part->lba_start = 0x0000;
|
||||
part->lba_end = 0x1FFF;
|
||||
gfx_printf(&gfx_con, "%s (%08X-%08X)\n",
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
out:;
|
||||
sleep(100000);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void dump_raw_emmc()
|
||||
{
|
||||
emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t));
|
||||
gfx_clear(&gfx_ctxt, 0xFF000000);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if(!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
|
||||
//LIST_INIT(gpt);
|
||||
//nx_emmc_gpt_parse(&gpt, &storage);
|
||||
|
||||
part->name[0] = 0x70;
|
||||
part->name[1] = 0x61;
|
||||
part->name[2] = 0x72;
|
||||
part->name[3] = 0x74;
|
||||
part->name[4] = 0x5f;
|
||||
part->name[6] = 0x0;
|
||||
|
||||
part->name[5] = 0x30;
|
||||
part->lba_start = 0x000000;
|
||||
part->lba_end = 0x7FFFFF;
|
||||
gfx_printf(&gfx_con, "%s (%08X-%08X)\n",
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
part->name[5] = 0x31;
|
||||
part->lba_start = 0x800000;
|
||||
part->lba_end = 0xFFFFFF;
|
||||
gfx_printf(&gfx_con, "%s (%08X-%08X)\n",
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
out:;
|
||||
sleep(100000);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void dump_raw_emmc1()
|
||||
{
|
||||
emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t));
|
||||
gfx_clear(&gfx_ctxt, 0xFF000000);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if(!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
|
||||
//LIST_INIT(gpt);
|
||||
//nx_emmc_gpt_parse(&gpt, &storage);
|
||||
|
||||
part->name[0] = 0x70;
|
||||
part->name[1] = 0x61;
|
||||
part->name[2] = 0x72;
|
||||
part->name[3] = 0x74;
|
||||
part->name[4] = 0x5f;
|
||||
part->name[6] = 0x0;
|
||||
|
||||
part->name[5] = 0x32;
|
||||
part->lba_start = 0x1000000;
|
||||
part->lba_end = 0x17FFFFF;
|
||||
gfx_printf(&gfx_con, "%s (%08X-%08X)\n",
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
part->name[5] = 0x33;
|
||||
part->lba_start = 0x1800000;
|
||||
part->lba_end = 0x1FFFFFF;
|
||||
gfx_printf(&gfx_con, "%s (%08X-%08X)\n",
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
out:;
|
||||
sleep(100000);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void dump_raw_emmc2()
|
||||
{
|
||||
emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t));
|
||||
gfx_clear(&gfx_ctxt, 0xFF000000);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if(!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
|
||||
//LIST_INIT(gpt);
|
||||
//nx_emmc_gpt_parse(&gpt, &storage);
|
||||
|
||||
part->name[0] = 0x70;
|
||||
part->name[1] = 0x61;
|
||||
part->name[2] = 0x72;
|
||||
part->name[3] = 0x74;
|
||||
part->name[4] = 0x5f;
|
||||
part->name[6] = 0x0;
|
||||
|
||||
part->name[5] = 0x34;
|
||||
part->lba_start = 0x2000000;
|
||||
part->lba_end = 0x27FFFFF;
|
||||
gfx_printf(&gfx_con, "%s (%08X-%08X)\n",
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
part->name[5] = 0x35;
|
||||
part->lba_start = 0x2800000;
|
||||
part->lba_end = 0x2FFFFFF;
|
||||
gfx_printf(&gfx_con, "%s (%08X-%08X)\n",
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
sdmmc_storage_end(&storage);
|
||||
|
||||
out:;
|
||||
sleep(100000);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void dump_raw_emmc3()
|
||||
{
|
||||
emmc_part_t *part = (emmc_part_t *)malloc(sizeof(emmc_part_t));
|
||||
gfx_clear(&gfx_ctxt, 0xFF000000);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
if (!sd_mount())
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdmmc_storage_t storage;
|
||||
sdmmc_t sdmmc;
|
||||
if(!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to init eMMC.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
|
||||
//LIST_INIT(gpt);
|
||||
//nx_emmc_gpt_parse(&gpt, &storage);
|
||||
|
||||
part->name[0] = 0x70;
|
||||
part->name[1] = 0x61;
|
||||
part->name[2] = 0x72;
|
||||
part->name[3] = 0x74;
|
||||
part->name[4] = 0x5f;
|
||||
part->name[6] = 0x0;
|
||||
|
||||
part->name[5] = 0x36;
|
||||
part->lba_start = 0x3000000;
|
||||
part->lba_end = 0x37FFFFF;
|
||||
gfx_printf(&gfx_con, "%s (%08X-%08X)\n",
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
part->name[5] = 0x37;
|
||||
part->lba_start = 0x3800000;
|
||||
part->lba_end = 0x3A3DFFF;
|
||||
gfx_printf(&gfx_con, "%s (%08X-%08X)\n",
|
||||
part->name, part->lba_start, part->lba_end);
|
||||
dump_emmc_part(part->name, &storage, part);
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
sdmmc_storage_end(&storage);
|
||||
gfx_puts(&gfx_con, "Done. Press any key.\n");
|
||||
|
||||
out:;
|
||||
sleep(100000);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void dump_emmc_system() { dump_emmc_selected(DUMP_SYSTEM); }
|
||||
void dump_emmc_user() { dump_emmc_selected(DUMP_USER); }
|
||||
void dump_emmc_boot() { dump_emmc_selected(DUMP_BOOT); }
|
||||
void dump_emmc_rawnand() { dump_emmc_selected(DUMP_RAW); }
|
||||
|
||||
void launch_firmware()
|
||||
{
|
||||
@@ -839,12 +878,25 @@ menu_t menu_cinfo = {
|
||||
"Console info", 0, 0
|
||||
};
|
||||
|
||||
ment_t ment_rawemmc[] = {
|
||||
MDEF_BACK(),
|
||||
MDEF_HANDLER("Boot0", dump_boot0_emmc),
|
||||
MDEF_HANDLER("Boot1", dump_boot1_emmc),
|
||||
MDEF_HANDLER("1st 8GB", dump_raw_emmc),
|
||||
MDEF_HANDLER("2nd 8GB", dump_raw_emmc1),
|
||||
MDEF_HANDLER("3rd 8GB", dump_raw_emmc2),
|
||||
MDEF_HANDLER("4th 8GB", dump_raw_emmc3),
|
||||
MDEF_END()
|
||||
};
|
||||
menu_t menu_rawemmc = {
|
||||
ment_rawemmc,
|
||||
"Dump raw eMMC", 0, 0
|
||||
};
|
||||
|
||||
ment_t ment_tools[] = {
|
||||
MDEF_BACK(),
|
||||
MDEF_HANDLER("Dump RAW eMMC", dump_emmc_rawnand),
|
||||
MDEF_HANDLER("Dump eMMC SYS", dump_emmc_system),
|
||||
MDEF_HANDLER("Dump eMMC USER", dump_emmc_user),
|
||||
MDEF_HANDLER("Dump eMMC BOOT", dump_emmc_boot),
|
||||
MDEF_HANDLER("Dump eMMC", dump_emmc),
|
||||
MDEF_MENU("Dump raw eMMC", &menu_rawemmc),
|
||||
MDEF_END()
|
||||
};
|
||||
menu_t menu_tools = {
|
||||
|
||||
@@ -40,13 +40,6 @@ PATCHSET_DEF(_secmon_2_patchset,
|
||||
{ 0xAC8 + 0xB58, _NOP() } //Sections SHA2.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_secmon_3_patchset,
|
||||
//Patch package2 decryption and signature/hash checks.
|
||||
{ 0xAC8 + 0xA30, _NOP() }, //Header signature.
|
||||
{ 0xAC8 + 0xAC0, _NOP() }, //Version.
|
||||
{ 0xAC8 + 0xADC, _NOP() } //Sections SHA2.
|
||||
);
|
||||
|
||||
/*
|
||||
* package1.1 header: <wb, ldr, sm>
|
||||
* package1.1 layout:
|
||||
@@ -63,7 +56,7 @@ static const pkg1_id_t _pkg1_ids[] = {
|
||||
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, _secmon_2_patchset }, //2.0.0
|
||||
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.0
|
||||
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.1
|
||||
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //4.0.0
|
||||
{ "20170921172629", 3, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //4.0.0
|
||||
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //5.0.0
|
||||
{ NULL, 0, 0, 0, 0 } //End.
|
||||
};
|
||||
|
||||
@@ -41,8 +41,5 @@
|
||||
#define APBDEV_PMC_SCRATCH188 0x810
|
||||
#define APBDEV_PMC_SCRATCH190 0x818
|
||||
#define APBDEV_PMC_SCRATCH200 0x840
|
||||
#define APBDEV_PMC_RST_STATUS_0 0x1B4
|
||||
#define APBDEV_PMC_SECURE_SCRATCH49_0 0x3A4
|
||||
#define APBDEV_PMC_SCRATCH49_0 0x244
|
||||
|
||||
#endif
|
||||
|
||||
15
ipl/sdmmc.c
15
ipl/sdmmc.c
@@ -492,7 +492,7 @@ static int _sd_storage_send_if_cond(sdmmc_storage_t *storage)
|
||||
if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5))
|
||||
return 0;
|
||||
|
||||
return (resp & 0xFF) == 0xAA ? 1 : 0;
|
||||
return (resp & 0xFFF) == 0x1AA ? 1 : 0;
|
||||
}
|
||||
|
||||
static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int is_version_1, int supports_low_voltage)
|
||||
@@ -518,8 +518,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
||||
{
|
||||
if (cond & 0x40000000)
|
||||
storage->has_sector_access = 1;
|
||||
// TODO: Some SD Card incorrectly report low voltage support
|
||||
// Disable it for now
|
||||
|
||||
if (cond & 0x1000000 && supports_low_voltage)
|
||||
{
|
||||
//The low voltage regulator configuration is valid for SDMMC1 only.
|
||||
@@ -538,7 +537,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
||||
}
|
||||
if (get_tmr() > timeout)
|
||||
break;
|
||||
sleep(10000); // Needs to be at least 10ms for some SD Cards
|
||||
sleep(1000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -759,9 +758,6 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
case 1:
|
||||
storage->sec_cnt = (1 + unstuff_bits(csd, 48, 22)) << 10;
|
||||
break;
|
||||
case 2:
|
||||
storage->sec_cnt = (1 + unstuff_bits(csd, 48, 22)) << 10;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("[sd] Unknown CSD structure %d\n", csd_struct);
|
||||
//TODO: I've encountered this with one of my SD cards, but
|
||||
@@ -797,8 +793,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
memcpy(storage->scr, buf, 8);
|
||||
DPRINTF("[sd] got scr\n");
|
||||
|
||||
// Check if card supports a wider bus and if it's not SD Version 1.0
|
||||
if (bus_width == SDMMC_BUS_WIDTH_4 && storage->scr[1] & 4 && (storage->scr[0] & 0xF))
|
||||
if (bus_width == SDMMC_BUS_WIDTH_4 && storage->scr[1] & 4)
|
||||
{
|
||||
if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN))
|
||||
{
|
||||
@@ -820,7 +815,7 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
}
|
||||
DPRINTF("[sd] enabled highspeed (low voltage)\n");
|
||||
}
|
||||
else if (type != 6 && (storage->scr[0] & 0xF) != 0)
|
||||
else if (type != 6 && storage->scr[0] & 0xF != 0)
|
||||
{
|
||||
if (!_sd_storage_enable_highspeed_high_volt(storage, buf))
|
||||
{
|
||||
|
||||
@@ -54,30 +54,24 @@ int sdmmc_get_voltage(sdmmc_t *sdmmc)
|
||||
|
||||
static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
|
||||
{
|
||||
u8 pwr = 0;
|
||||
|
||||
switch (power)
|
||||
{
|
||||
case SDMMC_POWER_OFF:
|
||||
sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
break;
|
||||
case SDMMC_POWER_1_8:
|
||||
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
sdmmc->regs->pwrcon =
|
||||
(sdmmc->regs->pwrcon & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK) |
|
||||
TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
break;
|
||||
case SDMMC_POWER_3_3:
|
||||
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
|
||||
pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (power != SDMMC_POWER_OFF)
|
||||
{
|
||||
pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
sdmmc->regs->pwrcon = pwr;
|
||||
}
|
||||
sdmmc->regs->pwrcon |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user