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
This commit is contained in:
sulokutdcmago@gmail.com
2012-09-14 15:03:10 +00:00
parent b9af1e0967
commit ca016f3151
3 changed files with 145 additions and 0 deletions

View File

@@ -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_0 || 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);
}

View File

@@ -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);

View File

@@ -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;
}