From ca016f315154a17b57d7b5b096796beae06eb862 Mon Sep 17 00:00:00 2001 From: "sulokutdcmago@gmail.com" Date: Fri, 14 Sep 2012 15:03:10 +0000 Subject: [PATCH] F-zero and Phantasy Star Online Ep I&II and Phantasy Star Online III savegames are patched uppon restoring so they will work on target card. Lot's of thanks to Ralf at gscentral.org forums http://board.gscentral.org/retro-hacking/53093.htm#post188949 --- source/card.c | 29 +++++++++++++ source/card.h | 7 ++++ source/mcard.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) diff --git a/source/card.c b/source/card.c index acbe134..57d246b 100644 --- a/source/card.c +++ b/source/card.c @@ -188,6 +188,7 @@ static s32 __card_updatedir(s32 chn,cardcallback callback); static s32 __card_writepage(s32 chn,cardcallback callback); s32 __card_sectorerase(s32 chn,u32 sector,cardcallback callback); static s32 __card_onreset(s32 final); +s32 CARD_GetSerialNo(s32 chn,u32 *serial1,u32 *serial2); static sys_resetinfo card_resetinfo = { {}, @@ -3199,3 +3200,31 @@ s32 CARD_SetGamecode(const char *gamecode) return CARD_ERROR_READY; } + +//The following code is made by Ralf at GSCentral forums (gscentral.org) +//http://board.gscentral.org/retro-hacking/53093.htm#post188949 + +/***********************************************************/ +/* CARD_GetSerialNo */ +/* */ +/* serial1 & serial2: Encrypted memory card serial numbers */ +/* chn: Memory card port */ +/* ret: Error code */ +/***********************************************************/ +//note the full serial number is an u64 (serial1+serial2) +s32 CARD_GetSerialNo(s32 chn,u32 *serial1,u32 *serial2) +{ + s32 ret; + card_block *card = NULL; + struct card_header *header; + + if(chn=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR; + if((ret=__card_getcntrlblock(chn,&card))<0) return ret; + + header = card->workarea; + + *serial1 = header->serial[0]^header->serial[2]^header->serial[4]^header->serial[6]; + *serial2 = header->serial[1]^header->serial[3]^header->serial[5]^header->serial[7]; + + return __card_putcntrlblock(card,ret); +} diff --git a/source/card.h b/source/card.h index baa5c64..4b634e5 100644 --- a/source/card.h +++ b/source/card.h @@ -620,6 +620,13 @@ s32 __card_getstatusex(s32 chn,s32 fileno,struct card_direntry *entry); */ s32 __card_setstatusex(s32 chn,s32 fileno,struct card_direntry *entry); +/* CARD_GetSerialNo */ +/* */ +/* serial1 & serial2: Encrypted memory card serial numbers */ +/* chn: Memory card port */ +/* ret: Error code */ +s32 CARD_GetSerialNo(s32 chn,u32 *serial1,u32 *serial2); + // Raw read and write functions s32 __card_read(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback); s32 __card_write(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback); diff --git a/source/mcard.c b/source/mcard.c index 6508358..ce46aec 100644 --- a/source/mcard.c +++ b/source/mcard.c @@ -58,6 +58,11 @@ s32 memsize, sectsize; GCI gci; +//The following code is made by Ralf at GSCentral forums (gscentral.org) +//http://board.gscentral.org/retro-hacking/53093.htm#post188949 +s32 FZEROGX_MakeSaveGameValid(s32 chn); +s32 PSO_MakeSaveGameValid(s32 chn); + /*--------------------------------------------------------------------------------- This function is called if a card is physically removed ---------------------------------------------------------------------------------*/ @@ -589,6 +594,10 @@ tryagain: return 0; } +//Thanks to Ralf, validate F-zero and PSO savegames + FZEROGX_MakeSaveGameValid(slot); + PSO_MakeSaveGameValid(slot); + /*** Now write the file data, in sector sized chunks ***/ offset = 0; while (offset < filelen) @@ -813,3 +822,103 @@ void MC_FormatMode(s32 slot) WaitPrompt("Format operation cancelled"); return; } + +//The following code is made by Ralf at GSCentral forums (gscentral.org) +//http://board.gscentral.org/retro-hacking/53093.htm#post188949 + +// u8 FileBuffer[MAXFILEBUFFER]: .gci file buffer +// MCDATAOFFSET: .gci header size (0x40 bytes) + +/*************************************************************/ +/* FZEROGX_MakeSaveGameValid */ +/* (use just before writing a F-Zero GX system .gci file) */ +/* */ +/* chn: Destination memory card port */ +/* ret: Error code */ +/*************************************************************/ + +s32 FZEROGX_MakeSaveGameValid(s32 chn) +{ + s32 ret; + u32 i,j; + u32 serial1,serial2; + u16 chksum = 0xFFFF; + + if(stricmp(&FileBuffer[0x08],"f_zero.dat")!=0) return CARD_ERROR_READY; // check for F-Zero GX system file + if((ret=CARD_GetSerialNo(chn,&serial1,&serial2))<0) return ret; // get encrypted destination memory card serial numbers + + *(u16*)&FileBuffer[0x2066+MCDATAOFFSET] = serial1 >> 16; // set new serial numbers + *(u16*)&FileBuffer[0x7580+MCDATAOFFSET] = serial2 >> 16; + *(u16*)&FileBuffer[0x2060+MCDATAOFFSET] = serial1 & 0xFFFF; + *(u16*)&FileBuffer[0x2200+MCDATAOFFSET] = serial2 & 0xFFFF; + + for(i=0x02+MCDATAOFFSET;i<0x8000+MCDATAOFFSET;i++) { // calc 16-bit checksum + chksum ^= (FileBuffer[i]&0xFF); + + for(j=8;j>0;j--) { + if (chksum&1) chksum = (chksum>>1)^0x8408; + else chksum >>= 1; + } + } + + *(u16*)&FileBuffer[0x00+MCDATAOFFSET] = ~chksum; // set new checksum + + return ret; +} + +/***********************************************************/ +/* PSO_MakeSaveGameValid */ +/* (use just before writing a PSO system .gci file) */ +/* */ +/* chn: Destination memory card port */ +/* ret: Error code */ +/***********************************************************/ + +s32 PSO_MakeSaveGameValid(s32 chn) +{ + s32 ret; + u32 i,j; + u32 chksum; + u32 crc32LUT[256]; + u32 serial1,serial2; + u32 pso3offset; + + if(stricmp(&FileBuffer[0x08],"PSO_SYSTEM")==0) { // check for PSO1&2 system file + pso3offset = 0x00; + goto exit; + } + + if(stricmp(&FileBuffer[0x08],"PSO3_SYSTEM")==0) { // check for PSO3 system file + pso3offset = 0x10; // PSO3 data block size adjustment + goto exit; + } + + return CARD_ERROR_READY; // nothing to do +exit: + if((ret=CARD_GetSerialNo(chn,&serial1,&serial2))<0) return ret; // get encrypted destination memory card serial numbers + + *(u32*)&FileBuffer[0x2158+MCDATAOFFSET] = serial1; // set new serial numbers + *(u32*)&FileBuffer[0x215C+MCDATAOFFSET] = serial2; + + for(i=0;i<256;i++) { // generate crc32 LUT + chksum = i; + + for(j=8;j>0;j--) { + if (chksum&1) chksum = (chksum>>1)^0xEDB88320; + else chksum >>= 1; + } + + crc32LUT[i] = chksum; + } + + chksum = 0xDEBB20E3; // PSO initial crc32 value + + for (i=0x204C+MCDATAOFFSET;i<0x2164+pso3offset+MCDATAOFFSET;i++) { // calc 32-bit checksum + chksum = ((chksum>>8)&0xFFFFFF)^crc32LUT[(chksum^FileBuffer[i])&0xFF]; + } + + *(u32*)&FileBuffer[0x2048+MCDATAOFFSET] = chksum^0xFFFFFFFF; // set new checksum + + return ret; +} +