usedbytes / rp2040-serial-bootloader

A serial bootloader for the Raspberry Pi RP2040 (Pico)
86 stars 29 forks source link

Wrong CRC calculation #4

Closed Thisora closed 2 years ago

Thisora commented 2 years ago

First of all, thank you for your project. I had an issue with the CRC calculation. RP2040 CRC was wrong. First i had to remove the final XOR on the read of 'dw_dma-> sniff_data' (in method calc_crc32(...)). Finally look like this :


static uint32_t calc_crc32(void *ptr, uint32_t len)
{
    uint32_t dummy_dest, crc;
    int channel = dma_claim_unused_channel(true);
    dma_channel_config c = dma_channel_get_default_config(channel);
    channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
    channel_config_set_read_increment(&c, true);
    channel_config_set_write_increment(&c, false);
    channel_config_set_sniff_enable(&c, true);

    // Seed the CRC calculation
    dma_hw->sniff_data = 0xFFFFFFFF;

    // Mode 1, then bit-reverse the result gives the same result as
    // golang's IEEE802.3 implementation
    dma_sniffer_enable(channel, DMA_MODE, true);

    dma_channel_configure(channel, &c, &dummy_dest, ptr , (len) / 4, true);

    dma_channel_wait_for_finish_blocking(channel);

    // Read the result before resetting
    crc = dma_hw->sniff_data;

    dma_sniffer_disable();
    dma_channel_unclaim(channel);

    return crc;
}

Second thing i had to change is in the python script (gen_imghdr.py). I had a lot of trubble but the biggest one was that the methode binascii.crc32() do not compute CRC the same as RP2040 DMA controller. I finally found that the correct CRC that RP2040 compute is the type CRC/MPEG-2. To do this i had to used the following function to compute CRC in python script:


def crc32mpeg2(buf, crc=0xffffffff):
    for val in buf:
        crc ^= val << 24
        for _ in range(8):
            crc = crc << 1 if (crc & 0x80000000) == 0 else (crc << 1) ^ 0x104c11db7
    return crc`

I was also able to debug with vscode/openocd. If you want more information feel free to contact me.

usedbytes commented 2 years ago

Hi, this sounds strange - I've been using this code fine for quite a while, and on my computer/pico it's all good.

I've tested the crc32 program, Python3 binascii.crc32, go crc32.ChecksumIEEE() and they all agree.

Here is some test data:

const unsigned char random_bin[] = {
    0x00, 0xfb, 0x51, 0x66, 0x26, 0xd4, 0xa5, 0xaf, 0xd6, 0x8b, 0x73, 0x7e,
    0x3e, 0xe1, 0xf4, 0xef, 0x31, 0x06, 0x2a, 0x8d, 0xa0, 0xef, 0x3d, 0x0c,
    0xe4, 0x2c, 0x3b, 0xd2, 0xa0, 0xcc, 0x59, 0x5c, 0x26, 0xbb, 0x9a, 0xe2,
    0x91, 0x8d, 0x51, 0xed, 0x88, 0x17, 0x0b, 0xda, 0xea, 0xe6, 0xb9, 0xf8,
    0x01, 0x65, 0x35, 0xe1, 0xb2, 0x4a, 0x72, 0x03, 0x28, 0x4f, 0x2a, 0x9e,
    0x6b, 0x28, 0x2d, 0xf9
};
unsigned int random_bin_len = 64;

And a Pico C program:

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/dma.h"
#include "hardware/flash.h"
#include "hardware/structs/dma.h"

// ptr must be 4-byte aligned and len must be a multiple of 4
static uint32_t calc_crc32(void *ptr, uint32_t len)
{
    uint32_t dummy_dest, crc;

    int channel = dma_claim_unused_channel(true);
    dma_channel_config c = dma_channel_get_default_config(channel);
    channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
    channel_config_set_read_increment(&c, true);
    channel_config_set_write_increment(&c, false);
    channel_config_set_sniff_enable(&c, true);

    // Seed the CRC calculation
    dma_hw->sniff_data = 0xffffffff;

    // Mode 1, then bit-reverse the result gives the same result as
    // golang's IEEE802.3 implementation
    dma_sniffer_enable(channel, 0x1, true);
    dma_hw->sniff_ctrl |= DMA_SNIFF_CTRL_OUT_REV_BITS;

    dma_channel_configure(channel, &c, &dummy_dest, ptr, len / 4, true);

    dma_channel_wait_for_finish_blocking(channel);

    // Read the result before resetting
    crc = dma_hw->sniff_data ^ 0xffffffff;

    dma_sniffer_disable();
    dma_channel_unclaim(channel);

    return crc;
}

const unsigned char random_bin[] = {
    0x00, 0xfb, 0x51, 0x66, 0x26, 0xd4, 0xa5, 0xaf, 0xd6, 0x8b, 0x73, 0x7e,
    0x3e, 0xe1, 0xf4, 0xef, 0x31, 0x06, 0x2a, 0x8d, 0xa0, 0xef, 0x3d, 0x0c,
    0xe4, 0x2c, 0x3b, 0xd2, 0xa0, 0xcc, 0x59, 0x5c, 0x26, 0xbb, 0x9a, 0xe2,
    0x91, 0x8d, 0x51, 0xed, 0x88, 0x17, 0x0b, 0xda, 0xea, 0xe6, 0xb9, 0xf8,
    0x01, 0x65, 0x35, 0xe1, 0xb2, 0x4a, 0x72, 0x03, 0x28, 0x4f, 0x2a, 0x9e,
    0x6b, 0x28, 0x2d, 0xf9
};
unsigned int random_bin_len = 64;

int main() {
    stdio_init_all();

    while (1) {
        sleep_ms(1000);

        uint32_t crc = calc_crc32((void *)random_bin, random_bin_len);

        printf("CRC Check: 0x%08x\n", crc);
    }
}

On my Pico, it gives the following output:

...
CRC Check: 0xee728bc0
CRC Check: 0xee728bc0
...

Then with a binary version of the same data, and this Python program:

#!/usr/bin/env python3

import binascii
import sys

infile = sys.argv[1]
idata = open(infile, "rb").read()
crc = binascii.crc32(idata)
print(f'{hex(crc)}')
$ ./calc_checksum.py random.bin
0xee728bc0

And this go program:

package main

import (
        "fmt"
        "hash/crc32"
        "io/ioutil"
        "os"
)

func main() {
        f, err := os.Open(os.Args[1])
        if err != nil {
                panic(err)
        }

        data, err := ioutil.ReadAll(f)
        if err != nil {
                panic(err)
        }

        crc := crc32.ChecksumIEEE(data)

        fmt.Printf("0x%08x\n", crc)
}
$ go run calc_checksum.go random.bin
0xee728bc0

And finally, with crc32:

$ crc32 random.bin
ee728bc0

You can see that they all give the same result.

So, I'm afraid I can't reproduce your issue. Maybe you could try my example C program above on your Pico and tell me what result you get.

Thisora commented 2 years ago

Humm i actually don't know. You are right your crc calculation is totally correct and i got this working just right now. Maybe i did something wrong the first time i tested it. I think the first time i tried my data was miss positioned in flash memory so my crc was wrong and i broke the calculation while trying to correct CRC.

Anyway, thank you for your answer.

pedrorovi commented 6 months ago

I have problems with crc too... Checking...