Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cb76be5fb | ||
|
|
075a9e0a9e | ||
|
|
bda777b1da | ||
|
|
eed1c6945d | ||
|
|
09267b884d | ||
|
|
cbd964306d | ||
|
|
4bfdee8b20 | ||
|
|
4d7f016e3a | ||
|
|
764231b418 | ||
|
|
5ca3bbcaf1 | ||
|
|
b6b000fd28 | ||
|
|
6878e87764 | ||
|
|
0a426db985 | ||
|
|
724970f795 | ||
|
|
5363029e60 | ||
|
|
fc0a94bd84 | ||
|
|
8d6b6c4f0e | ||
|
|
6ebfaa1200 | ||
|
|
8b9e65e76f |
9
Makefile
9
Makefile
@@ -49,14 +49,14 @@ LDFLAGS = $(ARCH) -nostartfiles -lgcc -Wl,--nmagic,--gc-sections
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(BUILD)/$(TARGET)
|
||||
all: $(TARGET).bin
|
||||
|
||||
clean:
|
||||
@rm -rf $(OBJS)
|
||||
@rm -rf $(BUILD)/$(TARGET).elf
|
||||
@rm -rf $(BUILD)/$(TARGET)
|
||||
@rm -rf $(BUILD)
|
||||
@rm -rf $(TARGET).bin
|
||||
|
||||
$(BUILD)/$(TARGET): $(BUILD)/$(TARGET).elf
|
||||
$(TARGET).bin: $(BUILD)/$(TARGET).elf
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
$(BUILD)/$(TARGET).elf: $(OBJS)
|
||||
@@ -66,4 +66,5 @@ $(BUILD)/%.o: $(SOURCEDIR)/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD)/%.o: $(SOURCEDIR)/%.S
|
||||
@mkdir -p "$(BUILD)"
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
@@ -65,6 +65,7 @@ static const u8 _gfx_font[] = {
|
||||
0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00,
|
||||
0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08,
|
||||
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08,
|
||||
0x00, 0x00, 0x00, 0x4c, 0x32, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
void gfx_init_ctxt(gfx_ctxt_t *ctxt, u32 *fb, u32 width, u32 height, u32 stride)
|
||||
@@ -112,7 +113,7 @@ void gfx_con_setpos(gfx_con_t *con, u32 x, u32 y)
|
||||
|
||||
void gfx_putc(gfx_con_t *con, char c)
|
||||
{
|
||||
if (c >= 32 && c < 128)
|
||||
if (c >= 32 && c <= 126)
|
||||
{
|
||||
u8 *cbuf = (u8 *)&_gfx_font[8 * (c - 32)];
|
||||
u32 *fb = con->gfx_ctxt->fb + con->x + con->y * con->gfx_ctxt->stride;
|
||||
|
||||
190
ipl/hos.c
190
ipl/hos.c
@@ -32,11 +32,20 @@
|
||||
#include "pkg2.h"
|
||||
#include "ff.h"
|
||||
|
||||
/*#include "gfx.h"
|
||||
#include "gfx.h"
|
||||
extern gfx_ctxt_t gfx_ctxt;
|
||||
extern gfx_con_t gfx_con;
|
||||
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)*/
|
||||
#define DPRINTF(...)
|
||||
#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
|
||||
//#define DPRINTF(...)
|
||||
|
||||
enum KB_FIRMWARE_VERSION {
|
||||
KB_FIRMWARE_VERSION_100_200 = 0,
|
||||
KB_FIRMWARE_VERSION_300 = 1,
|
||||
KB_FIRMWARE_VERSION_301 = 2,
|
||||
KB_FIRMWARE_VERSION_400 = 3,
|
||||
KB_FIRMWARE_VERSION_500 = 4,
|
||||
KB_FIRMWARE_VERSION_MAX
|
||||
};
|
||||
|
||||
#define NUM_KEYBLOB_KEYS 5
|
||||
static const u8 keyblob_keyseeds[NUM_KEYBLOB_KEYS][0x10] = {
|
||||
@@ -50,15 +59,22 @@ static const u8 keyblob_keyseeds[NUM_KEYBLOB_KEYS][0x10] = {
|
||||
static const u8 cmac_keyseed[0x10] =
|
||||
{ 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 };
|
||||
|
||||
static const u8 mkey_keyseed_retail[0x10] =
|
||||
static const u8 master_keyseed_retail[0x10] =
|
||||
{ 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C };
|
||||
|
||||
static const u8 ckey_keyseed[0x10] =
|
||||
static const u8 console_keyseed[0x10] =
|
||||
{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };
|
||||
|
||||
static const u8 key8_keyseed[] =
|
||||
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
|
||||
|
||||
static const u8 master_keyseed_4xx[0x10] =
|
||||
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
|
||||
|
||||
static const u8 console_keyseed_4xx[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++)
|
||||
@@ -86,24 +102,28 @@ static void _se_lock()
|
||||
gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
|
||||
}
|
||||
|
||||
//Key derivation for < 4.0.0
|
||||
static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||
// <-- key derivation algorithm
|
||||
int keygen(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||
{
|
||||
u8 *tmp = (u8 *)malloc(0x10);
|
||||
u8 tmp[0x10];
|
||||
|
||||
se_key_acc_ctrl(12, 0x15);
|
||||
se_key_acc_ctrl(13, 0x15);
|
||||
se_key_acc_ctrl(0x0D, 0x15);
|
||||
se_key_acc_ctrl(0x0E, 0x15);
|
||||
|
||||
//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);
|
||||
se_aes_key_set(0x0D, tmp, 0x10);
|
||||
|
||||
//Derive keyblob keys from TSEC+SBK.
|
||||
se_aes_crypt_block_ecb(0x0D, 0x00, tmp, keyblob_keyseeds[0]);
|
||||
se_aes_unwrap_key(0x0F, 0x0E, tmp);
|
||||
se_aes_crypt_block_ecb(0xD, 0x00, tmp, keyblob_keyseeds[kb]);
|
||||
se_aes_unwrap_key(0x0D, 0x0E, tmp);
|
||||
|
||||
// Clear SBK
|
||||
se_aes_key_clear(0x0E);
|
||||
|
||||
//TODO: verify keyblob CMAC.
|
||||
//se_aes_unwrap_key(11, 13, cmac_keyseed);
|
||||
@@ -111,33 +131,46 @@ static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw)
|
||||
//if (!memcmp(keyblob, tmp, 0x10))
|
||||
// return 0;
|
||||
|
||||
se_aes_crypt_block_ecb(0x0D, 0, tmp, cmac_keyseed);
|
||||
se_aes_unwrap_key(0x0B, 0x0D, cmac_keyseed);
|
||||
|
||||
//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);
|
||||
se_aes_crypt_ctr(0x0D, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
|
||||
se_aes_key_set(0x0B, keyblob + 0x20 + 0x80, 0x10); // package1 key
|
||||
se_aes_key_set(0x0C, keyblob + 0x20, 0x10);
|
||||
se_aes_key_set(0x0D, 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);
|
||||
se_aes_crypt_block_ecb(0x0C, 0, tmp, master_keyseed_retail);
|
||||
|
||||
//Generate retail master key.
|
||||
memcpy(tmp, mkey_keyseed_retail, 0x10);
|
||||
se_aes_unwrap_key(12, 12, tmp);
|
||||
switch (kb) {
|
||||
case KB_FIRMWARE_VERSION_100_200:
|
||||
case KB_FIRMWARE_VERSION_300:
|
||||
se_aes_unwrap_key(0x0D, 0x0F, console_keyseed);
|
||||
se_aes_unwrap_key(0x0C, 0x0C, master_keyseed_retail);
|
||||
break;
|
||||
|
||||
memcpy(tmp, key8_keyseed, 0x10);
|
||||
se_key_acc_ctrl(8, 0x15);
|
||||
se_aes_unwrap_key(8, 12, tmp);
|
||||
case KB_FIRMWARE_VERSION_400:
|
||||
se_aes_unwrap_key(0x0D, 0x0F, console_keyseed_4xx);
|
||||
se_aes_unwrap_key(0x0F, 0x0F, console_keyseed);
|
||||
se_aes_unwrap_key(0x0E, 0x0C, master_keyseed_4xx);
|
||||
se_aes_unwrap_key(0x0C, 0x0C, master_keyseed_retail);
|
||||
break;
|
||||
|
||||
//Generate console specific key.
|
||||
memcpy(tmp, ckey_keyseed, 0x10);
|
||||
se_aes_unwrap_key(13, 13, tmp);
|
||||
case KB_FIRMWARE_VERSION_500:
|
||||
default:
|
||||
se_aes_unwrap_key(0x0A, 0x0F, console_keyseed_4xx);
|
||||
se_aes_unwrap_key(0x0F, 0x0F, console_keyseed);
|
||||
se_aes_unwrap_key(0x0E, 0x0C, master_keyseed_4xx);
|
||||
se_aes_unwrap_key(0x0C, 0x0C, master_keyseed_retail);
|
||||
break;
|
||||
}
|
||||
|
||||
se_key_acc_ctrl(12, 0xFF);
|
||||
se_key_acc_ctrl(13, 0xFF);
|
||||
|
||||
free(tmp);
|
||||
// Package2 key
|
||||
se_key_acc_ctrl(0x08, 0x15);
|
||||
se_aes_unwrap_key(0x08, 0x0C, key8_keyseed);
|
||||
}
|
||||
|
||||
|
||||
typedef struct _launch_ctxt_t
|
||||
{
|
||||
void *keyblob;
|
||||
@@ -325,12 +358,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_1(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off);
|
||||
keygen(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)
|
||||
@@ -347,41 +380,66 @@ 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;
|
||||
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");
|
||||
|
||||
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;
|
||||
|
||||
//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("loaded warmboot.bin and secmon\n");
|
||||
|
||||
//Read package2.
|
||||
if (!_read_emmc_pkg2(&ctxt))
|
||||
return 0;
|
||||
|
||||
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];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
se_aes_key_clear(8);
|
||||
se_aes_key_clear(11);
|
||||
//se_aes_key_clear(13);
|
||||
//se_key_acc_ctrl(10, 0xFF);
|
||||
se_key_acc_ctrl(12, 0xFF);
|
||||
//se_key_acc_ctrl(13, 0xFF);
|
||||
//se_key_acc_ctrl(14, 0xFF);
|
||||
se_key_acc_ctrl(15, 0xFF);
|
||||
|
||||
//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);
|
||||
|
||||
@@ -411,6 +469,10 @@ DPRINTF("rebuilt pkg2\n");
|
||||
//Signal package2 available.
|
||||
*mb_in = 2;
|
||||
sleep(100);
|
||||
*mb_in = 3;
|
||||
sleep(100);
|
||||
|
||||
|
||||
|
||||
/*PMC(0x4) = 0x7FFFF3;
|
||||
PMC(0x2C4) = 0xFFFFFFFF;
|
||||
@@ -425,7 +487,7 @@ DPRINTF("rebuilt pkg2\n");
|
||||
//display_end();
|
||||
|
||||
//Signal to continue boot.
|
||||
*mb_in = 3;
|
||||
*mb_in = 4;
|
||||
sleep(100);
|
||||
|
||||
//Halt ourselves in waitevent state.
|
||||
|
||||
@@ -21,5 +21,6 @@
|
||||
#include "ini.h"
|
||||
|
||||
int hos_launch(ini_sec_t *cfg);
|
||||
int keygen(u8 *keyblob, u32 kb, void *tsec_fw);
|
||||
|
||||
#endif
|
||||
|
||||
552
ipl/main.c
552
ipl/main.c
@@ -46,6 +46,56 @@
|
||||
#include "se_t210.h"
|
||||
#include "hos.h"
|
||||
#include "pkg1.h"
|
||||
#include "mmc.h"
|
||||
|
||||
//TODO: ugly.
|
||||
sdmmc_t sd_sdmmc;
|
||||
sdmmc_storage_t sd_storage;
|
||||
FATFS sd_fs;
|
||||
int sd_mounted;
|
||||
|
||||
int sd_mount()
|
||||
{
|
||||
if (sd_mounted)
|
||||
return 1;
|
||||
|
||||
if (sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11) &&
|
||||
f_mount(&sd_fs, "", 1) == FR_OK)
|
||||
{
|
||||
sd_mounted = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *sd_file_read(char *path)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
return NULL;
|
||||
|
||||
u32 size = f_size(&fp);
|
||||
void *buf = malloc(size);
|
||||
|
||||
u8 *ptr = buf;
|
||||
while (size > 0)
|
||||
{
|
||||
u32 rsize = MIN(size, 512);
|
||||
if (f_read(&fp, ptr, rsize, NULL) != FR_OK)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr += rsize;
|
||||
size -= rsize;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void panic(u32 val)
|
||||
{
|
||||
@@ -171,6 +221,10 @@ 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()
|
||||
@@ -248,8 +302,36 @@ void print_fuseinfo()
|
||||
gfx_printf(&gfx_con, "%k(Unlocked) fuse cache:\n\n%k", 0xFFFF9955, 0xFFFFFFFF);
|
||||
gfx_hexdump(&gfx_con, 0x7000F900, (u8 *)0x7000F900, 0x2FC);
|
||||
|
||||
sleep(100000);
|
||||
btn_wait();
|
||||
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
sleep(1000000);
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (!sd_mount())
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n",
|
||||
0xFF0000FF, 0xFFFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
FIL fuseFp;
|
||||
char fuseFilename[9];
|
||||
memcpy(fuseFilename, "fuse.bin", 8);
|
||||
fuseFilename[8] = 0;
|
||||
if (f_open(&fuseFp, fuseFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
|
||||
{
|
||||
f_write(&fuseFp, (u8 *)0x7000F900, 0x2FC, NULL);
|
||||
f_close(&fuseFp);
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
}
|
||||
else
|
||||
gfx_printf(&gfx_con, "%k\nError creating fuse.bin file.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
}
|
||||
sleep(2000000);
|
||||
btn_wait();
|
||||
}
|
||||
}
|
||||
|
||||
void print_kfuseinfo()
|
||||
@@ -264,7 +346,248 @@ void print_kfuseinfo()
|
||||
else
|
||||
gfx_hexdump(&gfx_con, 0, (u8 *)buf, KFUSE_NUM_WORDS * 4);
|
||||
|
||||
sleep(100000);
|
||||
gfx_puts(&gfx_con, "\nPress POWER to dump them to SD Card.\nPress VOL to go to the menu.\n");
|
||||
|
||||
sleep(1000000);
|
||||
|
||||
u32 btn = btn_wait();
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
if (!sd_mount())
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n",
|
||||
0xFF0000FF, 0xFFFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
FIL kfuseFp;
|
||||
char kfuseFilename[10];
|
||||
memcpy(kfuseFilename, "kfuse.bin", 9);
|
||||
kfuseFilename[9] = 0;
|
||||
if (f_open(&kfuseFp, kfuseFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
|
||||
{
|
||||
f_write(&kfuseFp, (u8 *)buf, KFUSE_NUM_WORDS * 4, NULL);
|
||||
f_close(&kfuseFp);
|
||||
gfx_puts(&gfx_con, "\nDone!\n");
|
||||
}
|
||||
else
|
||||
gfx_printf(&gfx_con, "%k\nError creating kfuse.bin file.%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
}
|
||||
sleep(2000000);
|
||||
btn_wait();
|
||||
}
|
||||
}
|
||||
|
||||
void print_mmc_info()
|
||||
{
|
||||
gfx_clear(&gfx_ctxt, 0xFF000000);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 0x800;
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 card_type;
|
||||
u32 speed;
|
||||
|
||||
gfx_printf(&gfx_con, "%kCard IDentification:%k\n", 0xFFFFDD00, 0xFFFFFFFF);
|
||||
switch (storage.csd.mmca_vsn)
|
||||
{
|
||||
case 0: /* MMC v1.0 - v1.2 */
|
||||
case 1: /* MMC v1.4 */
|
||||
gfx_printf(&gfx_con,
|
||||
" Vendor ID: %03X\n\
|
||||
Model: %c%c%c%c%c%c%c\n\
|
||||
HW rev: %X\n\
|
||||
FW rev: %X\n\
|
||||
S/N: %03X\n\
|
||||
Month/Year: %02d/%04d\n\n",
|
||||
storage.cid.manfid,
|
||||
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
|
||||
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
|
||||
storage.cid.prod_name[6], storage.cid.hwrev, storage.cid.fwrev,
|
||||
storage.cid.serial, storage.cid.month, storage.cid.year);
|
||||
break;
|
||||
case 2: /* MMC v2.0 - v2.2 */
|
||||
case 3: /* MMC v3.1 - v3.3 */
|
||||
case 4: /* MMC v4 */
|
||||
gfx_printf(&gfx_con,
|
||||
" Vendor ID: %X\n\
|
||||
Card/BGA: %X\n\
|
||||
OEM ID: %02X\n\
|
||||
Model: %c%c%c%c%c%c\n\
|
||||
Prd Rev: %X\n\
|
||||
S/N: %04X\n\
|
||||
Month/Year: %02d/%04d\n\n",
|
||||
storage.cid.manfid, storage.cid.card_bga, storage.cid.oemid,
|
||||
storage.cid.prod_name[0], storage.cid.prod_name[1], storage.cid.prod_name[2],
|
||||
storage.cid.prod_name[3], storage.cid.prod_name[4], storage.cid.prod_name[5],
|
||||
storage.cid.prv, storage.cid.serial, storage.cid.month, storage.cid.year);
|
||||
break;
|
||||
default:
|
||||
gfx_printf(&gfx_con, "%keMMC has unknown MMCA version %d%k\n", 0xFF0000FF, storage.csd.mmca_vsn, 0xFFFFFFFF);
|
||||
break;
|
||||
}
|
||||
|
||||
if (storage.csd.structure == 0)
|
||||
gfx_printf(&gfx_con, "%kUnknown CSD structure%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
else
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kExtended Card-Specific Data V1.%d:%k\n",
|
||||
0xFFFFDD00, storage.ext_csd.ext_struct, 0xFFFFFFFF);
|
||||
card_type = storage.ext_csd.card_type;
|
||||
u8 card_type_support[96];
|
||||
u8 pos_type = 0;
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS_26)
|
||||
{
|
||||
memcpy(card_type_support, "HS26", 4);
|
||||
speed = (26 << 16) | 26;
|
||||
pos_type += 4;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
|
||||
{
|
||||
memcpy(card_type_support + pos_type, ", HS52", 6);
|
||||
speed = (52 << 16) | 52;
|
||||
pos_type += 6;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
|
||||
{
|
||||
memcpy(card_type_support + pos_type, ", DDR52_1.8V", 12);
|
||||
speed = (52 << 16) | 104;
|
||||
pos_type += 12;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
|
||||
{
|
||||
memcpy(card_type_support + pos_type, ", HS200_1.8V", 12);
|
||||
speed = (200 << 16) | 200;
|
||||
pos_type += 12;
|
||||
}
|
||||
if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
|
||||
{
|
||||
memcpy(card_type_support + pos_type, ", HS400_1.8V", 12);
|
||||
speed = (200 << 16) | 400;
|
||||
pos_type += 12;
|
||||
}
|
||||
card_type_support[pos_type] = 0;
|
||||
|
||||
gfx_printf(&gfx_con,
|
||||
" Spec Version: %02X\n\
|
||||
Extended Rev: 1.%d\n\
|
||||
Dev Version: %d\n\
|
||||
Cmd Classes: %02X\n\
|
||||
Capacity: %s\n\
|
||||
Max Speed: %d MB/s (%d MHz)\n\
|
||||
Type Support: %s\n\n",
|
||||
storage.csd.mmca_vsn, storage.ext_csd.rev, storage.ext_csd.dev_version, storage.csd.cmdclass,
|
||||
storage.csd.capacity == (4096 * 512) ? "High" : "Low", speed & 0xFFFF, (speed >> 16) & 0xFFFF, card_type_support);
|
||||
|
||||
u32 boot_size = storage.ext_csd.boot_mult << 17;
|
||||
u32 rpmb_size = storage.ext_csd.rpmb_mult << 17;
|
||||
gfx_printf(&gfx_con, "%keMMC Partitions:%k\n", 0xFFFFDD00, 0xFFFFFFFF);
|
||||
gfx_printf(&gfx_con, " 1: %kBOOT0 %kSize: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF00FF96, 0xFFFFFFFF,
|
||||
boot_size / 1024, boot_size / 1024 / 512);
|
||||
gfx_printf(&gfx_con, " 2: %kBOOT1 %kSize: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF00FF96, 0xFFFFFFFF,
|
||||
boot_size / 1024, boot_size / 1024 / 512);
|
||||
gfx_printf(&gfx_con, " 3: %kRPMB %kSize: %5d KiB (LBA Sectors: 0x%07X)\n", 0xFF00FF96, 0xFFFFFFFF,
|
||||
rpmb_size / 1024, rpmb_size / 1024 / 512);
|
||||
gfx_printf(&gfx_con, " 0: %kGPP (USER) %kSize: %05d MiB (LBA Sectors: 0x%07X)\n\n", 0xFF00FF96, 0xFFFFFFFF,
|
||||
storage.sec_cnt / SECTORS_TO_MIB_COEFF, storage.sec_cnt);
|
||||
gfx_printf(&gfx_con, "%kGPP (eMMC USER) partition table:%k\n", 0xFFFFDD00, 0xFFFFFFFF);
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
int gpp_idx = 0;
|
||||
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
|
||||
{
|
||||
gfx_printf(&gfx_con, " %02d: %k%s%k\n Size: % 5d MiB (LBA Sectors 0x%07X, LBA Range: %08X-%08X)%k\n",
|
||||
gpp_idx++, 0xFF14FDAE, part->name, 0xFFFFFFFF, (part->lba_end - part->lba_start + 1) / SECTORS_TO_MIB_COEFF,
|
||||
part->lba_end - part->lba_start + 1, part->lba_start, part->lba_end, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
sdmmc_storage_end(&storage);
|
||||
sleep(1000000);
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void print_sdcard_info()
|
||||
{
|
||||
gfx_clear(&gfx_ctxt, 0xFF000000);
|
||||
gfx_con_setpos(&gfx_con, 0, 0);
|
||||
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 0x800;
|
||||
|
||||
if (!sd_mount())
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kFailed to mount SD card (make sure that it is inserted).%k\n",
|
||||
0xFF0000FF, 0xFFFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 capacity;
|
||||
|
||||
gfx_printf(&gfx_con, "%kCard IDentification:%k\n", 0xFFFFDD00, 0xFFFFFFFF);
|
||||
gfx_printf(&gfx_con,
|
||||
" Vendor ID: %02x\n\
|
||||
OEM ID: %c%c\n\
|
||||
Model: %c%c%c%c%c\n\
|
||||
HW rev: %X\n\
|
||||
FW rev: %X\n\
|
||||
S/N: %08x\n\
|
||||
Month/Year: %02d/%04d\n\n",
|
||||
sd_storage.cid.manfid, (sd_storage.cid.oemid >> 8) & 0xFF, sd_storage.cid.oemid & 0xFF,
|
||||
sd_storage.cid.prod_name[0], sd_storage.cid.prod_name[1], sd_storage.cid.prod_name[2],
|
||||
sd_storage.cid.prod_name[3], sd_storage.cid.prod_name[4],
|
||||
sd_storage.cid.hwrev, sd_storage.cid.fwrev, sd_storage.cid.serial,
|
||||
sd_storage.cid.month, sd_storage.cid.year);
|
||||
|
||||
gfx_printf(&gfx_con, "%kCard-Specific Data V%d.0:%k\n", 0xFFFFDD00, sd_storage.csd.structure + 1, 0xFFFFFFFF);
|
||||
switch(sd_storage.csd.structure)
|
||||
{
|
||||
case 0:
|
||||
capacity = (sd_storage.csd.capacity << sd_storage.csd.read_blkbits) / 1024 / 1024;
|
||||
gfx_printf(&gfx_con,
|
||||
" Cmd Classes: %02X\n\
|
||||
Capacity: %d MiB\n",
|
||||
sd_storage.csd.cmdclass, capacity);
|
||||
break;
|
||||
case 1:
|
||||
capacity = (sd_storage.csd.c_size << sd_storage.csd.read_blkbits) / 1024;
|
||||
gfx_printf(&gfx_con,
|
||||
" Cmd Classes: %02X\n\
|
||||
Capacity: %d MiB\n",
|
||||
sd_storage.csd.cmdclass, capacity);
|
||||
break;
|
||||
}
|
||||
gfx_printf(&gfx_con,
|
||||
" Bus Width: %d\n\
|
||||
Speed Class: %d\n\
|
||||
UHS Grade: U%d\n\
|
||||
Video Class: V%d\n\
|
||||
App perf class: A%d\n\n",
|
||||
sd_storage.ssr.bus_width, sd_storage.ssr.speed_class, sd_storage.ssr.uhs_grade,
|
||||
sd_storage.ssr.video_class, sd_storage.ssr.app_class);
|
||||
|
||||
gfx_puts(&gfx_con, "Acquiring FAT volume info...\n\n");
|
||||
f_getfree("", &sd_fs.free_clst, NULL);
|
||||
gfx_printf(&gfx_con, "%kFound %s volume:%k\n Free: %d MiB\n", 0xFFFFDD00,
|
||||
sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", 0xFFFFFFFF,
|
||||
sd_fs.free_clst * sd_fs.csize / SECTORS_TO_MIB_COEFF);
|
||||
}
|
||||
|
||||
sleep(1000000);
|
||||
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
@@ -285,7 +608,8 @@ void print_tsec_key()
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
if (!pkg1_id)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kCould not identify package 1 version to read TSEC firmware (= '%s').%k\n", 0xFF0000FF, (char *)pkg1 + 0x10, 0xFFFFFFFF);
|
||||
gfx_printf(&gfx_con, "%kCould not identify package 1 version to read TSEC firmware (= '%s').%k\n",
|
||||
0xFF0000FF, (char *)pkg1 + 0x10, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -308,7 +632,7 @@ void print_tsec_key()
|
||||
out:;
|
||||
free(pkg1);
|
||||
sdmmc_storage_end(&storage);
|
||||
sleep(100000);
|
||||
sleep(1000000);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
@@ -331,60 +655,11 @@ void power_off()
|
||||
i2c_send_byte(I2C_5, 0x3C, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
|
||||
}
|
||||
|
||||
//TODO: ugly.
|
||||
sdmmc_t sd_sdmmc;
|
||||
sdmmc_storage_t sd_storage;
|
||||
FATFS sd_fs;
|
||||
int sd_mounted;
|
||||
|
||||
int sd_mount()
|
||||
{
|
||||
if (sd_mounted)
|
||||
return 1;
|
||||
|
||||
if (sdmmc_storage_init_sd(&sd_storage, &sd_sdmmc, SDMMC_1, SDMMC_BUS_WIDTH_4, 11) &&
|
||||
f_mount(&sd_fs, "", 1) == FR_OK)
|
||||
{
|
||||
sd_mounted = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *sd_file_read(char *path)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||
return NULL;
|
||||
|
||||
u32 size = f_size(&fp);
|
||||
void *buf = malloc(size);
|
||||
|
||||
u8 *ptr = buf;
|
||||
while (size > 0)
|
||||
{
|
||||
u32 rsize = MIN(size, 512);
|
||||
if (f_read(&fp, ptr, rsize, NULL) != FR_OK)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr += rsize;
|
||||
size -= rsize;
|
||||
}
|
||||
|
||||
f_close(&fp);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
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;
|
||||
static const u32 SECTORS_TO_MIB_COEFF = 0x800;
|
||||
|
||||
u32 totalSectors = part->lba_end - part->lba_start + 1;
|
||||
u32 currPartIdx = 0;
|
||||
@@ -392,6 +667,8 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
u32 maxSplitParts = 0;
|
||||
int isSmallSdCard = 0;
|
||||
int partialDumpInProgress = 0;
|
||||
int res = 0;
|
||||
int ignoreWriteErrors = 0;
|
||||
char* outFilename = sd_path;
|
||||
u32 sdPathLen = strlen(sd_path);
|
||||
|
||||
@@ -400,9 +677,9 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
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);
|
||||
gfx_printf(&gfx_con, "SD Card free space: %d MiB, Total dump size %d MiB\n",
|
||||
sd_fs.free_clst * sd_fs.csize / SECTORS_TO_MIB_COEFF,
|
||||
totalSectors / SECTORS_TO_MIB_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))
|
||||
@@ -440,7 +717,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
}
|
||||
|
||||
// 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))
|
||||
if (((sd_fs.fs_type != FS_EXFAT) && totalSectors > (FAT32_FILESIZE_LIMIT/NX_EMMC_BLOCKSIZE)) | isSmallSdCard)
|
||||
{
|
||||
static const u32 MULTIPART_SPLIT_SECTORS = MULTIPART_SPLIT_SIZE/NX_EMMC_BLOCKSIZE;
|
||||
numSplitParts = (totalSectors+MULTIPART_SPLIT_SECTORS-1)/MULTIPART_SPLIT_SECTORS;
|
||||
@@ -482,7 +759,8 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
|
||||
u32 lba_curr = part->lba_start;
|
||||
u32 bytesWritten = 0;
|
||||
u32 prevPct=200;
|
||||
u32 prevPct = 200;
|
||||
int retryCount = 0;
|
||||
|
||||
// Continue from where we left, if partial dump in proggress.
|
||||
if (partialDumpInProgress)
|
||||
@@ -508,7 +786,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
itoa(currPartIdx, &outFilename[sdPathLen], 10);
|
||||
|
||||
// More parts to dump that do not currently fit the sd card free space
|
||||
if (isSmallSdCard && currPartIdx >= maxSplitParts)
|
||||
if ((isSmallSdCard && currPartIdx >= maxSplitParts) || (res && !ignoreWriteErrors))
|
||||
{
|
||||
// Create partial dump index file
|
||||
if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
|
||||
@@ -523,12 +801,20 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
// Sd card fatal error.
|
||||
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 to continue");
|
||||
4. Run hekate - ipl again and press Dump RAW eMMC or eMMC USER to continue");
|
||||
|
||||
free(buf);
|
||||
return 1;
|
||||
@@ -542,7 +828,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
bytesWritten = 0;
|
||||
}
|
||||
|
||||
int retryCount=0;
|
||||
retryCount = 0;
|
||||
u32 num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
|
||||
while(!sdmmc_storage_read(storage, lba_curr, num, buf))
|
||||
{
|
||||
@@ -550,17 +836,26 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
|
||||
0xFF0000FF, num, lba_curr, ++retryCount, 0xFFFFFFFF);
|
||||
|
||||
sleep(500000);
|
||||
if (retryCount >= 6)
|
||||
if (retryCount >= 10)
|
||||
goto out;
|
||||
}
|
||||
retryCount=0;
|
||||
while (f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL)){
|
||||
gfx_printf(&gfx_con, "%kError writing %d blocks from eMMC LBA %08X to SD Card (try %d)%k\n",
|
||||
0xFF0000FF, num, lba_curr, ++retryCount, 0xFFFFFFFF);
|
||||
res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL);
|
||||
if (res && !ignoreWriteErrors)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%k\nFatal error %d when writing to SD Card%k\n\n\
|
||||
Press VOL to abort and try again.\nPress POWER to ignore errors (will produce a corrupt dump).\n",
|
||||
0xFF0000FF, res, 0xFFFFFFFF);
|
||||
u32 btn = btn_wait();
|
||||
|
||||
sleep(500000);
|
||||
if (retryCount >= 6)
|
||||
goto out;
|
||||
if (btn & BTN_POWER)
|
||||
{
|
||||
ignoreWriteErrors = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesWritten = MULTIPART_SPLIT_SIZE - num * NX_EMMC_BLOCKSIZE;
|
||||
currPartIdx--;
|
||||
}
|
||||
}
|
||||
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
|
||||
if (pct != prevPct)
|
||||
@@ -589,8 +884,9 @@ out:;
|
||||
if(partialDumpInProgress)
|
||||
{
|
||||
f_unlink(partialIdxFilename);
|
||||
gfx_printf(&gfx_con, "\n\nYou can now join the files and get the complete raw eMMC dump.\n");
|
||||
gfx_printf(&gfx_con, "\n\nYou can now join the files and get the complete raw eMMC dump.");
|
||||
}
|
||||
gfx_putc(&gfx_con, '\n');
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -605,16 +901,18 @@ typedef enum
|
||||
|
||||
static void dump_emmc_selected(dumpType_t dumpType)
|
||||
{
|
||||
u32 timer = 0;
|
||||
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);
|
||||
gfx_printf(&gfx_con, "%kFailed to init/mount SD card (make sure that it is inserted).%k\n", 0xFF0000FF, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -628,6 +926,7 @@ static void dump_emmc_selected(dumpType_t dumpType)
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
timer = get_tmr();
|
||||
if (dumpType & DUMP_BOOT)
|
||||
{
|
||||
static const u32 BOOT_PART_SIZE = 0x400000;
|
||||
@@ -693,11 +992,12 @@ static void dump_emmc_selected(dumpType_t dumpType)
|
||||
}
|
||||
}
|
||||
|
||||
gfx_printf(&gfx_con, "%kTime taken: %d seconds.%k\n", 0xFF00FF96, (get_tmr() - timer) / 1000000, 0xFFFFFFFF);
|
||||
sdmmc_storage_end(&storage);
|
||||
gfx_puts(&gfx_con, "Done. Press any key.\n");
|
||||
gfx_puts(&gfx_con, "\nDone. Press any key.\n");
|
||||
|
||||
out:;
|
||||
sleep(100000);
|
||||
sleep(1000000);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
@@ -706,6 +1006,103 @@ 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); }
|
||||
|
||||
u32 save_to_file(void * buf, u32 size, const char * filename)
|
||||
{
|
||||
FIL fp;
|
||||
if (f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
f_sync(&fp);
|
||||
f_write(&fp, buf, size, NULL);
|
||||
f_close(&fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dump_package1()
|
||||
{
|
||||
u8 * pkg1 = (u8 *)malloc(0x40000);
|
||||
u8 * warmboot = (u8 *)malloc(0x40000);
|
||||
u8 * secmon = (u8 *)malloc(0x40000);
|
||||
|
||||
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, 1);
|
||||
|
||||
//Read package1.
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
const pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + pkg1_id->pkg11_off + 0x20);
|
||||
if (!pkg1_id)
|
||||
{
|
||||
gfx_printf(&gfx_con, "%kCould not identify package 1 version to read TSEC firmware (= '%s').%k\n", 0xFF0000FF, (char *)pkg1 + 0x10, 0xFFFFFFFF);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
// Read keyblob
|
||||
u8 * keyblob = (u8 *)malloc(NX_EMMC_BLOCKSIZE);
|
||||
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + pkg1_id->kb, 1, keyblob);
|
||||
|
||||
// decrypt
|
||||
keygen(keyblob, pkg1_id->kb, (u8 *)pkg1 + pkg1_id->tsec_off);
|
||||
pkg1_decrypt(pkg1_id, pkg1);
|
||||
|
||||
pkg1_unpack(warmboot, secmon, pkg1_id, pkg1);
|
||||
|
||||
// display info
|
||||
gfx_printf(&gfx_con, "%kSecure monitor addr: %08X\n", 0xFF0000FF, pkg1_id->secmon_base);
|
||||
gfx_printf(&gfx_con, "%kSecure monitor size: %08X\n", 0xFF0000FF, hdr->sm_size);
|
||||
gfx_printf(&gfx_con, "%kSecure monitor off: %08X\n", 0xFF0000FF, hdr->sm_off);
|
||||
|
||||
// dump package1
|
||||
if (save_to_file(pkg1, 0x40000, "pkg_decr.bin") == -1) {
|
||||
gfx_printf(&gfx_con, "Failed to create pkg_decr.bin\n");
|
||||
goto out;
|
||||
}
|
||||
gfx_puts(&gfx_con, "%kPackage1 dumped to pkg_decr.bin\n");
|
||||
|
||||
// dump sm
|
||||
if (save_to_file(secmon, 0x40000, "sm.bin") == -1) {
|
||||
gfx_puts(&gfx_con, "Failed to create sm.bin\n");
|
||||
goto out;
|
||||
}
|
||||
gfx_puts(&gfx_con, "Secure Monitor dumped to sm.bin\n");
|
||||
|
||||
// dump warmboot
|
||||
if (save_to_file(warmboot, 0x40000, "warmboot.bin") == -1) {
|
||||
gfx_puts(&gfx_con, "Failed to create warmboot.bin\n");
|
||||
goto out;
|
||||
}
|
||||
gfx_puts(&gfx_con, "Warmboot dumped to warmboot.bin\n");
|
||||
|
||||
|
||||
sdmmc_storage_end(&storage);
|
||||
gfx_puts(&gfx_con, "Done. Press any key.\n");
|
||||
|
||||
out:;
|
||||
free(pkg1);
|
||||
free(secmon);
|
||||
free(warmboot);
|
||||
sleep(1000000);
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
void launch_firmware()
|
||||
{
|
||||
ini_sec_t *cfg_sec = NULL;
|
||||
@@ -808,6 +1205,8 @@ ment_t ment_cinfo[] = {
|
||||
MDEF_HANDLER("Print fuse info", print_fuseinfo),
|
||||
MDEF_HANDLER("Print kfuse info", print_kfuseinfo),
|
||||
MDEF_HANDLER("Print TSEC keys", print_tsec_key),
|
||||
MDEF_HANDLER("Print eMMC info", print_mmc_info),
|
||||
MDEF_HANDLER("Print SD Card info", print_sdcard_info),
|
||||
MDEF_END()
|
||||
};
|
||||
menu_t menu_cinfo = {
|
||||
@@ -821,6 +1220,7 @@ ment_t ment_tools[] = {
|
||||
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 Package1", dump_package1),
|
||||
MDEF_END()
|
||||
};
|
||||
menu_t menu_tools = {
|
||||
@@ -840,7 +1240,7 @@ ment_t ment_top[] = {
|
||||
};
|
||||
menu_t menu_top = {
|
||||
ment_top,
|
||||
"hekate - ipl", 0, 0
|
||||
"hekate - ipl (CTCaer mod v1.3)", 0, 0
|
||||
};
|
||||
|
||||
extern void pivot_stack(u32 stack_top);
|
||||
|
||||
@@ -289,6 +289,7 @@ c : clear by read
|
||||
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
|
||||
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */
|
||||
#define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */
|
||||
#define EXT_CSD_DEVICE_VERSION 262 /* RO, 2 bytes */
|
||||
#define EXT_CSD_PRE_EOL_INFO 267 /* RO */
|
||||
#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A 268 /* RO */
|
||||
#define EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B 269 /* RO */
|
||||
|
||||
40
ipl/pkg1.c
40
ipl/pkg1.c
@@ -40,6 +40,29 @@ 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.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_secmon_5_patchset,
|
||||
//Patch package2 decryption and signature/hash checks.
|
||||
{ 0x1218 + 0x6E68, _NOP() }, //Header signature.
|
||||
{ 0x1218 + 0x6E74, _NOP() }, //Version.
|
||||
{ 0x1218 + 0x6FE4, _NOP() }, //Sections SHA2.
|
||||
{ 0x1218 + 0x2DC, _NOP() } //Unknown.
|
||||
);
|
||||
|
||||
PATCHSET_DEF(_secmon_6_patchset,
|
||||
{ 0x12b0 + 0x4d0, _NOP() },
|
||||
{ 0x12b0 + 0x4dc, _NOP() },
|
||||
{ 0x12b0 + 0x794, _NOP() },
|
||||
{ 0x12b0 + 0xb30, _NOP() }//,
|
||||
//{ 0x12b0 + 0xa18 , _NOP() } // BootConfig Retail Check
|
||||
);
|
||||
|
||||
/*
|
||||
* package1.1 header: <wb, ldr, sm>
|
||||
* package1.1 layout:
|
||||
@@ -55,23 +78,12 @@ static const pkg1_id_t _pkg1_ids[] = {
|
||||
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, 0x40014020, _secmon_1_patchset }, //1.0.0
|
||||
{ "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, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //4.0.0
|
||||
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //5.0.0
|
||||
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.1
|
||||
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, _secmon_5_patchset }, //4.0.0
|
||||
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, _secmon_6_patchset }, //5.0.0
|
||||
{ NULL, 0, 0, 0, 0 } //End.
|
||||
};
|
||||
|
||||
typedef struct _pk11_hdr_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 wb_size;
|
||||
u32 wb_off;
|
||||
u32 pad;
|
||||
u32 ldr_size;
|
||||
u32 ldr_off;
|
||||
u32 sm_size;
|
||||
u32 sm_off;
|
||||
} pk11_hdr_t;
|
||||
|
||||
const pkg1_id_t *pkg1_identify(u8 *pkg1)
|
||||
{
|
||||
|
||||
13
ipl/pkg1.h
13
ipl/pkg1.h
@@ -42,6 +42,19 @@ typedef struct _pkg1_id_t
|
||||
patch_t *secmon_patchset;
|
||||
} pkg1_id_t;
|
||||
|
||||
|
||||
typedef struct _pk11_hdr_t
|
||||
{
|
||||
u32 magic;
|
||||
u32 wb_size;
|
||||
u32 wb_off;
|
||||
u32 pad;
|
||||
u32 ldr_size;
|
||||
u32 ldr_off;
|
||||
u32 sm_size;
|
||||
u32 sm_off;
|
||||
} pk11_hdr_t;
|
||||
|
||||
const pkg1_id_t *pkg1_identify(u8 *pkg1);
|
||||
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1);
|
||||
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, const pkg1_id_t *id, u8 *pkg1);
|
||||
|
||||
@@ -172,3 +172,4 @@ DPRINTF("INI1 encrypted\n");
|
||||
memset(hdr->ctr, 0 , 0x10);
|
||||
*(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,5 +41,8 @@
|
||||
#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
|
||||
|
||||
22
ipl/sd.h
22
ipl/sd.h
@@ -35,10 +35,11 @@
|
||||
#define SD_APP_SEND_SCR 51 /* adtc R1 */
|
||||
|
||||
/* OCR bit definitions */
|
||||
#define SD_OCR_S18R (1 << 24) /* 1.8V switching request */
|
||||
#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */
|
||||
#define SD_OCR_XPC (1 << 28) /* SDXC power control */
|
||||
#define SD_OCR_CCS (1 << 30) /* Card Capacity Status */
|
||||
#define SD_OCR_S18R (1 << 24) /* 1.8V switching request */
|
||||
#define SD_ROCR_S18A SD_OCR_S18R /* 1.8V switching accepted by card */
|
||||
#define SD_OCR_XPC (1 << 28) /* SDXC power control */
|
||||
#define SD_OCR_CCS (1 << 30) /* Card Capacity Status */
|
||||
#define SD_OCR_VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */
|
||||
|
||||
/*
|
||||
* SD_SWITCH argument format:
|
||||
@@ -64,10 +65,11 @@
|
||||
/*
|
||||
* SCR field definitions
|
||||
*/
|
||||
|
||||
#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
|
||||
#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
|
||||
#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00-3.0X */
|
||||
#define SD_SCR_BUS_WIDTH_1 (1<<0)
|
||||
#define SD_SCR_BUS_WIDTH_4 (1<<2)
|
||||
|
||||
/*
|
||||
* SD bus widths
|
||||
@@ -75,6 +77,16 @@
|
||||
#define SD_BUS_WIDTH_1 0
|
||||
#define SD_BUS_WIDTH_4 2
|
||||
|
||||
/*
|
||||
* SD bus speeds
|
||||
*/
|
||||
#define UHS_SDR12_BUS_SPEED 0
|
||||
#define HIGH_SPEED_BUS_SPEED 1
|
||||
#define UHS_SDR25_BUS_SPEED 1
|
||||
#define UHS_SDR50_BUS_SPEED 2
|
||||
#define UHS_SDR104_BUS_SPEED 3
|
||||
#define UHS_DDR50_BUS_SPEED 4
|
||||
|
||||
/*
|
||||
* SD_SWITCH mode
|
||||
*/
|
||||
|
||||
311
ipl/sdmmc.c
311
ipl/sdmmc.c
@@ -223,7 +223,7 @@ static int _mmc_storage_get_op_cond(sdmmc_storage_t *storage, u32 power)
|
||||
u32 cond = 0;
|
||||
if (!_mmc_storage_get_op_cond_inner(storage, &cond, power))
|
||||
break;
|
||||
if (cond & 0x80000000)
|
||||
if (cond & MMC_CARD_BUSY)
|
||||
{
|
||||
if (cond & 0x40000000)
|
||||
storage->has_sector_access = 1;
|
||||
@@ -242,6 +242,76 @@ static int _mmc_storage_set_relative_addr(sdmmc_storage_t *storage)
|
||||
return _sdmmc_storage_execute_cmd_type1(storage, MMC_SET_RELATIVE_ADDR, storage->rca << 16, 0, 0x10);
|
||||
}
|
||||
|
||||
static void _mmc_storage_parse_cid(sdmmc_storage_t *storage)
|
||||
{
|
||||
u32 *raw_cid = (u32 *)&(storage->raw_cid);
|
||||
|
||||
switch (storage->csd.mmca_vsn)
|
||||
{
|
||||
case 0: /* MMC v1.0 - v1.2 */
|
||||
case 1: /* MMC v1.4 */
|
||||
storage->cid.prod_name[6] = unstuff_bits(raw_cid, 48, 8);
|
||||
storage->cid.manfid = unstuff_bits(raw_cid, 104, 24);
|
||||
storage->cid.hwrev = unstuff_bits(raw_cid, 44, 4);
|
||||
storage->cid.fwrev = unstuff_bits(raw_cid, 40, 4);
|
||||
storage->cid.serial = unstuff_bits(raw_cid, 16, 24);
|
||||
break;
|
||||
case 2: /* MMC v2.0 - v2.2 */
|
||||
case 3: /* MMC v3.1 - v3.3 */
|
||||
case 4: /* MMC v4 */
|
||||
storage->cid.manfid = unstuff_bits(raw_cid, 120, 8);
|
||||
storage->cid.card_bga = unstuff_bits(raw_cid, 112, 2);
|
||||
storage->cid.oemid = unstuff_bits(raw_cid, 104, 8);
|
||||
storage->cid.prv = unstuff_bits(raw_cid, 48, 8);
|
||||
storage->cid.serial = unstuff_bits(raw_cid, 16, 32);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8);
|
||||
storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8);
|
||||
storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8);
|
||||
storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8);
|
||||
storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8);
|
||||
storage->cid.prod_name[5] = unstuff_bits(raw_cid, 56, 8);
|
||||
|
||||
storage->cid.month = unstuff_bits(raw_cid, 12, 4);
|
||||
storage->cid.year = unstuff_bits(raw_cid, 8, 4) + 1997;
|
||||
if (storage->ext_csd.rev >= 5)
|
||||
{
|
||||
if (storage->cid.year < 2010)
|
||||
storage->cid.year += 16;
|
||||
}
|
||||
}
|
||||
|
||||
static void _mmc_storage_parse_csd(sdmmc_storage_t *storage)
|
||||
{
|
||||
u32 *raw_csd = (u32 *)&(storage->raw_csd);
|
||||
|
||||
storage->csd.mmca_vsn = unstuff_bits(raw_csd, 122, 4);
|
||||
storage->csd.structure = unstuff_bits(raw_csd, 126, 2);
|
||||
storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12);
|
||||
storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4);
|
||||
storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2);
|
||||
}
|
||||
|
||||
static int _mmc_storage_parse_ext_csd(sdmmc_storage_t *storage, u8 *buf)
|
||||
{
|
||||
storage->ext_csd.rev = buf[EXT_CSD_REV];
|
||||
storage->ext_csd.ext_struct = buf[EXT_CSD_STRUCTURE];
|
||||
storage->ext_csd.card_type = buf[EXT_CSD_CARD_TYPE];
|
||||
storage->ext_csd.dev_version = *(u16 *)&buf[EXT_CSD_DEVICE_VERSION];
|
||||
storage->ext_csd.boot_mult = buf[EXT_CSD_BOOT_MULT];
|
||||
storage->ext_csd.rpmb_mult = buf[EXT_CSD_RPMB_MULT];
|
||||
storage->ext_csd.sectors = *(u32 *)&buf[EXT_CSD_SEC_CNT];
|
||||
storage->ext_csd.bkops = buf[EXT_CSD_BKOPS_SUPPORT];
|
||||
storage->ext_csd.bkops_en = buf[EXT_CSD_BKOPS_EN];
|
||||
storage->ext_csd.bkops_status = buf[EXT_CSD_BKOPS_STATUS];
|
||||
|
||||
storage->sec_cnt = *(u32 *)&buf[EXT_CSD_SEC_CNT];
|
||||
}
|
||||
|
||||
static int _mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf)
|
||||
{
|
||||
sdmmc_cmd_t cmdbuf;
|
||||
@@ -260,6 +330,8 @@ static int _mmc_storage_get_ext_csd(sdmmc_storage_t *storage, void *buf)
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
_mmc_storage_parse_ext_csd(storage, buf);
|
||||
|
||||
return _sdmmc_storage_check_result(tmp);
|
||||
}
|
||||
|
||||
@@ -388,7 +460,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
return 0;
|
||||
DPRINTF("[mmc] got op cond\n");
|
||||
|
||||
if (!_sdmmc_storage_get_cid(storage, storage->cid))
|
||||
if (!_sdmmc_storage_get_cid(storage, storage->raw_cid))
|
||||
return 0;
|
||||
DPRINTF("[mmc] got cid\n");
|
||||
|
||||
@@ -396,9 +468,10 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
return 0;
|
||||
DPRINTF("[mmc] set relative addr\n");
|
||||
|
||||
if (!_sdmmc_storage_get_csd(storage, storage->csd))
|
||||
if (!_sdmmc_storage_get_csd(storage, storage->raw_csd))
|
||||
return 0;
|
||||
DPRINTF("[mmc] got csd\n");
|
||||
_mmc_storage_parse_csd(storage);
|
||||
|
||||
if (!sdmmc_setup_clock(storage->sdmmc, 1))
|
||||
return 0;
|
||||
@@ -412,7 +485,7 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
return 0;
|
||||
DPRINTF("[mmc] set blocklen to 512\n");
|
||||
|
||||
u32 *csd = (u32 *)storage->csd;
|
||||
u32 *csd = (u32 *)storage->raw_csd;
|
||||
//Check system specification version, only version 4.0 and later support below features.
|
||||
if (unstuff_bits(csd, 122, 4) < CSD_SPEC_VER_4)
|
||||
{
|
||||
@@ -430,23 +503,28 @@ int sdmmc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
free(ext_csd);
|
||||
return 0;
|
||||
}
|
||||
free(ext_csd);
|
||||
DPRINTF("[mmc] got ext_csd\n");
|
||||
_mmc_storage_parse_cid(storage); //This needs to be after csd and ext_csd
|
||||
//gfx_hexdump(&gfx_con, 0, ext_csd, 512);
|
||||
|
||||
storage->sec_cnt = *(u32 *)&ext_csd[EXT_CSD_SEC_CNT];
|
||||
|
||||
if (storage->cid[0xE] == 0x11 && ext_csd[EXT_CSD_BKOPS_EN] & EXT_CSD_BKOPS_LEVEL_2)
|
||||
_mmc_storage_enable_bkops(storage);
|
||||
|
||||
if (!_mmc_storage_enable_highspeed(storage, ext_csd[EXT_CSD_CARD_TYPE], type))
|
||||
/* When auto BKOPS is enabled the mmc device should be powered all the time until we disable this and check status.
|
||||
Disable it for now until BKOPS disable added to power down sequence at sdmmc_storage_end().
|
||||
Additionally this works only when we put the device in idle mode which we don't after enabling it. */
|
||||
if (storage->ext_csd.bkops & 0x1 && !(storage->ext_csd.bkops_en & EXT_CSD_BKOPS_LEVEL_2) && 0)
|
||||
{
|
||||
free(ext_csd);
|
||||
return 0;
|
||||
_mmc_storage_enable_bkops(storage);
|
||||
DPRINTF("[mmc] BKOPS enabled\n");
|
||||
}
|
||||
DPRINTF("[mmc] switched to possible highspeed mode\n");
|
||||
else
|
||||
DPRINTF("[mmc] BKOPS disabled\n");
|
||||
|
||||
if (!_mmc_storage_enable_highspeed(storage, storage->ext_csd.card_type, type))
|
||||
return 0;
|
||||
DPRINTF("[mmc] switched to highspeed mode\n");
|
||||
|
||||
sdmmc_sd_clock_ctrl(storage->sdmmc, 1);
|
||||
|
||||
free(ext_csd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -484,21 +562,26 @@ static int _sd_storage_send_if_cond(sdmmc_storage_t *storage)
|
||||
sdmmc_cmd_t cmdbuf;
|
||||
sdmmc_init_cmd(&cmdbuf, SD_SEND_IF_COND, 0x1AA, SDMMC_RSP_TYPE_5, 0);
|
||||
if (!sdmmc_execute_cmd(storage->sdmmc, &cmdbuf, 0, 0))
|
||||
return 0;
|
||||
|
||||
//TODO: we may have received a timeout error in the above request, which indicates a version 1 card.
|
||||
return 1; // The SD Card is version 1.X
|
||||
|
||||
u32 resp = 0;
|
||||
if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5))
|
||||
return 0;
|
||||
return 2;
|
||||
|
||||
return (resp & 0xFFF) == 0x1AA ? 1 : 0;
|
||||
return (resp & 0xFF) == 0xAA ? 0 : 2;
|
||||
}
|
||||
|
||||
static int _sd_storage_get_op_cond_once(sdmmc_storage_t *storage, u32 *cond, int is_version_1, int supports_low_voltage)
|
||||
{
|
||||
sdmmc_cmd_t cmdbuf;
|
||||
u32 arg = (((~is_version_1 & 1) << 28) & 0xBFFFFFFF | ((~is_version_1 & 1) << 30)) & 0xFEFFFFFF | ((supports_low_voltage & ~is_version_1 & 1) << 24) | 0x100000;
|
||||
// Support for Current > 150mA
|
||||
u32 arg = (~is_version_1 & 1) ? SD_OCR_XPC : 0;
|
||||
// Support for handling block-addressed SDHC cards
|
||||
arg |= (~is_version_1 & 1) ? SD_OCR_CCS : 0;
|
||||
// Support for 1.8V
|
||||
arg |= (supports_low_voltage & ~is_version_1 & 1) ? SD_OCR_S18R : 0;
|
||||
// This is needed for most cards. Do not set bit7 even if 1.8V is supported.
|
||||
arg |= SD_OCR_VDD_32_33;
|
||||
sdmmc_init_cmd(&cmdbuf, SD_APP_OP_COND, arg, SDMMC_RSP_TYPE_3, 0);
|
||||
if (!_sd_storage_execute_app_cmd(storage, 0x10, is_version_1 ? 0x400000 : 0, &cmdbuf, 0, 0))
|
||||
return 0;
|
||||
@@ -514,12 +597,12 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
||||
u32 cond = 0;
|
||||
if (!_sd_storage_get_op_cond_once(storage, &cond, is_version_1, supports_low_voltage))
|
||||
break;
|
||||
if (cond & 0x80000000)
|
||||
if (cond & MMC_CARD_BUSY)
|
||||
{
|
||||
if (cond & 0x40000000)
|
||||
if (cond & SD_OCR_CCS)
|
||||
storage->has_sector_access = 1;
|
||||
|
||||
if (cond & 0x1000000 && supports_low_voltage)
|
||||
if (cond & SD_ROCR_S18A && supports_low_voltage)
|
||||
{
|
||||
//The low voltage regulator configuration is valid for SDMMC1 only.
|
||||
if (storage->sdmmc->id == SDMMC_1 &&
|
||||
@@ -537,7 +620,7 @@ static int _sd_storage_get_op_cond(sdmmc_storage_t *storage, int is_version_1, i
|
||||
}
|
||||
if (get_tmr() > timeout)
|
||||
break;
|
||||
sleep(1000);
|
||||
sleep(10000); // Needs to be at least 10ms for some SD Cards
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -573,7 +656,24 @@ static int _sd_storage_get_rca(sdmmc_storage_t *storage)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _sd_storage_get_scr(sdmmc_storage_t *storage, void *buf)
|
||||
static void _sd_storage_parse_scr(sdmmc_storage_t *storage)
|
||||
{
|
||||
// unstuff_bits can parse only 4 u32
|
||||
u32 resp[4];
|
||||
|
||||
resp[3] = *(u32 *)&storage->raw_scr[4];
|
||||
resp[2] = *(u32 *)&storage->raw_scr[0];
|
||||
|
||||
storage->scr.sda_vsn = unstuff_bits(resp, 56, 4);
|
||||
storage->scr.bus_widths = unstuff_bits(resp, 48, 4);
|
||||
if (storage->scr.sda_vsn == SCR_SPEC_VER_2)
|
||||
/* Check if Physical Layer Spec v3.0 is supported */
|
||||
storage->scr.sda_spec3 = unstuff_bits(resp, 47, 1);
|
||||
if (storage->scr.sda_spec3)
|
||||
storage->scr.cmds = unstuff_bits(resp, 32, 2);
|
||||
}
|
||||
|
||||
int _sd_storage_get_scr(sdmmc_storage_t *storage, u8 *buf)
|
||||
{
|
||||
sdmmc_cmd_t cmdbuf;
|
||||
sdmmc_init_cmd(&cmdbuf, SD_APP_SEND_SCR, 0, SDMMC_RSP_TYPE_1, 0);
|
||||
@@ -591,6 +691,17 @@ int _sd_storage_get_scr(sdmmc_storage_t *storage, void *buf)
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
//Prepare buffer for unstuff_bits
|
||||
for (int i = 0; i < 8; i+=4)
|
||||
{
|
||||
storage->raw_scr[i + 3] = buf[i];
|
||||
storage->raw_scr[i + 2] = buf[i + 1];
|
||||
storage->raw_scr[i + 1] = buf[i + 2];
|
||||
storage->raw_scr[i] = buf[i + 3];
|
||||
}
|
||||
_sd_storage_parse_scr(storage);
|
||||
//gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8);
|
||||
|
||||
return _sdmmc_storage_check_result(tmp);
|
||||
}
|
||||
|
||||
@@ -672,7 +783,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
||||
if (buf[13] & 8)
|
||||
{
|
||||
type = 11;
|
||||
hs_type = 3;
|
||||
hs_type = UHS_SDR104_BUS_SPEED;
|
||||
break;
|
||||
}
|
||||
//Fall through.
|
||||
@@ -680,7 +791,7 @@ int _sd_storage_enable_highspeed_low_volt(sdmmc_storage_t *storage, u32 type, u8
|
||||
if (!(buf[13] & 4))
|
||||
return 0;
|
||||
type = 10;
|
||||
hs_type = 2;
|
||||
hs_type = UHS_SDR50_BUS_SPEED;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
@@ -711,8 +822,115 @@ int _sd_storage_enable_highspeed_high_volt(sdmmc_storage_t *storage, u8 *buf)
|
||||
return sdmmc_setup_clock(storage->sdmmc, 7);
|
||||
}
|
||||
|
||||
static void _sd_storage_parse_ssr(sdmmc_storage_t *storage)
|
||||
{
|
||||
u32 *raw_ssr = (u32 *)&(storage->raw_ssr);
|
||||
storage->ssr.bus_width = unstuff_bits(raw_ssr, 510 - 384, 2) & SD_BUS_WIDTH_4 ? 4 : 1;
|
||||
switch(unstuff_bits(raw_ssr, 440 - 384, 8))
|
||||
{
|
||||
case 0:
|
||||
storage->ssr.speed_class = 0;
|
||||
break;
|
||||
case 1:
|
||||
storage->ssr.speed_class = 2;
|
||||
break;
|
||||
case 2:
|
||||
storage->ssr.speed_class = 4;
|
||||
break;
|
||||
case 3:
|
||||
storage->ssr.speed_class = 6;
|
||||
break;
|
||||
case 4:
|
||||
storage->ssr.speed_class = 10;
|
||||
break;
|
||||
default:
|
||||
storage->ssr.speed_class = unstuff_bits(raw_ssr, 440 - 384, 8);
|
||||
break;
|
||||
}
|
||||
storage->ssr.uhs_grade = unstuff_bits(raw_ssr, 396 - 384, 4);
|
||||
storage->ssr.video_class = unstuff_bits(raw_ssr, 384 - 384, 8);
|
||||
storage->ssr.app_class = unstuff_bits(raw_ssr + 16, 472 + 4 - 384, 4);
|
||||
}
|
||||
|
||||
static int _sd_storage_get_ssr(sdmmc_storage_t *storage, u8 *buf)
|
||||
{
|
||||
sdmmc_cmd_t cmdbuf;
|
||||
sdmmc_init_cmd(&cmdbuf, SD_APP_SD_STATUS, 0, SDMMC_RSP_TYPE_1, 0);
|
||||
|
||||
sdmmc_req_t reqbuf;
|
||||
reqbuf.buf = buf;
|
||||
reqbuf.blksize = 64;
|
||||
reqbuf.num_sectors = 1;
|
||||
reqbuf.is_write = 0;
|
||||
reqbuf.is_multi_block = 0;
|
||||
reqbuf.is_auto_cmd12 = 0;
|
||||
|
||||
if (!(storage->csd.cmdclass & CCC_APP_SPEC)) {
|
||||
DPRINTF("[sd] ssr: Card lacks mandatory SD Status function\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_sd_storage_execute_app_cmd(storage, R1_STATE_TRAN, 0, &cmdbuf, &reqbuf, 0))
|
||||
return 0;
|
||||
|
||||
u32 tmp = 0;
|
||||
sdmmc_get_rsp(storage->sdmmc, &tmp, 4, SDMMC_RSP_TYPE_1);
|
||||
//Prepare buffer for unstuff_bits
|
||||
for (int i = 0; i < 64; i+=4)
|
||||
{
|
||||
storage->raw_ssr[i + 3] = buf[i];
|
||||
storage->raw_ssr[i + 2] = buf[i + 1];
|
||||
storage->raw_ssr[i + 1] = buf[i + 2];
|
||||
storage->raw_ssr[i] = buf[i + 3];
|
||||
}
|
||||
_sd_storage_parse_ssr(storage);
|
||||
//gfx_hexdump(&gfx_con, 0, storage->raw_ssr, 64);
|
||||
|
||||
return _sdmmc_storage_check_result(tmp);
|
||||
}
|
||||
|
||||
static void _sd_storage_parse_cid(sdmmc_storage_t *storage)
|
||||
{
|
||||
u32 *raw_cid = (u32 *)&(storage->raw_cid);
|
||||
|
||||
storage->cid.manfid = unstuff_bits(raw_cid, 120, 8);
|
||||
storage->cid.oemid = unstuff_bits(raw_cid, 104, 16);
|
||||
storage->cid.prod_name[0] = unstuff_bits(raw_cid, 96, 8);
|
||||
storage->cid.prod_name[1] = unstuff_bits(raw_cid, 88, 8);
|
||||
storage->cid.prod_name[2] = unstuff_bits(raw_cid, 80, 8);
|
||||
storage->cid.prod_name[3] = unstuff_bits(raw_cid, 72, 8);
|
||||
storage->cid.prod_name[4] = unstuff_bits(raw_cid, 64, 8);
|
||||
storage->cid.hwrev = unstuff_bits(raw_cid, 60, 4);
|
||||
storage->cid.fwrev = unstuff_bits(raw_cid, 56, 4);
|
||||
storage->cid.serial = unstuff_bits(raw_cid, 24, 32);
|
||||
storage->cid.month = unstuff_bits(raw_cid, 8, 4);
|
||||
storage->cid.year = unstuff_bits(raw_cid, 12, 8) + 2000;
|
||||
}
|
||||
|
||||
static void _sd_storage_parse_csd(sdmmc_storage_t *storage)
|
||||
{
|
||||
u32 *raw_csd = (u32 *)&(storage->raw_csd);
|
||||
|
||||
storage->csd.structure = unstuff_bits(raw_csd, 126, 2);
|
||||
storage->csd.cmdclass = unstuff_bits(raw_csd, 84, 12);
|
||||
storage->csd.read_blkbits = unstuff_bits(raw_csd, 80, 4);
|
||||
switch(storage->csd.structure)
|
||||
{
|
||||
case 0:
|
||||
storage->csd.capacity = (1 + unstuff_bits(raw_csd, 62, 12)) << (unstuff_bits(raw_csd, 47, 3) + 2);
|
||||
break;
|
||||
case 1:
|
||||
storage->csd.c_size = (1 + unstuff_bits(raw_csd, 48, 22));
|
||||
storage->csd.capacity = storage->csd.c_size << 10;
|
||||
storage->csd.read_blkbits = 9;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32 bus_width, u32 type)
|
||||
{
|
||||
int is_version_1 = 0;
|
||||
|
||||
memset(storage, 0, sizeof(sdmmc_storage_t));
|
||||
storage->sdmmc = sdmmc;
|
||||
|
||||
@@ -726,44 +944,40 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
return 0;
|
||||
DPRINTF("[sd] went to idle state\n");
|
||||
|
||||
if (!_sd_storage_send_if_cond(storage))
|
||||
is_version_1 = _sd_storage_send_if_cond(storage);
|
||||
if (is_version_1 == 2)
|
||||
return 0;
|
||||
DPRINTF("[sd] after send if cond\n");
|
||||
|
||||
//TODO: use correct version here -----v
|
||||
if (!_sd_storage_get_op_cond(storage, 0, bus_width == SDMMC_BUS_WIDTH_4 && (type | 1) == 11))
|
||||
if (!_sd_storage_get_op_cond(storage, is_version_1, bus_width == SDMMC_BUS_WIDTH_4 && type == 11))
|
||||
return 0;
|
||||
DPRINTF("[sd] got op cond\n");
|
||||
|
||||
if (!_sdmmc_storage_get_cid(storage, storage->cid))
|
||||
if (!_sdmmc_storage_get_cid(storage, storage->raw_cid))
|
||||
return 0;
|
||||
DPRINTF("[sd] got cid\n");
|
||||
_sd_storage_parse_cid(storage);
|
||||
|
||||
if (!_sd_storage_get_rca(storage))
|
||||
return 0;
|
||||
DPRINTF("[sd] got rca (= %04X)\n", storage->rca);
|
||||
|
||||
if (!_sdmmc_storage_get_csd(storage, storage->csd))
|
||||
if (!_sdmmc_storage_get_csd(storage, storage->raw_csd))
|
||||
return 0;
|
||||
DPRINTF("[sd] got csd\n");
|
||||
|
||||
//Parse CSD.
|
||||
u32 *csd = (u32 *)storage->csd;
|
||||
u32 csd_struct = unstuff_bits(csd, 126, 2);
|
||||
switch (csd_struct)
|
||||
_sd_storage_parse_csd(storage);
|
||||
switch (storage->csd.structure)
|
||||
{
|
||||
case 0:
|
||||
storage->sec_cnt = (1 + unstuff_bits(csd, 62, 12)) << (unstuff_bits(csd, 47, 3) + 2);
|
||||
storage->sec_cnt = storage->csd.capacity;
|
||||
break;
|
||||
case 1:
|
||||
storage->sec_cnt = (1 + unstuff_bits(csd, 48, 22)) << 10;
|
||||
storage->sec_cnt = storage->csd.c_size << 10;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("[sd] Unknown CSD structure %d\n", csd_struct);
|
||||
//TODO: I've encountered this with one of my SD cards, but
|
||||
// according to the spec only version 0 and 1 are
|
||||
// supposed to be in use (mine was version 2).
|
||||
//return 0;
|
||||
DPRINTF("[sd] Unknown CSD structure %d\n", storage->csd.structure);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -790,10 +1004,11 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
u8 *buf = (u8 *)malloc(512);
|
||||
if (!_sd_storage_get_scr(storage, buf))
|
||||
return 0;
|
||||
memcpy(storage->scr, buf, 8);
|
||||
//gfx_hexdump(&gfx_con, 0, storage->raw_scr, 8);
|
||||
DPRINTF("[sd] got scr\n");
|
||||
|
||||
if (bus_width == SDMMC_BUS_WIDTH_4 && storage->scr[1] & 4)
|
||||
// Check if card supports a wider bus and if it's not SD Version 1.X
|
||||
if (bus_width == SDMMC_BUS_WIDTH_4 && (storage->scr.bus_widths & 4) && (storage->scr.sda_vsn & 0xF))
|
||||
{
|
||||
if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN))
|
||||
{
|
||||
@@ -815,7 +1030,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.sda_vsn & 0xF) != 0)
|
||||
{
|
||||
if (!_sd_storage_enable_highspeed_high_volt(storage, buf))
|
||||
{
|
||||
@@ -827,6 +1042,10 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
|
||||
|
||||
sdmmc_sd_clock_ctrl(sdmmc, 1);
|
||||
|
||||
// Parse additional card info from sd status
|
||||
if (_sd_storage_get_ssr(storage, buf))
|
||||
DPRINTF("[sd] got sd status\n");
|
||||
|
||||
free(buf);
|
||||
return 1;
|
||||
}
|
||||
@@ -843,7 +1062,7 @@ int _gc_storage_custom_cmd(sdmmc_storage_t *storage, void *buf)
|
||||
|
||||
sdmmc_req_t reqbuf;
|
||||
reqbuf.buf = buf;
|
||||
reqbuf.blksize = 0x40;
|
||||
reqbuf.blksize = 64;
|
||||
reqbuf.num_sectors = 1;
|
||||
reqbuf.is_write = 1;
|
||||
reqbuf.is_multi_block = 0;
|
||||
|
||||
70
ipl/sdmmc.h
70
ipl/sdmmc.h
@@ -20,6 +20,64 @@
|
||||
#include "types.h"
|
||||
#include "sdmmc_driver.h"
|
||||
|
||||
typedef struct _mmc_cid
|
||||
{
|
||||
u32 manfid;
|
||||
u8 prod_name[8];
|
||||
u8 card_bga;
|
||||
u8 prv;
|
||||
u32 serial;
|
||||
u16 oemid;
|
||||
u16 year;
|
||||
u8 hwrev;
|
||||
u8 fwrev;
|
||||
u8 month;
|
||||
} mmc_cid_t;
|
||||
|
||||
typedef struct _mmc_csd
|
||||
{
|
||||
u8 structure;
|
||||
u8 mmca_vsn;
|
||||
u16 cmdclass;
|
||||
u32 c_size;
|
||||
u32 r2w_factor;
|
||||
u32 max_dtr;
|
||||
u32 erase_size; /* In sectors */
|
||||
u32 read_blkbits;
|
||||
u32 write_blkbits;
|
||||
u32 capacity;
|
||||
} mmc_csd_t;
|
||||
|
||||
typedef struct _mmc_ext_csd
|
||||
{
|
||||
u8 rev;
|
||||
u32 sectors;
|
||||
int bkops; /* background support bit */
|
||||
int bkops_en; /* manual bkops enable bit */
|
||||
u8 ext_struct; /* 194 */
|
||||
u8 card_type; /* 196 */
|
||||
u8 bkops_status; /* 246 */
|
||||
u16 dev_version;
|
||||
u8 boot_mult;
|
||||
u8 rpmb_mult;
|
||||
} mmc_ext_csd_t;
|
||||
|
||||
typedef struct _sd_scr
|
||||
{
|
||||
u8 sda_vsn;
|
||||
u8 sda_spec3;
|
||||
u8 bus_widths;
|
||||
u8 cmds;
|
||||
} sd_scr_t;
|
||||
|
||||
typedef struct _sd_ssr {
|
||||
u8 bus_width;
|
||||
u8 speed_class;
|
||||
u8 uhs_grade;
|
||||
u8 video_class;
|
||||
u8 app_class;
|
||||
} sd_ssr_t;
|
||||
|
||||
/*! SDMMC storage context. */
|
||||
typedef struct _sdmmc_storage_t
|
||||
{
|
||||
@@ -29,9 +87,15 @@ typedef struct _sdmmc_storage_t
|
||||
u32 sec_cnt;
|
||||
int is_low_voltage;
|
||||
u32 partition;
|
||||
u8 cid[0x10];
|
||||
u8 csd[0x10];
|
||||
u8 scr[8];
|
||||
u8 raw_cid[0x10];
|
||||
u8 raw_csd[0x10];
|
||||
u8 raw_scr[8];
|
||||
u8 raw_ssr[0x40];
|
||||
mmc_cid_t cid;
|
||||
mmc_csd_t csd;
|
||||
mmc_ext_csd_t ext_csd;
|
||||
sd_scr_t scr;
|
||||
sd_ssr_t ssr;
|
||||
} sdmmc_storage_t;
|
||||
|
||||
int sdmmc_storage_end(sdmmc_storage_t *storage);
|
||||
|
||||
@@ -54,24 +54,30 @@ 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 =
|
||||
(sdmmc->regs->pwrcon & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK) |
|
||||
TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
|
||||
pwr = 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;
|
||||
}
|
||||
|
||||
sdmmc->regs->pwrcon |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
if (power != SDMMC_POWER_OFF)
|
||||
{
|
||||
pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
|
||||
sdmmc->regs->pwrcon = pwr;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -298,10 +304,30 @@ static int _sdmmc_cache_rsp(sdmmc_t *sdmmc, u32 *rsp, u32 size, u32 type)
|
||||
case SDMMC_RSP_TYPE_2:
|
||||
if (size < 0x10)
|
||||
return 0;
|
||||
rsp[0] = sdmmc->regs->rspreg0;
|
||||
rsp[1] = sdmmc->regs->rspreg1;
|
||||
rsp[2] = sdmmc->regs->rspreg2;
|
||||
rsp[3] = sdmmc->regs->rspreg3;
|
||||
// CRC is stripped, so shifting is needed.
|
||||
u32 tempreg;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case 0:
|
||||
tempreg = sdmmc->regs->rspreg3;
|
||||
break;
|
||||
case 1:
|
||||
tempreg = sdmmc->regs->rspreg2;
|
||||
break;
|
||||
case 2:
|
||||
tempreg = sdmmc->regs->rspreg1;
|
||||
break;
|
||||
case 3:
|
||||
tempreg = sdmmc->regs->rspreg0;
|
||||
break;
|
||||
}
|
||||
rsp[i] = tempreg << 8;
|
||||
|
||||
if (i != 0)
|
||||
rsp[i - 1] |= (tempreg >> 24) & 0xFF;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
||||
10
ipl/se.c
10
ipl/se.c
@@ -67,7 +67,7 @@ static int _se_wait()
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _se_execute(u32 op, void *dst, u32 dst_size, void *src, u32 src_size)
|
||||
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
se_ll_t *ll_dst = NULL, *ll_src = NULL;
|
||||
|
||||
@@ -99,7 +99,7 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, void *src, u32 src_size)
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, void *src, u32 src_size)
|
||||
static int _se_execute_one_block(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||
{
|
||||
u8 *block = (u8 *)malloc(0x10);
|
||||
memset(block, 0, 0x10);
|
||||
@@ -156,7 +156,7 @@ void se_aes_key_clear(u32 ks)
|
||||
}
|
||||
}
|
||||
|
||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, void *input)
|
||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
|
||||
{
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB);
|
||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_DECRYPT);
|
||||
@@ -164,7 +164,7 @@ int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, void *input)
|
||||
return _se_execute(OP_START, NULL, 0, input, 0x10);
|
||||
}
|
||||
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, void *src)
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
|
||||
{
|
||||
if (enc)
|
||||
{
|
||||
@@ -180,7 +180,7 @@ int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, void *src)
|
||||
return _se_execute(OP_START, dst, 0x10, src, 0x10);
|
||||
}
|
||||
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, void *src, u32 src_size, void *ctr)
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr)
|
||||
{
|
||||
SE(SE_SPARE_0_REG_OFFSET) = 1;
|
||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||
|
||||
7
ipl/se.h
7
ipl/se.h
@@ -23,8 +23,7 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags);
|
||||
void se_key_acc_ctrl(u32 ks, u32 flags);
|
||||
void se_aes_key_set(u32 ks, void *key, u32 size);
|
||||
void se_aes_key_clear(u32 ks);
|
||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, void *input);
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, void *src);
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, void *src, u32 src_size, void *ctr);
|
||||
|
||||
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
|
||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
|
||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user