]> git.tnoah.ca Git - lora-radio.git/commitdiff
Add firmware hash calculation to RAK4631 + more
authorjacob.eva <x00010@disroot.org>
Mon, 13 May 2024 21:25:24 +0000 (22:25 +0100)
committerjacob.eva <x00010@disroot.org>
Mon, 13 May 2024 21:25:24 +0000 (22:25 +0100)
Boards.h
Device.h
Makefile
RNode_Firmware.ino
ROM.h
Utilities.h
sx126x.cpp

index e9c069e6d6221177f8bb4e2986e88ae3fd45d00e..23f919119efc1f5772bb69a6b735338d96910583 100644 (file)
--- a/Boards.h
+++ b/Boards.h
@@ -41,7 +41,7 @@
   #define BOARD_RNODE_NG_21   0x41
   #define BOARD_RNODE_NG_22   0x42
   #define BOARD_GENERIC_NRF52 0x50
-  #define BOARD_RAK4630       0x51
+  #define BOARD_RAK4631       0x51
 
   #if defined(__AVR_ATmega1284P__)
     #define PLATFORM PLATFORM_AVR
@@ -61,7 +61,7 @@
   #endif
 
   #ifndef MODEM
-    #if BOARD_MODEL == BOARD_RAK4630
+    #if BOARD_MODEL == BOARD_RAK4631
       #define MODEM SX1262
     #elif BOARD_MODEL == BOARD_GENERIC_NRF52
       #define MODEM SX1262
     #endif
   
   #elif MCU_VARIANT == MCU_NRF52
-    #if BOARD_MODEL == BOARD_RAK4630
+    #if BOARD_MODEL == BOARD_RAK4631
       #define HAS_EEPROM false
-      #define HAS_DISPLAY true
+      #define HAS_DISPLAY false
       #define HAS_BLUETOOTH false
       #define HAS_BLE true
       #define HAS_CONSOLE false
       #define CONFIG_UART_BUFFER_SIZE 6144
       #define CONFIG_QUEUE_SIZE 6144
       #define CONFIG_QUEUE_MAX_LENGTH 200
-      #define EEPROM_SIZE 200
+      #define EEPROM_SIZE 296
       #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
       #define BLE_MANUFACTURER "RAK Wireless"
       #define BLE_MODEL "RAK4640"
index e3548477d2a8b7dbbea165a7651c90b460bb3e50..1f027dda30764b1fd791f145dc5d5f855c125e75 100644 (file)
--- a/Device.h
+++ b/Device.h
 #include "esp_ota_ops.h"
 #include "esp_flash_partitions.h"
 #include "esp_partition.h"
+
+#elif MCU_VARIANT == MCU_NRF52
+#include "Adafruit_nRFCrypto.h"
+
+// size of chunk to retrieve from flash sector
+#define CHUNK_SIZE 128
+
+#define END_SECTION_SIZE 256
+
+#if defined(NRF52840_XXAA)
+// https://learn.adafruit.com/introducing-the-adafruit-nrf52840-feather/hathach-memory-map
+// each section follows along from one another, in this order
+// this is always at the start of the memory map
+#define APPLICATION_START 0x26000
+
+#define USER_DATA_START 0xED000
+#endif
+
 #endif
 
 // Forward declaration from Utilities.h
 void eeprom_update(int mapped_addr, uint8_t byte);
+void eeprom_flush();
 uint8_t eeprom_read(uint32_t addr);
 void hard_reset(void);
 
@@ -112,12 +131,115 @@ void device_save_firmware_hash() {
   for (uint8_t i = 0; i < DEV_HASH_LEN; i++) {
     eeprom_update(dev_fwhash_addr(i), dev_firmware_hash_target[i]);
   }
+  eeprom_flush();
   if (!fw_signature_validated) hard_reset();
 }
 
