diff options
Diffstat (limited to 'arm9/src')
-rw-r--r-- | arm9/src/main.c | 5 | ||||
-rw-r--r-- | arm9/src/save.c | 918 | ||||
-rw-r--r-- | arm9/src/save_arrays.c | 120 |
3 files changed, 1039 insertions, 4 deletions
diff --git a/arm9/src/main.c b/arm9/src/main.c index 3f967380..06673b65 100644 --- a/arm9/src/main.c +++ b/arm9/src/main.c @@ -219,8 +219,6 @@ THUMB_FUNC void FUN_02000EE8(void) extern void FUN_0200E3A0(PMLCDTarget, int); extern BOOL FUN_02032DAC(void); -extern void FUN_020225F8(void); -extern void FUN_0202287C(void); // No Return THUMB_FUNC void DoSoftReset(u32 parameter) @@ -229,8 +227,7 @@ THUMB_FUNC void DoSoftReset(u32 parameter) FUN_0200E3A0(PM_LCD_BOTTOM, 0x7FFF); if (FUN_02032DAC()) { - FUN_020225F8(); - FUN_0202287C(); + FUN_0202287C(FUN_020225F8()); } do { diff --git a/arm9/src/save.c b/arm9/src/save.c new file mode 100644 index 00000000..700029c7 --- /dev/null +++ b/arm9/src/save.c @@ -0,0 +1,918 @@ +#include "global.h" +#include "MI_memory.h" +#include "save_block_2.h" +#include "heap.h" +#include "CARD_backup.h" + +#pragma thumb on + +// TODO: Migrate to headers + +// unk_02015EA0.s +extern void FUN_02016444(u8 mask); +extern void FUN_02016454(u8 mask); + +// unk_02089D90.s +extern void FUN_02089D90(int); + +// unk_02089F24.s +extern void FUN_0208A0B8(int, int); + +struct { + struct SaveBlock2 * ptr; + BOOL iswritten; +} UNK_021C59C8; + +struct SaveBlock2 * SaveBlock2_new(void) +{ + struct SaveBlock2 * sav2 = AllocFromHeap(1, sizeof(struct SaveBlock2)); + MI_CpuClearFast(sav2, sizeof(struct SaveBlock2)); + UNK_021C59C8.ptr = sav2; + sav2->flashOkay = SaveDetectFlash(); + sav2->unk_00004 = 0; + sav2->unk_00008 = 1; + sav2->largeSectorChanged = 1; + MATH_CRC16InitTable(&sav2->crcTable); + SaveBlock2_InitSubstructs(sav2->arrayHeaders); + FUN_02023160(sav2->saveSlotSpecs, sav2->arrayHeaders); + MI_CpuClearFast(sav2->unk_20218, 8); + switch (sav2->unk_00010 = FUN_02022AD8(sav2)) + { + case 1: + sav2->largeSectorChanged = 0; + // fallthrough + case 2: + Sav2_LoadDynamicRegion(sav2); + sav2->unk_00004 = 1; + sav2->unk_00008 = 0; + break; + case 0: + case 3: + Sav2_InitDynamicRegion(sav2); + break; + } + return sav2; +} + +struct SaveBlock2 * FUN_020225F8(void) +{ + GF_ASSERT(UNK_021C59C8.ptr != NULL); + return UNK_021C59C8.ptr; +} + +void * SavArray_get(struct SaveBlock2 * sav2, int idx) +{ + GF_ASSERT(idx < 36); + return (void *)(sav2->dynamic_region + sav2->arrayHeaders[idx].offset); +} + +void * FUN_02022634(struct SaveBlock2 * sav2, int idx) +{ + return SavArray_get(sav2, idx); +} + +// Sets bits at 0x021C491 +// Clears bits at 0x021C491 + +BOOL FUN_0202263C(struct SaveBlock2 * sav2) +{ + u8 * r6 = AllocFromHeapAtEnd(3, 0x1000); + FUN_02016444(1); + FlashClobberChunkFooter(sav2, 0, (u32)(sav2->unk_20220[0] == 0 ? 1 : 0)); + FlashClobberChunkFooter(sav2, 1, (u32)(sav2->unk_20220[1] == 0 ? 1 : 0)); + FlashClobberChunkFooter(sav2, 0, (u32)(sav2->unk_20220[0])); + FlashClobberChunkFooter(sav2, 1, (u32)(sav2->unk_20220[1])); + MIi_CpuClearFast(-1u, r6, 0x1000); + for (int i = 0; i < 64; i++) + { + FlashWriteChunk((u32)(0x1000 * i), r6, 0x1000); + FlashWriteChunk((u32)(0x1000 * (i + 0x40)), r6, 0x1000); + } + FreeToHeap(r6); + Sav2_InitDynamicRegion(sav2); + sav2->unk_00004 = 0; + FUN_02016454(1); + return TRUE; +} + +BOOL FUN_020226FC(struct SaveBlock2 * sav2) +{ + if (sav2->flashOkay == 0) + return FALSE; + if (Sav2_LoadDynamicRegion(sav2)) + { + sav2->unk_00004 = 1; + sav2->unk_00008 = 0; + return TRUE; + } + return FALSE; +} + +int FUN_02022720(struct SaveBlock2 * sav2) +{ + if (sav2->flashOkay == 0) + return 3; + if (sav2->unk_00008) + { + FUN_02016444(1); + FlashClobberChunkFooter(sav2, 0, (u32)(sav2->unk_20220[0] == 0 ? 1 : 0)); + FlashClobberChunkFooter(sav2, 1, (u32)(sav2->unk_20220[1] == 0 ? 1 : 0)); + FlashClobberChunkFooter(sav2, 0, (u32)(sav2->unk_20220[0])); + FlashClobberChunkFooter(sav2, 1, (u32)(sav2->unk_20220[1])); + FUN_02016454(1); + } + int ret = FUN_02023044(sav2); + if (ret == 2) + { + sav2->unk_00004 = 1; + sav2->unk_00008 = 0; + } + return ret; +} + +void FUN_020227A0(struct SaveBlock2 * sav2, int a1) +{ + GF_ASSERT(a1 < 2); + GF_ASSERT(sav2->unk_00008 == 0); + GF_ASSERT(sav2->unk_00004 == 1); + FUN_02022840(sav2, a1); + int res; + do + { + res = FUN_02022854(sav2); + } while (res == 0 || res == 1); +} + +void Sav2_InitDynamicRegion(struct SaveBlock2 * sav2) +{ + sav2->unk_00008 = 1; + sav2->largeSectorChanged = 1; + Sav2_InitDynamicRegion_Internal(sav2->dynamic_region, sav2->arrayHeaders); +} + +int FUN_020227FC(struct SaveBlock2 * sav2) +{ + return sav2->flashOkay; +} + +int FUN_02022800(struct SaveBlock2 * sav2) +{ + return sav2->unk_00010; +} + +int FUN_02022804(struct SaveBlock2 * sav2) +{ + return sav2->unk_00004; +} + +int FUN_02022808(struct SaveBlock2 * sav2) +{ + return sav2->unk_00008; +} + +BOOL FUN_0202280C(struct SaveBlock2 * sav2) +{ + return (FUN_02022808(sav2) != 0 && FUN_02022804(sav2) != 0); +} + +int SaveGetDirtyBit(struct SaveBlock2 * sav2) +{ + return sav2->largeSectorChanged; +} + +void SaveSetDirtyBit(void) +{ + UNK_021C59C8.ptr->largeSectorChanged = 1; +} + +void FUN_02022840(struct SaveBlock2 * sav2, int a1) +{ + FUN_02022DFC(sav2, &sav2->unk_2047C, a1); +} + +int FUN_02022854(struct SaveBlock2 * sav2) +{ + int r4 = FUN_02022E78(sav2, &sav2->unk_2047C); + if (r4 != 0 && r4 != 1) + { + FUN_02022F80(sav2, &sav2->unk_2047C, r4); + } + return r4; +} + +void FUN_0202287C(struct SaveBlock2 * sav2) +{ + FUN_02022FF0(sav2, &sav2->unk_2047C); +} + +void FUN_0202288C(struct UnkStruct_0202288C * header) +{ + header->unk_0 = 0; + header->offset = 0; + header->size = 0; +} + +u16 FUN_02022898(struct SaveBlock2 * sav2, void * data, u32 size) +{ + return MATH_CalcCRC16CCITT(&sav2->crcTable, data, size - 20); +} + +u32 GetChunkOffsetFromCurrentSaveSlot(u32 slot, struct SaveBlock2_Sub_20464 * header) +{ + u32 offset; + if (slot == 0) + offset = 0; + else + offset = 0x40000; + return offset + header->offset; +} + +struct SaveChunkFooter * FUN_020228B8(struct SaveBlock2 * sav2, u8 * offset, int idx) +{ + u8 * r4; + struct SaveBlock2_Sub_20464 * sub20464; + + sub20464 = &sav2->saveSlotSpecs[idx]; + r4 = offset + sub20464->offset; + GF_ASSERT(sub20464->size != 0); + return (struct SaveChunkFooter *)(r4 + sub20464->size - 20); +} + +BOOL FUN_020228E0(struct SaveBlock2 * sav2, void * data, int idx) +{ + struct SaveChunkFooter * r4; + struct SaveBlock2_Sub_20464 * sub20464; + + sub20464 = &sav2->saveSlotSpecs[idx]; + r4 = FUN_020228B8(sav2, data, idx); + u32 size = sub20464->size; + u32 offset = sub20464->offset; + if (r4->size != size) + return FALSE; + if (r4->magic != 0x20060623) + return FALSE; + if (r4->unk_10 != idx) + return FALSE; + return r4->crc == FUN_02022898(sav2, (u8 *)data + offset, size); +} + +void FUN_0202293C(struct UnkStruct_0202288C * r5, struct SaveBlock2 * sav2, void * data, int idx) +{ + struct SaveChunkFooter * r4; + r4 = FUN_020228B8(sav2, data, idx); + r5->unk_0 = FUN_020228E0(sav2, data, idx); + r5->offset = r4->unk_0; + r5->size = r4->offset; +} + +void FUN_02022968(struct SaveBlock2 * sav2, void * data, int idx) +{ + struct SaveChunkFooter * r4; + struct SaveBlock2_Sub_20464 * sub20464; + + sub20464 = &sav2->saveSlotSpecs[idx]; + r4 = FUN_020228B8(sav2, data, idx); + data = (void *)((u8 *)data + sub20464->offset); + r4->unk_0 = sav2->unk_20214; + r4->offset = sav2->unk_20218[idx]; + r4->size = sub20464->size; + r4->magic = 0x20060623; + r4->unk_10 = (u8)idx; + r4->crc = FUN_02022898(sav2, data, sub20464->size); +} + +int FUN_020229B8(u32 x, u32 y) +{ + if (x == -1u && y == 0) + return -1; + if (x == 0 && y == -1u) + return 1; + if (x > y) + return 1; + return -(x < y); +} + +int FUN_020229F0(struct UnkStruct_0202288C * r7, struct UnkStruct_0202288C * r6, u32 * r5, u32 * r4) +{ + int sp0 = FUN_020229B8(r7->offset, r6->offset); + int r0 = FUN_020229B8(r7->size, r6->size); + if (r7->unk_0 != 0 && r6->unk_0 != 0) + { + if (sp0 > 0) + { + GF_ASSERT(r0 > 0); + *r5 = 0; + *r4 = 1; + } + else if (sp0 < 0) + { + GF_ASSERT(r0 < 0); + *r5 = 1; + *r4 = 0; + } + else if (r0 > 0) + { + *r5 = 0; + *r4 = 1; + } + else if (r0 < 0) + { + *r5 = 1; + *r4 = 0; + } + else + { + *r5 = 0; + *r4 = 1; + } + return 2; + } + else if (r7->unk_0 != 0 && r6->unk_0 == 0) + { + *r5 = 0; + *r4 = 2; + return 1; + } + else if (r7->unk_0 == 0 && r6->unk_0 != 0) + { + *r5 = 1; + *r4 = 2; + return 1; + } + else + { + *r5 = 2; + *r4 = 2; + return 0; + } +} + +void FUN_02022AA0(struct SaveBlock2 * sav2, struct UnkStruct_0202288C * a1, struct UnkStruct_0202288C * a2, u32 a3, u32 a4) +{ + sav2->unk_20214 = a1[a3].offset; + sav2->unk_20218[0] = a1[a3].size; + sav2->unk_20218[1] = a2[a4].size; + sav2->unk_20220[0] = (u8)a3; + sav2->unk_20220[1] = (u8)a4; +} + +int FUN_02022AD8(struct SaveBlock2 * sav2) +{ + struct UnkStruct_0202288C sp2C[2]; + struct UnkStruct_0202288C sp14[2]; + u32 sp10; + u32 spC; + u32 sp8; + u32 sp4; + { + u8 *r6 = AllocFromHeapAtEnd(3, 0x20000); + u8 *r4 = AllocFromHeapAtEnd(3, 0x20000); + if (FlashLoadChunk(0, r6, 0x20000)) + { + FUN_0202293C(&sp2C[0], sav2, r6, 0); + FUN_0202293C(&sp14[0], sav2, r6, 1); + } + else + { + FUN_0202288C(&sp2C[0]); + FUN_0202288C(&sp14[0]); + } + if (FlashLoadChunk(0x40000, r4, 0x20000)) + { + FUN_0202293C(&sp2C[1], sav2, r4, 0); + FUN_0202293C(&sp14[1], sav2, r4, 1); + } + else + { + FUN_0202288C(&sp2C[1]); + FUN_0202288C(&sp14[1]); + } + FreeToHeap(r6); + FreeToHeap(r4); + } + { + int r4, r0; + r4 = FUN_020229F0(&sp2C[0], &sp2C[1], &sp10, &sp8); + r0 = FUN_020229F0(&sp14[0], &sp14[1], &spC, &sp4); + if (r4 == 0 && r0 == 0) + return 0; + else if (r4 == 0 || r0 == 0) + return 3; + else if (r4 == 2 && r0 == 2) + { + if (sp2C[sp10].offset == sp14[spC].offset) + { + FUN_02022AA0(sav2, sp2C, sp14, sp10, spC); + return 1; + } + else + { + FUN_02022AA0(sav2, sp2C, sp14, sp8, spC); + return 2; + } + } + else if (r4 == 1 && r0 == 2) + { + if (sp2C[sp10].offset == sp14[spC].offset) + { + FUN_02022AA0(sav2, sp2C, sp14, sp10, spC); + return 2; + } + else if (sp2C[sp10].offset == sp14[sp4].offset) + { + FUN_02022AA0(sav2, sp2C, sp14, sp10, sp4); + return 2; + } + else + { + return 3; + } + } + else if (r4 == 2 && r0 == 1) + { + if (sp2C[sp10].offset == sp14[spC].offset) + { + FUN_02022AA0(sav2, sp2C, sp14, sp10, spC); + return 1; + } + else + { + FUN_02022AA0(sav2, sp2C, sp14, sp8, spC); + return 2; + } + } + else if (r4 == 1 && r0 == 1 && sp10 == spC) + { + GF_ASSERT(sp2C[sp10].offset == sp14[spC].offset); + FUN_02022AA0(sav2, sp2C, sp14, sp10, spC); + return 1; + } + else + { + GF_ASSERT(sp2C[sp10].offset == sp14[spC].offset); + FUN_02022AA0(sav2, sp2C, sp14, sp10, spC); + return 2; + } + } +} + +BOOL FlashLoadChunkIntoDynamicRegionFromHeader(u32 slot, struct SaveBlock2_Sub_20464 * header, u8 * dest) +{ + return FlashLoadChunk(GetChunkOffsetFromCurrentSaveSlot(slot, header), dest + header->offset, header->size); +} + +BOOL Sav2_LoadDynamicRegion(struct SaveBlock2 * sav2) +{ + for (int i = 0; i < 2; i++) + { + if (!FlashLoadChunkIntoDynamicRegionFromHeader(sav2->unk_20220[i], &sav2->saveSlotSpecs[i], sav2->dynamic_region)) return FALSE; + if (!FUN_020228E0(sav2, sav2->dynamic_region, i)) return FALSE; + } + return TRUE; +} + +int FUN_02022D54(struct SaveBlock2 * sav2, int chunk, u8 slot) +{ + struct SaveBlock2_Sub_20464 * header = &sav2->saveSlotSpecs[chunk]; + FUN_02022968(sav2, sav2->dynamic_region, chunk); + return FlashWriteChunkInternal(GetChunkOffsetFromCurrentSaveSlot(slot, header), sav2->dynamic_region + header->offset, header->size - 20); +} + +int FUN_02022D94(struct SaveBlock2 * sav2, int chunk, u8 slot) +{ + struct SaveBlock2_Sub_20464 * header = &sav2->saveSlotSpecs[chunk]; + u32 size = header->size; + return FlashWriteChunkInternal(GetChunkOffsetFromCurrentSaveSlot(slot, header) + size - 20, sav2->dynamic_region + header->offset + size - 20, 20); +} + +int FUN_02022DC8(struct SaveBlock2 * sav2, int chunk, u8 slot) +{ + struct SaveBlock2_Sub_20464 * header = &sav2->saveSlotSpecs[chunk]; + u32 size = header->size; + return FlashWriteChunkInternal(GetChunkOffsetFromCurrentSaveSlot(slot, header) + size - 12, sav2->dynamic_region + header->offset + size - 12, 8); +} + +void FUN_02022DFC(struct SaveBlock2 * sav2, struct UnkSavSub_2047C * a1, int a2) +{ + for (int i = 0; i < 2; i++) + { + a1->unk_1C[i] = sav2->unk_20218[i]; + sav2->unk_20218[i]++; + } + a1->unk_14 = 0; + a1->unk_0 = 0; + if (a2 == 2) + { + if (sav2->largeSectorChanged) + { + a1->unk_0 = 1; + a1->unk_18 = sav2->unk_20214; + sav2->unk_20214++; + a1->unk_4 = 0; + a1->unk_8 = 0; + a1->unk_C = 2; + } + else + { + a1->unk_4 = 0; + a1->unk_8 = 0; + a1->unk_C = 1; + } + } + else + { + a1->unk_4 = a2; + a1->unk_8 = a2; + a1->unk_C = a2 + 1; + } + FUN_02016444(1); +} + +int FUN_02022E78(struct SaveBlock2 * sav2, struct UnkSavSub_2047C * a1) +{ + BOOL sp0; + switch (a1->unk_14) + { + case 0: + a1->unk_10 = FUN_02022D54(sav2, a1->unk_8, (u8)(sav2->unk_20220[a1->unk_8] == 0)); + a1->unk_14++; + // fallthrough + case 1: + if (!WaitFlashWrite(a1->unk_10, &sp0)) + break; + if (sp0 == 0) + return 3; + a1->unk_14++; + // fallthrough + case 2: + a1->unk_10 = FUN_02022DC8(sav2, a1->unk_8, (u8)(sav2->unk_20220[a1->unk_8] == 0)); + a1->unk_14++; + // fallthrough + case 3: + if (!WaitFlashWrite(a1->unk_10, &sp0)) + break; + if (sp0 == 0) + return 3; + a1->unk_14++; + if (a1->unk_8 + 1 == a1->unk_C) + return 1; + // fallthrough + case 4: + a1->unk_10 = FUN_02022D94(sav2, a1->unk_8, (u8)(sav2->unk_20220[a1->unk_8] == 0)); + a1->unk_14++; + // fallthrough + case 5: + if (!WaitFlashWrite(a1->unk_10, &sp0)) + break; + if (sp0 == 0) + return 3; + a1->unk_8++; + if (a1->unk_8 == a1->unk_C) + return 2; + a1->unk_14 = 0; + break; + } + return 0; +} + +void FUN_02022F80(struct SaveBlock2 * sav2, struct UnkSavSub_2047C * a1, int a2) +{ + int i; + if (a2 == 3) + { + if (a1->unk_0) + { + sav2->unk_20214 = a1->unk_18; + } + for (i = 0; i < 2; i++) + { + sav2->unk_20218[i] = a1->unk_1C[i]; + } + } + else + { + for (i = a1->unk_4; i < a1->unk_C; i++) + { + sav2->unk_20220[i] = (u8)(sav2->unk_20220[i] == 0); + } + sav2->unk_00004 = 1; + sav2->unk_00008 = 0; + sav2->largeSectorChanged = 0; + } + FUN_02016454(1); +} + +void FUN_02022FF0(struct SaveBlock2 * sav2, struct UnkSavSub_2047C * a1) +{ + if (a1->unk_0) + sav2->unk_20214 = a1->unk_18; + for (int i = 0; i < 2; i++) + { + sav2->unk_20218[i] = a1->unk_1C[i]; + } + if (!CARD_TryWaitBackupAsync()) + { + CARD_CancelBackupAsync(); + CARD_UnlockBackup((u16)a1->unk_10); + OS_ReleaseLockID((u16)a1->unk_10); + } + FUN_02016454(1); +} + +int FUN_02023044(struct SaveBlock2 * sav2) +{ + int r4; + struct UnkSavSub_2047C sp0; + FUN_02022DFC(sav2, &sp0, 2); + do + { + r4 = FUN_02022E78(sav2, &sp0); + } while (r4 == 0 || r4 == 1); + FUN_02022F80(sav2, &sp0, r4); + return r4; +} + +int FlashClobberChunkFooter(struct SaveBlock2 * sav2, int x, u32 y) +{ + u8 sp0[20]; + struct SaveBlock2_Sub_20464 * r5 = &sav2->saveSlotSpecs[x]; + MI_CpuFill8(sp0, 0xFF, 20); + return FlashWriteChunk((u32)(GetChunkOffsetFromCurrentSaveSlot(y, r5) + r5->size - 20), sp0, 20); +} + +u32 SavArray_sizeof(int idx) +{ + const struct SaveChunkHeader * sch = UNK_020EE700; + GF_ASSERT(idx < UNK_020EE6DC); + s32 ret = (s32)sch[idx].sizeFunc(); + ret += (4 - (ret % 4)); + return (u32)ret; +} + +void SaveBlock2_InitSubstructs(struct SavArrayHeader * headers) +{ + const struct SaveChunkHeader * sch = UNK_020EE700; + s32 offset = 0; + GF_ASSERT(UNK_020EE6DC == 36); + for (int i = 0; i < UNK_020EE6DC; i++) + { + GF_ASSERT(i == sch[i].id); + headers[i].id = sch[i].id; + headers[i].size = SavArray_sizeof(i); + headers[i].offset = (u32)offset; + headers[i].field_C = 0; + headers[i].field_E = (u16)sch[i].linkedId; + offset += headers[i].size; + if (i == UNK_020EE6DC - 1 || sch[i].linkedId != sch[i + 1].linkedId) + offset += 20; + } + GF_ASSERT(offset <= 0x20000); +} + +void FUN_02023160(struct SaveBlock2_Sub_20464 * spec, struct SavArrayHeader * headers) +{ + int i = 0; + int sp4 = 0; + u32 r12 = 0; + int j = 0; + for (i = 0; i < 2; i++) + { + spec[i].unk_0 = (u8)i; + spec[i].size = 0; + while (i == headers[j].field_E && j < UNK_020EE6DC) + { + spec[i].size += headers[j].size; + j++; + } + spec[i].size += 20; + spec[i].unk_1 = (u8)sp4; + spec[i].offset = r12; + spec[i].unk_2 = (u8)((spec[i].size + 0xFFF) / 0x1000); + sp4 += spec[i].unk_2; + r12 += spec[i].size; + } + GF_ASSERT(spec[1].unk_1 + spec[1].unk_2 == sp4); + GF_ASSERT(sp4 <= 32); +} + +void Sav2_InitDynamicRegion_Internal(u8 * dynamic_region, struct SavArrayHeader * headers) +{ + const struct SaveChunkHeader * sch = UNK_020EE700; + MI_CpuClearFast(dynamic_region, 0x20000); + for (int i = 0; i < UNK_020EE6DC; i++) + { + u32 offset = headers[i].offset; + MI_CpuClearFast(dynamic_region + offset, headers[i].size); + sch[i].initFunc((void *)(dynamic_region + offset)); + } +} + +void CreateChunkFooter(struct SaveBlock2 * sav2, u8 * data, int id, u32 size) +{ + struct SavArrayFooter * footer = (struct SavArrayFooter *)(data + size); + footer->magic = 0x20060623; + footer->unk_4 = sav2->unk_204A4 + 1; + footer->unk_8 = size; + footer->unk_C = (u16)id; + footer->crc = MATH_CalcCRC16CCITT(&sav2->crcTable, data, size + 14); +} + +BOOL ValidateChunk(struct SaveBlock2 * sav2, u8 * data, int id, u32 size) +{ + struct SavArrayFooter * footer = (struct SavArrayFooter *)(data + size); + if (footer->magic != 0x20060623) + return FALSE; + if (footer->unk_8 != size) + return FALSE; + if (footer->unk_C != id) + return FALSE; + return (footer->crc == MATH_CalcCRC16CCITT(&sav2->crcTable, data, size + 14)); +} + +u32 FUN_020232B4(u8 * data, u32 size) +{ + struct SavArrayFooter * footer = (struct SavArrayFooter *)(data + size); + return footer->unk_4; +} + +int WriteSaveFileToFlash(struct SaveBlock2 * sav2, int idx, u8 * data) +{ + FUN_02016444(1); + GF_ASSERT(idx < UNK_020EE6D8); + const struct SaveChunkHeader * sch = &UNK_020EE6E0[idx]; + GF_ASSERT(sch->id == idx); + u32 sp4 = sch->sizeFunc() + 16; + int sp0; + if (sav2->unk_204A0 == 1) + { + CreateChunkFooter(sav2, data, idx, sch->sizeFunc()); + sp0 = FlashWriteChunk((u32)(sch->linkedId << 12), data, sp4); + GF_ASSERT(ValidateChunk(sav2, data, idx, sch->sizeFunc()) == 1); + CreateChunkFooter(sav2, data, idx, sch->sizeFunc()); + sp0 |= FlashWriteChunk((u32)((sch->linkedId + 0x40) << 12), data, sp4); + GF_ASSERT(ValidateChunk(sav2, data, idx, sch->sizeFunc()) == 1); + } + else + { + CreateChunkFooter(sav2, data, idx, sch->sizeFunc()); + sp0 = FlashWriteChunk((u32)((sch->linkedId + 0x40) << 12), data, sp4); + GF_ASSERT(ValidateChunk(sav2, data, idx, sch->sizeFunc()) == 1); + CreateChunkFooter(sav2, data, idx, sch->sizeFunc()); + sp0 |= FlashWriteChunk((u32)(sch->linkedId << 12), data, sp4); + GF_ASSERT(ValidateChunk(sav2, data, idx, sch->sizeFunc()) == 1); + } + if (sp0 == 1) + { + FUN_02016454(1); + return 2; + } + FUN_02016454(1); + return 3; +} + +u8 * ReadSaveFileFromFlash(struct SaveBlock2 * sav2, u32 heap_id, int idx, int * ret_p) +{ + GF_ASSERT(idx < UNK_020EE6D8); + const struct SaveChunkHeader * sch = &UNK_020EE6E0[idx]; + GF_ASSERT(sch->id == idx); + u32 sp10 = sch->sizeFunc() + 16; + int spC; + u32 sp8; + int r7; + u32 sp4; + u8 * r6 = AllocFromHeap(heap_id, sp10); + FlashLoadChunk((u32)(sch->linkedId << 12), r6, sp10); + spC = ValidateChunk(sav2, r6, idx, sch->sizeFunc()); + sp8 = FUN_020232B4(r6, sch->sizeFunc()); + FlashLoadChunk((u32)((sch->linkedId + 0x40) << 12), r6, sp10); + r7 = ValidateChunk(sav2, r6, idx, sch->sizeFunc()); + sp4 = FUN_020232B4(r6, sch->sizeFunc()); + *ret_p = 1; + if (spC == 1 && r7 == 0) + { + sav2->unk_204A0 = 0; + sav2->unk_204A4 = sp8; + FlashLoadChunk((u32)(sch->linkedId << 12), r6, sp10); + return r6; + } + if (spC == 0 && r7 == 1) + { + sav2->unk_204A0 = 1; + sav2->unk_204A4 = sp4; + FlashLoadChunk((u32)((sch->linkedId + 0x40) << 12), r6, sp10); + return r6; + } + if (spC == 1 && r7 == 1) + { + if (FUN_020229B8(sp8, sp4) != -1) + { + sav2->unk_204A0 = 0; + sav2->unk_204A4 = sp8; + FlashLoadChunk((u32)(sch->linkedId << 12), r6, sp10); + return r6; + } + sav2->unk_204A0 = 1; + sav2->unk_204A4 = sp4; + FlashLoadChunk((u32)((sch->linkedId + 0x40) << 12), r6, sp10); + return r6; + } + *ret_p = 2; + sav2->unk_204A0 = 0; + sav2->unk_204A4 = 0; + return r6; +} + +BOOL SaveDetectFlash(void) +{ + int lock = OS_GetLockID(); + GF_ASSERT(lock != -3); + CARD_LockBackup((u16)lock); + u16 flash_type; + if (CARD_IdentifyBackup(0x1302)) + flash_type = 0x1302; + else if (CARD_IdentifyBackup(0x1202)) + flash_type = 0x1202; + else + flash_type = 0; + CARD_UnlockBackup((u16)lock); + OS_ReleaseLockID((u16)lock); + return flash_type != 0; +} + +int FlashWriteChunk(u32 offset, u8 * data, u32 size) +{ + int ret; + int id = FlashWriteChunkInternal(offset, data, size); + while (!WaitFlashWrite(id, &ret)) + ; + return ret; +} + +BOOL FlashLoadChunk(u32 src, void * dest, u32 size) +{ + int lock = OS_GetLockID(); + GF_ASSERT(lock != -3); + CARD_LockBackup((u16)lock); + CARDi_ReadBackup(src, dest, size, NULL, NULL, TRUE); + BOOL r5 = CARD_WaitBackupAsync(); + CARD_UnlockBackup((u16)lock); + OS_ReleaseLockID((u16)lock); + if (!r5) + { + FreeToHeap(UNK_021C59C8.ptr); + FUN_02089D90(1); + } + return r5; +} + +void FlashWriteCommandCallback(void * arg) +{ +#pragma unused(arg) + UNK_021C59C8.iswritten = TRUE; +} + +int FlashWriteChunkInternal(u32 dest, void * src, u32 size) +{ + int lock = OS_GetLockID(); + GF_ASSERT(lock != -3); + CARD_LockBackup((u16)lock); + int sp14; + if (!CARDi_ReadBackup(0, &sp14, 4, NULL, NULL, FALSE)) + SaveErrorHandling(lock, 1); + UNK_021C59C8.iswritten = FALSE; + CARDi_WriteAndVerifyBackup(dest, src, size, FlashWriteCommandCallback, NULL, TRUE); + return lock; +} + +BOOL WaitFlashWrite(int lock, BOOL * res) +{ + if (UNK_021C59C8.iswritten == TRUE) + { + CARD_UnlockBackup((u16)lock); + OS_ReleaseLockID((u16)lock); + switch (CARD_GetResultCode()) + { + case CARD_RESULT_SUCCESS: + *res = TRUE; + break; + default: + GF_ASSERT(0); + case CARD_RESULT_TIMEOUT: + *res = FALSE; + SaveErrorHandling(lock, 0); + case CARD_RESULT_NO_RESPONSE: + *res = FALSE; + SaveErrorHandling(lock, 1); + } + return TRUE; + } + return FALSE; +} + +void SaveErrorHandling(int lock, int errno) +{ + CARD_UnlockBackup((u16)lock); + OS_ReleaseLockID((u16)lock); + FreeToHeap(UNK_021C59C8.ptr); + FUN_0208A0B8(1, errno); +} diff --git a/arm9/src/save_arrays.c b/arm9/src/save_arrays.c new file mode 100644 index 00000000..abd09b1c --- /dev/null +++ b/arm9/src/save_arrays.c @@ -0,0 +1,120 @@ +#include "global.h" +#include "bag.h" +#include "player_data.h" +#include "save_block_2.h" +#include "party.h" +#include "event_data.h" + +extern u32 FUN_0202B034(void); +extern u32 FUN_0202AC20(void); +extern u32 FUN_0202376C(void); +extern u32 FUN_0204BE14(void); +extern u32 FUN_02034D7C(void); +extern u32 FUN_02023D64(void); +extern u32 FUN_02023C40(void); +extern u32 FUN_020254B8(void); +extern u32 FUN_02024E64(void); +extern u32 FUN_02034D80(void); +extern u32 FUN_02025954(void); +extern u32 FUN_02023AC8(void); +extern u32 FUN_02026FD8(void); +extern u32 FUN_02025844(void); +extern u32 FUN_02028054(void); +extern u32 FUN_020286F8(void); +extern u32 FUN_02028980(void); +extern u32 FUN_02029A84(void); +extern u32 FUN_02029FB0(void); +extern u32 FUN_02029C58(void); +extern u32 FUN_02029EC4(void); +extern u32 FUN_0202A89C(void); +extern u32 FUN_0202A8F4(void); +extern u32 FUN_0202A924(void); +extern u32 FUN_0202ABC8(void); +extern u32 FUN_0202B374(void); +extern u32 FUN_0202B8B0(void); +extern u32 FUN_020281E0(void); +extern u32 FUN_02029AE0(void); +extern u32 FUN_0202BE98(void); +extern u32 FUN_0202C0E0(void); +extern u32 FUN_02013B28(void); +extern u32 PCStorage_sizeof(void); +extern void FUN_0202B03C(void *); +extern void FUN_0202AC28(void *); +extern void FUN_02023770(void *); +extern void FUN_0204BE18(void *); +extern void FUN_02034D98(void *); +extern void FUN_02024378(void *); +extern void FUN_02023C48(void *); +extern void FUN_020254CC(void *); +extern void FUN_02024E6C(void *); +extern void FUN_02034D88(void *); +extern void FUN_0202597C(void *); +extern void FUN_02023AD8(void *); +extern void FUN_02026F60(void *); +extern void FUN_0202584C(void *); +extern void FUN_0202805C(void *); +extern void FUN_02028724(void *); +extern void FUN_02028994(void *); +extern void FUN_02029A8C(void *); +extern void FUN_02029FB8(void *); +extern void FUN_02029C60(void *); +extern void FUN_02029ECC(void *); +extern void FUN_0202A8A4(void *); +extern void FUN_0202A8F8(void *); +extern void FUN_0202A92C(void *); +extern void FUN_0202ABCC(void *); +extern void FUN_0202B37C(void *); +extern void FUN_0202B8B8(void *); +extern void FUN_020281E8(void *); +extern void FUN_02029AE8(void *); +extern void FUN_0202BEA0(void *); +extern void FUN_0202C0E4(void *); +extern void FUN_02013B2C(void *); +extern void PCStorage_init(void *); + +const struct SaveChunkHeader UNK_020EE6E0[] = { + { 0, 32, (SAVSIZEFN)FUN_0202B034, (SAVINITFN)FUN_0202B03C }, + { 1, 35, (SAVSIZEFN)FUN_0202AC20, (SAVINITFN)FUN_0202AC28 } +}; + +const struct SaveChunkHeader UNK_020EE700[] = { + { 0, 0, (SAVSIZEFN)FUN_0202376C, (SAVINITFN)FUN_02023770 }, + { 1, 0, (SAVSIZEFN)Sav2_PlayerData_sizeof, (SAVINITFN)Sav2_PlayerData_init }, + { 2, 0, (SAVSIZEFN)SavArray_Party_sizeof, (SAVINITFN)SavArray_Party_init }, + { 3, 0, (SAVSIZEFN)Sav2_Bag_sizeof, (SAVINITFN)Sav2_Bag_init }, + { 4, 0, (SAVSIZEFN)SavArray_Flags_sizeof, (SAVINITFN)SavArray_Flags_init }, + { 5, 0, (SAVSIZEFN)FUN_0204BE14, (SAVINITFN)FUN_0204BE18 }, + { 6, 0, (SAVSIZEFN)FUN_02034D7C, (SAVINITFN)FUN_02034D98 }, + { 7, 0, (SAVSIZEFN)FUN_02023D64, (SAVINITFN)FUN_02024378 }, + { 8, 0, (SAVSIZEFN)FUN_02023C40, (SAVINITFN)FUN_02023C48 }, + { 9, 0, (SAVSIZEFN)FUN_020254B8, (SAVINITFN)FUN_020254CC }, + { 10, 0, (SAVSIZEFN)FUN_02024E64, (SAVINITFN)FUN_02024E6C }, + { 11, 0, (SAVSIZEFN)FUN_02034D80, (SAVINITFN)FUN_02034D88 }, + { 12, 0, (SAVSIZEFN)FUN_02025954, (SAVINITFN)FUN_0202597C }, + { 13, 0, (SAVSIZEFN)FUN_02023AC8, (SAVINITFN)FUN_02023AD8 }, + { 14, 0, (SAVSIZEFN)FUN_02026FD8, (SAVINITFN)FUN_02026F60 }, + { 15, 0, (SAVSIZEFN)FUN_02025844, (SAVINITFN)FUN_0202584C }, + { 16, 0, (SAVSIZEFN)FUN_02028054, (SAVINITFN)FUN_0202805C }, + { 17, 0, (SAVSIZEFN)FUN_020286F8, (SAVINITFN)FUN_02028724 }, + { 18, 0, (SAVSIZEFN)FUN_02028980, (SAVINITFN)FUN_02028994 }, + { 19, 0, (SAVSIZEFN)FUN_02029A84, (SAVINITFN)FUN_02029A8C }, + { 20, 0, (SAVSIZEFN)FUN_02029FB0, (SAVINITFN)FUN_02029FB8 }, + { 21, 0, (SAVSIZEFN)FUN_02029C58, (SAVINITFN)FUN_02029C60 }, + { 22, 0, (SAVSIZEFN)FUN_02029EC4, (SAVINITFN)FUN_02029ECC }, + { 23, 0, (SAVSIZEFN)FUN_0202A89C, (SAVINITFN)FUN_0202A8A4 }, + { 24, 0, (SAVSIZEFN)FUN_0202A8F4, (SAVINITFN)FUN_0202A8F8 }, + { 25, 0, (SAVSIZEFN)FUN_0202A924, (SAVINITFN)FUN_0202A92C }, + { 26, 0, (SAVSIZEFN)FUN_0202ABC8, (SAVINITFN)FUN_0202ABCC }, + { 27, 0, (SAVSIZEFN)FUN_0202B374, (SAVINITFN)FUN_0202B37C }, + { 28, 0, (SAVSIZEFN)FUN_0202B8B0, (SAVINITFN)FUN_0202B8B8 }, + { 29, 0, (SAVSIZEFN)FUN_020281E0, (SAVINITFN)FUN_020281E8 }, + { 30, 0, (SAVSIZEFN)FUN_02029AE0, (SAVINITFN)FUN_02029AE8 }, + { 31, 0, (SAVSIZEFN)FUN_0202AC20, (SAVINITFN)FUN_0202AC28 }, + { 32, 0, (SAVSIZEFN)FUN_0202BE98, (SAVINITFN)FUN_0202BEA0 }, + { 33, 0, (SAVSIZEFN)FUN_0202C0E0, (SAVINITFN)FUN_0202C0E4 }, + { 34, 0, (SAVSIZEFN)FUN_02013B28, (SAVINITFN)FUN_02013B2C }, + { 35, 1, (SAVSIZEFN)PCStorage_sizeof, (SAVINITFN)PCStorage_init }, +}; + +const int UNK_020EE6D8 = NELEMS(UNK_020EE6E0); +const int UNK_020EE6DC = NELEMS(UNK_020EE700); |