forked from Mirror/GodMode9
Card-2 saves: Detect save size from ExHeader
This also limits the save blanking to the actual save area. This way every byte of the cart can be read again.
This commit is contained in:
parent
60f2c5192d
commit
9f52deedad
@ -121,6 +121,37 @@ u32 SetSecureAreaEncryption(bool encrypted) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 GetCtrCartSaveSize(CartData* cdata) {
|
||||||
|
NcsdHeader* ncsd = (NcsdHeader*) (void*) cdata->header;
|
||||||
|
u32 ncch_sector = ncsd->partitions[0].offset;
|
||||||
|
|
||||||
|
// Load header and ExHeader for first partition
|
||||||
|
u8 buffer[0x400];
|
||||||
|
CTR_CmdReadData(ncch_sector, 0x200, 2, buffer);
|
||||||
|
NcchHeader* ncch = (NcchHeader*) (void*) buffer;
|
||||||
|
if (ValidateNcchHeader(ncch) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure first partition has ExHeader
|
||||||
|
if (ncch->size_exthdr < 0x200) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt ExHeader
|
||||||
|
if ((NCCH_ENCRYPTED(ncch)) && (SetupNcchCrypto(ncch, NCCH_NOCRYPTO) == 0)) {
|
||||||
|
DecryptNcch(buffer + NCCH_EXTHDR_OFFSET, NCCH_EXTHDR_OFFSET, sizeof(buffer) - NCCH_EXTHDR_OFFSET, ncch, NULL);
|
||||||
|
}
|
||||||
|
u64 savesize = getle64(buffer + NCCH_EXTHDR_OFFSET + 0x1C0);
|
||||||
|
|
||||||
|
// check our work
|
||||||
|
if (savesize <= UINT32_MAX) {
|
||||||
|
return (u32) savesize;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
u32 InitCartRead(CartData* cdata) {
|
u32 InitCartRead(CartData* cdata) {
|
||||||
get_dstime(&init_time);
|
get_dstime(&init_time);
|
||||||
encrypted_sa = false;
|
encrypted_sa = false;
|
||||||
@ -184,7 +215,13 @@ u32 InitCartRead(CartData* cdata) {
|
|||||||
u32 card2_offset = getle32(cdata->header + 0x200);
|
u32 card2_offset = getle32(cdata->header + 0x200);
|
||||||
if (card2_offset != 0xFFFFFFFF) {
|
if (card2_offset != 0xFFFFFFFF) {
|
||||||
cdata->save_type = CARD_SAVE_CARD2;
|
cdata->save_type = CARD_SAVE_CARD2;
|
||||||
cdata->save_size = cdata->cart_size - card2_offset * NCSD_MEDIA_UNIT;
|
cdata->save_size = GetCtrCartSaveSize(cdata);
|
||||||
|
// Sanity checks
|
||||||
|
if ((cdata->save_size == 0) ||
|
||||||
|
(card2_offset * NCSD_MEDIA_UNIT >= cdata->cart_size) ||
|
||||||
|
(card2_offset * NCSD_MEDIA_UNIT + cdata->save_size > cdata->cart_size)) {
|
||||||
|
cdata->save_type = CARD_SAVE_NONE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cdata->spi_save_type = CardSPIGetCardSPIType(false);
|
cdata->spi_save_type = CardSPIGetCardSPIType(false);
|
||||||
if (cdata->spi_save_type.chip == NO_CHIP) {
|
if (cdata->spi_save_type.chip == NO_CHIP) {
|
||||||
@ -274,14 +311,26 @@ u32 ReadCartSectors(void* buffer, u32 sector, u32 count, CartData* cdata, bool c
|
|||||||
|
|
||||||
// overwrite the card2 savegame with 0xFF
|
// overwrite the card2 savegame with 0xFF
|
||||||
u32 card2_offset = getle32(cdata->header + 0x200);
|
u32 card2_offset = getle32(cdata->header + 0x200);
|
||||||
|
u32 save_sectors = cdata->save_size / 0x200;
|
||||||
if (card2_blanking &&
|
if (card2_blanking &&
|
||||||
(card2_offset != 0xFFFFFFFF) &&
|
(cdata->save_type == CARD_SAVE_CARD2) &&
|
||||||
((card2_offset * 0x200) >= cdata->data_size) &&
|
((card2_offset * 0x200) >= cdata->data_size) &&
|
||||||
(sector + count > card2_offset)) {
|
(sector + count > card2_offset) && // requested area ends after the save starts
|
||||||
if (sector > card2_offset)
|
(sector < card2_offset + save_sectors)) { // requested area starts before the save ends
|
||||||
memset(buffer8, 0xFF, (count * 0x200));
|
u32 blank_start_sector, blank_end_sector;
|
||||||
else memset(buffer8 + (card2_offset - sector) * 0x200, 0xFF,
|
if (sector > card2_offset) {
|
||||||
(count - (card2_offset - sector)) * 0x200);
|
blank_start_sector = sector;
|
||||||
|
} else {
|
||||||
|
blank_start_sector = card2_offset;
|
||||||
|
}
|
||||||
|
if (sector + count < card2_offset + save_sectors) {
|
||||||
|
blank_end_sector = sector + count;
|
||||||
|
} else {
|
||||||
|
blank_end_sector = card2_offset + save_sectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(buffer8 + (blank_start_sector - sector) * 0x200, 0xFF,
|
||||||
|
(blank_end_sector - blank_start_sector) * 0x200);
|
||||||
}
|
}
|
||||||
} else if (cdata->cart_type & CART_NTR) {
|
} else if (cdata->cart_type & CART_NTR) {
|
||||||
u8* buff = buffer8;
|
u8* buff = buffer8;
|
||||||
@ -384,8 +433,11 @@ u32 ReadCartSave(u8* buffer, u64 offset, u64 count, CartData* cdata) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CARD_SAVE_CARD2:
|
case CARD_SAVE_CARD2:
|
||||||
return ReadCartBytes(buffer, cdata->cart_size - cdata->save_size + offset, count, cdata, false);
|
{
|
||||||
|
u32 card2_offset = getle32(cdata->header + 0x200);
|
||||||
|
return ReadCartBytes(buffer, card2_offset * NCSD_MEDIA_UNIT + offset, count, cdata, false);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user