-#if MCU_VARIANT == MCU_ESP32
+#if MCU_VARIANT == MCU_NRF52
+void calculate_region_hash(unsigned long long start, unsigned long long end, uint8_t* return_hash) {
+    // this function calculates the hash digest of a region of memory,
+    // currently it is only designed to work for the application region
+    uint8_t chunk[CHUNK_SIZE] = {0};
+
+    // to store potential last chunk of program
+    uint8_t chunk_next[CHUNK_SIZE] = {0};
+    nRFCrypto_Hash hash;
+
+    hash.begin(CRYS_HASH_SHA256_mode);
+
+    bool finish = false;
+    uint8_t size;
+    bool application = true;
+    int end_count = 0;
+    unsigned long length = 0;
+
+    while (start < end - 1 ) {
+        const void* src = (const void*)start;
+        if (start + CHUNK_SIZE >= end) {
+            size = (end - 1) - start;
+        }
+        else {
+            size = CHUNK_SIZE;
+        }
+
+        memcpy(chunk, src, CHUNK_SIZE);
+
+        // check if we've reached the end of the program
+        // if we're checking the application region
+        if (application) {
+            for (int i = 0; i < CHUNK_SIZE; i++) {
+                if (chunk[i] == 0xFF) {
+                    bool matched = true;
+                    end_count = 1;
+                    // check if rest of chunk is FFs as well, only if FF is not
+                    // at the end of chunk
+                    if (i < CHUNK_SIZE - 1) {
+                        for (int x = 0; x < CHUNK_SIZE - i; x++) {
+                            if (chunk[i+x] != 0xFF) {
+                                matched = false;
+                                break;
+                            }
+                            end_count++;
+                        }
+                    }
+
+                    if (matched) {
+                        while (end_count < END_SECTION_SIZE) {
+                            // check if bytes in next chunk up to total
+                            // required are also FFs
+                            for (int x = 1; x <= ceil(END_SECTION_SIZE / CHUNK_SIZE); x++) {
+                                const void* src_next = (const void*)start + CHUNK_SIZE*x;
+                                if ((END_SECTION_SIZE - end_count) > CHUNK_SIZE) {
+                                    size = CHUNK_SIZE;
+                                } else {
+                                    size = END_SECTION_SIZE - end_count;
+                                }
+                                memcpy(chunk_next, src_next, size);
+                                for (int y = 0; y < size; y++) {
+                                    if (chunk_next[y] != 0xFF) {
+                                        matched = false;
+                                        break;
+                                    }
+                                    end_count++;
+                                }
+
+                                if (!matched) {
+                                    break;
+                                }
+                            }
+                            if (!matched) {
+                                break;
+                            }
+                        }
+
+                        if (matched) {
+                            finish = true;
+                            size = i;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (finish) {
+            hash.update(chunk, size);
+            length += size;
+            break;
+        } else {
+            hash.update(chunk, size);
+        }
+
+        start += CHUNK_SIZE;
+        length += CHUNK_SIZE;
+    }
+    hash.end(return_hash);
+}
+#endif
+
 void device_validate_partitions() {
   device_load_firmware_hash();
+  #if MCU_VARIANT == MCU_ESP32
   esp_partition_t partition;
   partition.address   = ESP_PARTITION_TABLE_OFFSET;
   partition.size      = ESP_PARTITION_TABLE_MAX_LEN;
@@ -128,6 +250,10 @@ void device_validate_partitions() {
   partition.type      = ESP_PARTITION_TYPE_APP;
   esp_partition_get_sha256(&partition, dev_bootloader_hash);
   esp_partition_get_sha256(esp_ota_get_running_partition(), dev_firmware_hash);
+  #elif MCU_VARIANT == MCU_NRF52
+  // todo, add bootloader, partition table, or softdevice?
+  calculate_region_hash(APPLICATION_START, USER_DATA_START, dev_firmware_hash);
+  #endif
   #if VALIDATE_FIRMWARE
     for (uint8_t i = 0; i < DEV_HASH_LEN; i++) {
       if (dev_firmware_hash_target[i] != dev_firmware_hash[i]) {
@@ -137,15 +263,15 @@ void device_validate_partitions() {
     }
   #endif
 }
-#endif
 
 bool device_firmware_ok() {
   return fw_signature_validated;
 }
 
-#if MCU_VARIANT == MCU_ESP32
+#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
 bool device_init() {
   if (bt_ready) {
+    #if MCU_VARIANT == MCU_ESP32
     for (uint8_t i=0; i<EEPROM_SIG_LEN; i++){dev_eeprom_signature[i]=EEPROM.read(eeprom_addr(ADDR_SIGNATURE+i));}
     mbedtls_md_context_t ctx;
     mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;     
@@ -161,9 +287,32 @@ bool device_init() {
     mbedtls_md_update(&ctx, dev_eeprom_signature, EEPROM_SIG_LEN);
     mbedtls_md_finish(&ctx, dev_hash);
     mbedtls_md_free(&ctx);
+    #elif MCU_VARIANT == MCU_NRF52
+    for (uint8_t i=0; i<EEPROM_SIG_LEN; i++){dev_eeprom_signature[i]=eeprom_read(eeprom_addr(ADDR_SIGNATURE+i));}
+    nRFCrypto.begin();
+
+    nRFCrypto_Hash hash;
+
+    hash.begin(CRYS_HASH_SHA256_mode);
+
+    #if HAS_BLUETOOTH == true || HAS_BLE == true
+      hash.update(dev_bt_mac, BT_DEV_ADDR_LEN);
+    #else
+      // TODO: Get from BLE stack instead
+      // hash.update(dev_bt_mac, BT_DEV_ADDR_LEN);
+    #endif
+    hash.update(dev_eeprom_signature, EEPROM_SIG_LEN);
+
+    hash.end(dev_hash);
+    #endif
     device_load_signature();
     device_validate_signature();
+
     device_validate_partitions();
+
+    #if MCU_VARIANT == MCU_NRF52
+    nRFCrypto.end();
+    #endif
     device_init_done = true;
     return device_init_done && fw_signature_validated;
   } else {
index 6f893a35786175055e5e6e7cb8286ffc860d5ecd..08ba9a5fb99db00bbf9315b885a2a74705202692 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -110,7 +110,7 @@ firmware-featheresp32:
 firmware-genericesp32:
        arduino-cli compile --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\""
 
-firmware-rak4630:
+firmware-rak4631:
        arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\""
 
 upload:
@@ -189,7 +189,7 @@ upload-featheresp32:
        @sleep 3
        python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
 
-upload-rak4630:
+upload-rak4631:
        arduino-cli upload -p /dev/ttyACM0 --fqbn rakwireless:nrf52:WisCoreRAK4631Board
 
 
@@ -363,3 +363,8 @@ release-mega2560:
        arduino-cli compile --fqbn arduino:avr:mega -e --build-property "compiler.cpp.extra_flags=\"-DMODEM=0x01\""
        cp build/arduino.avr.mega/RNode_Firmware.ino.hex Release/rnode_firmware_m2560.hex
        rm -r build
+
+release-rak4631:
+       arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\""
+       cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware.ino.hex build/rnode_firmware_rak4631.hex
+       adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_rak4631.hex Release/rnode_firmware_rak4631.zip
index 34d31e7b2418568ed1a9727cfe1a13c72450c695..2fa93d3c44cf15880c38aae681e696e95e7c9812 100644 (file)
@@ -77,7 +77,13 @@ void setup() {
   fifo_init(&serialFIFO, serialBuffer, CONFIG_UART_BUFFER_SIZE);
 
   Serial.begin(serial_baudrate);
+  #if BOARD_MODEL != BOARD_RAK4631
+  // Some boards need to wait until the hardware UART is set up before booting
+  // the full firmware. In the case of the RAK4631, the line below will wait
+  // until a serial connection is actually established with a master. Thus, it
+  // is disabled on this platform.
   while (!Serial);
+  #endif
 
   serial_interrupt_init();
 
@@ -1112,7 +1118,7 @@ void validate_status() {
         if (eeprom_checksum_valid()) {
           eeprom_ok = true;
           if (modem_installed) {
-            #if PLATFORM == PLATFORM_ESP32
+            #if PLATFORM == PLATFORM_ESP32 || PLATFORM == PLATFORM_NRF52
               if (device_init()) {
                 hw_ready = true;
               } else {
diff --git a/ROM.h b/ROM.h
index a945d970615c291568ce9e15ff3af398f19529a1..7a343c071415ba06edf93e046ff48a2afd5592dc 100644 (file)
--- a/ROM.h
+++ b/ROM.h
@@ -26,6 +26,9 @@
        #define PRODUCT_T32_21 0xB1
        #define PRODUCT_H32_V2 0xC0
        #define PRODUCT_H32_V3 0xC1
+    #define PRODUCT_RAK4631 0x10
+    #define MODEL_11 0x11
+    #define MODEL_12 0x12
        #define MODEL_A1 0xA1
        #define MODEL_A6 0xA6
        #define MODEL_A4 0xA4
index 22080de59a26af82186c0bf2e13a01710c8fad92..090e5d5ffa984629e3bb0a9974a9ec8c37aeb19c 100644 (file)
@@ -227,7 +227,7 @@ uint8_t boot_vector = 0x00;
                void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
        #endif
 #elif MCU_VARIANT == MCU_NRF52
-    #if BOARD_MODEL == BOARD_RAK4630
+    #if BOARD_MODEL == BOARD_RAK4631
                void led_rx_on()  { digitalWrite(pin_led_rx, HIGH); }
                void led_rx_off() {     digitalWrite(pin_led_rx, LOW); }
                void led_tx_on()  { digitalWrite(pin_led_tx, HIGH); }
@@ -244,7 +244,7 @@ void hard_reset(void) {
        #elif MCU_VARIANT == MCU_ESP32
                ESP.restart();
        #elif MCU_VARIANT == MCU_NRF52
-        // currently not possible to restart on this platform
+        NVIC_SystemReset();
        #endif
 }
 
@@ -1218,6 +1218,15 @@ void kiss_dump_eeprom() {
        serial_write(FEND);
 }
 
+#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
+void eeprom_flush() {
+    // sync file contents to flash
+    file.close();
+    file.open(EEPROM_FILE, FILE_O_WRITE);
+    written_bytes = 0;
+}
+#endif
+
 void eeprom_update(int mapped_addr, uint8_t byte) {
        #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
                EEPROM.update(mapped_addr, byte);
@@ -1227,6 +1236,8 @@ void eeprom_update(int mapped_addr, uint8_t byte) {
                        EEPROM.commit();
                }
     #elif !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
+        // todo: clean up this implementation, writing one byte and syncing
+        // each time is really slow, but this is also suboptimal
         uint8_t read_byte;
         void* read_byte_ptr = &read_byte;
         file.seek(mapped_addr);
@@ -1236,8 +1247,15 @@ void eeprom_update(int mapped_addr, uint8_t byte) {
             file.write(byte);
         }
         written_bytes++;
+        
+        if ((mapped_addr - eeprom_addr(0)) == ADDR_INFO_LOCK) {
+            #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
+                // have to do a flush because we're only writing 1 byte and it syncs after 4
+                eeprom_flush();
+            #endif
+        }
 
-        if (written_bytes >= 8) {
+        if (written_bytes >= 4) {
             file.close();
             file.open(EEPROM_FILE, FILE_O_WRITE);
             written_bytes = 0;
@@ -1245,15 +1263,6 @@ void eeprom_update(int mapped_addr, uint8_t byte) {
        #endif
 }
 
-#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
-void eeprom_flush() {
-    // sync file contents to flash
-    file.close();
-    file.open(EEPROM_FILE, FILE_O_WRITE);
-    written_bytes = 0;
-}
-#endif
-
 void eeprom_write(uint8_t addr, uint8_t byte) {
        if (!eeprom_info_locked() && addr >= 0 && addr < EEPROM_RESERVED) {
                eeprom_update(eeprom_addr(addr), byte);
@@ -1293,7 +1302,7 @@ bool eeprom_product_valid() {
        #elif PLATFORM == PLATFORM_ESP32
        if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3) {
        #elif PLATFORM == PLATFORM_NRF52
-       if (rval == PRODUCT_HMBRW) {
+       if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW) {
        #else
        if (false) {
        #endif
@@ -1331,8 +1340,8 @@ bool eeprom_model_valid() {
        if (model == MODEL_C4 || model == MODEL_C9) {
        #elif BOARD_MODEL == BOARD_HELTEC32_V3
        if (model == MODEL_C5 || model == MODEL_CA) {
-    #elif BOARD_MODEL == BOARD_RAK4630
-    if (model == MODEL_FF) {
+    #elif BOARD_MODEL == BOARD_RAK4631
+    if (model == MODEL_11 || model == MODEL_12) {
        #elif BOARD_MODEL == BOARD_HUZZAH32
        if (model == MODEL_FF) {
        #elif BOARD_MODEL == BOARD_GENERIC_ESP32
index a425e00a30905ff9e4554898b5eb94d0ac36586d..d371251ad96a8467a34e79fa61a76b90c526f9a8 100644 (file)
@@ -717,7 +717,7 @@ void sx126x::sleep()
 
 void sx126x::enableTCXO() {
   #if HAS_TCXO
-    #if BOARD_MODEL == BOARD_RAK4630 || BOARD_MODEL == BOARD_HELTEC32_V3
+    #if BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_HELTEC32_V3
       uint8_t buf[4] = {MODE_TCXO_3_3V_6X, 0x00, 0x00, 0xFF};
     #elif BOARD_MODEL == BOARD_TBEAM
       uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};