Compare commits

..

3 Commits
v1.2 ... 1.1

Author SHA1 Message Date
Kostas Missos
b77f185269 Fix small typo 2018-05-03 20:21:10 +03:00
Kostas Missos
f776c1f79f Add SD write retry and some other changes
Increase retry count to 6 tries
Add colors and change a little bit some messages
Change some namings
2018-05-03 19:26:57 +03:00
Kostas Missos
c0bad45cde Add partial dumping when free space is not enough 2018-05-03 19:23:26 +03:00
6 changed files with 76 additions and 240 deletions

227
ipl/hos.c
View File

@@ -59,13 +59,6 @@ static const u8 ckey_keyseed[0x10] =
static const u8 key8_keyseed[] = static const u8 key8_keyseed[] =
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 }; { 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() static void _se_lock()
{ {
for (u32 i = 0; i < 16; i++) 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);*/ gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
} }
// <-- key derivation algorithm //Key derivation for < 4.0.0
static int keygen(u8 *keyblob, u32 kb, void *tsec_fw) static int _keygen_1(u8 *keyblob, u32 kb, void *tsec_fw)
{ {
u8 *tmp = (u8 *)malloc(0x10); u8 *tmp = (u8 *)malloc(0x10);
@@ -104,143 +97,47 @@ static int keygen(u8 *keyblob, u32 kb, void *tsec_fw)
//Get TSEC key. //Get TSEC key.
if (tsec_query(tmp, 1, tsec_fw) < 0) if (tsec_query(tmp, 1, tsec_fw) < 0)
return 0; return 0;
se_aes_key_set(13, tmp, 0x10); 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. //TODO: verify keyblob CMAC.
//se_aes_unwrap_key(11, 13, cmac_keyseed); //se_aes_unwrap_key(11, 13, cmac_keyseed);
//se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0); //se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0);
//if (!memcmp(keyblob, tmp, 0x10)) //if (!memcmp(keyblob, tmp, 0x10))
// return 0; // return 0;
switch(kb) { //Decrypt keyblob and set keyslots.
// 1.0.0~2.0.0 FW se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
case 0: { se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10);
se_aes_key_set(12, keyblob + 0x20, 0x10);
//Derive keyblob key from TSEC+SBK. //TODO: for some reason SE likes to hang if we don't execute an operation here.
memcpy(tmp, keyblob_keyseeds[kb], 0x10); memcpy(tmp, mkey_keyseed_retail, 0x10);
se_aes_crypt_block_ecb(13, 0, tmp, tmp); se_aes_crypt_block_ecb(12, 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); //Generate retail master key.
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); memcpy(tmp, mkey_keyseed_retail, 0x10);
se_aes_key_set(12, keyblob + 0x20, 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, key8_keyseed, 0x10);
memcpy(tmp, mkey_keyseed_retail, 0x10); se_key_acc_ctrl(8, 0x15);
se_aes_crypt_block_ecb(12, 0, tmp, tmp); se_aes_unwrap_key(8, 12, tmp);
//Generate retail master key. //Generate console specific key.
memcpy(tmp, mkey_keyseed_retail, 0x10); memcpy(tmp, ckey_keyseed, 0x10);
se_aes_unwrap_key(12, 12, tmp); se_aes_unwrap_key(13, 13, tmp);
//Generate console specific key. se_key_acc_ctrl(12, 0xFF);
memcpy(tmp, ckey_keyseed, 0x10); se_key_acc_ctrl(13, 0xFF);
se_aes_unwrap_key(13, 13, tmp);
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); free(tmp);
} }
typedef struct _launch_ctxt_t typedef struct _launch_ctxt_t
{ {
void *keyblob; void *keyblob;
@@ -428,12 +325,12 @@ int hos_launch(ini_sec_t *cfg)
return 0; return 0;
//XXX: remove this once we support 3+. //XXX: remove this once we support 3+.
//if (ctxt.pkg1_id->kb > 0) if (ctxt.pkg1_id->kb > 0)
// return 0; return 0;
DPRINTF("loaded pkg1 and keyblob\n"); DPRINTF("loaded pkg1 and keyblob\n");
//Generate keys. //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"); DPRINTF("generated keys\n");
//Decrypt and unpack package1 if we require parts of it. //Decrypt and unpack package1 if we require parts of it.
if (!ctxt.warmboot || !ctxt.secmon) if (!ctxt.warmboot || !ctxt.secmon)
@@ -450,57 +347,41 @@ DPRINTF("decrypted and unpacked pkg1\n");
//Set warmboot address in PMC. //Set warmboot address in PMC.
PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000; PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000;
//Replace 'SecureMonitor' if requested. //Replace 'SecureMonitor' if requested.
if (ctxt.secmon) { if (ctxt.secmon)
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size); memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
}
else else
{ {
//Else we patch it to allow for an unsigned package2. //Else we patch it to allow for an unsigned package2.
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset; patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
if (secmon_patchset != NULL) { for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++) *(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
*(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;
DPRINTF("read pkg2\n");
//Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2);
//Read package2. LIST_INIT(kip1_info);
if (!_read_emmc_pkg2(&ctxt)) pkg2_parse_kips(&kip1_info, pkg2_hdr);
return 0; DPRINTF("parsed ini1\n");
//Use the kernel included in package2 in case we didn't load one already.
DPRINTF("read pkg2\n"); if (!ctxt.kernel)
//Decrypt package2 and parse KIP1 blobs in INI1 section. {
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2); ctxt.kernel = pkg2_hdr->data;
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
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);
//Rebuild and encrypt package2.
pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info);
DPRINTF("rebuilt pkg2\n");
//Clear 'BootConfig'. //Clear 'BootConfig'.
memset((void *)0x4003D000, 0, 0x3000); memset((void *)0x4003D000, 0, 0x3000);

View File

@@ -171,10 +171,6 @@ void config_se_brom()
SE(SE_INT_STATUS_REG_OFFSET) = 0x1F; SE(SE_INT_STATUS_REG_OFFSET) = 0x1F;
//Lock SSK (although it's not set and unused anyways). //Lock SSK (although it's not set and unused anyways).
SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E; 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() void config_hw()
@@ -396,8 +392,6 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
u32 maxSplitParts = 0; u32 maxSplitParts = 0;
int isSmallSdCard = 0; int isSmallSdCard = 0;
int partialDumpInProgress = 0; int partialDumpInProgress = 0;
int res = 0;
int ignoreWriteErrors = 0;
char* outFilename = sd_path; char* outFilename = sd_path;
u32 sdPathLen = strlen(sd_path); u32 sdPathLen = strlen(sd_path);
@@ -488,8 +482,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
u32 lba_curr = part->lba_start; u32 lba_curr = part->lba_start;
u32 bytesWritten = 0; u32 bytesWritten = 0;
u32 prevPct = 200; u32 prevPct=200;
int retryCount = 0;
// Continue from where we left, if partial dump in proggress. // Continue from where we left, if partial dump in proggress.
if (partialDumpInProgress) if (partialDumpInProgress)
@@ -515,7 +508,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
itoa(currPartIdx, &outFilename[sdPathLen], 10); itoa(currPartIdx, &outFilename[sdPathLen], 10);
// More parts to dump that do not currently fit the sd card free space // More parts to dump that do not currently fit the sd card free space
if ((isSmallSdCard && currPartIdx >= maxSplitParts) || (res && !ignoreWriteErrors)) if (isSmallSdCard && currPartIdx >= maxSplitParts)
{ {
// Create partial dump index file // Create partial dump index file
if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK) if (f_open(&partialIdxFp, partialIdxFilename, FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
@@ -530,19 +523,12 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
free(buf); free(buf);
return 0; 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\ 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 \ 2. Move the files from SD card to free space.\n \
Don\'t move the partial.idx file!\n\ Don\'t move the partial.idx file!\n\
3. Unplug and re-plug USB while pressing Vol+.\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"); 4. Run hekate - ipl again and press Dump RAW eMMC to continue");
free(buf); free(buf);
return 1; return 1;
@@ -556,7 +542,7 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
bytesWritten = 0; bytesWritten = 0;
} }
retryCount = 0; int retryCount=0;
u32 num = MIN(totalSectors, NUM_SECTORS_PER_ITER); u32 num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
while(!sdmmc_storage_read(storage, lba_curr, num, buf)) while(!sdmmc_storage_read(storage, lba_curr, num, buf))
{ {
@@ -564,26 +550,17 @@ int dump_emmc_part(char *sd_path, sdmmc_storage_t *storage, emmc_part_t *part)
0xFF0000FF, num, lba_curr, ++retryCount, 0xFFFFFFFF); 0xFF0000FF, num, lba_curr, ++retryCount, 0xFFFFFFFF);
sleep(500000); sleep(500000);
if (retryCount >= 10) if (retryCount >= 6)
goto out; goto out;
} }
res = f_write(&fp, buf, NX_EMMC_BLOCKSIZE * num, NULL); retryCount=0;
if (res && !ignoreWriteErrors) 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",
gfx_printf(&gfx_con, "%kFatal error %d when writing to SD Card%k\n\ 0xFF0000FF, num, lba_curr, ++retryCount, 0xFFFFFFFF);
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) sleep(500000);
{ if (retryCount >= 6)
bytesWritten = MULTIPART_SPLIT_SIZE - num * NX_EMMC_BLOCKSIZE; goto out;
currPartIdx--;
}
else
{
ignoreWriteErrors = 1;
}
} }
u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start); u32 pct = (u64)((u64)(lba_curr - part->lba_start) * 100u) / (u64)(part->lba_end - part->lba_start);
if (pct != prevPct) if (pct != prevPct)
@@ -638,7 +615,6 @@ static void dump_emmc_selected(dumpType_t dumpType)
} }
else else
{ {
gfx_puts(&gfx_con, "Checking for available free space...\n");
// Get SD Card free space for partial dumping // Get SD Card free space for partial dumping
f_getfree("", &sd_fs.free_clst, NULL); f_getfree("", &sd_fs.free_clst, NULL);
} }

