1

I'm currently trying to format a disk to exFAT using a micro controller. My issue is that I need to calculate a checksum that uses the bytes from sector 1 to 11 of the VBR (Volume Boot Region) to store it into sector 12 but my result is incorrect. When the checksum isn't correct, the disk cannot be used by Windows or any other OS that recognizes exFAT since the checksum is verified and a fatal error occures if it's incorrect.

Here's the function that calculates the 32-bit checksum:

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;
}

From what I've been able to read, the function is correct so my guess is that the data that I use are incorrect. I'm simply taking the 11 sectors needed so with 512 bytes per sector it results in an array of 5632 bytes.

I've used a similar function to calculate the checksum of the entry set (a 16 bit checksum) and the result is correct, it really has to be the data but I don't understand what I'm missing there!

Anyone who knows about exFAT can help me out? Thanks!

max66
  • 65,235
  • 10
  • 71
  • 111

1 Answers1

1

I suspect it's a problem of operator precedence.

In this page I see the crc definition where checksum is modified in this way

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

that is, if I'm not wrong, equivalent to

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

because (if I remember well) the plus operator (+) has a bigger precedence than the bit or operator (|).

On the contrary, your code is

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

that is a total different code because you first apply the bitwise or and next the plus.

I suppose could work with

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

p.s.: sorry for my bad English

---EDIT 2016.06.09---

Another problem should be the signedness of data.

You define data as a pointer of char; ntfs.com define data as an array of const unsigned char.

The pointer/array difference isn't a problem; the const part ins't important (but I suggest you to define your data as const too); the problem (I suppose) is the conversion to uint32_t of a char, if char is signed with a negative values, instead of a unsigned char.

An example: suppose that the value of your data[i] is -1; with (uint32_t) data[i], if I remember well, first data[i] is converted in int(-1) and next in uint32_t(-1). So you get 4294967295.

If your data[i] is an unsigned char, instead of -1 data[i] value is 255; so (uint32_t) data[i] first convert 255 to int(255), that is 255, next to uint32_t(255), that remain 255.

Briefly, my suggestion is: change

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

in

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

or simply

checksum = (checksum << 31) | ((checksum >> 1) + (unsigned char) data[i]);
max66
  • 65,235
  • 10
  • 71
  • 111
  • You are correct indeed, I tried with your parenthesis and without any parenthesis and I get the same result for both so it seems that I misinterpreted the operator's priority! But still, the result is incorrect. I get 0x95672D57 while I should have 0xF1924082. Thanks for your help! – Arthur Penguin Jun 09 '16 at 08:11
  • 1
    @ArthurPenguin - solved a problem, let's see if we can solve another; I've edited my anser suggesting another change in your code to solve a signedness problem – max66 Jun 09 '16 at 11:43
  • There seems to be/was some confusion concerning at least one part of the algorithm. `((checksum << 31) | (checksum >> 1))` is the "C" equivalent to a single "atomic" assembly language instruction `ror DWORD [checksum], 1`, that is rotate variable right by one. Typically in assembly language a register would be used. – Mike Gonta Jan 21 '17 at 20:51