Skip to content
Permalink
Browse files

GCMemcard: The update counters are interpreted as signed values for t…

…he newer-than comparison.
  • Loading branch information...
AdmiralCurtiss committed Aug 14, 2019
1 parent 8fc2f0f commit 7d4cabea07c48186688570df531b0c203dcb94d0
Showing with 7 additions and 5 deletions.
  1. +5 −2 Source/Core/Core/HW/GCMemcard/GCMemcard.cpp
  2. +2 −3 Source/Core/Core/HW/GCMemcard/GCMemcard.h
@@ -249,8 +249,11 @@ std::pair<GCMemcardErrorCode, std::optional<GCMemcard>> GCMemcard::Open(std::str
error_code |= bat_block_1_error_code;

// select the in-use Dir and BAT blocks based on update counter
// TODO: Is there a special case for wraparound after 65535 block updates, or is it assumed that
// the hardware fails long before that anyway?

// These are compared as signed values by the GC BIOS. There is no protection against overflow, so
// if one block is MAX_VAL and the other is MIN_VAL it still picks the MAX_VAL one as the active
// one, even if that results in a corrupted memory card.
// TODO: We could try to be smarter about this to rescue seemingly-corrupted cards.

if (card.m_directory_blocks[0].m_update_counter >= card.m_directory_blocks[1].m_update_counter)
card.m_active_directory = 0;
@@ -311,8 +311,7 @@ struct Directory
std::array<u8, 0x3a> m_padding;

// 2 bytes at 0x1ffa: Update Counter
// TODO: What happens if this overflows? Is there a special case for preferring 0 over max value?
Common::BigEndianValue<u16> m_update_counter;
Common::BigEndianValue<s16> m_update_counter;

// 2 bytes at 0x1ffc: Additive Checksum
u16 m_checksum;
@@ -343,7 +342,7 @@ struct BlockAlloc
u16 m_checksum_inv;

// 2 bytes at 0x0004: Update Counter
Common::BigEndianValue<u16> m_update_counter;
Common::BigEndianValue<s16> m_update_counter;

// 2 bytes at 0x0006: Free Blocks
Common::BigEndianValue<u16> m_free_blocks;

0 comments on commit 7d4cabe

Please sign in to comment.
You can’t perform that action at this time.