diff --git a/include/libultra/libultra.h b/include/libultra/libultra.h index 5eeed67f..69d4814b 100644 --- a/include/libultra/libultra.h +++ b/include/libultra/libultra.h @@ -6,7 +6,7 @@ #include "dolphin/os/OSCache.h" int bcmp (void *v1, void *v2, u32 size); -void bcopy(void *dst, void *src, size_t n); +void bcopy(void *src, void *dst, size_t n); void bzero(void *ptr, size_t size); void osSyncPrintf(const char* fmt, ...); void osWritebackDCache(void* vaddr, u32 nbytes); diff --git a/include/m_common_data.h b/include/m_common_data.h index 0a46a9e9..adcbacab 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -5,6 +5,7 @@ #include "m_actor_type.h" #include "m_land_h.h" #include "lb_rtc.h" +#include "m_flashrom.h" #ifdef __cplusplus extern "C" { @@ -29,13 +30,17 @@ typedef struct time_s { } Time_c; typedef struct Save_s { - u8 _tmp0[0x9120]; + /* 0x000000 */ mFRm_chk_t save_check; + /* 0x000014 */ int scene_no; + u8 _tmp0[0x9108]; /* 0x009120 */ mLd_land_info_c land_info; u8 _tmp1[0x17DE8]; /* 0x020F14 */ lbRTC_ymd_t renew_time; - u8 _tmp2[0x1610]; + u8 _tmp2[0x476]; + /* 0x02138E */ u8 saved_rom_debug; + u8 _tmp3[0x1199]; /* 0x022528 */ OSTime time_delta; - u8 _tmp3[0x3AD0]; + u8 _tmp4[0x3AD0]; } Save_t; typedef union save_u { diff --git a/include/m_flashrom.h b/include/m_flashrom.h index 403df437..db78c687 100644 --- a/include/m_flashrom.h +++ b/include/m_flashrom.h @@ -2,14 +2,46 @@ #define M_FLASHROM_H #include "types.h" +#include "libu64/gfxprint.h" #ifdef __cplusplus extern "C" { #endif +#define mFRm_SAVE_ID ('GAFE') + +extern void mFRm_set_msg_idx(int idx); +extern int mFRm_get_msg_idx(); +extern u16 mFRm_ReturnCheckSum(u16* data, s32 size); +extern u16 mFRm_GetFlatCheckSum(u16* data, s32 size, s16 now_checksum); +extern int mFRm_CheckSaveData_ID(mFRm_chk_t* save_check); +extern int mFRm_CheckSaveData_common(mFRm_chk_t* save_check, u16 land_id); +extern int mFRm_CheckSaveData(); +extern void mFRm_ClearSaveCheckData(mFRm_chk_t* save_check); +extern void mFRm_SetSaveCheckData(mFRm_chk_t* save_check); extern void mFRm_PrintSavedDebug(gfxprint_t* gfxprint); +extern void mFRm_clear_err_info(); +extern void mFRm_save_data_check(); extern void mFRm_display_errInfo(gfxprint_t* gfxprint); +#define mFRm_ERROR_INFO_NUM 10 +#define mFRm_NO_ERROR_NO 7 + +typedef struct mFRm_chk_s { + /* 0x00 */ int version; + /* 0x04 */ u32 code; + /* 0x08 */ u16 land_id; + /* 0x0A */ lbRTC_time_c time; + /* 0x12 */ u16 checksum; +} mFRm_chk_t; + +typedef struct flashrom_error_info { + int err_no; + int proc_idx; +} mFRm_err_info_c; + +typedef int (save_check_proc)(void); + #ifdef __cplusplus } #endif diff --git a/include/m_land.h b/include/m_land.h index 25d79beb..104b0b56 100644 --- a/include/m_land.h +++ b/include/m_land.h @@ -10,6 +10,7 @@ extern "C" { #define mLd_BITMASK 0x3000 #define mLd_CHECK_ID(id) (((id) & mLd_BITMASK) == mLd_BITMASK) +#define mLd_CHECK_LAND_ID(id) (((id) & 0xFF00) == mLd_BITMASK) #define NATIVE 0 #define FOREIGN 1 diff --git a/rel/m_flashrom.c b/rel/m_flashrom.c new file mode 100644 index 00000000..914981b5 --- /dev/null +++ b/rel/m_flashrom.c @@ -0,0 +1,409 @@ +/** + * @file m_flashrom.c + * @brief Save game check and error handling functions. + * + * This file contains functions related to save game checks, error handling, + * and related utility functions. The functions are responsible for verifying + * save data integrity, managing error information, and displaying save data + * check results and error information. + * + * Global Functions: + * - mFRm_set_msg_idx() : Set the message index. + * - mFRm_get_msg_idx() : Get the message index. + * - mFRm_ReturnCheckSum() : Calculate the checksum of the given data. + * - mFRm_GetFlatCheckSum() : Calculate the flat checksum for save data. + * - mFRm_CheckSaveData_ID() : Check if the save data ID matches the expected ID. + * - mFRm_CheckSaveData_common(): Check the save data for various conditions. + * - mFRm_CheckSaveData() : Perform a save data check. + * - mFRm_ClearSaveCheckData() : Clear the save check data structure. + * - mFRm_SetSaveCheckData() : Set the save check data structure. + * - mFRm_PrintSavedDebug() : Print a debug indicator if saved debug data is found. + * - mFRm_clear_err_info() : Clear the error information array. + * - mFRm_save_data_check() : Perform a series of save data checks and store errors. + * - mFRm_display_errInfo() : Display error information on the screen. + * + * File-local Functions: + * - mFRm_get_free_errInfo() : Find a free slot in the error information array. + * - mFRm_set_errInfo() : Set error information in the error information array. + * - mFRm_get_errInfoNum() : Get the number of errors in the error information array. + */ + +/* TODO: finish & include sChk_ZZZ files each programmer wrote */ +/* TODO: A few removed functions need to be matched on N64 and included for proper .rodata layout */ + +#include "m_flashrom.h" + +#include "m_common_data.h" +#include "m_time.h" +#include "m_land.h" +#include "zurumode.h" + +static int l_mfrm_msg_idx; +static int l_mfrm_now_color; +static mFRm_err_info_c l_mfrm_err_info[mFRm_ERROR_INFO_NUM]; +static int l_mfrm_err_debug[] = {0, 0, 0, 0, 0, 0}; + +/* Predeclaration for save check functions */ +static int sChk_check_save_data(); +static int sChk_check_save_gen(); +static int sChk_CheckSaveData_MYK(); +static int sChk_CheckSaveData_NSW(); +static int sChk_check_save_take(); +static int sChk_CheckSaveData_YSD(); +static int sChk_CheckSaveData_komatu(); + +/** + * @brief Set the current message index value. + * + * This function sets the global message index value to the provided input. + * + * @param idx The message index value to be set. + */ +extern void mFRm_set_msg_idx(int idx) { + l_mfrm_msg_idx = idx; +} + +/** + * @brief Get the current message index value. + * + * This function returns the global message index value. + * + * @return int The current message index value. + */ +extern int mFRm_get_msg_idx() { + return l_mfrm_msg_idx; +} + +/** + * @brief Calculate the checksum of the given data. + * + * This function calculates the checksum of the provided data by adding + * all the 16-bit data elements together. + * + * @param data A pointer to the data buffer. + * @param size The size of the data buffer in bytes. + * @return u16 The calculated checksum. + */ +extern u16 mFRm_ReturnCheckSum(u16* data, int size) { + u16 checksum = 0; + + // Check if the size is even + if ((size & 1) == 0) { + // Calculate the checksum by adding all 16-bit data elements + while (size != 0) { + checksum += *data; + data++; + size -= sizeof(u16); + } + } + + return checksum; +} + +/** + * @brief Calculate the flat checksum of the given data. + * + * This function calculates the flat checksum of the provided data by + * subtracting the current checksum from the calculated checksum and + * then performing a bitwise complement and incrementing by 1. + * + * @param data A pointer to the data buffer. + * @param size The size of the data buffer in bytes. + * @param now_checksum The current checksum of the data buffer. + * @return u16 The calculated flat checksum. + */ +extern u16 mFRm_GetFlatCheckSum(u16* data, int size, u16 now_checksum) { + // Calculate the checksum + u16 checksum = mFRm_ReturnCheckSum(data, size) - now_checksum; + + // Perform bitwise complement and increment by 1 + return (u16)(((~checksum & 0xFFFF) + 1) & 0xFFFF); +} + +/** + * @brief Check if the save data ID is valid. + * + * This function checks if the provided save_check structure contains a valid + * save data ID. + * + * @param save_check A pointer to the mFRm_chk_t structure containing the save data ID. + * @return int Returns TRUE if the save data ID is valid, otherwise FALSE. + */ +extern int mFRm_CheckSaveData_ID(mFRm_chk_t* save_check) { + int ret = FALSE; + + // Check if the save data ID is valid + if ((save_check->code == mFRm_SAVE_ID)) { + ret = TRUE; + } + + return ret; +} + +/** + * @brief Check if the save data is valid. + * + * This function checks if the provided save_check structure contains valid save data, + * comparing the land ID with the provided land_id parameter. + * + * @param save_check A pointer to the mFRm_chk_t structure containing the save data. + * @param land_id The land ID to check against the save data. + * @return int Returns TRUE if the save data is valid, otherwise FALSE. + */ +extern int mFRm_CheckSaveData_common(mFRm_chk_t* save_check, u16 land_id) { + int ret = FALSE; + + // Check if the save data ID is valid and land IDs match + if (mFRm_CheckSaveData_ID(save_check) != 0 && + mLd_CHECK_LAND_ID(save_check->land_id) && + save_check->land_id == land_id) { + ret = TRUE; + } + + return ret; +} + +/** + * @brief Check if the current save data is valid. + * + * This function checks if the current save data is valid using mFRm_CheckSaveData_common. + * + * @return int Returns TRUE if the save data is valid, otherwise FALSE. + */ +extern int mFRm_CheckSaveData() { + return mFRm_CheckSaveData_common(Save_GetPointer(save_check), Save_Get(land_info.id)); +} + +/** + * @brief Clear the save check data. + * + * This function clears the provided save_check structure by setting its fields to their + * default values. + * + * @param save_check A pointer to the mFRm_chk_t structure to be cleared. + */ +extern void mFRm_ClearSaveCheckData(mFRm_chk_t* save_check) { + // Set the save check data fields to their default values + save_check->code = -1; + save_check->land_id = 0xFFFF; + bcopy((lbRTC_time_c*)&mTM_rtcTime_clear_code, &save_check->time, sizeof(lbRTC_time_c)); + save_check->checksum = 0; +} + +/** + * @brief Set the save check data. + * + * This function sets the save check data fields based on the current save data + * and real-time clock values. + * + * @param save_check A pointer to the mFRm_chk_t structure to be set. + */ +extern void mFRm_SetSaveCheckData(mFRm_chk_t* save_check) { + u16 land_id = Save_Get(land_info.id); + + // Set the save check data fields + save_check->code = mFRm_SAVE_ID; + save_check->land_id = land_id; + lbRTC_TimeCopy(&save_check->time, &common_data.time.rtc_time); +} + +/** + * @brief Print the saved debug information. + * + * This function prints an 'X' to the screen if the saved debug information is available. + * + * @param gfxprint A pointer to the gfxprint_t structure for screen printing. + */ +extern void mFRm_PrintSavedDebug(gfxprint_t* gfxprint) { + // Check if the saved debug information is available + if (Save_Get(saved_rom_debug) == TRUE) { + // Set the print color and location + gfxprint_color(gfxprint, 50, 250, 100, 255); + gfxprint_locate8x8(gfxprint, 29, 3); + // Print an 'X' to the screen + gfxprint_printf(gfxprint, "X"); + } +} + +/** + * @brief Clear the error information. + * + * This function clears the error information by setting all error numbers + * to mFRm_NO_ERROR_NO. + */ +extern void mFRm_clear_err_info() { + int i; + // Zero out the error information array + bzero(l_mfrm_err_info, sizeof(mFRm_err_info_c) * mFRm_ERROR_INFO_NUM); + + // Set all error numbers to mFRm_NO_ERROR_NO + for (i = 0; i < mFRm_ERROR_INFO_NUM; i++) { + l_mfrm_err_info[i].err_no = mFRm_NO_ERROR_NO; + } +} + +/** + * @brief Get a free error information slot. + * + * This function returns a pointer to the first available error information slot. + * + * @param err_info A pointer to the error information array. + * @param count The number of error information slots. + * @return mFRm_err_info_c* A pointer to the first available error information slot or NULL if none are available. + */ +static mFRm_err_info_c* mFRm_get_free_errInfo(mFRm_err_info_c* err_info, int count) { + mFRm_err_info_c* ret = NULL; + + // Iterate through the error information slots + while (count != 0) { + // Check if the current slot is available + if (err_info->err_no == mFRm_NO_ERROR_NO) { + ret = err_info; + break; + } + err_info++; + count--; + } + return ret; +} + +/** + * @brief Set the error information for a specific process. + * + * This function sets the error information for the specified process index and error number. + * + * @param err_info A pointer to the error information array. + * @param proc_idx The process index for which the error occurred. + * @param err_no The error number to be set. + */ +static void mFRm_set_errInfo(mFRm_err_info_c* err_info, int proc_idx, int err_no) { + // Get a free error information slot + mFRm_err_info_c* free = mFRm_get_free_errInfo(err_info, mFRm_ERROR_INFO_NUM); + + // Set the error information if a free slot is available + if (free != NULL) { + free->err_no = err_no; + free->proc_idx = proc_idx; + } +} + +/** + * @brief Get the number of error information slots with errors. + * + * This function returns the number of error information slots with error numbers + * different from mFRm_NO_ERROR_NO. + * + * @param err_info A pointer to the error information array. + * @param count The number of error information slots. + * @return int The number of error information slots with errors. + */ +static int mFRm_get_errInfoNum(mFRm_err_info_c* err_info, int count) { + int ret = 0; + + // Loop through the error information slots + while (count != 0) { + // Increment the count if the error number is not mFRm_NO_ERROR_NO + if (err_info->err_no != mFRm_NO_ERROR_NO) { + ret++; + } + err_info++; + count--; + } + return ret; +} + +/** + * @brief Perform save data checks. + * + * This function performs save data checks for different procedures and + * increments the color index upon each check. + */ +extern void mFRm_save_data_check() { + // Define save data check procedures + static save_check_proc* proc[] = { + &sChk_check_save_data, &sChk_check_save_gen, &sChk_CheckSaveData_MYK, + &sChk_CheckSaveData_NSW, &sChk_check_save_take, &sChk_CheckSaveData_YSD, + &sChk_CheckSaveData_komatu + }; + + int i = 0; + mFRm_err_info_c* err_info = l_mfrm_err_info; + l_mfrm_now_color = 0; + + // If zurumode_flag is greater or equal to 2 and scene_no is 7, perform save data checks + if ((zurumode_flag >= 2) && (Save_Get(scene_no) == 7)) { + // If there are no errors, perform the save data checks + if (mFRm_get_errInfoNum(err_info, mFRm_ERROR_INFO_NUM) == 0) { + while (i < 7) { + (*proc[i])(); + l_mfrm_now_color++; + i++; + } + } + } +} + +/* Color table for displaying error information */ +static u32 l_mfrm_color_table[7][3] = { + { 0, 0, 0}, /* Black */ + {255, 0, 0}, /* Red */ + {255, 255, 255}, /* White */ + { 0, 190, 0}, /* Green */ + {100, 100, 100}, /* Gray */ + { 0, 0, 255}, /* Blue */ + {255, 0, 255} /* Magenta */ +}; + +/* This needs pool_data on */ +#pragma pool_data on +/** + * @brief Display error information on the screen. + * + * This function displays the error information on the screen if there are + * any errors and if the zurumode_flag is greater than or equal to 2. + * + * @param gfxprint A pointer to the gfxprint_t structure for screen printing. + */ +extern void mFRm_display_errInfo(gfxprint_t* gfxprint) { + mFRm_err_info_c* err_info = l_mfrm_err_info; + int i; + + // If zurumode_flag is greater or equal to 2 and scene_no is 7, display + // error information + if ((zurumode_flag >= 2) && (Save_Get(scene_no) == 7)) { + gfxprint_locate8x8(gfxprint, 37, 17); + gfxprint_color(gfxprint, 255, 255, 255, 255); + gfxprint_printf(gfxprint, "-"); + + // If there are errors, display them on the screen + if (mFRm_get_errInfoNum(err_info, mFRm_ERROR_INFO_NUM) > 0) { + for (i = 0; i < 10; i++) { + gfxprint_locate8x8(gfxprint, 30, i + 18); + + // Break the loop if no error is found + if (err_info->err_no == mFRm_NO_ERROR_NO) { + break; + } + + // Set the color for displaying the error information + gfxprint_color( + gfxprint, + l_mfrm_color_table[err_info->err_no][0], + l_mfrm_color_table[err_info->err_no][1], + l_mfrm_color_table[err_info->err_no][2], + 255 + ); + + // Display the error information + gfxprint_printf( + gfxprint, + "x%dx %d", + err_info->err_no, + err_info->proc_idx + ); + err_info++; + } + } + } +} +#pragma pool_data reset diff --git a/rel/save_check.c_inc b/rel/save_check.c_inc new file mode 100644 index 00000000..e69de29b diff --git a/rel/save_check_MYK.c_inc b/rel/save_check_MYK.c_inc new file mode 100644 index 00000000..e69de29b diff --git a/rel/save_check_NSW.c_inc b/rel/save_check_NSW.c_inc new file mode 100644 index 00000000..e69de29b diff --git a/rel/save_check_YSD.c_inc b/rel/save_check_YSD.c_inc new file mode 100644 index 00000000..e69de29b diff --git a/rel/save_check_gen.c_inc b/rel/save_check_gen.c_inc new file mode 100644 index 00000000..e69de29b diff --git a/rel/save_check_komatu.c_inc b/rel/save_check_komatu.c_inc new file mode 100644 index 00000000..e69de29b diff --git a/rel/save_check_take.c_inc b/rel/save_check_take.c_inc new file mode 100644 index 00000000..e69de29b