ch32-rs / wchisp

WCH ISP Tool in Rust
https://ch32-rs.github.io/wchisp/
GNU General Public License v2.0
164 stars 28 forks source link

USB boot wipe #28

Open kimstik opened 1 year ago

kimstik commented 1 year ago

I made simple stupid blinker on PA0 for ch32v203. It works fine. My issue that when it assembled with clang instead of GCC it creates bit different elf file which somehow magically erase/disable internal 28k USB bootloader code.

wchisp.exe flash main.elf

After programming this elf file i am not able anymore to use USB ISP, but SDI way still works. now wch-link over SDI shows empty region of 28k bootloader @0x1FFF8000.

wchisp is flashing stack region over address 0x20002000

May someone confirm the issue? Any ideas to recover USB bootloader functionality?

wchisp v0.2.0 main.elf.zip

robots commented 1 year ago

This is very interesting feature :-)

robots commented 1 year ago
19:53:56 [INFO] Read ../../../main.elf as ELF format
19:53:56 [INFO] Found loadable segment, physical address: 0x00000000, virtual address: 0x00000000, flags: 0x5
19:53:56 [INFO] Section names: [".init"]
19:53:56 [INFO] Found loadable segment, physical address: 0x00000004, virtual address: 0x00000004, flags: 0x6
19:53:56 [INFO] Section names: [".vector"]
19:53:56 [INFO] Found loadable segment, physical address: 0x00000034, virtual address: 0x00000034, flags: 0x5
19:53:56 [INFO] Section names: [".text"]
19:53:56 [INFO] Found loadable segment, physical address: 0x20002000, virtual address: 0x20002000, flags: 0x6
19:53:56 [INFO] Section names: [".stack"]
19:53:56 [INFO] Firmware size: 536881152
19:53:56 [INFO] Erasing...
19:53:56 [INFO] Erased 524299 code flash sectors
19:53:57 [INFO] Erase done
19:53:57 [INFO] Writing to code flash...

I have just tested this "feature", I want to find way how to replace bootloader with my own. So this is good starting point.

firmware size is wrongly generated, and erase is run on many more sectors than needed

kimstik commented 1 year ago
19:53:56 [INFO] Read ../../../main.elf as ELF format
19:53:56 [INFO] Found loadable segment, physical address: 0x00000000, virtual address: 0x00000000, flags: 0x5
19:53:56 [INFO] Section names: [".init"]
19:53:56 [INFO] Found loadable segment, physical address: 0x00000004, virtual address: 0x00000004, flags: 0x6
19:53:56 [INFO] Section names: [".vector"]
19:53:56 [INFO] Found loadable segment, physical address: 0x00000034, virtual address: 0x00000034, flags: 0x5
19:53:56 [INFO] Section names: [".text"]
19:53:56 [INFO] Found loadable segment, physical address: 0x20002000, virtual address: 0x20002000, flags: 0x6
19:53:56 [INFO] Section names: [".stack"]
19:53:56 [INFO] Firmware size: 536881152
19:53:56 [INFO] Erasing...
19:53:56 [INFO] Erased 524299 code flash sectors
19:53:57 [INFO] Erase done
19:53:57 [INFO] Writing to code flash...

I have just tested this "feature", I want to find way how to replace bootloader with my own. So this is good starting point.

firmware size is wrongly generated, and erase is run on many more sectors than needed

Is USB ISP in this chip is dead?

robots commented 1 year ago

Yes, i read the bootloader flash as zeros, that means it was written to zeros. Erased flash in these chips is 0x39 0xe3

robots commented 1 year ago

I played a bit more with this thing, It seemed that the chip locked itself. After connecting to wch linke utility it unlocked and the bootloader section is indeed erased. More tests to come....

robots commented 1 year ago

So, i connected the chip to the WCHlink utility in windows. It told me that the chip was locked. Unlocking the chip helped, and i can read the bootlaoder memory as empty:

(gdb) monitor mdw 0x1fff8000 100
0x1fff8000: e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339
0x1fff8020: e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339
0x1fff8040: e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339
0x1fff8060: e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339
0x1fff8080: e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339
0x1fff80a0: e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339 e339e339

I think what happened is, that the chip tried to erase flash in 64kB blocks. Flash memory in these chips is external SPI or QSPI flash.

Bootloader erases memory like this: shot-2023-04-23_15-57-52

First at most 0x3f 64kB blocks, then at most 0x1f 32kBlocks, then at most 3x 4kBlocks, then rest as 1kBlocks (4x256). minimum amount is 8sectors, maximum 0x1e0 (480) sectors. Sector is 1k.

If you request erase of 480sectors, that is 0x78000. This chip's flash memory goes up to address 0x38000. So the bootloader tries to erase memory "beyond".

The problem here is:

How to get data back ? Well that is problem. When you try to program anything higher than 0x08038000 you get hardfault. Except when you try to program 0x1fff8000 address space. But it wont get written, but it will not hardfault either! It will hang there for the write in progress flag to drop.

My guess is that there is some "unlock bootloader" for ch32v20x/30x chips. But i have not found it yet. (I have tested the ch32v003 method FLASH_BOOT_MODEKEYR).

Here is the test code i use: test.txt

any suggestions are welcome :-)

elfmimi commented 1 year ago

Thanks for sharing your findings. it's very interesting.

robots commented 1 year ago

IMG_20230413_105327

robots commented 1 year ago

you can see second die in upper left corner

elfmimi commented 1 year ago

Wow!

robots commented 1 year ago

fiddling with bits that you should not ....

(gdb) monitor mdw 0x1fff8000 10
0x1fff8000: 12341234 12341234 12341234 e339e339 e339e339 e339e339 e339e339 e339e339
0x1fff8020: e339e339 e339e339

I call it success (at least partial), the flash controller locked up, and needed power cycle. But the data is there !!

kimstik commented 1 year ago

Now it will be nice to find a way to change the bootloader part (at least one bit) There is a possibility that my code simply disabled access to the bootloader, but did not erase it.

Xelus22 commented 1 year ago

Is there a datasheet on the bootloader sequence? Looks like as you said there is no check in the bootloader (or a logic error). I also would like to know if you can USB ISP over the USB HS interface (on CH32V305/7).

robots commented 1 year ago

Sorry guys for looong time waiting :)

https://github.com/robots/wch-ch32v20x-flash

I have written soft to repair the bootloader (or replace it with anything else)

elfmimi commented 1 year ago

amazing!

Xelus22 commented 1 year ago

Potentially could get a tinyUF2 going in the bootloader then :O (at least for ch32v307 as that is support in tinyUSB)

kimstik commented 1 year ago

Potentially could get a tinyUF2 going in the bootloader then :O (at least for ch32v307 as that is support in tinyUSB)

Exactly! Or tiny DFU bootloader if UF2 will not fit.

kimstik commented 1 year ago

Sorry guys for looong time waiting :)

https://github.com/robots/wch-ch32v20x-flash

I have written soft to repair the bootloader (or replace it with anything else)

    // unlock bootloader area - 0x1fff8000
    FLASH->CTLR |= 0x20 00 00 00;

Perfect catch!