Skip to content

Commit

Permalink
[NAND]: Fix a bug with metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
Vali0004 committed Mar 4, 2025
1 parent 4b4fee0 commit eb06132
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 19 deletions.
40 changes: 22 additions & 18 deletions Xenon/Core/NAND/NAND.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,33 +77,36 @@ void NAND::Write(u64 writeAddress, u64 data, u8 byteCount) {

//*Checks ECD Page.
bool NAND::CheckPageECD(u8 *data, s32 offset) {
u8 actualData[4]{};
u8 calculatedECD[4]{};
NANDMetadata metadata{};
NANDMetadata calculatedMetadata{};

// This directly takes the NAND block's metadata
// and skips to the last 4 ECC bytes, calculates the error corrrecting data on it,
// and calculates the error corrrecting data on the ECC bytes
// and checks against what the nand provided
memcpy(actualData, rawNANDData.data() + (offset + 0x200 + 0xC), sizeof(actualData));
memcpy(&metadata, rawNANDData.data() + (offset + 0x200), sizeof(metadata));

CalculateECD(data, offset, calculatedECD);
CalculateECD(data, offset, calculatedMetadata);

return (
calculatedECD[0] == actualData[0] && calculatedECD[1] == actualData[1] &&
calculatedECD[2] == actualData[2] && calculatedECD[3] == actualData[3]);
metadata.ECC3 == calculatedMetadata.ECC3 &&
metadata.ECC2 == calculatedMetadata.ECC2 &&
metadata.ECC1 == calculatedMetadata.ECC1 &&
metadata.ECC0 == calculatedMetadata.ECC0
);
}

//*Calculates the ECD.
void NAND::CalculateECD(u8 *data, int offset, u8 ret[]) {
void NAND::CalculateECD(u8 *data, int offset, NANDMetadata &metadata) {
u32 i, val = 0, v = 0;
u32 count = 0;
for (i = 0; i < 0x1066; i++) {
if ((i & 31) == 0) {
u32 value = u32((u8)(data[count + offset]) << 24 |
(u8)(data[count + offset + 1]) << 16 |
(u8)(data[count + offset + 2]) << 8 |
(u8)(data[count + offset + 3]));
value = std::byteswap<u32>(value);
v = ~value;
v = ~std::byteswap<u32>(
(u8)(data[count + offset + 0]) << 24 |
(u8)(data[count + offset + 1]) << 16 |
(u8)(data[count + offset + 2]) << 8 |
(u8)(data[count + offset + 3])
);
count += 4;
}
val ^= v & 1;
Expand All @@ -113,10 +116,11 @@ void NAND::CalculateECD(u8 *data, int offset, u8 ret[]) {
val >>= 1;
}
val = ~val;
ret[0] = (val << 6);
ret[1] = (val >> 2) & 0xFF;
ret[2] = (val >> 10) & 0xFF;
ret[3] = (val >> 18) & 0xFF;
// Shift ECC3 to the upper 2 bits
metadata.ECC3 = (val << 6);
metadata.ECC2 = (val >> 2) & 0xFF;
metadata.ECC1 = (val >> 10) & 0xFF;
metadata.ECC0 = (val >> 18) & 0xFF;
}

// Check if the nand provided to us contains a valid metadata or not
Expand Down
22 changes: 21 additions & 1 deletion Xenon/Core/NAND/NAND.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@ enum MetaType {
metaTypeNone = 4 // No spare type or unknown
};

struct NANDMetadata {
u8 BlockID1; // LBA/ID = (((BlockID0 & 0xF) << 8) + (BlockID1))
u8 BlockID0 : 4;
u8 FsUnused0 : 4;
u8 FsSequence0; // Not reversed
u8 FsSequence1;
u8 FsSequence2;
u8 BadBlock;
u8 FsSequence3;
u8 FsSize1; // ((FsSize0 << 8) + FsSize1) = cert size
u8 FsSize0;
u8 FsPageCount; // Free pages left in block (ie: If 3 pages are used by cert then this would be 29:0x1D)
u8 FsUnused1[0x2];
u8 FsBlockType : 6;
u8 ECC3 : 2;
u8 ECC2; // 14 bit ECD
u8 ECC1;
u8 ECC0;
};

class NAND : public SystemDevice {
public:
NAND(const char *deviceName, const std::string filePath,
Expand All @@ -39,7 +59,7 @@ class NAND : public SystemDevice {
bool CheckMagic(u8 magicOut[2] = nullptr);
void CheckSpare();
bool CheckPageECD(u8 *data, s32 offset);
void CalculateECD(u8 *data, int offset, u8 ret[]);
void CalculateECD(u8 *data, int offset, NANDMetadata& metadata);
MetaType DetectSpareType(bool firstTry = true);

// void SeekPos(s32 address);
Expand Down

0 comments on commit eb06132

Please sign in to comment.