diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp b/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp index 11676f4faf..cfa0d5ad47 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp +++ b/Source/Core/Core/HW/GCMemcard/GCMemcard.cpp @@ -64,14 +64,16 @@ GCMemcard::GCMemcard() { } -std::optional GCMemcard::Create(std::string filename, u16 size_mbits, bool shift_jis) +std::optional GCMemcard::Create(std::string filename, const CardFlashId& flash_id, + u16 size_mbits, bool shift_jis, u32 rtc_bias, + u32 sram_language, u64 format_time) { GCMemcard card; card.m_filename = std::move(filename); // TODO: Format() not only formats the card but also writes it to disk at m_filename. // Those tasks should probably be separated. - if (!card.Format(shift_jis, size_mbits)) + if (!card.Format(flash_id, size_mbits, shift_jis, rtc_bias, sram_language, format_time)) return std::nullopt; return std::move(card); @@ -1367,29 +1369,32 @@ std::optional> GCMemcard::ReadAnimRGBA return output; } -bool GCMemcard::Format(u8* card_data, bool shift_jis, u16 SizeMb) +bool GCMemcard::Format(u8* card_data, const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, + u32 rtc_bias, u32 sram_language, u64 format_time) { if (!card_data) return false; memset(card_data, 0xFF, BLOCK_SIZE * 3); memset(card_data + BLOCK_SIZE * 3, 0, BLOCK_SIZE * 2); - *((Header*)card_data) = Header(SLOT_A, SizeMb, shift_jis); + *((Header*)card_data) = + Header(flash_id, size_mbits, shift_jis, rtc_bias, sram_language, format_time); *((Directory*)(card_data + BLOCK_SIZE)) = Directory(); *((Directory*)(card_data + BLOCK_SIZE * 2)) = Directory(); - *((BlockAlloc*)(card_data + BLOCK_SIZE * 3)) = BlockAlloc(SizeMb); - *((BlockAlloc*)(card_data + BLOCK_SIZE * 4)) = BlockAlloc(SizeMb); + *((BlockAlloc*)(card_data + BLOCK_SIZE * 3)) = BlockAlloc(size_mbits); + *((BlockAlloc*)(card_data + BLOCK_SIZE * 4)) = BlockAlloc(size_mbits); return true; } -bool GCMemcard::Format(bool shift_jis, u16 SizeMb) +bool GCMemcard::Format(const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, u32 rtc_bias, + u32 sram_language, u64 format_time) { - m_header_block = Header(SLOT_A, SizeMb, shift_jis); + m_header_block = Header(flash_id, size_mbits, shift_jis, rtc_bias, sram_language, format_time); m_directory_blocks[0] = m_directory_blocks[1] = Directory(); - m_bat_blocks[0] = m_bat_blocks[1] = BlockAlloc(SizeMb); + m_bat_blocks[0] = m_bat_blocks[1] = BlockAlloc(size_mbits); - m_size_mb = SizeMb; + m_size_mb = size_mbits; m_size_blocks = (u32)m_size_mb * MBIT_TO_BLOCKS; m_data_blocks.clear(); m_data_blocks.resize(m_size_blocks - MC_FST_BLOCKS); @@ -1538,25 +1543,33 @@ void GCMBlock::Erase() memset(m_block.data(), 0xFF, m_block.size()); } -Header::Header(int slot, u16 size_mbits, bool shift_jis) +Header::Header() +{ + static_assert(std::is_trivially_copyable_v
); + std::memset(this, 0xFF, BLOCK_SIZE); +} + +Header::Header(const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, u32 rtc_bias, + u32 sram_language, u64 format_time) { // Nintendo format algorithm. // Constants are fixed by the GC SDK // Changing the constants will break memory card support - memset(this, 0xFF, BLOCK_SIZE); + static_assert(std::is_trivially_copyable_v
); + std::memset(this, 0xFF, BLOCK_SIZE); m_size_mb = size_mbits; m_encoding = shift_jis ? 1 : 0; - u64 rand = Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH; - m_format_time = rand; + m_format_time = format_time; + u64 rand = format_time; for (int i = 0; i < 12; i++) { rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); - m_serial[i] = (u8)(g_SRAM.settings_ex.flash_id[slot][i] + (u32)rand); + m_serial[i] = (u8)(flash_id[i] + (u32)rand); rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); rand &= (u64)0x0000000000007fffULL; } - m_sram_bias = g_SRAM.settings.rtc_bias; - m_sram_language = static_cast(g_SRAM.settings.language); + m_sram_bias = rtc_bias; + m_sram_language = sram_language; // TODO: determine the purpose of m_unknown_2 // 1 works for slot A, 0 works for both slot A and slot B memset(m_unknown_2.data(), 0, diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcard.h b/Source/Core/Core/HW/GCMemcard/GCMemcard.h index 71b593134d..2d023e4a1a 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcard.h +++ b/Source/Core/Core/HW/GCMemcard/GCMemcard.h @@ -213,8 +213,12 @@ struct Header // 0x1e00 bytes at 0x0200: Unused (0xff) std::array m_unused_2; - explicit Header(int slot = 0, u16 size_mbits = MBIT_SIZE_MEMORY_CARD_2043, - bool shift_jis = false); + // initialize an unformatted header block + explicit Header(); + + // initialize a formatted header block + explicit Header(const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, u32 rtc_bias, + u32 sram_language, u64 format_time); // Calculates the card serial numbers used for encrypting some save files. std::pair CalculateSerial() const; @@ -401,7 +405,9 @@ private: void UpdateBat(const BlockAlloc& bat); public: - static std::optional Create(std::string filename, u16 size_mbits, bool shift_jis); + static std::optional Create(std::string filename, const CardFlashId& flash_id, + u16 size_mbits, bool shift_jis, u32 rtc_bias, + u32 sram_language, u64 format_time); static std::pair> Open(std::string filename); @@ -413,9 +419,10 @@ public: bool IsValid() const { return m_valid; } bool IsShiftJIS() const; bool Save(); - bool Format(bool shift_jis = false, u16 SizeMb = MBIT_SIZE_MEMORY_CARD_2043); - static bool Format(u8* card_data, bool shift_jis = false, - u16 SizeMb = MBIT_SIZE_MEMORY_CARD_2043); + bool Format(const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, u32 rtc_bias, + u32 sram_language, u64 format_time); + static bool Format(u8* card_data, const CardFlashId& flash_id, u16 size_mbits, bool shift_jis, + u32 rtc_bias, u32 sram_language, u64 format_time); static s32 FZEROGX_MakeSaveGameValid(const Header& cardheader, const DEntry& direntry, std::vector& FileBuffer); static s32 PSO_MakeSaveGameValid(const Header& cardheader, const DEntry& direntry, diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp index 2cfb80b47b..398e5b031c 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp +++ b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp @@ -26,9 +26,13 @@ #include "Common/MsgHandler.h" #include "Common/StringUtil.h" #include "Common/Thread.h" +#include "Common/Timer.h" + #include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/HW/EXI/EXI_DeviceIPL.h" +#include "Core/HW/Sram.h" #include "Core/NetPlayProto.h" static const char* MC_HDR = "MC_SYSTEM_AREA"; @@ -148,8 +152,10 @@ std::vector GCMemcardDirectory::GetFileNamesForGameID(const std::st GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u16 size_mbits, bool shift_jis, int game_id) : MemoryCardBase(slot, size_mbits), m_game_id(game_id), m_last_block(-1), - m_hdr(slot, size_mbits, shift_jis), m_bat1(size_mbits), m_saves(0), - m_save_directory(directory), m_exiting(false) + m_hdr(g_SRAM.settings_ex.flash_id[slot], size_mbits, shift_jis, g_SRAM.settings.rtc_bias, + static_cast(g_SRAM.settings.language), + Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH), + m_bat1(size_mbits), m_saves(0), m_save_directory(directory), m_exiting(false) { // Use existing header data if available { diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcardRaw.cpp b/Source/Core/Core/HW/GCMemcard/GCMemcardRaw.cpp index 90d715eedd..7e8a472c12 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcardRaw.cpp +++ b/Source/Core/Core/HW/GCMemcard/GCMemcardRaw.cpp @@ -22,9 +22,13 @@ #include "Common/MsgHandler.h" #include "Common/StringUtil.h" #include "Common/Thread.h" +#include "Common/Timer.h" + #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/HW/EXI/EXI_DeviceIPL.h" #include "Core/HW/GCMemcard/GCMemcard.h" +#include "Core/HW/Sram.h" #define SIZE_TO_Mb (1024 * 8 * 16) #define MC_HDR_SIZE 0xA000 @@ -51,9 +55,18 @@ MemoryCard::MemoryCard(const std::string& filename, int card_index, u16 size_mbi m_memory_card_size = size_mbits * SIZE_TO_Mb; m_memcard_data = std::make_unique(m_memory_card_size); - // Fills in MC_HDR_SIZE bytes - Memcard::GCMemcard::Format(&m_memcard_data[0], m_filename.find(".JAP.raw") != std::string::npos, - size_mbits); + + // Fills in the first 5 blocks (MC_HDR_SIZE bytes) + const CardFlashId& flash_id = g_SRAM.settings_ex.flash_id[Memcard::SLOT_A]; + const bool shift_jis = m_filename.find(".JAP.raw") != std::string::npos; + const u32 rtc_bias = g_SRAM.settings.rtc_bias; + const u32 sram_language = static_cast(g_SRAM.settings.language); + const u64 format_time = + Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH; + Memcard::GCMemcard::Format(&m_memcard_data[0], flash_id, size_mbits, shift_jis, rtc_bias, + sram_language, format_time); + + // Fills in the remaining blocks memset(&m_memcard_data[MC_HDR_SIZE], 0xFF, m_memory_card_size - MC_HDR_SIZE); INFO_LOG(EXPANSIONINTERFACE, "No memory card found. A new one was created instead."); diff --git a/Source/Core/DolphinQt/GCMemcardCreateNewDialog.cpp b/Source/Core/DolphinQt/GCMemcardCreateNewDialog.cpp index 36a12627f4..b54766d157 100644 --- a/Source/Core/DolphinQt/GCMemcardCreateNewDialog.cpp +++ b/Source/Core/DolphinQt/GCMemcardCreateNewDialog.cpp @@ -14,8 +14,11 @@ #include "Common/FileUtil.h" #include "Common/MsgHandler.h" +#include "Common/Timer.h" +#include "Core/HW/EXI/EXI_DeviceIPL.h" #include "Core/HW/GCMemcard/GCMemcard.h" +#include "Core/HW/Sram.h" GCMemcardCreateNewDialog::GCMemcardCreateNewDialog(QWidget* parent) : QDialog(parent) { @@ -74,8 +77,16 @@ bool GCMemcardCreateNewDialog::CreateCard() if (path.isEmpty()) return false; + // TODO: The dependency on g_SRAM here is sketchy. We should instead use sensible default values. + const CardFlashId& flash_id = g_SRAM.settings_ex.flash_id[Memcard::SLOT_A]; + const u32 rtc_bias = g_SRAM.settings.rtc_bias; + const u32 sram_language = static_cast(g_SRAM.settings.language); + const u64 format_time = + Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH; + const std::string p = path.toStdString(); - auto memcard = Memcard::GCMemcard::Create(p, size, is_shift_jis); + auto memcard = Memcard::GCMemcard::Create(p, flash_id, size, is_shift_jis, rtc_bias, + sram_language, format_time); if (memcard && memcard->Save()) { m_card_path = p;