diff --git a/include/dolphin/CARDPriv.h b/include/dolphin/CARDPriv.h index 678df8ee..a7702cb0 100644 --- a/include/dolphin/CARDPriv.h +++ b/include/dolphin/CARDPriv.h @@ -5,12 +5,12 @@ extern "C" { #endif -#define CARD_FAT_AVAIL 0x0000u -#define CARD_FAT_CHECKSUM 0x0000u -#define CARD_FAT_CHECKSUMINV 0x0001u -#define CARD_FAT_CHECKCODE 0x0002u -#define CARD_FAT_FREEBLOCKS 0x0003u -#define CARD_FAT_LASTSLOT 0x0004u +#define CARD_FAT_AVAIL 0x0000u +#define CARD_FAT_CHECKSUM 0x0000u +#define CARD_FAT_CHECKSUMINV 0x0001u +#define CARD_FAT_CHECKCODE 0x0002u +#define CARD_FAT_FREEBLOCKS 0x0003u +#define CARD_FAT_LASTSLOT 0x0004u #define CARD_PAGE_SIZE 128u #define CARD_SEG_SIZE 512u @@ -20,28 +20,35 @@ extern "C" { #define CARD_MAX_MOUNT_STEP (CARD_NUM_SYSTEM_BLOCK + 2) -typedef struct CARDDir -{ - u8 gameName[4]; - u8 company[2]; - u8 _padding0; - u8 bannerFormat; - u8 fileName[CARD_FILENAME_MAX]; - u32 time; // seconds since 01/01/2000 midnight +typedef struct CARDDir { + u8 gameName[4]; + u8 company[2]; + u8 _padding0; + u8 bannerFormat; + u8 fileName[CARD_FILENAME_MAX]; + u32 time; // seconds since 01/01/2000 midnight - u32 iconAddr; // 0xffffffff if not used - u16 iconFormat; - u16 iconSpeed; + u32 iconAddr; // 0xffffffff if not used + u16 iconFormat; + u16 iconSpeed; - u8 permission; - u8 copyTimes; - u16 startBlock; - u16 length; - u8 _padding1[2]; + u8 permission; + u8 copyTimes; + u16 startBlock; + u16 length; + u8 _padding1[2]; - u32 commentAddr; // 0xffffffff if not used + u32 commentAddr; // 0xffffffff if not used } CARDDir; +typedef struct CARDDirCheck { + u8 padding0[64 - 2 * 4]; + u16 padding1; + s16 checkCode; + u16 checkSum; + u16 checkSumInv; +} CARDDirCheck; + typedef struct CARDControl { BOOL attached; s32 result; @@ -57,7 +64,7 @@ typedef struct CARDControl { u32 scramble; DSPTaskInfo task; void* workArea; - CARDDir* dir; + CARDDir* currentDir; u16* currentFat; OSThreadQueue threadQueue; u8 cmd[9]; @@ -95,15 +102,17 @@ typedef struct CARDID { u16 checkSumInv; } CARDID; -#define CARDIsValidBlockNo(card, iBlock) (CARD_NUM_SYSTEM_BLOCK <= (iBlock) && (iBlock) < (card)->cBlock) +#define CARDIsValidBlockNo(card, iBlock) (CARD_NUM_SYSTEM_BLOCK <= (iBlock) && (iBlock) < (card)->cBlock) +#define __CARDGetDirCheck(dir) ((CARDDirCheck*) &(dir)[CARD_MAX_FILE]) -CARDDir* __CARDGetDirBlock( CARDControl* card ); -u16* __CARDGetFatBlock ( CARDControl* card ); +CARDDir* __CARDGetDirBlock(CARDControl* card); +u16* __CARDGetFatBlock(CARDControl* card); s32 __CARDUpdateFatBlock(s32 chan, u16* fat, CARDCallback callback); - +void __CARDCheckSum(void* ptr, int length, u16* checkSum, u16* checkSumInv); +u16 __CARDGetFontEncode(); extern CARDControl __CARDBlock[2]; -extern DVDDiskID __CARDDiskNone; +extern DVDDiskID __CARDDiskNone; #ifdef __cplusplus } diff --git a/include/dolphin/OSRtcPriv.h b/include/dolphin/OSRtcPriv.h new file mode 100644 index 00000000..71a80a6f --- /dev/null +++ b/include/dolphin/OSRtcPriv.h @@ -0,0 +1,31 @@ +#ifndef __OSRTCPRIV_H__ +#define __OSRTCPRIV_H__ + +#include + +typedef struct OSSram { + u16 checkSum; + u16 checkSumInv; + u32 ead0; + u32 ead1; + u32 counterBias; + s8 displayOffsetH; + u8 ntd; + u8 language; + + u8 flags; +} OSSram; + +typedef struct OSSramEx { + u8 flashID[2][12]; + u32 wirelessKeyboardID; + u16 wirelessPadID[4]; + u8 dvdErrorCode; + u8 _padding0; + u8 flashIDCheckSum[2]; + u16 gbs; + u8 _padding1[2]; +} OSSramEx; + +OSSramEx* __OSLockSramEx(); +#endif diff --git a/obj_files.mk b/obj_files.mk index 1e2f8e75..1ab89283 100644 --- a/obj_files.mk +++ b/obj_files.mk @@ -819,7 +819,7 @@ CARD_FILES :=\ $(BUILD_DIR)/src/Dolphin/card/CARDUnlock.ep.o\ $(BUILD_DIR)/src/Dolphin/card/CARDRdwr.ep.o\ $(BUILD_DIR)/src/Dolphin/card/CARDBlock.ep.o\ - $(BUILD_DIR)/asm/Dolphin/card/CARDDir.o\ + $(BUILD_DIR)/src/Dolphin/card/CARDDir.ep.o\ $(BUILD_DIR)/asm/Dolphin/card/CARDCheck.o\ $(BUILD_DIR)/asm/Dolphin/card/CARDMount.o\ $(BUILD_DIR)/asm/Dolphin/card/CARDFormat.o\ diff --git a/src/Dolphin/card/CARDBios.c b/src/Dolphin/card/CARDBios.c index 897cdc56..671a2392 100644 --- a/src/Dolphin/card/CARDBios.c +++ b/src/Dolphin/card/CARDBios.c @@ -447,7 +447,7 @@ void CARDInit(void) { OSRegisterResetFunction(&ResetFunctionInfo); } -u16 __CARDGetFontEncode(s32 chan) { return __CARDEncode; } +u16 __CARDGetFontEncode() { return __CARDEncode; } void __CARDSetDiskID(const DVDDiskID* id) { __CARDBlock[0].diskID = id ? id : &__CARDDiskNone; diff --git a/src/Dolphin/card/CARDCheck.c b/src/Dolphin/card/CARDCheck.c new file mode 100644 index 00000000..ceeb050b --- /dev/null +++ b/src/Dolphin/card/CARDCheck.c @@ -0,0 +1,318 @@ +#include +#include +#include +#include + +#include +#include + +#define __CARDGetDirCheck(dir) ((CARDDirCheck*)&(dir)[CARD_MAX_FILE]) + +void __CARDCheckSum(void* ptr, int length, u16* checksum, u16* checksumInv) { + u16* p; + int i; + + length /= sizeof(u16); + *checksum = *checksumInv = 0; + for (i = 0, p = ptr; i < length; i++, p++) { + *checksum += *p; + *checksumInv += ~*p; + } + if (*checksum == 0xffff) { + *checksum = 0; + } + if (*checksumInv == 0xffff) { + *checksumInv = 0; + } +} + +static s32 VerifyID(CARDControl* card) { + CARDID* id; + u16 checksum; + u16 checksumInv; + OSSramEx* sramEx; + OSTime rand; + int i; + + id = card->workArea; + + if (id->deviceID != 0 || id->size != card->size) { + return CARD_RESULT_BROKEN; + } + + __CARDCheckSum(id, sizeof(CARDID) - sizeof(u32), &checksum, &checksumInv); + if (id->checkSum != checksum || id->checkSumInv != checksumInv) { + return CARD_RESULT_BROKEN; + } + + rand = *(OSTime*)&id->serial[12]; + sramEx = __OSLockSramEx(); + + for (i = 0; i < 12; i++) { + rand = (rand * 1103515245 + 12345) >> 16; + if (id->serial[i] != (u8)(sramEx->flashID[card - __CARDBlock][i] + rand)) { + __OSUnlockSramEx(FALSE); + return CARD_RESULT_BROKEN; + } + rand = ((rand * 1103515245 + 12345) >> 16) & 0x7FFF; + } + + __OSUnlockSramEx(FALSE); + if (id->encode != __CARDGetFontEncode()) { + return CARD_RESULT_ENCODING; + } + + return CARD_RESULT_READY; +} + +static s32 VerifyDir(CARDControl* card, int* outCurrent) { + CARDDir* dir[2]; + CARDDirCheck* check[2]; + u16 checkSum; + u16 checkSumInv; + int i; + int errors; + int current; + + current = errors = 0; + for (i = 0; i < 2; i++) { + dir[i] = (CARDDir*)((u8*)card->workArea + (1 + i) * CARD_SYSTEM_BLOCK_SIZE); + check[i] = __CARDGetDirCheck(dir[i]); + __CARDCheckSum(dir[i], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &checkSum, &checkSumInv); + if (check[i]->checkSum != checkSum || check[i]->checkSumInv != checkSumInv) { + ++errors; + current = i; + card->currentDir = 0; + } + } + + if (0 == errors) { + if (card->currentDir == 0) { + if ((check[0]->checkCode - check[1]->checkCode) < 0) { + current = 0; + } else { + current = 1; + } + card->currentDir = dir[current]; + memcpy(dir[current], dir[current ^ 1], CARD_SYSTEM_BLOCK_SIZE); + } else { + current = (card->currentDir == dir[0]) ? 0 : 1; + } + } + if (outCurrent) { + *outCurrent = current; + } + return errors; +} + +static s32 VerifyFAT(CARDControl* card, int* outCurrent) { + u16* fat[2]; + u16* fatp; + u16 nBlock; + u16 cFree; + int i; + u16 checkSum; + u16 checkSumInv; + int errors; + int current; + + current = errors = 0; + for (i = 0; i < 2; i++) { + fatp = fat[i] = (u16*)((u8*)card->workArea + (3 + i) * CARD_SYSTEM_BLOCK_SIZE); + + __CARDCheckSum(&fatp[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &checkSum, &checkSumInv); + if (fatp[CARD_FAT_CHECKSUM] != checkSum || fatp[CARD_FAT_CHECKSUMINV] != checkSumInv) { + ++errors; + current = i; + card->currentFat = 0; + continue; + } + + cFree = 0; + for (nBlock = CARD_NUM_SYSTEM_BLOCK; nBlock < card->cBlock; nBlock++) { + if (fatp[nBlock] == CARD_FAT_AVAIL) { + cFree++; + } + } + if (cFree != fatp[CARD_FAT_FREEBLOCKS]) { + ++errors; + current = i; + card->currentFat = 0; + continue; + } + } + + if (0 == errors) { + if (card->currentFat == 0) { + if (((s16)fat[0][CARD_FAT_CHECKCODE] - (s16)fat[1][CARD_FAT_CHECKCODE]) < 0) { + current = 0; + } else { + current = 1; + } + card->currentFat = fat[current]; + memcpy(fat[current], fat[current ^ 1], CARD_SYSTEM_BLOCK_SIZE); + } else { + current = (card->currentFat == fat[0]) ? 0 : 1; + } + } + if (outCurrent) { + *outCurrent = current; + } + return errors; +} + +s32 __CARDVerify(CARDControl* card) { + s32 result; + int errors; + + result = VerifyID(card); + if (result < 0) { + return result; + } + + errors = VerifyDir(card, NULL); + errors += VerifyFAT(card, NULL); + switch (errors) { + case 0: + return CARD_RESULT_READY; + case 1: + return CARD_RESULT_BROKEN; + default: + return CARD_RESULT_BROKEN; + } +} + +s32 CARDCheckExAsync(s32 chan, s32* xferBytes, CARDCallback callback) { + CARDControl* card; + CARDDir* dir[2]; + u16* fat[2]; + u16* map; + s32 result; + int errors; + int currentFat; + int currentDir; + s32 fileNo; + u16 iBlock; + u16 cBlock; + u16 cFree; + BOOL updateFat = FALSE; + BOOL updateDir = FALSE; + BOOL updateOrphan = FALSE; + + if (xferBytes) { + *xferBytes = 0; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + result = VerifyID(card); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + errors = VerifyDir(card, ¤tDir); + errors += VerifyFAT(card, ¤tFat); + if (1 < errors) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + + dir[0] = (CARDDir*)((u8*)card->workArea + (1 + 0) * CARD_SYSTEM_BLOCK_SIZE); + dir[1] = (CARDDir*)((u8*)card->workArea + (1 + 1) * CARD_SYSTEM_BLOCK_SIZE); + fat[0] = (u16*)((u8*)card->workArea + (3 + 0) * CARD_SYSTEM_BLOCK_SIZE); + fat[1] = (u16*)((u8*)card->workArea + (3 + 1) * CARD_SYSTEM_BLOCK_SIZE); + + switch (errors) { + case 0: + break; + case 1: + if (!card->currentDir) { + card->currentDir = dir[currentDir]; + memcpy(dir[currentDir], dir[currentDir ^ 1], CARD_SYSTEM_BLOCK_SIZE); + updateDir = TRUE; + } else { + card->currentFat = fat[currentFat]; + memcpy(fat[currentFat], fat[currentFat ^ 1], CARD_SYSTEM_BLOCK_SIZE); + updateFat = TRUE; + } + break; + } + + map = fat[currentFat ^ 1]; + memset(map, 0, CARD_SYSTEM_BLOCK_SIZE); + + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + CARDDir* ent; + + ent = &card->currentDir[fileNo]; + if (ent->gameName[0] == 0xff) { + continue; + } + + for (iBlock = ent->startBlock, cBlock = 0; iBlock != 0xFFFF && cBlock < ent->length; + iBlock = card->currentFat[iBlock], ++cBlock) { + if (!CARDIsValidBlockNo(card, iBlock) || 1 < ++map[iBlock]) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + if (cBlock != ent->length || iBlock != 0xFFFF) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + + cFree = 0; + for (iBlock = CARD_NUM_SYSTEM_BLOCK; iBlock < card->cBlock; iBlock++) { + u16 nextBlock; + + nextBlock = card->currentFat[iBlock]; + if (map[iBlock] == 0) { + if (nextBlock != CARD_FAT_AVAIL) { + card->currentFat[iBlock] = CARD_FAT_AVAIL; + updateOrphan = TRUE; + } + cFree++; + } else if (!CARDIsValidBlockNo(card, nextBlock) && nextBlock != 0xFFFF) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + if (cFree != card->currentFat[CARD_FAT_FREEBLOCKS]) { + card->currentFat[CARD_FAT_FREEBLOCKS] = cFree; + updateOrphan = TRUE; + } + if (updateOrphan) { + __CARDCheckSum(&card->currentFat[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &card->currentFat[CARD_FAT_CHECKSUM], + &card->currentFat[CARD_FAT_CHECKSUMINV]); + } + + memcpy(fat[currentFat ^ 1], fat[currentFat], CARD_SYSTEM_BLOCK_SIZE); + + if (updateDir) { + if (xferBytes) { + *xferBytes = CARD_SYSTEM_BLOCK_SIZE; + } + return __CARDUpdateDir(chan, callback); + } + + if (updateFat | updateOrphan) { + if (xferBytes) { + *xferBytes = CARD_SYSTEM_BLOCK_SIZE; + } + return __CARDUpdateFatBlock(chan, card->currentFat, callback); + } + + __CARDPutControlBlock(card, CARD_RESULT_READY); + if (callback) { + BOOL enabled = OSDisableInterrupts(); + callback(chan, CARD_RESULT_READY); + OSRestoreInterrupts(enabled); + } + return CARD_RESULT_READY; +} + +s32 CARDCheckAsync(s32 chan, CARDCallback callback) { + s32 xferBytes; + + return CARDCheckExAsync(chan, &xferBytes, callback); +} diff --git a/src/Dolphin/card/CARDDir.c b/src/Dolphin/card/CARDDir.c new file mode 100644 index 00000000..1daecf8e --- /dev/null +++ b/src/Dolphin/card/CARDDir.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include + +#include + +CARDDir* __CARDGetDirBlock(CARDControl* card) { return card->currentDir; } + +static void WriteCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (0 <= result) { + CARDDir* dir0 = (CARDDir*)((u8*)card->workArea + 0x2000); + CARDDir* dir1 = (CARDDir*)((u8*)card->workArea + 0x4000); + + if (card->currentDir == dir0) { + card->currentDir = dir1; + memcpy(dir1, dir0, 0x2000); + } else { + card->currentDir = dir0; + memcpy(dir0, dir1, 0x2000); + } + } + +error: + if (card->apiCallback == 0) { + __CARDPutControlBlock(card, result); + } + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = 0; + callback(chan, result); + } +} + +static void EraseCallback(s32 chan, s32 result) { + CARDControl* card; + CARDCallback callback; + CARDDir* dir; + u32 tmp[2]; + u32 addr; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + dir = __CARDGetDirBlock(card); + addr = ((u32)dir - (u32)card->workArea) / 0x2000 * card->sectorSize; + result = __CARDWrite(chan, addr, 0x2000, dir, WriteCallback); + if (result < 0) { + goto error; + } + + return; + +error: + if (card->apiCallback == 0) { + __CARDPutControlBlock(card, result); + } + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = 0; + callback(chan, result); + } +} + +s32 __CARDUpdateDir(s32 chan, CARDCallback callback) { + CARDControl* card; + CARDDirCheck* check; + u32 tmp[2]; + u32 addr; + CARDDir* dir; + + card = &__CARDBlock[chan]; + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + dir = __CARDGetDirBlock(card); + check = __CARDGetDirCheck(dir); + ++check->checkCode; + __CARDCheckSum(dir, 0x2000 - sizeof(u32), &check->checkSum, &check->checkSumInv); + DCStoreRange(dir, 0x2000); + + card->eraseCallback = callback; + addr = ((u32)dir - (u32)card->workArea) / 0x2000 * card->sectorSize; + return __CARDEraseSector(chan, addr, EraseCallback); +}