dmitrystu / sboot_stm32

Secure USB DFU1.1 bootloader for STM32
Apache License 2.0
313 stars 67 forks source link

stm32g491 support? #52

Open salyzyn opened 1 year ago

salyzyn commented 1 year ago

My WAG and heads up, stuff like (untested, I am a few weeks away from this being a priority) is missing:

    stm32g491xe \:
            ${MAKE} bootloader FWCPU='-mcpu=cortex-m4' \
                    FWSTARTUP='mcu/stm32g4xx.S' \
                    FWDEFS='STM32G4 STM32G491xx' \
                    LDPARAMS='ROMLEN=512K RAMLEN=112K USBD_ASM_DRIVER'

But I am sure that is flawed since usb driver, albeit similar to stm32f4 from the HAL perspective, might not be from the lower level driver perspective. IDK. I have a NUCLEO-G491RE in my hands where I am working on porting an application from stm32f429 and noticed that to use sboot_stm32, it was borken. Once application port and bringup is done, then I can test sboot_stm32.

salyzyn commented 1 year ago

Confirmed, code is not appropriate for a Category 4 stm32g4 device :-(, the code in mcu is only for Category 2 and Category 3 devices. Attempts to flash fail during the erase phase as it tries to use the Category 3 option. Is there anything I can do to help?

salyzyn commented 1 month ago

I was expecting the following to fix the 'problem' with stm32g491, but I still get an error:

Erase [ ] 0% 0 bytesDFU state(10) = dfuERROR, status(3) = Device is unable to write memory dfu-util: Wrong state after command "ERASE_PAGE" download

Here is the code adjustment:

/* calculating PNB[6:0]: ADDR[17:11] -> CR[9:3] */
     lsrs    r4, 11
     bfi     r5, r4, 3, 7
+#elif defined(STM32G491xx) //Cat4
+/* calculating PNB[7:0]: ADDR[18:11] -> CR[10:3] */
+    lsrs    r4, 11
+    bfi     r5, r4, 3, 8
 #else // Cat3
 /* check dual bank */
     ldr     r5, [r3, FLASH_OPTR]
salyzyn commented 1 month ago

Found out why we got the error, dfu-util insists on sending ERASE_PAGE and SET_ADDRESS DFU commands, which are not supported by src/bootblock.c, here is my hacky code adjustment following. I probably need to investigate what sboot_stm32 is doing that results in dfu-util wanting to use these two commands.

Add support for erase page and set address commands

Signed-off-by: Mark Salyzyn <mark.salyzyn@gmail.com>

diff --git a/src/bootloader.c b/src/bootloader.c
index b412b7b..cf93e48 100644
--- a/src/bootloader.c
+++ b/src/bootloader.c
@@ -16,6 +16,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include <string.h>
 #include "config.h"
 #include "stm32.h"
 #include "usb.h"
@@ -166,8 +167,38 @@ static usbd_respond dfu_dnload(void *buf, size_t blksize) {
             dfu_data.bState = USB_DFU_STATE_DFU_ERROR;
             return usbd_ack;
         }
-        aes_decrypt(buf, buf, blksize );
-        dfu_data.bStatus = dfu_data.flash(dfu_data.dptr, buf, blksize);
+        if (blksize == 5) {
+            uint8_t *cp = buf;
+            uint8_t command = *cp;
+            if ((command == 0x41) || (command == 0x21)) {
+                uint32_t address = cp[1]
+                                 | (cp[2] << 8)
+                                 | (cp[3] << 16)
+                                 | (cp[4] << 24);
+                // stm32g491 specific
+                if ((0x08004000 <= address)
+                 && (address < (0x08080000 - DFU_BLOCKSZ))) {
+                    if (command == 0x41) {
+                        memset(buf, 0xFF, sizeof(uint64_t));
+                        dfu_data.bStatus = dfu_data.flash(
+                            (void*)(uintptr_t)address,
+                            buf,
+                            sizeof(uint64_t));
+                    } else {
+                        dfu_data.dptr = (void*)(uintptr_t)address;
+                        dfu_data.bStatus = USB_DFU_STATUS_OK;
+                    }
+                    blksize = 0;
+                } else {
+                    dfu_data.bStatus = USB_DFU_STATUS_ERR_ADDRESS;
+                }
+            } else {
+                dfu_data.bStatus = USB_DFU_STATUS_ERR_TARGET;
+            }
+        } else {
+            aes_decrypt(buf, buf, blksize);
+            dfu_data.bStatus = dfu_data.flash(dfu_data.dptr, buf, blksize);
+        }

         if (dfu_data.bStatus == USB_DFU_STATUS_OK) {
             dfu_data.dptr += blksize;

Edit: my DFU_STR_FLASH had keys that optionally enabled ERASE cycle, before FLASH cycle, so I can turn that off. However the latest dfu-util will insist on using the SET_ADDRESS command blowing sboot_stm32's compatibility unless we add support for it first.