exFAT校验和的计算

Calculation of exFAT checksum

我目前正在尝试使用微控制器将磁盘格式化为 exFAT。我的问题是我需要计算一个校验和,该校验和使用 VBR(卷引导区域)的扇区 1 到 11 的字节将其存储到扇区 12,但我的结果不正确。当校验和不正确时,磁盘不能被 Windows 或任何其他识别 exFAT 的 OS 使用,因为校验和已被验证,如果不正确则会发生致命错误。

这是计算 32 位校验和的函数:

uint32_t BootChecksum(char * data, long bytes){
    uint32_t checksum = 0; 
    for (uint32_t i = 0 ; i < bytes ; i++){
        if (i == 106 || i == 107 || i == 112)
            continue;
        checksum = ((checksum << 31) | (checksum >> 1)) + (uint32_t) data[i];
        if(checksum == 0xF1924082){
            printf("%02X | i = %d", checksum, i);
        }
    }
    return checksum;
}

据我所知,函数是正确的,所以我猜测我使用的数据不正确。我只是简单地获取所需的 11 个扇区,因此每个扇区 512 字节,它会产生一个 5632 字节的数组。

我使用了类似的函数来计算条目集的校验和(16 位校验和),结果是正确的,它确实必须是数据,但我不明白我遗漏了什么那里!

哪位知道exFAT的可以帮帮我?谢谢!

我怀疑这是运算符优先级的问题。

this page中我看到crc定义checksum是这样修改的

checksum = (checksum<<31) | (checksum>> 1) + data[i];

也就是说,如果我没记错的话,相当于

checksum = (checksum<<31) | ((checksum>> 1) + data[i]);

因为(如果我没记错的话)加号运算符 (+) 的优先级高于位或运算符 (|)。

相反,你的代码是

checksum = ((checksum << 31) | (checksum >> 1)) + (uint32_t) data[i];

这是完全不同的代码,因为您首先应用按位或,然后应用加号。

我想可以和

一起工作
checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) data[i]);

p.s.: 对不起我的英语不好

---编辑 2016.06.09---

另一个问题应该是 data 的符号性。

你将data定义为char的指针; ntfs.com 将 data 定义为 const unsigned char.

的数组

pointer/array 差异不是问题; const 部分并不重要(但我建议您也将 data 定义为 const);问题(我想)是 charuint32_t 的转换,如果 char 是用负值签名的,而不是 unsigned char.

举个例子:假设你的data[i]的值为-1;对于 (uint32_t) data[i],如果我没记错的话,首先 data[i]int(-1) 中转换,然后在 uint32_t(-1) 中转换。所以你得到 4294967295.

如果你的 data[i] 是一个 unsigned char,而不是 -1 data[i] 值是 255;所以(uint32_t) data[i]首先将255转换为int(255),也就是255,紧接着uint32_t(255),剩下的就是255.

简而言之,我的建议是:改变

checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) data[i]);

checksum = (checksum << 31) | ((checksum >> 1) + (uint32_t) (unsigned char) data[i]);

或干脆

checksum = (checksum << 31) | ((checksum >> 1) + (unsigned char) data[i]);