View File

@@ -40,13 +40,6 @@ PATCHSET_DEF(_secmon_2_patchset,
{ 0xAC8 + 0xB58, _NOP() } //Sections SHA2. { 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 header: <wb, ldr, sm>
* package1.1 layout: * 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 { "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 { "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, NULL }, //3.0.1 { "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 { "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, NULL }, //5.0.0
{ NULL, 0, 0, 0, 0 } //End. { NULL, 0, 0, 0, 0 } //End.
}; };

View File

@@ -41,8 +41,5 @@
#define APBDEV_PMC_SCRATCH188 0x810 #define APBDEV_PMC_SCRATCH188 0x810
#define APBDEV_PMC_SCRATCH190 0x818 #define APBDEV_PMC_SCRATCH190 0x818
#define APBDEV_PMC_SCRATCH200 0x840 #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 #endif

View File

@@ -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)) if (!sdmmc_get_rsp(storage->sdmmc, &resp, 4, SDMMC_RSP_TYPE_5))
return 0; 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) 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) if (cond & 0x40000000)
storage->has_sector_access = 1; storage->has_sector_access = 1;
// TODO: Some SD Card incorrectly report low voltage support
// Disable it for now
if (cond & 0x1000000 && supports_low_voltage) if (cond & 0x1000000 && supports_low_voltage)
{ {
//The low voltage regulator configuration is valid for SDMMC1 only. //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) if (get_tmr() > timeout)
break; break;
sleep(10000); // Needs to be at least 10ms for some SD Cards sleep(1000);
} }
return 0; return 0;
@@ -759,9 +758,6 @@ int sdmmc_storage_init_sd(sdmmc_storage_t *storage, sdmmc_t *sdmmc, u32 id, u32
case 1: case 1:
storage->sec_cnt = (1 + unstuff_bits(csd, 48, 22)) << 10; storage->sec_cnt = (1 + unstuff_bits(csd, 48, 22)) << 10;
break; break;
case 2:
storage->sec_cnt = (1 + unstuff_bits(csd, 48, 22)) << 10;
break;
default: default:
DPRINTF("[sd] Unknown CSD structure %d\n", csd_struct); DPRINTF("[sd] Unknown CSD structure %d\n", csd_struct);
//TODO: I've encountered this with one of my SD cards, but //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); memcpy(storage->scr, buf, 8);
DPRINTF("[sd] got scr\n"); 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)
if (bus_width == SDMMC_BUS_WIDTH_4 && storage->scr[1] & 4 && (storage->scr[0] & 0xF))
{ {
if (!_sd_storage_execute_app_cmd_type1(storage, &tmp, SD_APP_SET_BUS_WIDTH, SD_BUS_WIDTH_4, 0, R1_STATE_TRAN)) 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"); 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)) if (!_sd_storage_enable_highspeed_high_volt(storage, buf))
{ {

View File

@@ -54,30 +54,24 @@ int sdmmc_get_voltage(sdmmc_t *sdmmc)
static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power) static int _sdmmc_set_voltage(sdmmc_t *sdmmc, u32 power)
{ {
u8 pwr = 0;
switch (power) switch (power)
{ {
case SDMMC_POWER_OFF: case SDMMC_POWER_OFF:
sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER; sdmmc->regs->pwrcon &= ~TEGRA_MMC_PWRCTL_SD_BUS_POWER;
break; break;
case SDMMC_POWER_1_8: case SDMMC_POWER_1_8:
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8; sdmmc->regs->pwrcon =
pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8; (sdmmc->regs->pwrcon & TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_MASK) |
TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V1_8;
break; break;
case SDMMC_POWER_3_3: case SDMMC_POWER_3_3:
sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3; sdmmc->regs->pwrcon = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
pwr = TEGRA_MMC_PWRCTL_SD_BUS_VOLTAGE_V3_3;
break; break;
default: default:
return 0; return 0;
} }
if (power != SDMMC_POWER_OFF) sdmmc->regs->pwrcon |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
{
pwr |= TEGRA_MMC_PWRCTL_SD_BUS_POWER;
sdmmc->regs->pwrcon = pwr;
}
return 1; return 1;
} }