mirror of
https://github.com/pret/berry-fix.git
synced 2026-04-25 07:27:25 -05:00
Sync save
This commit is contained in:
parent
43d0fa817e
commit
df4fa5e88b
8
payload/common_syms/save.txt
Normal file
8
payload/common_syms/save.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
gLastWrittenSector
|
||||
gLastSaveCounter
|
||||
gLastKnownGoodSector
|
||||
gDamagedSaveSectors
|
||||
gSaveCounter
|
||||
gReadWriteSector
|
||||
gIncrementalSectorId
|
||||
gFlashIdentIsValid
|
||||
|
|
@ -42,6 +42,13 @@ enum
|
|||
SECTOR_CHECK, // unused
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SAVE_NORMAL, // Save full save slot
|
||||
SAVE_SAVEBLOCKS, // Save just SaveBlock1 and SaveBlock2
|
||||
SAVE_SAVEBLOCK2, // Save just SaveBlock2
|
||||
};
|
||||
|
||||
enum MsgBoxUpdateMessage
|
||||
{
|
||||
MSGBOX_WILL_NOW_UPDATE = 0,
|
||||
|
|
@ -62,13 +69,9 @@ struct SaveSector
|
|||
}; // size is SECTOR_SIZE (0x1000)
|
||||
|
||||
#define SECTOR_SECURITY_OFFSET offsetof(struct SaveSector, security)
|
||||
#define SECTOR_COUNTER_OFFSET offsetof(struct SaveSector, counter)
|
||||
|
||||
#define eSaveSection ((struct SaveSector *)0x2020000)
|
||||
|
||||
|
||||
bool32 flash_maincb_ident_is_valid(void);
|
||||
bool8 flash_maincb_read_save(u32);
|
||||
bool32 BerryFix_IdentifyFlash(void);
|
||||
bool8 BerryFix_LoadSave(u32);
|
||||
void msg_load_gfx(void);
|
||||
void msg_display(enum MsgBoxUpdateMessage);
|
||||
bool32 flash_maincb_check_need_reset_pacifidlog_tm(void);
|
||||
|
|
|
|||
|
|
@ -200,13 +200,13 @@ void main_callback(u32 * state, void * unused1, void * unused2)
|
|||
++(*state); // MAINCB_CHECK_FLASH
|
||||
break;
|
||||
case MAINCB_CHECK_FLASH:
|
||||
if (flash_maincb_ident_is_valid() == TRUE)
|
||||
if (BerryFix_IdentifyFlash() == TRUE)
|
||||
++(*state); // MAINCB_READ_SAVE
|
||||
else
|
||||
*state = MAINCB_ERROR;
|
||||
break;
|
||||
case MAINCB_READ_SAVE:
|
||||
if (flash_maincb_read_save(0) == SAVE_STATUS_OK)
|
||||
if (BerryFix_LoadSave(0) == SAVE_STATUS_OK)
|
||||
++(*state); // MAINCB_CHECK_TIME
|
||||
else
|
||||
*state = MAINCB_ERROR;
|
||||
|
|
|
|||
|
|
@ -3,31 +3,38 @@
|
|||
#include "save.h"
|
||||
#include "rtc.h"
|
||||
|
||||
/*
|
||||
The Berry Fix Program contains a copy of most of Ruby/Sapphire's save code.
|
||||
Much of it lies unused.
|
||||
*/
|
||||
|
||||
struct SaveBlockChunk
|
||||
{
|
||||
u8 * data;
|
||||
u16 size;
|
||||
};
|
||||
|
||||
u8 WriteSaveBlockChunks(u16, const struct SaveBlockChunk *);
|
||||
u8 WriteSingleChunk(u16, const struct SaveBlockChunk *);
|
||||
u8 TryWriteSector(u8, u8 *);
|
||||
static u8 WriteSaveSectorOrSlot(u16, const struct SaveBlockChunk *);
|
||||
static u8 HandleWriteSector(u16, const struct SaveBlockChunk *);
|
||||
static u8 TryWriteSector(u8, u8 *);
|
||||
static u8 HandleReplaceSector(u16, const struct SaveBlockChunk *);
|
||||
u8 TryReadAllSaveSectorsCurrentSlot(u16, const struct SaveBlockChunk *);
|
||||
u8 ReadAllSaveSectorsCurrentSlot(u16, const struct SaveBlockChunk *);
|
||||
u8 GetSaveValidStatus(const struct SaveBlockChunk *);
|
||||
u32 DoReadFlashWholeSection(u8, struct SaveSector *);
|
||||
u16 CalculateChecksum(const void *, u16);
|
||||
static u8 TryLoadSaveSlot(u16, const struct SaveBlockChunk *);
|
||||
static u8 CopySaveSlotData(u16, const struct SaveBlockChunk *);
|
||||
static u8 GetSaveValidStatus(const struct SaveBlockChunk *);
|
||||
static u32 ReadFlashSector(u8, struct SaveSector *);
|
||||
static u16 CalculateChecksum(const void *, u16);
|
||||
|
||||
u16 gLastWrittenSector;
|
||||
u32 gPrevSaveCounter;
|
||||
u32 gLastSaveCounter;
|
||||
u16 gLastKnownGoodSector;
|
||||
u32 gDamagedSaveSectors;
|
||||
u32 gSaveCounter;
|
||||
struct SaveSector * gReadWriteSector;
|
||||
u16 gCurSaveChunk;
|
||||
u16 gIncrementalSectorId;
|
||||
bool32 gFlashIdentIsValid;
|
||||
|
||||
#define gSaveDataBuffer ((struct SaveSector *)(EWRAM_START + 0x20000))
|
||||
|
||||
EWRAM_DATA struct SaveBlock2 gSaveBlock2 = {};
|
||||
EWRAM_DATA struct SaveBlock1 gSaveBlock1 = {};
|
||||
EWRAM_DATA struct PokemonStorage gPokemonStorage = {};
|
||||
|
|
@ -62,7 +69,7 @@ const u16 gInfoMessagesPal[] = INCBIN_U16("graphics/msg_box.gbapal");
|
|||
const u8 gInfoMessagesTilemap[] = INCBIN_U8("graphics/msg_box.tilemap.lz");
|
||||
const u8 gInfoMessagesGfx[] = INCBIN_U8("graphics/msg_box.4bpp.lz");
|
||||
|
||||
bool32 flash_maincb_ident_is_valid(void)
|
||||
bool32 BerryFix_IdentifyFlash(void)
|
||||
{
|
||||
gFlashIdentIsValid = TRUE;
|
||||
if (!IdentifyFlash())
|
||||
|
|
@ -74,61 +81,59 @@ bool32 flash_maincb_ident_is_valid(void)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
void Call_ReadFlash(u16 sectorNum, ptrdiff_t offset, void * dest, size_t size)
|
||||
// Unused
|
||||
static void BerryFix_ReadFlash(u16 sectorNum, ptrdiff_t offset, void * dest, size_t size)
|
||||
{
|
||||
ReadFlash(sectorNum, offset, dest, size);
|
||||
}
|
||||
|
||||
u8 Call_WriteSaveBlockChunks(u16 a0, const struct SaveBlockChunk * a1)
|
||||
static u8 BerryFix_WriteSaveSectorOrSlot(u16 sectorId, const struct SaveBlockChunk * chunks)
|
||||
{
|
||||
return WriteSaveBlockChunks(a0, a1);
|
||||
return WriteSaveSectorOrSlot(sectorId, chunks);
|
||||
}
|
||||
|
||||
u8 Call_TryReadAllSaveSectorsCurrentSlot(u16 a0, const struct SaveBlockChunk * a1)
|
||||
static u8 BerryFix_TryLoadSaveSlot(u16 sectorId, const struct SaveBlockChunk * chunks)
|
||||
{
|
||||
return TryReadAllSaveSectorsCurrentSlot(a0, a1);
|
||||
return TryLoadSaveSlot(sectorId, chunks);
|
||||
}
|
||||
|
||||
u32 * GetDamagedSaveSectorsPtr(void)
|
||||
static u32 * BerryFix_GetDamagedSaveSectors(void)
|
||||
{
|
||||
return &gDamagedSaveSectors;
|
||||
}
|
||||
|
||||
s32 flash_write_save_block_chunks(u8 a0)
|
||||
static s32 BerryFix_Save(u8 mode)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
switch (a0)
|
||||
switch (mode)
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
Call_WriteSaveBlockChunks(0xFFFF, sSaveBlockChunks);
|
||||
break;
|
||||
case 1:
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
Call_WriteSaveBlockChunks(i, sSaveBlockChunks);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
Call_WriteSaveBlockChunks(0, sSaveBlockChunks);
|
||||
break;
|
||||
case SAVE_NORMAL:
|
||||
default:
|
||||
BerryFix_WriteSaveSectorOrSlot(FULL_SAVE_SLOT, sSaveBlockChunks);
|
||||
break;
|
||||
case SAVE_SAVEBLOCKS:
|
||||
for (i = SECTOR_ID_SAVEBLOCK2; i <= SECTOR_ID_SAVEBLOCK1_END; i++)
|
||||
BerryFix_WriteSaveSectorOrSlot(i, sSaveBlockChunks);
|
||||
break;
|
||||
case SAVE_SAVEBLOCK2:
|
||||
BerryFix_WriteSaveSectorOrSlot(SECTOR_ID_SAVEBLOCK2, sSaveBlockChunks);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 flash_write_save_block_chunks_check_damage(u8 a0)
|
||||
u8 BerryFix_TrySave(u8 mode)
|
||||
{
|
||||
flash_write_save_block_chunks(a0);
|
||||
if (*GetDamagedSaveSectorsPtr() == 0)
|
||||
return 1;
|
||||
return 0xFF;
|
||||
BerryFix_Save(mode);
|
||||
if (*BerryFix_GetDamagedSaveSectors() == 0)
|
||||
return SAVE_STATUS_OK;
|
||||
return SAVE_STATUS_ERROR;
|
||||
}
|
||||
|
||||
u8 flash_maincb_read_save(u32 unused)
|
||||
u8 BerryFix_LoadSave(u32 unused)
|
||||
{
|
||||
return Call_TryReadAllSaveSectorsCurrentSlot(0xFFFF, sSaveBlockChunks);
|
||||
return BerryFix_TryLoadSaveSlot(FULL_SAVE_SLOT, sSaveBlockChunks);
|
||||
}
|
||||
|
||||
void msg_load_gfx(void)
|
||||
|
|
@ -139,7 +144,7 @@ void msg_load_gfx(void)
|
|||
REG_BLDCNT = 0;
|
||||
LZ77UnCompVram(gInfoMessagesGfx, (void *)BG_VRAM);
|
||||
LZ77UnCompVram(gInfoMessagesTilemap, (void *)BG_SCREEN_ADDR(28));
|
||||
CpuCopy16(gInfoMessagesPal, (void *)BG_PLTT, 0x200);
|
||||
CpuCopy16(gInfoMessagesPal, (void *)BG_PLTT, BG_PLTT_SIZE);
|
||||
REG_BG0CNT = BGCNT_SCREENBASE(28) | BGCNT_TXT512x512;
|
||||
REG_DISPCNT = DISPCNT_BG0_ON;
|
||||
}
|
||||
|
|
@ -171,199 +176,220 @@ void msg_display(enum MsgBoxUpdateMessage a0)
|
|||
}
|
||||
}
|
||||
|
||||
void Save_EraseAllData(void)
|
||||
// Unused
|
||||
static void ClearSaveData(void)
|
||||
{
|
||||
u16 i;
|
||||
for (i = 0; i < 32; i++)
|
||||
for (i = 0; i < SECTORS_COUNT; i++)
|
||||
EraseFlashSector(i);
|
||||
}
|
||||
|
||||
void Save_ResetSaveCounters(void)
|
||||
// Unused
|
||||
static void Save_ResetSaveCounters(void)
|
||||
{
|
||||
gSaveCounter = 0;
|
||||
gLastWrittenSector = 0;
|
||||
gDamagedSaveSectors = 0;
|
||||
}
|
||||
|
||||
bool32 SetSectorDamagedStatus(u8 op, u8 sectorNum)
|
||||
static bool32 SetDamagedSectorBits(u8 op, u8 sectorId)
|
||||
{
|
||||
bool32 retVal = FALSE;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case SECTOR_DAMAGED:
|
||||
gDamagedSaveSectors |= (1 << sectorNum);
|
||||
break;
|
||||
case SECTOR_OK:
|
||||
gDamagedSaveSectors &= ~(1 << sectorNum);
|
||||
break;
|
||||
case SECTOR_CHECK: // unused
|
||||
if (gDamagedSaveSectors & (1 << sectorNum))
|
||||
retVal = TRUE;
|
||||
break;
|
||||
case SECTOR_DAMAGED:
|
||||
gDamagedSaveSectors |= (1 << sectorId);
|
||||
break;
|
||||
case SECTOR_OK:
|
||||
gDamagedSaveSectors &= ~(1 << sectorId);
|
||||
break;
|
||||
case SECTOR_CHECK: // unused
|
||||
if (gDamagedSaveSectors & (1 << sectorId))
|
||||
retVal = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
u8 WriteSaveBlockChunks(u16 chunkId, const struct SaveBlockChunk *chunks)
|
||||
static u8 WriteSaveSectorOrSlot(u16 sectorId, const struct SaveBlockChunk *chunks)
|
||||
{
|
||||
u32 retVal;
|
||||
u32 status;
|
||||
u16 i;
|
||||
|
||||
gReadWriteSector = eSaveSection;
|
||||
gReadWriteSector = gSaveDataBuffer;
|
||||
|
||||
if (chunkId != 0xFFFF) // write single chunk
|
||||
if (sectorId != FULL_SAVE_SLOT)
|
||||
{
|
||||
retVal = WriteSingleChunk(chunkId, chunks);
|
||||
// A sector was specified, just write that sector.
|
||||
status = HandleWriteSector(sectorId, chunks);
|
||||
}
|
||||
else // write all chunks
|
||||
else
|
||||
{
|
||||
// No sector was specified, write full save slot.
|
||||
gLastKnownGoodSector = gLastWrittenSector;
|
||||
gPrevSaveCounter = gSaveCounter;
|
||||
gLastSaveCounter = gSaveCounter;
|
||||
gLastWrittenSector++;
|
||||
gLastWrittenSector %= NUM_SECTORS_PER_SLOT;
|
||||
gSaveCounter++;
|
||||
retVal = SAVE_STATUS_OK;
|
||||
status = SAVE_STATUS_OK;
|
||||
|
||||
for (i = 0; i < NUM_SECTORS_PER_SLOT; i++)
|
||||
WriteSingleChunk(i, chunks);
|
||||
HandleWriteSector(i, chunks);
|
||||
|
||||
// Check for any bad sectors
|
||||
if (gDamagedSaveSectors != 0) // skip the damaged sector.
|
||||
if (gDamagedSaveSectors)
|
||||
{
|
||||
retVal = SAVE_STATUS_ERROR;
|
||||
// At least one sector save failed
|
||||
status = SAVE_STATUS_ERROR;
|
||||
gLastWrittenSector = gLastKnownGoodSector;
|
||||
gSaveCounter = gPrevSaveCounter;
|
||||
gSaveCounter = gLastSaveCounter;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
return status;
|
||||
}
|
||||
|
||||
u8 WriteSingleChunk(u16 chunkId, const struct SaveBlockChunk * chunks)
|
||||
static u8 HandleWriteSector(u16 sectorId, const struct SaveBlockChunk * chunks)
|
||||
{
|
||||
u16 i;
|
||||
u16 sectorNum;
|
||||
u8 *chunkData;
|
||||
u16 chunkSize;
|
||||
u8 *data;
|
||||
u16 size;
|
||||
|
||||
// select sector number
|
||||
sectorNum = chunkId + gLastWrittenSector;
|
||||
// Adjust sector id for current save slot
|
||||
sectorNum = sectorId + gLastWrittenSector;
|
||||
sectorNum %= NUM_SECTORS_PER_SLOT;
|
||||
// select save slot
|
||||
sectorNum += NUM_SECTORS_PER_SLOT * (gSaveCounter % 2);
|
||||
sectorNum += NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS);
|
||||
|
||||
chunkData = chunks[chunkId].data;
|
||||
chunkSize = chunks[chunkId].size;
|
||||
// Get current save data
|
||||
data = chunks[sectorId].data;
|
||||
size = chunks[sectorId].size;
|
||||
|
||||
// clear save section.
|
||||
for (i = 0; i < sizeof(struct SaveSector); i++)
|
||||
// Clear temp save sector
|
||||
for (i = 0; i < SECTOR_SIZE; i++)
|
||||
((u8 *)gReadWriteSector)[i] = 0;
|
||||
|
||||
gReadWriteSector->id = chunkId;
|
||||
// Set footer data
|
||||
gReadWriteSector->id = sectorId;
|
||||
gReadWriteSector->security = SECTOR_SECURITY_NUM;
|
||||
gReadWriteSector->counter = gSaveCounter;
|
||||
for (i = 0; i < chunkSize; i++)
|
||||
gReadWriteSector->data[i] = chunkData[i];
|
||||
gReadWriteSector->checksum = CalculateChecksum(chunkData, chunkSize);
|
||||
|
||||
// Copy current data to temp buffer for writing
|
||||
for (i = 0; i < size; i++)
|
||||
gReadWriteSector->data[i] = data[i];
|
||||
|
||||
gReadWriteSector->checksum = CalculateChecksum(data, size);
|
||||
|
||||
return TryWriteSector(sectorNum, gReadWriteSector->data);
|
||||
}
|
||||
|
||||
u8 HandleWriteSectorNBytes(u8 sectorNum, u8 *data, u16 size)
|
||||
// Unused
|
||||
static u8 HandleWriteSectorNBytes(u8 sectorId, u8 *data, u16 size)
|
||||
{
|
||||
u16 i;
|
||||
struct SaveSector *section = eSaveSection;
|
||||
struct SaveSector *sector = gSaveDataBuffer;
|
||||
|
||||
for (i = 0; i < sizeof(struct SaveSector); i++)
|
||||
((char *)section)[i] = 0;
|
||||
// Clear temp save sector
|
||||
for (i = 0; i < SECTOR_SIZE; i++)
|
||||
((u8 *)sector)[i] = 0;
|
||||
|
||||
section->security = SECTOR_SECURITY_NUM;
|
||||
sector->security = SECTOR_SECURITY_NUM;
|
||||
|
||||
// Copy data to temp buffer for writing
|
||||
for (i = 0; i < size; i++)
|
||||
section->data[i] = data[i];
|
||||
section->id = CalculateChecksum(data, size); // though this appears to be incorrect, it might be some sector checksum instead of a whole save checksum and only appears to be relevent to HOF data, if used.
|
||||
sector->data[i] = data[i];
|
||||
|
||||
return TryWriteSector(sectorNum, section->data);
|
||||
sector->id = CalculateChecksum(data, size); // though this appears to be incorrect, it might be some sector checksum instead of a whole save checksum and only appears to be relevent to HOF data, if used.
|
||||
return TryWriteSector(sectorId, sector->data);
|
||||
}
|
||||
|
||||
u8 TryWriteSector(u8 sectorNum, u8 *data)
|
||||
static u8 TryWriteSector(u8 sectorNum, u8 *data)
|
||||
{
|
||||
if (ProgramFlashSectorAndVerify(sectorNum, data) != 0) // is damaged?
|
||||
{
|
||||
SetSectorDamagedStatus(SECTOR_DAMAGED, sectorNum); // set damaged sector bits.
|
||||
// Failed
|
||||
SetDamagedSectorBits(SECTOR_DAMAGED, sectorNum);
|
||||
return SAVE_STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSectorDamagedStatus(SECTOR_OK, sectorNum); // unset damaged sector bits. it's safe now.
|
||||
// Succeeded
|
||||
SetDamagedSectorBits(SECTOR_OK, sectorNum);
|
||||
return SAVE_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
u32 RestoreSaveBackupVarsAndIncrement(const struct SaveBlockChunk *chunk) // chunk is unused
|
||||
// Unused
|
||||
static u32 RestoreSaveBackupVarsAndIncrement(const struct SaveBlockChunk *chunks)
|
||||
{
|
||||
gReadWriteSector = eSaveSection;
|
||||
gReadWriteSector = gSaveDataBuffer;
|
||||
gLastKnownGoodSector = gLastWrittenSector;
|
||||
gPrevSaveCounter = gSaveCounter;
|
||||
gLastSaveCounter = gSaveCounter;
|
||||
gLastWrittenSector++;
|
||||
gLastWrittenSector %= NUM_SECTORS_PER_SLOT;
|
||||
gSaveCounter++;
|
||||
gCurSaveChunk = 0;
|
||||
gIncrementalSectorId = 0;
|
||||
gDamagedSaveSectors = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 RestoreSaveBackupVars(const struct SaveBlockChunk *chunk)
|
||||
// Unused
|
||||
static u32 RestoreSaveBackupVars(const struct SaveBlockChunk *chunks)
|
||||
{
|
||||
gReadWriteSector = eSaveSection;
|
||||
gReadWriteSector = gSaveDataBuffer;
|
||||
gLastKnownGoodSector = gLastWrittenSector;
|
||||
gPrevSaveCounter = gSaveCounter;
|
||||
gCurSaveChunk = 0;
|
||||
gLastSaveCounter = gSaveCounter;
|
||||
gIncrementalSectorId = 0;
|
||||
gDamagedSaveSectors = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 WriteSingleChunkAndIncrement(u16 a1, const struct SaveBlockChunk * chunk)
|
||||
// Unused
|
||||
static u8 HandleWriteIncrementalSector(u16 numSectors, const struct SaveBlockChunk * chunks)
|
||||
{
|
||||
u8 retVal;
|
||||
u8 status;
|
||||
|
||||
if (gCurSaveChunk < a1 - 1)
|
||||
if (gIncrementalSectorId < numSectors - 1)
|
||||
{
|
||||
retVal = SAVE_STATUS_OK;
|
||||
WriteSingleChunk(gCurSaveChunk, chunk);
|
||||
gCurSaveChunk++;
|
||||
status = SAVE_STATUS_OK;
|
||||
HandleWriteSector(gIncrementalSectorId, chunks);
|
||||
gIncrementalSectorId++;
|
||||
if (gDamagedSaveSectors)
|
||||
{
|
||||
retVal = SAVE_STATUS_ERROR;
|
||||
status = SAVE_STATUS_ERROR;
|
||||
gLastWrittenSector = gLastKnownGoodSector;
|
||||
gSaveCounter = gPrevSaveCounter;
|
||||
gSaveCounter = gLastSaveCounter;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = SAVE_STATUS_ERROR;
|
||||
// Exceeded max sector, finished
|
||||
status = SAVE_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
return status;
|
||||
}
|
||||
|
||||
u8 ErasePreviousChunk(u16 a1, const struct SaveBlockChunk *chunk)
|
||||
// Unused
|
||||
static u8 HandleReplaceSectorAndVerify(u16 sectorId, const struct SaveBlockChunk *chunks)
|
||||
{
|
||||
u8 retVal = SAVE_STATUS_OK;
|
||||
u8 status = SAVE_STATUS_OK;
|
||||
|
||||
HandleReplaceSector(a1 - 1, chunk);
|
||||
HandleReplaceSector(sectorId - 1, chunks);
|
||||
|
||||
if (gDamagedSaveSectors)
|
||||
{
|
||||
retVal = SAVE_STATUS_ERROR;
|
||||
status = SAVE_STATUS_ERROR;
|
||||
gLastWrittenSector = gLastKnownGoodSector;
|
||||
gSaveCounter = gPrevSaveCounter;
|
||||
gSaveCounter = gLastSaveCounter;
|
||||
}
|
||||
return retVal;
|
||||
return status;
|
||||
}
|
||||
|
||||
static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *locations)
|
||||
// Unused
|
||||
// Similar to HandleWriteSector, but fully erases the sector first, and skips writing the first security byte
|
||||
static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *chunks)
|
||||
{
|
||||
u16 i;
|
||||
u16 sector;
|
||||
|
|
@ -377,8 +403,8 @@ static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *locatio
|
|||
sector += NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS);
|
||||
|
||||
// Get current save data
|
||||
data = locations[sectorId].data;
|
||||
size = locations[sectorId].size;
|
||||
data = chunks[sectorId].data;
|
||||
size = chunks[sectorId].size;
|
||||
|
||||
// Clear temp save sector.
|
||||
for (i = 0; i < SECTOR_SIZE; i++)
|
||||
|
|
@ -412,7 +438,7 @@ static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *locatio
|
|||
if (status == SAVE_STATUS_ERROR)
|
||||
{
|
||||
// Writing save data failed
|
||||
SetSectorDamagedStatus(SECTOR_DAMAGED, sector);
|
||||
SetDamagedSectorBits(SECTOR_DAMAGED, sector);
|
||||
return SAVE_STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
|
|
@ -434,19 +460,20 @@ static u8 HandleReplaceSector(u16 sectorId, const struct SaveBlockChunk *locatio
|
|||
if (status == SAVE_STATUS_ERROR)
|
||||
{
|
||||
// Writing security/counter failed
|
||||
SetSectorDamagedStatus(SECTOR_DAMAGED, sector);
|
||||
SetDamagedSectorBits(SECTOR_DAMAGED, sector);
|
||||
return SAVE_STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Succeeded
|
||||
SetSectorDamagedStatus(SECTOR_OK, sector);
|
||||
SetDamagedSectorBits(SECTOR_OK, sector);
|
||||
return SAVE_STATUS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static u8 CopySectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *locations)
|
||||
// Unused
|
||||
static u8 CopySectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *chunks)
|
||||
{
|
||||
// Adjust sector id for current save slot
|
||||
u16 sector = sectorId + gLastWrittenSector - 1;
|
||||
|
|
@ -457,19 +484,20 @@ static u8 CopySectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *loca
|
|||
if (ProgramFlashByte(sector, SECTOR_SECURITY_OFFSET, ((u8 *)gReadWriteSector)[SECTOR_SECURITY_OFFSET]))
|
||||
{
|
||||
// Sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter.
|
||||
SetSectorDamagedStatus(SECTOR_DAMAGED, sector);
|
||||
SetDamagedSectorBits(SECTOR_DAMAGED, sector);
|
||||
gLastWrittenSector = gLastKnownGoodSector;
|
||||
gSaveCounter = gPrevSaveCounter;
|
||||
gSaveCounter = gLastSaveCounter;
|
||||
return SAVE_STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSectorDamagedStatus(SECTOR_OK, sector);
|
||||
SetDamagedSectorBits(SECTOR_OK, sector);
|
||||
return SAVE_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 WriteSectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *locations)
|
||||
// Unused
|
||||
static u8 WriteSectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *chunks)
|
||||
{
|
||||
// Adjust sector id for current save slot
|
||||
u16 sector = sectorId + gLastWrittenSector - 1;
|
||||
|
|
@ -480,52 +508,57 @@ static u8 WriteSectorSecurityByte(u16 sectorId, const struct SaveBlockChunk *loc
|
|||
if (ProgramFlashByte(sector, SECTOR_SECURITY_OFFSET, SECTOR_SECURITY_NUM & 0xFF))
|
||||
{
|
||||
// Sector is damaged, so enable the bit in gDamagedSaveSectors and restore the last written sector and save counter.
|
||||
SetSectorDamagedStatus(SECTOR_DAMAGED, sector);
|
||||
SetDamagedSectorBits(SECTOR_DAMAGED, sector);
|
||||
gLastWrittenSector = gLastKnownGoodSector;
|
||||
gSaveCounter = gPrevSaveCounter;
|
||||
gSaveCounter = gLastSaveCounter;
|
||||
return SAVE_STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Succeeded
|
||||
SetSectorDamagedStatus(SECTOR_OK, sector);
|
||||
SetDamagedSectorBits(SECTOR_OK, sector);
|
||||
return SAVE_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
u8 TryReadAllSaveSectorsCurrentSlot(u16 a1, const struct SaveBlockChunk *chunk)
|
||||
static u8 TryLoadSaveSlot(u16 sectorId, const struct SaveBlockChunk *chunks)
|
||||
{
|
||||
u8 retVal;
|
||||
gReadWriteSector = eSaveSection;
|
||||
if (a1 != 0xFFFF)
|
||||
u8 status;
|
||||
gReadWriteSector = gSaveDataBuffer;
|
||||
if (sectorId != FULL_SAVE_SLOT)
|
||||
{
|
||||
retVal = SAVE_STATUS_ERROR;
|
||||
// This function may not be used with a specific sector id
|
||||
status = SAVE_STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = GetSaveValidStatus(chunk);
|
||||
ReadAllSaveSectorsCurrentSlot(0xFFFF, chunk);
|
||||
status = GetSaveValidStatus(chunks);
|
||||
CopySaveSlotData(FULL_SAVE_SLOT, chunks);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
return status;
|
||||
}
|
||||
|
||||
u8 ReadAllSaveSectorsCurrentSlot(u16 a1, const struct SaveBlockChunk *chunks)
|
||||
// sectorId arg is ignored, this always reads the full save slot
|
||||
static u8 CopySaveSlotData(u16 sectorId, const struct SaveBlockChunk *chunks)
|
||||
{
|
||||
u16 i;
|
||||
u16 checksum;
|
||||
u16 sector = NUM_SECTORS_PER_SLOT * (gSaveCounter % 2);
|
||||
u16 slotOffset = NUM_SECTORS_PER_SLOT * (gSaveCounter % NUM_SAVE_SLOTS);
|
||||
u16 id;
|
||||
|
||||
for (i = 0; i < NUM_SECTORS_PER_SLOT; i++)
|
||||
{
|
||||
DoReadFlashWholeSection(i + sector, gReadWriteSector);
|
||||
ReadFlashSector(i + slotOffset, gReadWriteSector);
|
||||
|
||||
id = gReadWriteSector->id;
|
||||
if (id == 0)
|
||||
gLastWrittenSector = i;
|
||||
|
||||
checksum = CalculateChecksum(gReadWriteSector->data, chunks[id].size);
|
||||
if (gReadWriteSector->security == SECTOR_SECURITY_NUM
|
||||
&& gReadWriteSector->checksum == checksum)
|
||||
|
||||
// Only copy data for sectors whose security and checksum fields are correct
|
||||
if (gReadWriteSector->security == SECTOR_SECURITY_NUM && gReadWriteSector->checksum == checksum)
|
||||
{
|
||||
u16 j;
|
||||
for (j = 0; j < chunks[id].size; j++)
|
||||
|
|
@ -533,13 +566,13 @@ u8 ReadAllSaveSectorsCurrentSlot(u16 a1, const struct SaveBlockChunk *chunks)
|
|||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return SAVE_STATUS_OK;
|
||||
}
|
||||
|
||||
u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks)
|
||||
static u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks)
|
||||
{
|
||||
u16 sector;
|
||||
bool8 signatureValid;
|
||||
u16 i;
|
||||
bool8 securityPassed;
|
||||
u16 checksum;
|
||||
u32 slot1saveCounter = 0;
|
||||
u32 slot2saveCounter = 0;
|
||||
|
|
@ -548,15 +581,15 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks)
|
|||
u32 validSectors;
|
||||
const u32 ALL_SECTORS = (1 << NUM_SECTORS_PER_SLOT) - 1; // bitmask of all saveblock sectors
|
||||
|
||||
// check save slot 1.
|
||||
// Check save slot 1
|
||||
validSectors = 0;
|
||||
signatureValid = FALSE;
|
||||
for (sector = 0; sector < NUM_SECTORS_PER_SLOT; sector++)
|
||||
securityPassed = FALSE;
|
||||
for (i = 0; i < NUM_SECTORS_PER_SLOT; i++)
|
||||
{
|
||||
DoReadFlashWholeSection(sector, gReadWriteSector);
|
||||
ReadFlashSector(i, gReadWriteSector);
|
||||
if (gReadWriteSector->security == SECTOR_SECURITY_NUM)
|
||||
{
|
||||
signatureValid = TRUE;
|
||||
securityPassed = TRUE;
|
||||
checksum = CalculateChecksum(gReadWriteSector->data, chunks[gReadWriteSector->id].size);
|
||||
if (gReadWriteSector->checksum == checksum)
|
||||
{
|
||||
|
|
@ -566,7 +599,7 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks)
|
|||
}
|
||||
}
|
||||
|
||||
if (signatureValid)
|
||||
if (securityPassed)
|
||||
{
|
||||
if (validSectors == ALL_SECTORS)
|
||||
slot1Status = SAVE_STATUS_OK;
|
||||
|
|
@ -575,18 +608,19 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks)
|
|||
}
|
||||
else
|
||||
{
|
||||
// No sectors in slot 1 have the security number, treat it as empty
|
||||
slot1Status = SAVE_STATUS_EMPTY;
|
||||
}
|
||||
|
||||
// check save slot 2.
|
||||
// Check save slot 2
|
||||
validSectors = 0;
|
||||
signatureValid = FALSE;
|
||||
for (sector = 0; sector < NUM_SECTORS_PER_SLOT; sector++)
|
||||
securityPassed = FALSE;
|
||||
for (i = 0; i < NUM_SECTORS_PER_SLOT; i++)
|
||||
{
|
||||
DoReadFlashWholeSection(NUM_SECTORS_PER_SLOT + sector, gReadWriteSector);
|
||||
ReadFlashSector(NUM_SECTORS_PER_SLOT + i, gReadWriteSector);
|
||||
if (gReadWriteSector->security == SECTOR_SECURITY_NUM)
|
||||
{
|
||||
signatureValid = TRUE;
|
||||
securityPassed = TRUE;
|
||||
checksum = CalculateChecksum(gReadWriteSector->data, chunks[gReadWriteSector->id].size);
|
||||
if (gReadWriteSector->checksum == checksum)
|
||||
{
|
||||
|
|
@ -596,7 +630,7 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks)
|
|||
}
|
||||
}
|
||||
|
||||
if (signatureValid)
|
||||
if (securityPassed)
|
||||
{
|
||||
if (validSectors == ALL_SECTORS)
|
||||
slot2Status = SAVE_STATUS_OK;
|
||||
|
|
@ -605,13 +639,15 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks)
|
|||
}
|
||||
else
|
||||
{
|
||||
// No sectors in slot 2 have the security number, treat it as empty.
|
||||
slot2Status = SAVE_STATUS_EMPTY;
|
||||
}
|
||||
|
||||
if (slot1Status == SAVE_STATUS_OK && slot2Status == SAVE_STATUS_OK)
|
||||
{
|
||||
// Choose counter of the most recent save file
|
||||
if ((slot1saveCounter == -1 && slot2saveCounter == 0) || (slot1saveCounter == 0 && slot2saveCounter == -1))
|
||||
if ((slot1saveCounter == -1 && slot2saveCounter == 0)
|
||||
|| (slot1saveCounter == 0 && slot2saveCounter == -1))
|
||||
{
|
||||
if ((unsigned)(slot1saveCounter + 1) < (unsigned)(slot2saveCounter + 1))
|
||||
gSaveCounter = slot2saveCounter;
|
||||
|
|
@ -628,69 +664,78 @@ u8 GetSaveValidStatus(const struct SaveBlockChunk *chunks)
|
|||
return SAVE_STATUS_OK;
|
||||
}
|
||||
|
||||
// One or both save slots are not OK
|
||||
|
||||
if (slot1Status == SAVE_STATUS_OK)
|
||||
{
|
||||
gSaveCounter = slot1saveCounter;
|
||||
if (slot2Status == SAVE_STATUS_ERROR)
|
||||
return SAVE_STATUS_ERROR;
|
||||
return SAVE_STATUS_ERROR; // Slot 2 errored
|
||||
else
|
||||
return SAVE_STATUS_OK;
|
||||
return SAVE_STATUS_OK; // Slot 1 is OK, slot 2 is empty
|
||||
}
|
||||
|
||||
if (slot2Status == SAVE_STATUS_OK)
|
||||
{
|
||||
gSaveCounter = slot2saveCounter;
|
||||
if (slot1Status == SAVE_STATUS_ERROR)
|
||||
return SAVE_STATUS_ERROR;
|
||||
return SAVE_STATUS_ERROR; // Slot 1 errored
|
||||
else
|
||||
return SAVE_STATUS_OK;
|
||||
return SAVE_STATUS_OK; // Slot 2 is OK, slot 1 is empty
|
||||
}
|
||||
|
||||
if (slot1Status == SAVE_STATUS_EMPTY && slot2Status == SAVE_STATUS_EMPTY)
|
||||
// Neither slot is OK, check if both are empty
|
||||
if (slot1Status == SAVE_STATUS_EMPTY
|
||||
&& slot2Status == SAVE_STATUS_EMPTY)
|
||||
{
|
||||
gSaveCounter = 0;
|
||||
gLastWrittenSector = 0;
|
||||
return SAVE_STATUS_EMPTY;
|
||||
}
|
||||
|
||||
// Both slots errored
|
||||
gSaveCounter = 0;
|
||||
gLastWrittenSector = 0;
|
||||
return 2;
|
||||
return SAVE_STATUS_CORRUPT;
|
||||
}
|
||||
|
||||
u8 ReadSomeUnknownSectorAndVerify(u8 sector, u8 *data, u16 size)
|
||||
// Unused
|
||||
static u8 TryLoadSaveSector(u8 sectorId, u8 *data, u16 size)
|
||||
{
|
||||
u16 i;
|
||||
struct SaveSector *section = eSaveSection;
|
||||
|
||||
DoReadFlashWholeSection(sector, section);
|
||||
if (section->security == SECTOR_SECURITY_NUM)
|
||||
struct SaveSector *sector = gSaveDataBuffer;
|
||||
ReadFlashSector(sectorId, sector);
|
||||
if (sector->security == SECTOR_SECURITY_NUM)
|
||||
{
|
||||
u16 checksum = CalculateChecksum(section->data, size);
|
||||
if (section->id == checksum)
|
||||
u16 checksum = CalculateChecksum(sector->data, size);
|
||||
if (sector->id == checksum)
|
||||
{
|
||||
// Security and checksum are correct, copy data
|
||||
for (i = 0; i < size; i++)
|
||||
data[i] = section->data[i];
|
||||
data[i] = sector->data[i];
|
||||
return SAVE_STATUS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 2;
|
||||
// Incorrect checksum
|
||||
return SAVE_STATUS_CORRUPT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Incorrect security value
|
||||
return SAVE_STATUS_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
u32 DoReadFlashWholeSection(u8 sector, struct SaveSector *section)
|
||||
// Return value always ignored
|
||||
static u32 ReadFlashSector(u8 sectorId, struct SaveSector *sector)
|
||||
{
|
||||
ReadFlash(sector, 0, section->data, sizeof(struct SaveSector));
|
||||
ReadFlash(sectorId, 0, sector->data, SECTOR_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
u16 CalculateChecksum(const void *data, u16 size)
|
||||
static u16 CalculateChecksum(const void *data, u16 size)
|
||||
{
|
||||
u16 i;
|
||||
u32 checksum = 0;
|
||||
|
|
@ -704,15 +749,18 @@ u16 CalculateChecksum(const void *data, u16 size)
|
|||
return ((checksum >> 16) + checksum);
|
||||
}
|
||||
|
||||
void nullsub_0201182C()
|
||||
// Unused
|
||||
static void SaveDummy1()
|
||||
{
|
||||
}
|
||||
|
||||
void nullsub_02011830()
|
||||
// Unused
|
||||
static void SaveDummy2()
|
||||
{
|
||||
}
|
||||
|
||||
void nullsub_02011834()
|
||||
// Unused
|
||||
static void SaveDummy3()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -745,7 +793,7 @@ bool32 flash_maincb_reset_pacifidlog_tm(void)
|
|||
if (gRtcUTCTime.days < 0)
|
||||
return FALSE;
|
||||
*GetVarPointer(VAR_PACIFIDLOG_TM_RECEIVED_DAY) = 1;
|
||||
if (flash_write_save_block_chunks_check_damage(0) != TRUE)
|
||||
if (BerryFix_TrySave(SAVE_NORMAL) != SAVE_STATUS_OK)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +1,4 @@
|
|||
.include "main.o"
|
||||
.include "rtc.o"
|
||||
|
||||
.align 4
|
||||
gLastWrittenSector: @ 0x03001220
|
||||
.space 0x4
|
||||
|
||||
gPrevSaveCounter: @ 0x03001224
|
||||
.space 0x4
|
||||
|
||||
gLastKnownGoodSector: @ 0x03001228
|
||||
.space 0x4
|
||||
|
||||
gDamagedSaveSectors: @ 0x0300122C
|
||||
.space 0x4
|
||||
|
||||
gSaveCounter: @ 0x03001230
|
||||
.space 0x4
|
||||
|
||||
gReadWriteSector: @ 0x03001234
|
||||
.space 0x4
|
||||
|
||||
gCurSaveChunk:
|
||||
.space 0x4
|
||||
|
||||
gFlashIdentIsValid: @ 0x0300123C
|
||||
.space 0x4
|
||||
|
||||
.include "agb_flash.o"
|
||||
.include "save.o"
|
||||
.include "agb_flash.o"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user