diff --git a/.github/workflows/emu-test-stm32h5.yml b/.github/workflows/emu-test-stm32h5.yml new file mode 100644 index 0000000000..6745f6580b --- /dev/null +++ b/.github/workflows/emu-test-stm32h5.yml @@ -0,0 +1,28 @@ +name: emu-test-stm32h5 + +on: + push: + pull_request: + +jobs: + emu-test-stm32h5: + runs-on: ubuntu-latest + container: + image: ghcr.io/danielinux/m33mu-ci:testing + steps: + - uses: actions/checkout@v4 + + - name: Init submodules + run: | + git config --global --add safe.directory "$GITHUB_WORKSPACE" + git submodule update --init --single-branch + + - name: Configure stm32h5 (TZ) and build wolfboot + run: | + cp config/examples/stm32h5-tz.config .config + make wolfboot.bin + + - name: Run emu test (stm32h5) + working-directory: test-app/emu-test-apps + run: | + SCENARIOS=C ./test.sh diff --git a/.gitignore b/.gitignore index 61451464e0..42556e40b6 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ *.idb *.pdb *.gdb +*.log # automatically generated keys *.der @@ -91,6 +92,9 @@ tools/delta/bmpatch # otp-keystore-gen binary tools/keytools/otp/otp-keystore-gen +# test-server binary +test-app/emu-test-apps/*/test-update-server + # Vim swap files .*.swp diff --git a/.gitmodules b/.gitmodules index e528d9353a..6cd81662fe 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,4 +12,4 @@ url = https://github.com/wolfssl/wolfhsm.git [submodule "lib/wolfPSA"] path = lib/wolfPSA - url = git@github.com:wolfSSL/wolfPSA.git + url = https://github.com/wolfSSL/wolfPSA.git diff --git a/Makefile b/Makefile index bb62d3d320..e604bc8f08 100644 --- a/Makefile +++ b/Makefile @@ -340,6 +340,9 @@ hal/$(TARGET).o: keytools_check: keytools +test-emu: + $(MAKE) -C test-app/emu-test-apps WOLFBOOT_ROOT="$(CURDIR)" test-emu + # Generate the initial signing key (only if not using user-provided keys) # - Creates wolfboot_signing_private_key.der when USER_PRIVATE_KEY is not set # - If CERT_CHAIN_VERIFY is enabled and USER_CERT_CHAIN not provided, also generates cert chain with leaf key diff --git a/hal/stm32_tz.c b/hal/stm32_tz.c index fd2d0c8c1d..d9dc1139eb 100644 --- a/hal/stm32_tz.c +++ b/hal/stm32_tz.c @@ -301,11 +301,18 @@ void hal_tz_sau_init(void) sau_init_region(0, WOLFBOOT_NSC_ADDRESS, WOLFBOOT_NSC_ADDRESS + WOLFBOOT_NSC_SIZE - 1, 1); - /* Secure: application flash area (first bank) */ - sau_init_region(1, WOLFBOOT_PARTITION_BOOT_ADDRESS, FLASH_BANK2_BASE - 1, 0); - - /* Secure: application flash area (second bank) */ - sau_init_region(2, WOLFBOOT_PARTITION_UPDATE_ADDRESS, FLASH_TOP, 0); + /* Non-secure flash alias (entire NS flash window) */ + sau_init_region(1, 0x08000000, FLASH_TOP, 0); + + /* Secure: update partition in secure alias (use matching FLASH_TOP base) */ + uint32_t flash_top_secure = FLASH_TOP; + if ((WOLFBOOT_PARTITION_UPDATE_ADDRESS & 0xFF000000u) != + (FLASH_TOP & 0xFF000000u)) { + flash_top_secure = + (WOLFBOOT_PARTITION_UPDATE_ADDRESS & 0xFF000000u) | + (FLASH_TOP & 0x00FFFFFFu); + } + sau_init_region(2, WOLFBOOT_PARTITION_UPDATE_ADDRESS, flash_top_secure, 1); /* Secure RAM regions in SRAM1/SRAM2 */ sau_init_region(3, 0x30000000, 0x3004FFFF, 1); @@ -435,4 +442,3 @@ int hal_trng_get_entropy(unsigned char *out, unsigned len) } #endif - diff --git a/include/image.h b/include/image.h index 6aa56da3f0..3d42b71bc1 100644 --- a/include/image.h +++ b/include/image.h @@ -419,15 +419,27 @@ static void __attribute__((noinline)) wolfBoot_image_clear_signature_ok( asm volatile("ldr r2, [%0]" ::"r"(p_res)); \ asm volatile("cmp r2, #1":::"cc"); \ asm volatile("bne nope"); \ + asm volatile("mvn r3, r2":::"r3"); \ + asm volatile("cmp r3, #0xFFFFFFFE":::"cc"); \ + asm volatile("bne nope"); \ asm volatile("ldr r2, [%0]" ::"r"(p_res)); \ asm volatile("cmp r2, #1":::"cc"); \ asm volatile("bne nope"); \ + asm volatile("mvn r3, r2":::"r3"); \ + asm volatile("cmp r3, #0xFFFFFFFE":::"cc"); \ + asm volatile("bne nope"); \ asm volatile("ldr r2, [%0]" ::"r"(p_res)); \ asm volatile("cmp r2, #1":::"cc"); \ asm volatile("bne nope"); \ + asm volatile("mvn r3, r2":::"r3"); \ + asm volatile("cmp r3, #0xFFFFFFFE":::"cc"); \ + asm volatile("bne nope"); \ asm volatile("ldr r2, [%0]" ::"r"(p_res)); \ asm volatile("cmp r2, #1":::"cc"); \ asm volatile("bne nope"); \ + asm volatile("mvn r3, r2":::"r3"); \ + asm volatile("cmp r3, #0xFFFFFFFE":::"cc"); \ + asm volatile("bne nope"); \ /* Confirm that the signature is OK */ \ wolfBoot_image_confirm_signature_ok(img); \ asm volatile("nope:"); \ @@ -460,15 +472,27 @@ static void __attribute__((noinline)) wolfBoot_image_clear_signature_ok( "ldr r2, [%0]\n" \ "cmp r2, #1\n" \ "bne 1f\n" \ + "mvn r3, r2\n" \ + "cmp r3, #0xFFFFFFFE\n" \ + "bne 1f\n" \ "ldr r2, [%0]\n" \ "cmp r2, #1\n" \ "bne 1f\n" \ + "mvn r3, r2\n" \ + "cmp r3, #0xFFFFFFFE\n" \ + "bne 1f\n" \ "ldr r2, [%0]\n" \ "cmp r2, #1\n" \ "bne 1f\n" \ + "mvn r3, r2\n" \ + "cmp r3, #0xFFFFFFFE\n" \ + "bne 1f\n" \ "ldr r2, [%0]\n" \ "cmp r2, #1\n" \ "bne 1f\n" \ + "mvn r3, r2\n" \ + "cmp r3, #0xFFFFFFFE\n" \ + "bne 1f\n" \ /* Load 'img' into r0 (first argument to the function) */ \ "mov r0, %1\n" \ /* Load the function pointer into r3 */ \ @@ -480,7 +504,7 @@ static void __attribute__((noinline)) wolfBoot_image_clear_signature_ok( "2:\n" \ : /* No output operands */ \ : "r"(p_res), "r"(img), "r"(confirm_func) /* Input operands */ \ - : "r0", "r2", "lr" /* Clobbered registers */ \ + : "r0", "r2", "r3", "lr" /* Clobbered registers */ \ ); \ } while (0) #endif @@ -507,93 +531,94 @@ static void __attribute__((noinline)) wolfBoot_image_clear_signature_ok( #if defined(__GNUC__) #define VERIFY_VERSION_ALLOWED(fb_ok) \ - /* Stash the registry values */ \ - asm volatile("push {r4, r5, r6, r7}"); \ - /* Redundant initialization with 'failure' values */ \ - asm volatile("mov r0, #0":::"r0"); \ - asm volatile("mov r4, #1":::"r4"); \ - asm volatile("mov r5, #0":::"r5"); \ - asm volatile("mov r6, #2":::"r6"); \ - asm volatile("mov r7, #0":::"r7"); \ - asm volatile("mov r0, #0":::"r0"); \ - asm volatile("mov r4, #1":::"r4"); \ - asm volatile("mov r5, #0":::"r5"); \ - asm volatile("mov r6, #2":::"r6"); \ - asm volatile("mov r7, #0":::"r7"); \ - /* Read the fb_ok flag, jump to end_check \ - * if proven fb_ok == 1 */ \ - asm volatile("mov r0, %0" ::"r"(fb_ok):"r0"); \ - asm volatile("cmp r0, #1":::"cc"); \ - asm volatile("bne do_check"); \ - asm volatile("cmp r0, #1":::"cc"); \ - asm volatile("bne do_check"); \ - asm volatile("cmp r0, #1":::"cc"); \ - asm volatile("bne do_check"); \ - asm volatile("b end_check"); \ - /* Do the actual version check: */ \ - asm volatile("do_check:"); \ - /* Read update versions to reg r5 and r7 */ \ - asm volatile("mov r0, #1":::"r0"); \ - asm volatile("mov r0, #1":::"r0"); \ - asm volatile("mov r0, #1":::"r0"); \ - asm volatile("bl wolfBoot_get_image_version"); \ - asm volatile("mov r5, r0":::"r5"); \ - asm volatile("mov r5, r0":::"r5"); \ - asm volatile("mov r5, r0":::"r5"); \ - asm volatile("mov r0, #1":::"r0"); \ - asm volatile("mov r0, #1":::"r0"); \ - asm volatile("mov r0, #1":::"r0"); \ - asm volatile("bl wolfBoot_get_image_version"); \ - asm volatile("mov r7, r0":::"r7"); \ - asm volatile("mov r7, r0":::"r7"); \ - asm volatile("mov r7, r0":::"r7"); \ - /* Compare r5 and r7, if not equal, something went very wrong, */ \ - asm volatile("cmp r5, r7":::"cc"); \ - asm volatile("bne ."); \ - asm volatile("cmp r5, r7":::"cc"); \ - asm volatile("bne .-4"); \ - asm volatile("cmp r5, r7":::"cc"); \ - asm volatile("bne .-8"); \ - asm volatile("cmp r5, r7":::"cc"); \ - asm volatile("bne .-12"); \ - /* Read current versions to reg r4 and r6 */ \ - asm volatile("mov r0, #0":::"r0"); \ - asm volatile("mov r0, #0":::"r0"); \ - asm volatile("mov r0, #0":::"r0"); \ - asm volatile("bl wolfBoot_get_image_version"); \ - asm volatile("mov r4, r0":::"r4"); \ - asm volatile("mov r4, r0":::"r4"); \ - asm volatile("mov r4, r0":::"r4"); \ - asm volatile("mov r0, #0":::"r0"); \ - asm volatile("mov r0, #0":::"r0"); \ - asm volatile("mov r0, #0":::"r0"); \ - asm volatile("bl wolfBoot_get_image_version"); \ - asm volatile("mov r6, r0":::"r6"); \ - asm volatile("mov r6, r0":::"r6"); \ - asm volatile("mov r6, r0":::"r6"); \ - asm volatile("cmp r4, r6":::"cc"); \ - asm volatile("bne ."); \ - asm volatile("cmp r4, r6":::"cc"); \ - asm volatile("bne .-4"); \ - asm volatile("cmp r4, r6":::"cc"); \ - asm volatile("bne .-8"); \ - asm volatile("cmp r4, r6":::"cc"); \ - asm volatile("bne .-12"); \ - asm volatile("mov r0, #0":::"r0"); \ - asm volatile("mov r0, #0":::"r0"); \ - asm volatile("mov r0, #0":::"r0"); \ - /* Compare the two versions in registries */ \ - asm volatile("cmp r4, r5":::"cc"); \ - asm volatile("bge ."); \ - asm volatile("cmp r6, r7":::"cc"); \ - asm volatile("bge .-4"); \ - asm volatile("cmp r4, r5":::"cc"); \ - asm volatile("bge .-8"); \ - asm volatile("cmp r6, r7":::"cc"); \ - asm volatile("bge .-12"); \ - asm volatile("end_check:"); \ - /* Restore previously saved registry values */ \ - asm volatile("pop {r4, r5, r6, r7}":::"r4", "r5", "r6", "r7") + asm volatile( \ + "push {r4, r5, r6, r7}\n" \ + "mov r0, #0\n" \ + "mov r4, #1\n" \ + "mov r5, #0\n" \ + "mov r6, #2\n" \ + "mov r7, #0\n" \ + "mov r0, #0\n" \ + "mov r4, #1\n" \ + "mov r5, #0\n" \ + "mov r6, #2\n" \ + "mov r7, #0\n" \ + "mov r0, %0\n" \ + "mov r4, %0\n" \ + "cmp r0, #1\n" \ + "bne do_check\n" \ + "cmp r4, #1\n" \ + "bne do_check\n" \ + "cmp r0, r4\n" \ + "bne do_check\n" \ + "cmp r0, #1\n" \ + "bne do_check\n" \ + "b end_check\n" \ + "do_check:\n" \ + "mov r0, #1\n" \ + "mov r0, #1\n" \ + "mov r0, #1\n" \ + "bl wolfBoot_get_image_version\n" \ + "mov r5, r0\n" \ + "mov r5, r0\n" \ + "mov r5, r0\n" \ + "mov r0, #1\n" \ + "mov r0, #1\n" \ + "mov r0, #1\n" \ + "bl wolfBoot_get_image_version\n" \ + "mov r7, r0\n" \ + "mov r7, r0\n" \ + "mov r7, r0\n" \ + "cmp r5, r7\n" \ + "bne ver_panic\n" \ + "cmp r5, r7\n" \ + "bne ver_panic\n" \ + "cmp r5, r7\n" \ + "bne ver_panic\n" \ + "cmp r5, r7\n" \ + "bne ver_panic\n" \ + "mov r0, #0\n" \ + "mov r0, #0\n" \ + "mov r0, #0\n" \ + "bl wolfBoot_get_image_version\n" \ + "mov r4, r0\n" \ + "mov r4, r0\n" \ + "mov r4, r0\n" \ + "mov r0, #0\n" \ + "mov r0, #0\n" \ + "mov r0, #0\n" \ + "bl wolfBoot_get_image_version\n" \ + "mov r6, r0\n" \ + "mov r6, r0\n" \ + "mov r6, r0\n" \ + "cmp r4, r6\n" \ + "bne ver_panic\n" \ + "cmp r4, r6\n" \ + "bne ver_panic\n" \ + "cmp r4, r6\n" \ + "bne ver_panic\n" \ + "cmp r4, r6\n" \ + "bne ver_panic\n" \ + "mov r0, #0\n" \ + "mov r0, #0\n" \ + "mov r0, #0\n" \ + "cmp r4, r5\n" \ + "bhs ver_panic\n" \ + "cmp r6, r7\n" \ + "bhs ver_panic\n" \ + "cmp r4, r5\n" \ + "bhs ver_panic\n" \ + "cmp r6, r7\n" \ + "bhs ver_panic\n" \ + "b end_check\n" \ + "ver_panic:\n" \ + "b .\n" \ + "end_check:\n" \ + "pop {r4, r5, r6, r7}\n" \ + : \ + : "r"(fb_ok) \ + : "r0", "r4", "r5", "r6", "r7", "lr", "cc", "memory" \ + ) #elif defined(__ICCARM__) && defined(__IAR_SYSTEMS_ICC__) @@ -612,10 +637,25 @@ static void __attribute__((noinline)) wolfBoot_image_clear_signature_ok( "mov r6, #2\n" \ "mov r7, #0\n" \ "mov r0, %0\n" \ + "mov r4, %0\n" \ + "cmp r0, #0\n" \ + "beq 4f\n" \ "cmp r0, #1\n" \ - "bne 1f\n" \ + "beq 4f\n" \ + "bkpt 0xE1\n" \ + "4:\n" \ + "cmp r4, #0\n" \ + "beq 5f\n" \ + "cmp r4, #1\n" \ + "beq 5f\n" \ + "bkpt 0xE1\n" \ + "5:\n" \ "cmp r0, #1\n" \ "bne 1f\n" \ + "cmp r4, #1\n" \ + "bne 1f\n" \ + "cmp r0, r4\n" \ + "bne 1f\n" \ "cmp r0, #1\n" \ "bne 1f\n" \ "b 2f\n" \ @@ -635,13 +675,13 @@ static void __attribute__((noinline)) wolfBoot_image_clear_signature_ok( "mov r7, r0\n" \ "mov r7, r0\n" \ "cmp r5, r7\n" \ - "bne .\n" \ + "bne 3f\n" \ "cmp r5, r7\n" \ - "bne .-4\n" \ + "bne 3f\n" \ "cmp r5, r7\n" \ - "bne .-8\n" \ + "bne 3f\n" \ "cmp r5, r7\n" \ - "bne .-12\n" \ + "bne 3f\n" \ "mov r0, #0\n" \ "mov r0, #0\n" \ "mov r0, #0\n" \ @@ -657,24 +697,27 @@ static void __attribute__((noinline)) wolfBoot_image_clear_signature_ok( "mov r6, r0\n" \ "mov r6, r0\n" \ "cmp r4, r6\n" \ - "bne .\n" \ + "bne 3f\n" \ "cmp r4, r6\n" \ - "bne .-4\n" \ + "bne 3f\n" \ "cmp r4, r6\n" \ - "bne .-8\n" \ + "bne 3f\n" \ "cmp r4, r6\n" \ - "bne .-12\n" \ + "bne 3f\n" \ "mov r0, #0\n" \ "mov r0, #0\n" \ "mov r0, #0\n" \ "cmp r4, r5\n" \ - "bge .\n" \ + "bhs 3f\n" \ "cmp r6, r7\n" \ - "bge .-4\n" \ + "bhs 3f\n" \ "cmp r4, r5\n" \ - "bge .-8\n" \ + "bhs 3f\n" \ "cmp r6, r7\n" \ - "bge .-12\n" \ + "bhs 3f\n" \ + "b 2f\n" \ + "3:\n" \ + "b .\n" \ "2:\n" \ "pop {r4, r5, r6, r7}\n" \ : /* No output operands */ \ diff --git a/src/image.c b/src/image.c index a3ce62cfc0..55a9dcfb9b 100644 --- a/src/image.c +++ b/src/image.c @@ -803,6 +803,26 @@ static void wolfBoot_verify_signature_ml_dsa(uint8_t key_slot, img->sha_hash, WOLFBOOT_SHA_DIGEST_SIZE, &verify_res); + #ifdef WOLFBOOT_ARMORED + if (ret == 0) { + uint32_t v = (uint32_t)verify_res; + uint32_t v_inv = ~v; + if ((v == 1U) && (v_inv == 0xFFFFFFFEU) && + (v == (uint32_t)verify_res) && + (v_inv == ~(uint32_t)verify_res)) { + wolfBoot_printf("info: wc_MlDsaKey_Verify returned OK\n"); + wolfBoot_image_confirm_signature_ok(img); + } + else { + wolfBoot_printf("error: wc_MlDsaKey_Verify returned: ret=%d, " + "res=%d\n", ret, verify_res); + } + } + else { + wolfBoot_printf("error: wc_MlDsaKey_Verify returned: ret=%d, " + "res=%d\n", ret, verify_res); + } + #else if (ret == 0 && verify_res == 1) { wolfBoot_printf("info: wc_MlDsaKey_Verify returned OK\n"); wolfBoot_image_confirm_signature_ok(img); @@ -811,6 +831,7 @@ static void wolfBoot_verify_signature_ml_dsa(uint8_t key_slot, wolfBoot_printf("error: wc_MlDsaKey_Verify returned: ret=%d, " "res=%d\n", ret, verify_res); } + #endif } wc_MlDsaKey_Free(&ml_dsa); @@ -2150,8 +2171,15 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img) wolfBoot_verify_signature_primary(key_slot, img, stored_signature); (void)stored_signature_size; +#ifdef WOLFBOOT_ARMORED +#define SIG_OK(imgp) (((imgp)->signature_ok == 1) && \ + ((imgp)->not_signature_ok == ~(uint32_t)1)) +#else +#define SIG_OK(imgp) ((imgp)->signature_ok == 1) +#endif + #ifdef SIGN_HYBRID - if (img->signature_ok == 1) { + if (SIG_OK(img)) { uint8_t *stored_secondary_signature; uint16_t stored_secondary_signature_size; /* Invalidate the signature_ok flag */ @@ -2177,10 +2205,18 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img) } } #endif - if (img->signature_ok == 1) { +#ifdef WOLFBOOT_ARMORED + if (SIG_OK(img)) { return 0; } return -2; +#else + if (SIG_OK(img)) { + return 0; + } + return -2; +#endif +#undef SIG_OK } #endif diff --git a/src/update_flash.c b/src/update_flash.c index b51f400a97..8f2e053605 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -686,6 +686,11 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed) int inverse = 0; #endif int fallback_image = 0; +#ifndef DISABLE_BACKUP + int rollback = 0; + int bootStateRet = -1; + uint8_t bootState = 0; +#endif #if defined(DISABLE_BACKUP) && defined(EXT_ENCRYPTED) uint8_t key[ENCRYPT_KEY_SIZE]; uint8_t nonce[ENCRYPT_NONCE_SIZE]; @@ -748,6 +753,13 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed) cur_ver = wolfBoot_current_firmware_version(); upd_ver = wolfBoot_update_firmware_version(); +#ifndef DISABLE_BACKUP + bootStateRet = wolfBoot_get_partition_state(PART_BOOT, &bootState); + if ((bootStateRet == 0) && (bootState == IMG_STATE_TESTING) && + (fallback_allowed != 0) && (cur_ver >= upd_ver)) { + rollback = 1; + } +#endif wolfBoot_get_update_sector_flag(0, &flag); /* Check the first sector to detect interrupted update */ @@ -787,11 +799,12 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed) cur_ver, upd_ver); #ifndef ALLOW_DOWNGRADE - if ( ((fallback_allowed==1) && - (~(uint32_t)fallback_allowed == 0xFFFFFFFE)) || - (cur_ver < upd_ver) ) { - VERIFY_VERSION_ALLOWED(fallback_allowed); - } else { + { + uint32_t fb_ok = (fallback_allowed == 1); + VERIFY_VERSION_ALLOWED(fb_ok); + (void)fb_ok; + } + if ((fallback_allowed == 0) && (cur_ver >= upd_ver)) { wolfBoot_printf("Update version not allowed\n"); return -1; } @@ -973,6 +986,19 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed) /* start re-entrant final erase, return code is only for resumption in * wolfBoot_start */ wolfBoot_swap_and_final_erase(0); +#ifndef DISABLE_BACKUP + if (rollback) { + hal_flash_unlock(); +#ifdef EXT_FLASH + ext_flash_unlock(); +#endif + wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_SUCCESS); +#ifdef EXT_FLASH + ext_flash_lock(); +#endif + hal_flash_lock(); + } +#endif #else /* Mark boot partition as TESTING - this tells bootloader to fallback if update fails */ wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_TESTING); @@ -1201,13 +1227,27 @@ void RAMFUNCTION wolfBoot_start(void) #if !defined(DISABLE_BACKUP) && !defined(CUSTOM_PARTITION_TRAILER) /* resume the final erase in case the power failed before it finished */ resumedFinalErase = wolfBoot_swap_and_final_erase(1); - if (resumedFinalErase != 0) + if ((resumedFinalErase != 0) || + ((bootRet == 0) && (bootState == IMG_STATE_TESTING))) #endif { /* Check if the BOOT partition is still in TESTING, * to trigger fallback. */ if ((bootRet == 0) && (bootState == IMG_STATE_TESTING)) { + if (updateRet != 0) { + hal_flash_unlock(); +#ifdef EXT_FLASH + ext_flash_unlock(); +#endif + wolfBoot_set_partition_state(PART_UPDATE, IMG_STATE_UPDATING); +#ifdef EXT_FLASH + ext_flash_lock(); +#endif + hal_flash_lock(); + updateRet = 0; + updateState = IMG_STATE_UPDATING; + } wolfBoot_update(1); } diff --git a/test-app/emu-test-apps/Makefile b/test-app/emu-test-apps/Makefile new file mode 100644 index 0000000000..52a79ea165 --- /dev/null +++ b/test-app/emu-test-apps/Makefile @@ -0,0 +1,85 @@ +-include ../../.config +include ../../tools/config.mk +include ../../options.mk +include ../../tools/test.mk + +ifneq ($(wildcard $(WOLFBOOT_ROOT)/lib/wolfssl/wolfcrypt/src/asn.c),) + WOLFBOOT_LIB_WOLFSSL:=$(WOLFBOOT_ROOT)/lib/wolfssl +else ifneq ($(wildcard $(WOLFBOOT_ROOT)/../wolfssl/wolfcrypt/src/asn.c),) + WOLFBOOT_LIB_WOLFSSL:=$(WOLFBOOT_ROOT)/../wolfssl +endif +export WOLFBOOT_LIB_WOLFSSL + +WOLFBOOT_ROOT?=$(abspath ../..) + +EMU_VERSION?=1 +EMU_EXPECT_VERSION?=$(EMU_VERSION) +PRIVATE_KEY?=$(WOLFBOOT_ROOT)/wolfboot_signing_private_key.der + +M33MU?=$(WOLFBOOT_ROOT)/../m33mu/build/m33mu + +ifeq ($(TARGET),stm32h563) + EMU_DIR=stm32h563 + EMU_CPU=stm32h563 +else ifeq ($(TARGET),stm32h5) + EMU_DIR=stm32h563 + EMU_CPU=stm32h563 +else ifeq ($(TARGET),stm32u585) + EMU_DIR=stm32u585 + EMU_CPU=stm32u585 +else ifeq ($(TARGET),stm32u5) + EMU_DIR=stm32u585 + EMU_CPU=stm32u585 +else ifeq ($(TARGET),stm32l552) + EMU_DIR=stm32l552 + EMU_CPU=stm32l552 +else ifeq ($(TARGET),stm32l5) + EMU_DIR=stm32l552 + EMU_CPU=stm32l552 +else ifeq ($(TARGET),nrf5340) + EMU_DIR=nrf5340 + EMU_CPU=nrf5340 +else ifeq ($(TARGET),mcxw) + EMU_DIR=mcxw71 + EMU_CPU=mcxw71c +else ifeq ($(TARGET),mcxw71) + EMU_DIR=mcxw71 + EMU_CPU=mcxw71c +else + EMU_DIR= + EMU_CPU= +endif + +ifeq ($(strip $(EMU_DIR)),) + $(error Unsupported or unset TARGET=$(TARGET). Use TARGET=stm32h563|stm32h5|stm32u585|stm32u5|stm32l552|stm32l5|nrf5340|mcxw) +endif + +EMU_PATH=$(WOLFBOOT_ROOT)/test-app/emu-test-apps/$(EMU_DIR) + +.PHONY: all clean test-emu sign-emu run-emu + +all: + $(MAKE) -C $(EMU_PATH) clean app.bin + +sign-emu: all $(WOLFBOOT_ROOT)/wolfboot_signing_private_key.der + @cp $(EMU_PATH)/app.bin $(EMU_PATH)/image.bin + $(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) $(EMU_PATH)/image.bin $(PRIVATE_KEY) $(EMU_VERSION) + +run-emu: sign-emu + @echo "[EMU] CPU=$(EMU_CPU) VERSION=$(EMU_VERSION)" + @$(M33MU) --cpu $(EMU_CPU) --uart-stdout --no-tz --boot-offset=$(IMAGE_HEADER_SIZE) \ + $(EMU_PATH)/image_v$(EMU_VERSION)_signed.bin --timeout 2 \ + | tee $(EMU_PATH)/emu_uart.log + @grep -q "get_version=$(EMU_EXPECT_VERSION)" $(EMU_PATH)/emu_uart.log + +# Entry point for top-level make test-emu +# Builds, signs, runs, and validates UART output. + +test-emu: run-emu + +clean: + $(MAKE) -C $(EMU_PATH) clean + @rm -f $(EMU_PATH)/image.bin $(EMU_PATH)/image_v*_signed.bin $(EMU_PATH)/emu_uart.log + +$(WOLFBOOT_ROOT)/wolfboot_signing_private_key.der: + $(MAKE) -C $(WOLFBOOT_ROOT) WOLFBOOT_LIB_WOLFSSL="$(WOLFBOOT_LIB_WOLFSSL)" wolfboot_signing_private_key.der diff --git a/test-app/emu-test-apps/common/emu_app.h b/test-app/emu-test-apps/common/emu_app.h new file mode 100644 index 0000000000..a081bca088 --- /dev/null +++ b/test-app/emu-test-apps/common/emu_app.h @@ -0,0 +1,10 @@ +#ifndef EMU_APP_H +#define EMU_APP_H + +#include + +void emu_uart_init(void); +int emu_uart_read(uint8_t *c); +void emu_uart_write(uint8_t c); + +#endif /* EMU_APP_H */ diff --git a/test-app/emu-test-apps/common/emu_hal.c b/test-app/emu-test-apps/common/emu_hal.c new file mode 100644 index 0000000000..b3a3b58276 --- /dev/null +++ b/test-app/emu-test-apps/common/emu_hal.c @@ -0,0 +1,115 @@ +#include +#include +#include "target.h" +#include "hal.h" + +#ifndef EMU_FLASH_SECTOR_SIZE +#define EMU_FLASH_SECTOR_SIZE WOLFBOOT_SECTOR_SIZE +#endif + +#if defined(EMU_STM32) +#define FLASH_BASE 0x40022000u +#define FLASH_NSKEYR (*(volatile uint32_t *)(FLASH_BASE + 0x004u)) +#define FLASH_NSCR (*(volatile uint32_t *)(FLASH_BASE + 0x028u)) +#define FLASH_KEY1 0x45670123u +#define FLASH_KEY2 0xCDEF89ABu +#define FLASH_CR_LOCK (1u << 0) +#define FLASH_CR_PG (1u << 1) +#define FLASH_CR_SER (1u << 2) +#define FLASH_CR_STRT (1u << 5) +#define FLASH_CR_SNB_SHIFT 6 +#define FLASH_CR_SNB_MASK (0x7fu << FLASH_CR_SNB_SHIFT) +#endif + +#if defined(EMU_NRF5340) +#define NVMC_BASE 0x40039000u +#define NVMC_CONFIG (*(volatile uint32_t *)(NVMC_BASE + 0x504u)) +#endif + +void hal_init(void) +{ +} + +void hal_prepare_boot(void) +{ +} + +int hal_flash_write(uint32_t address, const uint8_t *data, int len) +{ + if (data == 0 || len <= 0) { + return 0; + } + memcpy((void *)address, data, (size_t)len); + return 0; +} + +int hal_flash_erase(uint32_t address, int len) +{ +#if defined(EMU_NRF5340) + (void)address; + (void)len; + return 0; +#else + uint32_t end; +#if defined(EMU_STM32) + uint32_t base = WOLFBOOT_PARTITION_BOOT_ADDRESS; + uint32_t sector = EMU_FLASH_SECTOR_SIZE; + uint32_t start_sector; + uint32_t end_sector; + uint32_t snb; + static uint32_t last_erase_sector = 0xFFFFFFFFu; +#endif + if (len <= 0) { + return 0; + } +#if defined(EMU_STM32) + if (sector == 0u) { + return 0; + } + if (address < base) { + return 0; + } + end = address + (uint32_t)len; + start_sector = (address - base) / sector; + end_sector = ((end - 1u) - base) / sector; + for (snb = start_sector; snb <= end_sector; ++snb) { + if (snb == last_erase_sector) { + continue; + } + uint32_t cr = FLASH_NSCR & ~FLASH_CR_SNB_MASK; + cr |= FLASH_CR_SER | (snb << FLASH_CR_SNB_SHIFT); + FLASH_NSCR = cr; + FLASH_NSCR = cr | FLASH_CR_STRT; + last_erase_sector = snb; + } + FLASH_NSCR &= ~FLASH_CR_SER; +#else + end = address + (uint32_t)len; + memset((void *)address, 0xFF, (size_t)(end - address)); +#endif + return 0; +#endif +} + +void hal_flash_unlock(void) +{ +#if defined(EMU_STM32) + if ((FLASH_NSCR & FLASH_CR_LOCK) != 0u) { + FLASH_NSKEYR = FLASH_KEY1; + FLASH_NSKEYR = FLASH_KEY2; + } + FLASH_NSCR |= FLASH_CR_PG; +#elif defined(EMU_NRF5340) + NVMC_CONFIG = 1u; +#endif +} + +void hal_flash_lock(void) +{ +#if defined(EMU_STM32) + FLASH_NSCR &= ~FLASH_CR_PG; + FLASH_NSCR |= FLASH_CR_LOCK; +#elif defined(EMU_NRF5340) + NVMC_CONFIG = 0u; +#endif +} diff --git a/test-app/emu-test-apps/common/emu_ivt.c b/test-app/emu-test-apps/common/emu_ivt.c new file mode 100644 index 0000000000..6a30fd9250 --- /dev/null +++ b/test-app/emu-test-apps/common/emu_ivt.c @@ -0,0 +1,38 @@ +#include + +extern void Reset_Handler(void); +extern unsigned long _estack; + +static void default_handler(void) +{ + while (1) { + } +} + +void NMI_Handler(void) __attribute__((weak, alias("default_handler"))); +void HardFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void MemManage_Handler(void) __attribute__((weak, alias("default_handler"))); +void BusFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void UsageFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void SVC_Handler(void) __attribute__((weak, alias("default_handler"))); +void DebugMon_Handler(void) __attribute__((weak, alias("default_handler"))); +void PendSV_Handler(void) __attribute__((weak, alias("default_handler"))); +void SysTick_Handler(void) __attribute__((weak, alias("default_handler"))); + +__attribute__((section(".isr_vector"))) +const uint32_t vector_table[16 + 48] = { + [0] = (uint32_t)&_estack, + [1] = (uint32_t)&Reset_Handler, + [2] = (uint32_t)&NMI_Handler, + [3] = (uint32_t)&HardFault_Handler, + [4] = (uint32_t)&MemManage_Handler, + [5] = (uint32_t)&BusFault_Handler, + [6] = (uint32_t)&UsageFault_Handler, + [7] = 0, [8] = 0, [9] = 0, [10] = 0, + [11] = (uint32_t)&SVC_Handler, + [12] = (uint32_t)&DebugMon_Handler, + [13] = 0, + [14] = (uint32_t)&PendSV_Handler, + [15] = (uint32_t)&SysTick_Handler, + [16 ... 63] = (uint32_t)&default_handler +}; diff --git a/test-app/emu-test-apps/common/emu_startup.c b/test-app/emu-test-apps/common/emu_startup.c new file mode 100644 index 0000000000..6a78c052e0 --- /dev/null +++ b/test-app/emu-test-apps/common/emu_startup.c @@ -0,0 +1,32 @@ +#include + +extern uint32_t _sidata; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; +extern void __libc_init_array(void); + +int main(void); + +void Reset_Handler(void) +{ + uint32_t *src; + uint32_t *dst; + + src = &_sidata; + for (dst = &_sdata; dst < &_edata; ) { + *dst++ = *src++; + } + + for (dst = &_sbss; dst < &_ebss; ) { + *dst++ = 0u; + } + + __libc_init_array(); + (void)main(); + + while (1) { + __asm volatile("wfi"); + } +} diff --git a/test-app/emu-test-apps/common/emu_syscalls.c b/test-app/emu-test-apps/common/emu_syscalls.c new file mode 100644 index 0000000000..2828b52c77 --- /dev/null +++ b/test-app/emu-test-apps/common/emu_syscalls.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include + +extern uint32_t _ebss; +extern uint32_t _estack; +extern volatile uint32_t systick_ms; +void emu_uart_putc(char c); + +static char *heap_end; + +int _write(int file, const char *ptr, int len) +{ + int i; + (void)file; + for (i = 0; i < len; ++i) { + emu_uart_putc(ptr[i]); + } + return len; +} + +int _close(int file) +{ + (void)file; + return -1; +} + +int _fstat(int file, struct stat *st) +{ + (void)file; + if (st == 0) { + errno = EINVAL; + return -1; + } + st->st_mode = S_IFCHR; + return 0; +} + +int _isatty(int file) +{ + (void)file; + return 1; +} + +int _lseek(int file, int ptr, int dir) +{ + (void)file; + (void)ptr; + (void)dir; + return 0; +} + +int _read(int file, char *ptr, int len) +{ + (void)file; + (void)ptr; + (void)len; + return 0; +} + +void *_sbrk(ptrdiff_t incr) +{ + char *prev; + if (heap_end == 0) { + heap_end = (char *)&_ebss; + } + prev = heap_end; + if ((heap_end + incr) >= (char *)&_estack) { + errno = ENOMEM; + return (void *)-1; + } + heap_end += incr; + return prev; +} + +int _gettimeofday(struct timeval *tv, void *tzvp) +{ + (void)tzvp; + if (tv == 0) { + errno = EINVAL; + return -1; + } + tv->tv_sec = (time_t)(systick_ms / 1000u); + tv->tv_usec = (suseconds_t)((systick_ms % 1000u) * 1000u); + return 0; +} + +time_t time(time_t *t) +{ + time_t now = (time_t)(systick_ms / 1000u); + if (t != 0) { + *t = now; + } + return now; +} + +void _exit(int status) +{ + (void)status; + while (1) { + __asm volatile("wfi"); + } +} + +int _kill(int pid, int sig) +{ + (void)pid; + (void)sig; + errno = EINVAL; + return -1; +} + +int _getpid(void) +{ + return 1; +} + +void _init(void) +{ +} + +void _fini(void) +{ +} diff --git a/test-app/emu-test-apps/common/emu_update.c b/test-app/emu-test-apps/common/emu_update.c new file mode 100644 index 0000000000..5cc59b367a --- /dev/null +++ b/test-app/emu-test-apps/common/emu_update.c @@ -0,0 +1,305 @@ +#include +#include +#include +#include + +#include "emu_app.h" +#include "target.h" +#include "hal.h" +#include "wolfboot/wolfboot.h" + +#define MSGSIZE 16 +#define PAGESIZE 256 + +volatile uint32_t systick_ms = 0; + +static uint8_t page[PAGESIZE]; +static uint8_t msg[MSGSIZE]; + +static const uint8_t ERR = '!'; +static const uint8_t START = '*'; +static const uint8_t ACK = '#'; + +static uint32_t emu_im2n(uint32_t val) +{ +#ifdef BIG_ENDIAN_ORDER + val = (((val & 0x000000FFu) << 24) | + ((val & 0x0000FF00u) << 8) | + ((val & 0x00FF0000u) >> 8) | + ((val & 0xFF000000u) >> 24)); +#endif + return val; +} + +static uint8_t emu_read_u8(uintptr_t addr) +{ + uint8_t v; + __asm volatile("ldrb %0, [%1]" : "=r"(v) : "r"(addr) : "memory"); + return v; +} + +static uint32_t emu_read_u32(uintptr_t addr) +{ + uint32_t v; + __asm volatile("ldr %0, [%1]" : "=r"(v) : "r"(addr) : "memory"); + return v; +} + +static uint32_t emu_get_blob_version_addr(uintptr_t base) +{ + uintptr_t p = base + IMAGE_HEADER_OFFSET; + uintptr_t max_p = base + IMAGE_HEADER_SIZE; + uint32_t magic = emu_read_u32(base); + + if (magic != WOLFBOOT_MAGIC) { + return 0; + } + + while ((p + 4u) <= max_p) { + uint16_t htype = (uint16_t)(emu_read_u8(p) | (emu_read_u8(p + 1u) << 8)); + uint16_t len; + + if (htype == 0u) { + break; + } + if ((emu_read_u8(p) == HDR_PADDING) || ((p & 1u) != 0u)) { + p++; + continue; + } + + len = (uint16_t)(emu_read_u8(p + 2u) | (emu_read_u8(p + 3u) << 8)); + if ((4u + len) > (uint16_t)(IMAGE_HEADER_SIZE - IMAGE_HEADER_OFFSET)) { + break; + } + if (p + 4u + len > max_p) { + break; + } + + p += 4u; + if (htype == HDR_VERSION) { + return emu_im2n(emu_read_u32(p)); + } + p += len; + } + return 0; +} + +static uint32_t emu_current_version(void) +{ + uintptr_t addr = (uintptr_t)WOLFBOOT_PARTITION_BOOT_ADDRESS; + +#ifdef WOLFCRYPT_SECURE_MODE + return wolfBoot_nsc_current_firmware_version(); +#else + if (addr == 0u) { + return emu_get_blob_version_addr(0u); + } + return wolfBoot_get_blob_version((uint8_t *)addr); +#endif +} + +void emu_uart_putc(char c) +{ + emu_uart_write((uint8_t)c); +} + +static void uart_write_buf(const uint8_t *buf, uint32_t len) +{ + uint32_t i; + for (i = 0; i < len; ++i) { + emu_uart_write(buf[i]); + } +} + +static uint8_t uart_read_blocking(void) +{ + uint8_t c = 0; + while (!emu_uart_read(&c)) { + __asm volatile("nop"); + } + return c; +} + +static void ack(uint32_t off) +{ + uint8_t *bytes = (uint8_t *)&off; + uint32_t i; + emu_uart_write(ACK); + for (i = 0; i < 4; i++) { + emu_uart_write(bytes[i]); + } +} + +static int check(uint8_t *pkt, int size) +{ + int i; + uint16_t c = 0; + uint16_t c_rx = *((uint16_t *)(pkt + 2)); + uint16_t *p = (uint16_t *)(pkt + 4); + for (i = 0; i < ((size - 4) >> 1); i++) { + c += p[i]; + } + if (c == c_rx) { + return 0; + } + return -1; +} + +static void wait_for_update(uint32_t version) +{ + uint32_t tlen = 0; + uint32_t recv_seq = 0; + uint32_t r_total = 0; + uint32_t tot_len = 0; + uint32_t next_seq = 0; + uint8_t *v_array = (uint8_t *)&version; + int i; + + memset(page, 0xFF, PAGESIZE); + +#ifndef WOLFCRYPT_SECURE_MODE + hal_flash_unlock(); +#endif + + emu_uart_write(START); + for (i = 3; i >= 0; i--) { + emu_uart_write(v_array[i]); + } + + while (1) { + r_total = 0; + do { + while (r_total < 2) { + msg[r_total++] = uart_read_blocking(); + if ((r_total == 2) && ((msg[0] != 0xA5) || (msg[1] != 0x5A))) { + r_total = 0; + continue; + } + } + msg[r_total++] = uart_read_blocking(); + if ((tot_len == 0) && r_total == 2 + sizeof(uint32_t)) { + break; + } + if ((r_total > 8) && (tot_len <= ((r_total - 8) + next_seq))) { + break; + } + } while (r_total < MSGSIZE); + + if (tot_len == 0) { + tlen = msg[2] + (msg[3] << 8) + (msg[4] << 16) + (msg[5] << 24); + if (tlen > WOLFBOOT_PARTITION_SIZE - 8) { + emu_uart_write(ERR); + emu_uart_write(ERR); + emu_uart_write(ERR); + emu_uart_write(ERR); + emu_uart_write(START); + recv_seq = 0; + tot_len = 0; + continue; + } + tot_len = tlen; + ack(0); + continue; + } + + if (check(msg, r_total) < 0) { + ack(next_seq); + continue; + } + + recv_seq = msg[4] + (msg[5] << 8) + (msg[6] << 16) + (msg[7] << 24); + if (recv_seq == next_seq) { + int psize = r_total - 8; + int page_idx = (int)(recv_seq % PAGESIZE); + memcpy(&page[page_idx], msg + 8, psize); + page_idx += psize; + if ((page_idx == PAGESIZE) || (next_seq + (uint32_t)psize >= tot_len)) { + uint32_t dst = (WOLFBOOT_PARTITION_UPDATE_ADDRESS + recv_seq + (uint32_t)psize) - (uint32_t)page_idx; + uint32_t dst_off = (recv_seq + (uint32_t)psize) - (uint32_t)page_idx; +#ifdef WOLFCRYPT_SECURE_MODE + if ((dst_off % WOLFBOOT_SECTOR_SIZE) == 0u) { + wolfBoot_nsc_erase_update(dst_off, WOLFBOOT_SECTOR_SIZE); + } + wolfBoot_nsc_write_update(dst_off, page, PAGESIZE); +#else + if ((dst % WOLFBOOT_SECTOR_SIZE) == 0u) { + hal_flash_erase(dst, WOLFBOOT_SECTOR_SIZE); + } + hal_flash_write(dst, page, PAGESIZE); +#endif + memset(page, 0xFF, PAGESIZE); + } + next_seq += (uint32_t)psize; + } + ack(next_seq); + if (next_seq >= tot_len) { + uint32_t update_ver; +#ifdef WOLFCRYPT_SECURE_MODE + update_ver = wolfBoot_nsc_update_firmware_version(); +#else + update_ver = wolfBoot_get_blob_version((uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS); +#endif + if (update_ver == 7u) { + __asm volatile("bkpt #0x4D"); + break; + } +#ifdef WOLFCRYPT_SECURE_MODE + wolfBoot_nsc_update_trigger(); +#else + wolfBoot_update_trigger(); +#endif + __asm volatile("bkpt #0x47"); + break; + } + } + +#ifndef WOLFCRYPT_SECURE_MODE + hal_flash_lock(); +#endif + + while (1) { + __asm volatile("wfi"); + } +} + +int main(void) +{ + uint32_t version; + + emu_uart_init(); + + version = emu_current_version(); + printf("get_version=%lu\n", (unsigned long)version); + + if (version == 4u) { +#ifdef WOLFCRYPT_SECURE_MODE + wolfBoot_nsc_success(); +#else + wolfBoot_success(); +#endif + __asm volatile("bkpt #0x4A"); + while (1) { + __asm volatile("wfi"); + } + } + if (version == 3u) { + __asm volatile("bkpt #0x4B"); + while (1) { + __asm volatile("wfi"); + } + } + if (version == 8u) { +#ifdef WOLFCRYPT_SECURE_MODE + wolfBoot_nsc_success(); +#else + wolfBoot_success(); +#endif + __asm volatile("bkpt #0x4E"); + while (1) { + __asm volatile("wfi"); + } + } + + wait_for_update(version); + return 0; +} diff --git a/test-app/emu-test-apps/mcxw71/Makefile b/test-app/emu-test-apps/mcxw71/Makefile new file mode 100644 index 0000000000..9644beb281 --- /dev/null +++ b/test-app/emu-test-apps/mcxw71/Makefile @@ -0,0 +1,43 @@ +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb +MCXW71_SDK ?= ../../../../MCXW71 +CFLAGS += -I. -I../common -I../../../include +CFLAGS += -DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) +CFLAGS += -DCPU_MCXW716CMFPA +CFLAGS += -I$(MCXW71_SDK)/devices/MCXW716C -I$(MCXW71_SDK)/devices/MCXW716C/periph2 +CFLAGS += -I$(MCXW71_SDK)/CMSIS/Core/Include +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections +LDLIBS := -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +NSC_OBJ := +ifeq ($(TZEN),1) + CFLAGS += -DWOLFCRYPT_SECURE_MODE + NSC_OBJ := ../../../src/wc_secure_calls.o +endif + +VPATH := ../common + +COMMON_SRCS := emu_ivt.c emu_startup.c emu_syscalls.c emu_update.c emu_hal.c +LIBWOLFBOOT_SRC := ../../../src/libwolfboot.c +SRCS := $(COMMON_SRCS) uart.c +OBJS := $(SRCS:.c=.o) libwolfboot.o $(NSC_OBJ) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libwolfboot.o: $(LIBWOLFBOOT_SRC) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(SRCS:.c=.o) libwolfboot.o app.elf app.bin + +.PHONY: all clean diff --git a/test-app/emu-test-apps/mcxw71/target.ld b/test-app/emu-test-apps/mcxw71/target.ld new file mode 100644 index 0000000000..3f81a1769c --- /dev/null +++ b/test-app/emu-test-apps/mcxw71/target.ld @@ -0,0 +1,64 @@ +/* Minimal linker script for MCXW716C memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000100, LENGTH = 0x000FFF00 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0001C000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/mcxw71/target.ld.in b/test-app/emu-test-apps/mcxw71/target.ld.in new file mode 100644 index 0000000000..edc05193f6 --- /dev/null +++ b/test-app/emu-test-apps/mcxw71/target.ld.in @@ -0,0 +1,64 @@ +/* Minimal linker script for MCXW716C memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x000FFF00 + RAM (rwx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x0001C000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/mcxw71/uart.c b/test-app/emu-test-apps/mcxw71/uart.c new file mode 100644 index 0000000000..9e528f7b0c --- /dev/null +++ b/test-app/emu-test-apps/mcxw71/uart.c @@ -0,0 +1,46 @@ +#include +#include "fsl_device_registers.h" +#include "emu_app.h" + +/* MRCC */ +#define MRCC_BASE 0x4001C000u +#define MRCC_LPUART0 0xE0u + +static inline void mrcc_enable(uint32_t off) +{ + volatile uint32_t *reg = (volatile uint32_t *)(MRCC_BASE + off); + *reg = (1u << 31) | (1u << 30) | 1u; +} + +/* LPUART0 */ +#define LPUART0_BASE 0x40038000u +#define LPUART_STAT(b) (*(volatile uint32_t *)((b) + 0x14u)) +#define LPUART_CTRL(b) (*(volatile uint32_t *)((b) + 0x18u)) +#define LPUART_DATA(b) (*(volatile uint32_t *)((b) + 0x1Cu)) + +#define LPUART_STAT_TDRE (1u << 23) +#define LPUART_STAT_RDRF (1u << 21) +#define LPUART_CTRL_RE (1u << 18) +#define LPUART_CTRL_TE (1u << 19) + +void emu_uart_init(void) +{ + mrcc_enable(MRCC_LPUART0); + LPUART_CTRL(LPUART0_BASE) = LPUART_CTRL_TE | LPUART_CTRL_RE; +} + +void emu_uart_write(uint8_t c) +{ + while ((LPUART_STAT(LPUART0_BASE) & LPUART_STAT_TDRE) == 0u) { + } + LPUART_DATA(LPUART0_BASE) = (uint32_t)c; +} + +int emu_uart_read(uint8_t *c) +{ + if ((LPUART_STAT(LPUART0_BASE) & LPUART_STAT_RDRF) == 0u) { + return 0; + } + *c = (uint8_t)LPUART_DATA(LPUART0_BASE); + return 1; +} diff --git a/test-app/emu-test-apps/nrf5340/Makefile b/test-app/emu-test-apps/nrf5340/Makefile new file mode 100644 index 0000000000..23bd250fdd --- /dev/null +++ b/test-app/emu-test-apps/nrf5340/Makefile @@ -0,0 +1,39 @@ +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb +CFLAGS += -I. -I../common -I../../../include -DEMU_NRF5340 +CFLAGS += -DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections +LDLIBS := -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +NSC_OBJ := +ifeq ($(TZEN),1) + CFLAGS += -DWOLFCRYPT_SECURE_MODE + NSC_OBJ := ../../../src/wc_secure_calls.o +endif + +VPATH := ../common + +COMMON_SRCS := emu_ivt.c emu_startup.c emu_syscalls.c emu_update.c emu_hal.c +LIBWOLFBOOT_SRC := ../../../src/libwolfboot.c +SRCS := $(COMMON_SRCS) uart.c +OBJS := $(SRCS:.c=.o) libwolfboot.o $(NSC_OBJ) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libwolfboot.o: $(LIBWOLFBOOT_SRC) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(SRCS:.c=.o) libwolfboot.o app.elf app.bin + +.PHONY: all clean diff --git a/test-app/emu-test-apps/nrf5340/target.ld b/test-app/emu-test-apps/nrf5340/target.ld new file mode 100644 index 0000000000..de88a7e0f8 --- /dev/null +++ b/test-app/emu-test-apps/nrf5340/target.ld @@ -0,0 +1,69 @@ +/* Minimal linker script for nRF5340 (application core) memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000100, LENGTH = 0x000FFF00 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00080000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM + + .testpage ORIGIN(FLASH) + LENGTH(FLASH) - 0x1000 : + { + KEEP(*(.testpage*)) + } > FLASH +} diff --git a/test-app/emu-test-apps/nrf5340/target.ld.in b/test-app/emu-test-apps/nrf5340/target.ld.in new file mode 100644 index 0000000000..62c25bfe90 --- /dev/null +++ b/test-app/emu-test-apps/nrf5340/target.ld.in @@ -0,0 +1,69 @@ +/* Minimal linker script for nRF5340 (application core) memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x000FFF00 + RAM (rwx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x00080000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM + + .testpage ORIGIN(FLASH) + LENGTH(FLASH) - 0x1000 : + { + KEEP(*(.testpage*)) + } > FLASH +} diff --git a/test-app/emu-test-apps/nrf5340/uart.c b/test-app/emu-test-apps/nrf5340/uart.c new file mode 100644 index 0000000000..7a7492a243 --- /dev/null +++ b/test-app/emu-test-apps/nrf5340/uart.c @@ -0,0 +1,63 @@ +#include +#include "emu_app.h" + +#define UARTE0_BASE 0x40008000u +#define CLOCK_BASE 0x40005000u +#define CLOCK_TASKS_HFCLKSTART (*(volatile uint32_t *)((CLOCK_BASE) + 0x000u)) +#define UARTE_TASKS_STARTRX(b) (*(volatile uint32_t *)((b) + 0x000u)) +#define UARTE_TASKS_STOPRX(b) (*(volatile uint32_t *)((b) + 0x004u)) +#define UARTE_TASKS_STARTTX(b) (*(volatile uint32_t *)((b) + 0x008u)) +#define UARTE_EVENTS_ENDRX(b) (*(volatile uint32_t *)((b) + 0x110u)) +#define UARTE_EVENTS_ENDTX(b) (*(volatile uint32_t *)((b) + 0x120u)) +#define UARTE_ENABLE(b) (*(volatile uint32_t *)((b) + 0x500u)) +#define UARTE_PSEL_TXD(b) (*(volatile uint32_t *)((b) + 0x50Cu)) +#define UARTE_PSEL_RXD(b) (*(volatile uint32_t *)((b) + 0x514u)) +#define UARTE_BAUDRATE(b) (*(volatile uint32_t *)((b) + 0x524u)) +#define UARTE_RXD_PTR(b) (*(volatile uint32_t *)((b) + 0x534u)) +#define UARTE_RXD_MAXCNT(b) (*(volatile uint32_t *)((b) + 0x538u)) +#define UARTE_TXD_PTR(b) (*(volatile uint32_t *)((b) + 0x544u)) +#define UARTE_TXD_MAXCNT(b) (*(volatile uint32_t *)((b) + 0x548u)) + +static volatile uint8_t uart_tx_byte; +static volatile uint8_t uart_rx_byte; + +static void uarte0_start_rx(void) +{ + UARTE_RXD_PTR(UARTE0_BASE) = (uint32_t)&uart_rx_byte; + UARTE_RXD_MAXCNT(UARTE0_BASE) = 1u; + UARTE_EVENTS_ENDRX(UARTE0_BASE) = 0u; + UARTE_TASKS_STARTRX(UARTE0_BASE) = 1u; +} + +void emu_uart_init(void) +{ + CLOCK_TASKS_HFCLKSTART = 1u; + UARTE_ENABLE(UARTE0_BASE) = 0u; + UARTE_PSEL_TXD(UARTE0_BASE) = 0u; + UARTE_PSEL_RXD(UARTE0_BASE) = 0u; + UARTE_BAUDRATE(UARTE0_BASE) = 0x01D7E000u; /* 115200 */ + UARTE_ENABLE(UARTE0_BASE) = 8u; + uarte0_start_rx(); +} + +void emu_uart_write(uint8_t c) +{ + uart_tx_byte = c; + UARTE_TXD_PTR(UARTE0_BASE) = (uint32_t)&uart_tx_byte; + UARTE_TXD_MAXCNT(UARTE0_BASE) = 1u; + UARTE_EVENTS_ENDTX(UARTE0_BASE) = 0u; + UARTE_TASKS_STARTTX(UARTE0_BASE) = 1u; + while (UARTE_EVENTS_ENDTX(UARTE0_BASE) == 0u) { + } +} + +int emu_uart_read(uint8_t *c) +{ + if (UARTE_EVENTS_ENDRX(UARTE0_BASE) == 0u) { + return 0; + } + UARTE_EVENTS_ENDRX(UARTE0_BASE) = 0u; + *c = uart_rx_byte; + uarte0_start_rx(); + return 1; +} diff --git a/test-app/emu-test-apps/stm32h563/Makefile b/test-app/emu-test-apps/stm32h563/Makefile new file mode 100644 index 0000000000..838979fb09 --- /dev/null +++ b/test-app/emu-test-apps/stm32h563/Makefile @@ -0,0 +1,39 @@ +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb +CFLAGS += -I. -I../common -I../../../include -DEMU_STM32 +CFLAGS += -DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections +LDLIBS := -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +NSC_OBJ := +ifeq ($(TZEN),1) + CFLAGS += -DWOLFCRYPT_SECURE_MODE + NSC_OBJ := ../../../src/wc_secure_calls.o +endif + +VPATH := ../common + +COMMON_SRCS := emu_ivt.c emu_startup.c emu_syscalls.c emu_update.c emu_hal.c +LIBWOLFBOOT_SRC := ../../../src/libwolfboot.c +SRCS := $(COMMON_SRCS) uart.c +OBJS := $(SRCS:.c=.o) libwolfboot.o $(NSC_OBJ) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libwolfboot.o: $(LIBWOLFBOOT_SRC) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(SRCS:.c=.o) libwolfboot.o app.elf app.bin + +.PHONY: all clean diff --git a/test-app/emu-test-apps/stm32h563/target.ld b/test-app/emu-test-apps/stm32h563/target.ld new file mode 100644 index 0000000000..a4afef0ad1 --- /dev/null +++ b/test-app/emu-test-apps/stm32h563/target.ld @@ -0,0 +1,62 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x8060400, LENGTH = 0x9fc00 + RAM (rwx) : ORIGIN = 0x20050000, LENGTH = 0x40000 +} + +SECTIONS +{ + .text : + { + _start_text = .; + . = ALIGN(8); + KEEP(*(.isr_vector)) + . = ALIGN(8); + *(.init) + *(.fini) + *(.text*) + *(.rodata*) + . = ALIGN(8); + _end_text = .; + } > FLASH + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > FLASH + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(8); + KEEP(*(.ramcode)) + . = ALIGN(8); + _end_data = .; + } > RAM + + .bss : + { + _start_bss = .; + *(.bss*) + *(COMMON) + . = ALIGN(8); + _end_bss = .; + _end = .; + } > RAM +} + +PROVIDE(_start_heap = _end); +PROVIDE(_heap_size = 4K); +PROVIDE(_end_stack = ORIGIN(RAM) + LENGTH(RAM)); + +/* Emu app startup expects these symbols. */ +_estack = _end_stack; +_sidata = _stored_data; +_sdata = _start_data; +_edata = _end_data; +_sbss = _start_bss; +_ebss = _end_bss; diff --git a/test-app/emu-test-apps/stm32h563/target.ld.in b/test-app/emu-test-apps/stm32h563/target.ld.in new file mode 100644 index 0000000000..c20e2ce966 --- /dev/null +++ b/test-app/emu-test-apps/stm32h563/target.ld.in @@ -0,0 +1,64 @@ +/* Minimal linker script for STM32H563 memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x001FFF00 + RAM (rwx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x000A0000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/stm32h563/target_v8.ld b/test-app/emu-test-apps/stm32h563/target_v8.ld new file mode 100644 index 0000000000..dfae293cd4 --- /dev/null +++ b/test-app/emu-test-apps/stm32h563/target_v8.ld @@ -0,0 +1,64 @@ +/* Minimal linker script for STM32H563 memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x8060100, LENGTH = 0x001FFF00 + RAM (rwx) : ORIGIN = 0x8060100, LENGTH = 0x000A0000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/stm32h563/tmp_server b/test-app/emu-test-apps/stm32h563/tmp_server new file mode 100755 index 0000000000..331da84195 Binary files /dev/null and b/test-app/emu-test-apps/stm32h563/tmp_server differ diff --git a/test-app/emu-test-apps/stm32h563/uart.c b/test-app/emu-test-apps/stm32h563/uart.c new file mode 100644 index 0000000000..a981f94327 --- /dev/null +++ b/test-app/emu-test-apps/stm32h563/uart.c @@ -0,0 +1,93 @@ +#include +#include "emu_app.h" + +#define SYSCLK_HZ 64000000u + +/* RCC */ +#define RCC_BASE 0x44020C00u +#define RCC_AHB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x8Cu)) +#define RCC_APB1LENR (*(volatile uint32_t *)(RCC_BASE + 0x9Cu)) + +/* GPIOA/GPIOB/GPIOD */ +#define GPIOA_BASE 0x42020000u +#define GPIOB_BASE 0x42020400u +#define GPIOD_BASE 0x42020C00u +#define GPIO_MODER(x) (*(volatile uint32_t *)((x) + 0x00u)) +#define GPIO_OTYPER(x) (*(volatile uint32_t *)((x) + 0x04u)) +#define GPIO_OSPEEDR(x) (*(volatile uint32_t *)((x) + 0x08u)) +#define GPIO_PUPDR(x) (*(volatile uint32_t *)((x) + 0x0Cu)) +#define GPIO_AFRH(x) (*(volatile uint32_t *)((x) + 0x24u)) + +/* USART3 */ +#define USART3_BASE 0x40004800u +#define USART_CR1(b) (*(volatile uint32_t *)((b) + 0x00u)) +#define USART_CR2(b) (*(volatile uint32_t *)((b) + 0x04u)) +#define USART_CR3(b) (*(volatile uint32_t *)((b) + 0x08u)) +#define USART_BRR(b) (*(volatile uint32_t *)((b) + 0x0Cu)) +#define USART_ISR(b) (*(volatile uint32_t *)((b) + 0x1Cu)) +#define USART_RDR(b) (*(volatile uint32_t *)((b) + 0x24u)) +#define USART_TDR(b) (*(volatile uint32_t *)((b) + 0x28u)) + +static void gpio_config_usart3_pd8_pd9(void) +{ + uint32_t v; + RCC_AHB2ENR |= (1u << 3); + + v = GPIO_MODER(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_MODER(GPIOD_BASE) = v; + + v = GPIO_OTYPER(GPIOD_BASE); + v &= ~((1u << 8) | (1u << 9)); + GPIO_OTYPER(GPIOD_BASE) = v; + + v = GPIO_OSPEEDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_OSPEEDR(GPIOD_BASE) = v; + + v = GPIO_PUPDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (1u << (9u * 2u)); + GPIO_PUPDR(GPIOD_BASE) = v; + + v = GPIO_AFRH(GPIOD_BASE); + v &= ~((0xFu << ((8u - 8u) * 4u)) | (0xFu << ((9u - 8u) * 4u))); + v |= (7u << ((8u - 8u) * 4u)) | (7u << ((9u - 8u) * 4u)); + GPIO_AFRH(GPIOD_BASE) = v; +} + +static void usart3_init_115200(void) +{ + uint32_t brr; + RCC_APB1LENR |= (1u << 18); + USART_CR1(USART3_BASE) = 0; + USART_CR2(USART3_BASE) = 0; + USART_CR3(USART3_BASE) = 0; + brr = SYSCLK_HZ / 115200u; + USART_BRR(USART3_BASE) = brr; + USART_CR1(USART3_BASE) = (1u << 0) | (1u << 2) | (1u << 3); +} + +void emu_uart_init(void) +{ + gpio_config_usart3_pd8_pd9(); + usart3_init_115200(); +} + +void emu_uart_write(uint8_t c) +{ + while ((USART_ISR(USART3_BASE) & (1u << 7)) == 0u) { + } + USART_TDR(USART3_BASE) = (uint32_t)c; +} + +int emu_uart_read(uint8_t *c) +{ + if ((USART_ISR(USART3_BASE) & (1u << 5)) == 0u) { + return 0; + } + *c = (uint8_t)USART_RDR(USART3_BASE); + return 1; +} diff --git a/test-app/emu-test-apps/stm32l552/Makefile b/test-app/emu-test-apps/stm32l552/Makefile new file mode 100644 index 0000000000..838979fb09 --- /dev/null +++ b/test-app/emu-test-apps/stm32l552/Makefile @@ -0,0 +1,39 @@ +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb +CFLAGS += -I. -I../common -I../../../include -DEMU_STM32 +CFLAGS += -DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections +LDLIBS := -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +NSC_OBJ := +ifeq ($(TZEN),1) + CFLAGS += -DWOLFCRYPT_SECURE_MODE + NSC_OBJ := ../../../src/wc_secure_calls.o +endif + +VPATH := ../common + +COMMON_SRCS := emu_ivt.c emu_startup.c emu_syscalls.c emu_update.c emu_hal.c +LIBWOLFBOOT_SRC := ../../../src/libwolfboot.c +SRCS := $(COMMON_SRCS) uart.c +OBJS := $(SRCS:.c=.o) libwolfboot.o $(NSC_OBJ) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libwolfboot.o: $(LIBWOLFBOOT_SRC) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(SRCS:.c=.o) libwolfboot.o app.elf app.bin + +.PHONY: all clean diff --git a/test-app/emu-test-apps/stm32l552/target.ld b/test-app/emu-test-apps/stm32l552/target.ld new file mode 100644 index 0000000000..a9e5366223 --- /dev/null +++ b/test-app/emu-test-apps/stm32l552/target.ld @@ -0,0 +1,64 @@ +/* Minimal linker script for STM32L552 memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000100, LENGTH = 0x0007FF00 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/stm32l552/target.ld.in b/test-app/emu-test-apps/stm32l552/target.ld.in new file mode 100644 index 0000000000..4d4aa48b6e --- /dev/null +++ b/test-app/emu-test-apps/stm32l552/target.ld.in @@ -0,0 +1,64 @@ +/* Minimal linker script for STM32L552 memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x0007FF00 + RAM (rwx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x00040000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/stm32l552/uart.c b/test-app/emu-test-apps/stm32l552/uart.c new file mode 100644 index 0000000000..caab44694d --- /dev/null +++ b/test-app/emu-test-apps/stm32l552/uart.c @@ -0,0 +1,93 @@ +#include +#include "emu_app.h" + +#define SYSCLK_HZ 64000000u + +/* RCC */ +#define RCC_BASE 0x40021000u +#define RCC_AHB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x4Cu)) +#define RCC_APB1LENR (*(volatile uint32_t *)(RCC_BASE + 0x58u)) + +/* GPIOA/GPIOB/GPIOD */ +#define GPIOA_BASE 0x42020000u +#define GPIOB_BASE 0x42020400u +#define GPIOD_BASE 0x42020C00u +#define GPIO_MODER(x) (*(volatile uint32_t *)((x) + 0x00u)) +#define GPIO_OTYPER(x) (*(volatile uint32_t *)((x) + 0x04u)) +#define GPIO_OSPEEDR(x) (*(volatile uint32_t *)((x) + 0x08u)) +#define GPIO_PUPDR(x) (*(volatile uint32_t *)((x) + 0x0Cu)) +#define GPIO_AFRH(x) (*(volatile uint32_t *)((x) + 0x24u)) + +/* USART3 */ +#define USART3_BASE 0x40004800u +#define USART_CR1(b) (*(volatile uint32_t *)((b) + 0x00u)) +#define USART_CR2(b) (*(volatile uint32_t *)((b) + 0x04u)) +#define USART_CR3(b) (*(volatile uint32_t *)((b) + 0x08u)) +#define USART_BRR(b) (*(volatile uint32_t *)((b) + 0x0Cu)) +#define USART_ISR(b) (*(volatile uint32_t *)((b) + 0x1Cu)) +#define USART_RDR(b) (*(volatile uint32_t *)((b) + 0x24u)) +#define USART_TDR(b) (*(volatile uint32_t *)((b) + 0x28u)) + +static void gpio_config_usart3_pd8_pd9(void) +{ + uint32_t v; + RCC_AHB2ENR |= (1u << 3); + + v = GPIO_MODER(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_MODER(GPIOD_BASE) = v; + + v = GPIO_OTYPER(GPIOD_BASE); + v &= ~((1u << 8) | (1u << 9)); + GPIO_OTYPER(GPIOD_BASE) = v; + + v = GPIO_OSPEEDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_OSPEEDR(GPIOD_BASE) = v; + + v = GPIO_PUPDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (1u << (9u * 2u)); + GPIO_PUPDR(GPIOD_BASE) = v; + + v = GPIO_AFRH(GPIOD_BASE); + v &= ~((0xFu << ((8u - 8u) * 4u)) | (0xFu << ((9u - 8u) * 4u))); + v |= (7u << ((8u - 8u) * 4u)) | (7u << ((9u - 8u) * 4u)); + GPIO_AFRH(GPIOD_BASE) = v; +} + +static void usart3_init_115200(void) +{ + uint32_t brr; + RCC_APB1LENR |= (1u << 18); + USART_CR1(USART3_BASE) = 0; + USART_CR2(USART3_BASE) = 0; + USART_CR3(USART3_BASE) = 0; + brr = SYSCLK_HZ / 115200u; + USART_BRR(USART3_BASE) = brr; + USART_CR1(USART3_BASE) = (1u << 0) | (1u << 2) | (1u << 3); +} + +void emu_uart_init(void) +{ + gpio_config_usart3_pd8_pd9(); + usart3_init_115200(); +} + +void emu_uart_write(uint8_t c) +{ + while ((USART_ISR(USART3_BASE) & (1u << 7)) == 0u) { + } + USART_TDR(USART3_BASE) = (uint32_t)c; +} + +int emu_uart_read(uint8_t *c) +{ + if ((USART_ISR(USART3_BASE) & (1u << 5)) == 0u) { + return 0; + } + *c = (uint8_t)USART_RDR(USART3_BASE); + return 1; +} diff --git a/test-app/emu-test-apps/stm32u585/Makefile b/test-app/emu-test-apps/stm32u585/Makefile new file mode 100644 index 0000000000..838979fb09 --- /dev/null +++ b/test-app/emu-test-apps/stm32u585/Makefile @@ -0,0 +1,39 @@ +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb +CFLAGS += -I. -I../common -I../../../include -DEMU_STM32 +CFLAGS += -DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections +LDLIBS := -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +NSC_OBJ := +ifeq ($(TZEN),1) + CFLAGS += -DWOLFCRYPT_SECURE_MODE + NSC_OBJ := ../../../src/wc_secure_calls.o +endif + +VPATH := ../common + +COMMON_SRCS := emu_ivt.c emu_startup.c emu_syscalls.c emu_update.c emu_hal.c +LIBWOLFBOOT_SRC := ../../../src/libwolfboot.c +SRCS := $(COMMON_SRCS) uart.c +OBJS := $(SRCS:.c=.o) libwolfboot.o $(NSC_OBJ) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libwolfboot.o: $(LIBWOLFBOOT_SRC) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(SRCS:.c=.o) libwolfboot.o app.elf app.bin + +.PHONY: all clean diff --git a/test-app/emu-test-apps/stm32u585/target.ld b/test-app/emu-test-apps/stm32u585/target.ld new file mode 100644 index 0000000000..07f6835a1d --- /dev/null +++ b/test-app/emu-test-apps/stm32u585/target.ld @@ -0,0 +1,64 @@ +/* Minimal linker script for STM32U585 memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000100, LENGTH = 0x001FFF00 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x000C0000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/stm32u585/target.ld.in b/test-app/emu-test-apps/stm32u585/target.ld.in new file mode 100644 index 0000000000..6097ac1baa --- /dev/null +++ b/test-app/emu-test-apps/stm32u585/target.ld.in @@ -0,0 +1,64 @@ +/* Minimal linker script for STM32U585 memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x001FFF00 + RAM (rwx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x000C0000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/stm32u585/uart.c b/test-app/emu-test-apps/stm32u585/uart.c new file mode 100644 index 0000000000..09bf2dd353 --- /dev/null +++ b/test-app/emu-test-apps/stm32u585/uart.c @@ -0,0 +1,93 @@ +#include +#include "emu_app.h" + +#define SYSCLK_HZ 64000000u + +/* RCC */ +#define RCC_BASE 0x46020C00u +#define RCC_AHB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x8Cu)) +#define RCC_APB1LENR (*(volatile uint32_t *)(RCC_BASE + 0x9Cu)) + +/* GPIOA/GPIOB/GPIOD */ +#define GPIOA_BASE 0x42020000u +#define GPIOB_BASE 0x42020400u +#define GPIOD_BASE 0x42020C00u +#define GPIO_MODER(x) (*(volatile uint32_t *)((x) + 0x00u)) +#define GPIO_OTYPER(x) (*(volatile uint32_t *)((x) + 0x04u)) +#define GPIO_OSPEEDR(x) (*(volatile uint32_t *)((x) + 0x08u)) +#define GPIO_PUPDR(x) (*(volatile uint32_t *)((x) + 0x0Cu)) +#define GPIO_AFRH(x) (*(volatile uint32_t *)((x) + 0x24u)) + +/* USART3 */ +#define USART3_BASE 0x40004800u +#define USART_CR1(b) (*(volatile uint32_t *)((b) + 0x00u)) +#define USART_CR2(b) (*(volatile uint32_t *)((b) + 0x04u)) +#define USART_CR3(b) (*(volatile uint32_t *)((b) + 0x08u)) +#define USART_BRR(b) (*(volatile uint32_t *)((b) + 0x0Cu)) +#define USART_ISR(b) (*(volatile uint32_t *)((b) + 0x1Cu)) +#define USART_RDR(b) (*(volatile uint32_t *)((b) + 0x24u)) +#define USART_TDR(b) (*(volatile uint32_t *)((b) + 0x28u)) + +static void gpio_config_usart3_pd8_pd9(void) +{ + uint32_t v; + RCC_AHB2ENR |= (1u << 3); + + v = GPIO_MODER(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_MODER(GPIOD_BASE) = v; + + v = GPIO_OTYPER(GPIOD_BASE); + v &= ~((1u << 8) | (1u << 9)); + GPIO_OTYPER(GPIOD_BASE) = v; + + v = GPIO_OSPEEDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_OSPEEDR(GPIOD_BASE) = v; + + v = GPIO_PUPDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (1u << (9u * 2u)); + GPIO_PUPDR(GPIOD_BASE) = v; + + v = GPIO_AFRH(GPIOD_BASE); + v &= ~((0xFu << ((8u - 8u) * 4u)) | (0xFu << ((9u - 8u) * 4u))); + v |= (7u << ((8u - 8u) * 4u)) | (7u << ((9u - 8u) * 4u)); + GPIO_AFRH(GPIOD_BASE) = v; +} + +static void usart3_init_115200(void) +{ + uint32_t brr; + RCC_APB1LENR |= (1u << 18); + USART_CR1(USART3_BASE) = 0; + USART_CR2(USART3_BASE) = 0; + USART_CR3(USART3_BASE) = 0; + brr = SYSCLK_HZ / 115200u; + USART_BRR(USART3_BASE) = brr; + USART_CR1(USART3_BASE) = (1u << 0) | (1u << 2) | (1u << 3); +} + +void emu_uart_init(void) +{ + gpio_config_usart3_pd8_pd9(); + usart3_init_115200(); +} + +void emu_uart_write(uint8_t c) +{ + while ((USART_ISR(USART3_BASE) & (1u << 7)) == 0u) { + } + USART_TDR(USART3_BASE) = (uint32_t)c; +} + +int emu_uart_read(uint8_t *c) +{ + if ((USART_ISR(USART3_BASE) & (1u << 5)) == 0u) { + return 0; + } + *c = (uint8_t)USART_RDR(USART3_BASE); + return 1; +} diff --git a/test-app/emu-test-apps/test.sh b/test-app/emu-test-apps/test.sh new file mode 100755 index 0000000000..bb0ca99d72 --- /dev/null +++ b/test-app/emu-test-apps/test.sh @@ -0,0 +1,525 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +WOLFBOOT_ROOT="${WOLFBOOT_ROOT:-$(cd "$script_dir/../.." && pwd)}" +EMU_APPS="$WOLFBOOT_ROOT/test-app/emu-test-apps" +M33MU="${M33MU:-$(command -v m33mu || true)}" +UPDATE_SERVER_SRC="$WOLFBOOT_ROOT/tools/test-update-server/server.c" +BIN_ASSEMBLE="$WOLFBOOT_ROOT/tools/bin-assemble/bin-assemble" + +log() { + echo "==> $*" +} + +die() { + echo "error: $*" >&2 + exit 1 +} + +need_cmd() { + command -v "$1" >/dev/null 2>&1 || die "missing required command: $1" +} + +cfg_get() { + local key="$1" + local val + val="$(grep -m1 -E "^${key}[?]*[:]*=" "$WOLFBOOT_ROOT/.config" 2>/dev/null | sed -E "s/^${key}[?]*[:]*=//" || true)" + echo "${val}" +} + +if [[ -z "${TARGET:-}" && -f "$WOLFBOOT_ROOT/.config" ]]; then + TARGET="$(cfg_get TARGET)" +fi +TARGET="${TARGET:-}" +[[ -n "$TARGET" ]] || die "TARGET not set (export TARGET=... or set in .config)" + +EMU_DIR="" +UART_BASE="" + +get_m33mu_target() { + case "$1" in + stm32h563|stm32h5) echo "stm32h563" ;; + stm32u585|stm32u5) echo "stm32u585" ;; + stm32l552|stm32l5) echo "stm32l552" ;; + nrf5340) echo "nrf5340" ;; + mcxw|mcxw71) echo "mcxw71c" ;; + *) echo "" ;; + esac +} + +case "$TARGET" in + stm32h563|stm32h5) EMU_DIR=stm32h563; UART_BASE=40004800 ;; + stm32u585|stm32u5) EMU_DIR=stm32u585; UART_BASE=40004800 ;; + stm32l552|stm32l5) EMU_DIR=stm32l552; UART_BASE=40004800 ;; + nrf5340) EMU_DIR=nrf5340; UART_BASE=40008000 ;; + mcxw|mcxw71) EMU_DIR=mcxw71; UART_BASE=40038000 ;; + *) die "unsupported TARGET=$TARGET" ;; + esac + +EMU_CPU="$(get_m33mu_target "$TARGET")" +[[ -n "$EMU_CPU" ]] || die "unsupported TARGET=$TARGET (no m33mu mapping)" + +need_cmd "$M33MU" +need_cmd make +need_cmd grep +need_cmd python3 +need_cmd gcc +need_cmd sed +need_cmd cut +need_cmd tac + +IMAGE_HEADER_SIZE="$(cfg_get IMAGE_HEADER_SIZE)" +IMAGE_HEADER_SIZE="${IMAGE_HEADER_SIZE:-256}" +ARCH_OFFSET="$(cfg_get ARCH_OFFSET)" +ARCH_OFFSET="${ARCH_OFFSET:-0}" +BOOT_ADDR="$(cfg_get WOLFBOOT_PARTITION_BOOT_ADDRESS)" +UPDATE_ADDR="$(cfg_get WOLFBOOT_PARTITION_UPDATE_ADDRESS)" +PART_SIZE="$(cfg_get WOLFBOOT_PARTITION_SIZE)" +SECTOR_SIZE="$(cfg_get WOLFBOOT_SECTOR_SIZE)" +RAM_CODE="$(cfg_get RAM_CODE)" +TZEN="$(cfg_get TZEN)" + +[[ -n "$BOOT_ADDR" && -n "$UPDATE_ADDR" && -n "$PART_SIZE" && -n "$SECTOR_SIZE" ]] || \ + die "missing required config values (boot/update addr, partition/sector size)" + +# If ARCH_OFFSET is unset/0 but partitions are in 0x0800_0000 (STM32), use that +# as the base so bin-assemble offsets stay within the flash image. +if [[ "$ARCH_OFFSET" == "0" || "$ARCH_OFFSET" == "0x0" ]]; then + if (( BOOT_ADDR >= 0x08000000 )); then + ARCH_OFFSET=0x08000000 + fi +fi + +normalize_flash_addr() { + local addr="$1" + if [[ "$ARCH_OFFSET" == "0x08000000" ]]; then + if (( addr >= 0x0c000000 && addr < 0x10000000 )); then + addr=$((addr - 0x04000000)) + fi + fi + echo "$addr" +} + +BOOT_ADDR_NORM="$(normalize_flash_addr "$BOOT_ADDR")" +UPDATE_ADDR_NORM="$(normalize_flash_addr "$UPDATE_ADDR")" + +BOOT_OFFSET=$((BOOT_ADDR_NORM - ARCH_OFFSET)) +UPDATE_OFFSET=$((UPDATE_ADDR_NORM - ARCH_OFFSET)) +BOOT_OFFSET_HEX=$(printf "0x%x" "$BOOT_OFFSET") +UPDATE_OFFSET_HEX=$(printf "0x%x" "$UPDATE_OFFSET") + +get_check_config_val() { + local key="$1" + local val + make -C "$WOLFBOOT_ROOT/tools/check_config" check_config RAM_CODE=0 >/dev/null + val="$("$WOLFBOOT_ROOT/tools/check_config/check_config" | grep -m1 "^${key}" | sed 's/.*: *//')" + [[ -n "$val" ]] || die "missing ${key} from tools/check_config output" + echo "0x$val" +} + +BOOT_FLAGS_ADDR="$(get_check_config_val PART_BOOT_ENDFLAGS)" +UPDATE_FLAGS_ADDR="$(get_check_config_val PART_UPDATE_ENDFLAGS)" +BOOT_FLAGS_ADDR_NORM="$(normalize_flash_addr "$BOOT_FLAGS_ADDR")" +UPDATE_FLAGS_ADDR_NORM="$(normalize_flash_addr "$UPDATE_FLAGS_ADDR")" +BOOT_FLAGS_OFFSET=$((BOOT_FLAGS_ADDR_NORM - ARCH_OFFSET)) +UPDATE_FLAGS_OFFSET=$((UPDATE_FLAGS_ADDR_NORM - ARCH_OFFSET)) +BOOT_FLAGS_OFFSET_HEX=$(printf "0x%x" "$BOOT_FLAGS_OFFSET") +UPDATE_FLAGS_OFFSET_HEX=$(printf "0x%x" "$UPDATE_FLAGS_OFFSET") + +M33MU_TZ_ARGS=(--no-tz) +if [[ "${TZEN}" == "1" ]]; then + M33MU_TZ_ARGS=() +fi + +STDBUF="" +if command -v stdbuf >/dev/null 2>&1; then + STDBUF="stdbuf -o0 -e0" +fi + +SCENARIOS_RAW="${SCENARIOS:-}" +SCENARIOS_UP="$(echo "$SCENARIOS_RAW" | tr '[:lower:]' '[:upper:]' | tr -d ' ' | sed -e 's/,,*/,/g' -e 's/^,//' -e 's/,$//')" + +want_scenario() { + local s="$1" + if [[ -z "$SCENARIOS_UP" ]]; then + return 0 + fi + echo "$SCENARIOS_UP" | grep -Eq "(^|,)$s(,|$)" +} + +EMU_PATH="$EMU_APPS/$EMU_DIR" +WOLFBOOT_BIN="$WOLFBOOT_ROOT/wolfboot.bin" +FACTORY_FLASH="$EMU_PATH/factory.bin" +UPDATE_SERVER_BIN="$EMU_PATH/test-update-server" + +UPDATE_IMAGE_V1="$EMU_PATH/image_v1_signed.bin" +UPDATE_IMAGE_V3="$EMU_PATH/image_v3_signed.bin" +UPDATE_IMAGE_V4="$EMU_PATH/image_v4_signed.bin" +UPDATE_IMAGE_V7="$EMU_PATH/image_v7_signed.bin" +UPDATE_IMAGE_V8="$EMU_PATH/image_v8_signed.bin" + +BOOT_TIMEOUT="${BOOT_TIMEOUT:-10}" +UPDATE_TIMEOUT="${UPDATE_TIMEOUT:-10}" +REBOOT_TIMEOUT="${REBOOT_TIMEOUT:-10}" + +write_target_ld() { + local tpl="" + local base="" + local addr + local size + addr=$((BOOT_ADDR + IMAGE_HEADER_SIZE)) + size=$((PART_SIZE - IMAGE_HEADER_SIZE)) + + case "$TARGET" in + stm32h563|stm32h5) base="ARM-stm32h5" ;; + stm32u585|stm32u5) base="ARM-stm32u5" ;; + stm32l552|stm32l5) base="ARM-stm32l5" ;; + nrf5340) base="ARM-nrf5340" ;; + mcxw|mcxw71) base="ARM-mcxw" ;; + *) die "unsupported TARGET for linker template: $TARGET" ;; + esac + + if [[ "${TZEN}" == "1" && -f "$WOLFBOOT_ROOT/test-app/${base}-ns.ld" ]]; then + tpl="$WOLFBOOT_ROOT/test-app/${base}-ns.ld" + else + tpl="$WOLFBOOT_ROOT/test-app/${base}.ld" + fi + + [[ -f "$tpl" ]] || die "missing linker template: $tpl" + + sed -e "s/@WOLFBOOT_TEST_APP_ADDRESS@/0x$(printf '%x' "$addr")/g" \ + -e "s/@WOLFBOOT_TEST_APP_SIZE@/0x$(printf '%x' "$size")/g" \ + "$tpl" > "$EMU_PATH/target.ld" + cat <<'SYM' >> "$EMU_PATH/target.ld" + +/* Emu app startup expects these symbols. */ +_estack = _end_stack; +_sidata = _stored_data; +_sdata = _start_data; +_edata = _end_data; +_sbss = _start_bss; +_ebss = _end_bss; +SYM +} + +check_pty_available() { + python3 - <<'PY' +import pty, os +m, s = pty.openpty() +os.close(m) +os.close(s) +PY +} + +wait_for_pts() { + local log_file="$1" + local base="$2" + local pid="$3" + local pts="" + local i + for i in $(seq 1 2000); do + pts="$(grep "\\[UART\\] ${base} attached to" "$log_file" | tail -n1 | sed 's/.* //' || true)" + if [[ -n "$pts" ]]; then + echo "$pts" + return 0 + fi + kill -0 "$pid" >/dev/null 2>&1 || break + sleep 0.05 + done + return 1 +} + +build_update_server() { + local uart_dev="$1" + gcc -Wall -g -ggdb -DUART_DEV="\"$uart_dev\"" -o "$UPDATE_SERVER_BIN" \ + "$UPDATE_SERVER_SRC" -lpthread +} + +assemble_factory() { + log "Assembling factory.bin from wolfboot.bin + image_v1_signed.bin" + "$BIN_ASSEMBLE" "$FACTORY_FLASH" \ + 0 "$WOLFBOOT_BIN" \ + "$BOOT_OFFSET_HEX" "$UPDATE_IMAGE_V1" >/dev/null +} + +print_partition_flags() { + local label="$1" + python3 - "$FACTORY_FLASH" "$BOOT_FLAGS_OFFSET_HEX" "$UPDATE_FLAGS_OFFSET_HEX" "$SECTOR_SIZE" <<'PY' | sed "s/^/==> ${label}: /" +import sys +path, boot_s, update_s, sect_s = sys.argv[1:5] +boot = int(boot_s, 0) +update = int(update_s, 0) +sect = int(sect_s, 0) + +def decode(state): + if state is None: + return "MISSING" + if state == 0xFF: + return "NEW(0xFF)" + if state == 0x70: + return "UPDATING(0x70)" + if state == 0x10: + return "TESTING(0x10)" + if state == 0x00: + return "SUCCESS(0x00)" + return f"0x{state:02x}" + +def read_state(endflags): + try: + with open(path, "rb") as f: + f.seek(endflags - 4) + magic = f.read(4) + if magic != b"BOOT": + return None + f.seek(endflags - 5) + b = f.read(1) + if not b: + return None + return b[0] + except Exception: + return None + +def read_state_alt(endflags): + try: + with open(path, "rb") as f: + f.seek(endflags - sect - 4) + magic = f.read(4) + if magic != b"BOOT": + return None + f.seek(endflags - sect - 5) + b = f.read(1) + if not b: + return None + return b[0] + except Exception: + return None + +bs0 = read_state(boot) +bs1 = read_state_alt(boot) +us0 = read_state(update) +us1 = read_state_alt(update) +print(f"boot_flags=[S0:{decode(bs0)} S1:{decode(bs1)}] update_flags=[S0:{decode(us0)} S1:{decode(us1)}]") +PY +} + +print_partition_versions() { + local label="$1" + local boot_ver + local update_ver + boot_ver="$(python3 - "$FACTORY_FLASH" "$BOOT_OFFSET_HEX" "$IMAGE_HEADER_SIZE" <<'PY' +import sys, struct +path, off_s, hdr_s = sys.argv[1], sys.argv[2], sys.argv[3] +off = int(off_s, 16) +hdr = int(hdr_s, 0) +data = open(path, "rb").read() +if off + 8 > len(data): + print("NA") + sys.exit(0) +magic, = struct.unpack_from(" end: + break + if t == 1: + ver = struct.unpack_from(" len(data): + print("NA") + sys.exit(0) +magic, = struct.unpack_from(" end: + break + if t == 1: + ver = struct.unpack_from(""$update_log" + check_pty_available || die "no PTY devices available (needed for test-update-server)" + print_partition_flags "$label: flags before" + log "$label: start emulator (expect BKPT $expected_bkpt when update completes)" + $STDBUF "$M33MU" --cpu "$EMU_CPU" "${M33MU_TZ_ARGS[@]}" --persist \ + --timeout "$UPDATE_TIMEOUT" --expect-bkpt="$expected_bkpt" --quit-on-faults \ + "$FACTORY_FLASH" >"$update_log" 2>&1 & + emu_pid=$! + + pts="$(wait_for_pts "$update_log" "$UART_BASE" "$emu_pid")" || { + tail -n 60 "$update_log" | sed 's/^/ | /' + die "$label: failed to detect UART PTY" + } + log "$label: UART attached at $pts" + build_update_server "$pts" + + log "$label: transferring update image (v$expected_version) over UART" + $STDBUF "$UPDATE_SERVER_BIN" "$update_image" >"$server_log" 2>&1 & + server_pid=$! + + set +e + wait "$emu_pid" + emu_rc=$? + set -e + + kill "$server_pid" >/dev/null 2>&1 || true + wait "$server_pid" >/dev/null 2>&1 || true + + if ! grep -q "\\[EXPECT BKPT\\] Success" "$update_log"; then + tail -n 80 "$update_log" | sed 's/^/ | /' + die "$label: expected BKPT $expected_bkpt" + fi + + log "$label: BKPT $expected_bkpt hit" + print_partition_flags "$label: flags after" + + if [[ $emu_rc -ne 0 && $emu_rc -ne 127 ]]; then + die "$label: m33mu exited with $emu_rc" + fi +} + +log "Rebuilding wolfboot.bin (TZEN=${TZEN:-0})" +make -C "$WOLFBOOT_ROOT" clean wolfboot.bin + +log "Building emu-test-apps images" +write_target_ld +make -C "$EMU_APPS" TARGET="$TARGET" TZEN="${TZEN:-0}" EMU_VERSION=1 IMAGE_HEADER_SIZE="$IMAGE_HEADER_SIZE" sign-emu +make -C "$EMU_APPS" TARGET="$TARGET" TZEN="${TZEN:-0}" EMU_VERSION=3 IMAGE_HEADER_SIZE="$IMAGE_HEADER_SIZE" sign-emu +make -C "$EMU_APPS" TARGET="$TARGET" TZEN="${TZEN:-0}" EMU_VERSION=4 IMAGE_HEADER_SIZE="$IMAGE_HEADER_SIZE" sign-emu +make -C "$EMU_APPS" TARGET="$TARGET" TZEN="${TZEN:-0}" EMU_VERSION=7 IMAGE_HEADER_SIZE="$IMAGE_HEADER_SIZE" sign-emu +make -C "$EMU_APPS" TARGET="$TARGET" TZEN="${TZEN:-0}" EMU_VERSION=8 IMAGE_HEADER_SIZE="$IMAGE_HEADER_SIZE" sign-emu + +if want_scenario "A"; then + assemble_factory + + log "Scenario A: factory boot" + print_partition_flags "Scenario A: flags before factory run" + log "factory run: boot image v1, expect UART get_version=1" + set +e + $STDBUF "$M33MU" --cpu "$EMU_CPU" --uart-stdout "${M33MU_TZ_ARGS[@]}" \ + --timeout "$BOOT_TIMEOUT" --quit-on-faults \ + "$FACTORY_FLASH" >"$EMU_PATH/factory.log" 2>&1 + factory_rc=$? + set -e + if ! grep -q "get_version=1" "$EMU_PATH/factory.log"; then + tail -n 80 "$EMU_PATH/factory.log" | sed 's/^/ | /' + die "factory run: expected get_version=1" + fi + if [[ $factory_rc -ne 0 && $factory_rc -ne 127 ]]; then + die "factory run: m33mu exited with $factory_rc" + fi + log "factory run: ok (version=1)" + + log "Scenario A: receive v7 update without trigger (expect BKPT 0x4D, stay on v1)" + assemble_factory + run_update_scenario "scenario_a_update_v7" "$UPDATE_IMAGE_V7" 7 0x4d + print_partition_versions "Scenario A: v7 update stored, version remains 1" +fi + +if want_scenario "B"; then + log "Scenario B: successful update from v1 to v4" + assemble_factory + print_partition_flags "Scenario B: flags before update" + run_update_scenario "scenario_b_update" "$UPDATE_IMAGE_V4" 4 0x47 + + for i in 1 2; do + run_log="$EMU_PATH/reboot_v4_${i}.log" + log "Scenario B: reboot run $i: boot updated image v4, expect BKPT 0x4A (success)" + $STDBUF "$M33MU" --cpu "$EMU_CPU" --uart-stdout "${M33MU_TZ_ARGS[@]}" \ + --timeout "$REBOOT_TIMEOUT" --expect-bkpt=0x4a --quit-on-faults \ + "$FACTORY_FLASH" >"$run_log" 2>&1 || die "reboot v4 run $i: m33mu failed" + grep -q "\\[EXPECT BKPT\\] Success" "$run_log" || die "reboot v4 run $i: expected BKPT 0x4A" + log "Scenario B: reboot run $i: BKPT 0x4A hit" + done +fi + +if want_scenario "C"; then + log "Scenario C: update from v1 to v3, then fallback (no wolfBoot_success is called)" + assemble_factory + print_partition_flags "Scenario C: flags before update" + run_update_scenario "scenario_c_update" "$UPDATE_IMAGE_V3" 3 0x47 + + log "Scenario C: first boot after update: reboot into v3 (expect BKPT 0x4B, no success call)" + run_log_v3="$EMU_PATH/reboot_v3.log" + print_partition_flags "Scenario C: flags before v3 reboot" + $STDBUF "$M33MU" --cpu "$EMU_CPU" --uart-stdout "${M33MU_TZ_ARGS[@]}" \ + --timeout "$REBOOT_TIMEOUT" --expect-bkpt=0x4b --persist --quit-on-faults \ + "$FACTORY_FLASH" >"$run_log_v3" 2>&1 || die "reboot v3 run: m33mu failed" + grep -q "\\[EXPECT BKPT\\] Success" "$run_log_v3" || die "reboot v3 run: expected BKPT 0x4B" + log "Scenario C: reboot v3: BKPT 0x4B hit" + print_partition_flags "Scenario C: flags after v3 reboot" + + log "Scenario C: second reboot, expect v1 after fallback" + run_log_fallback="$EMU_PATH/reboot_fallback_v1.log" + set +e + $STDBUF "$M33MU" --cpu "$EMU_CPU" --uart-stdout "${M33MU_TZ_ARGS[@]}" \ + --timeout "$UPDATE_TIMEOUT" --persist --quit-on-faults \ + "$FACTORY_FLASH" >"$run_log_fallback" 2>&1 + fallback_rc=$? + set -e + print_partition_flags "Scenario C: flags after fallback run" + print_partition_versions "Scenario C: versions after fallback run" + if ! grep -q "get_version=1" "$run_log_fallback"; then + tail -n 80 "$run_log_fallback" | sed 's/^/ | /' + die "fallback run: expected get_version=1" + fi + if [[ $fallback_rc -ne 0 && $fallback_rc -ne 127 ]]; then + die "fallback run: m33mu exited with $fallback_rc" + fi + log "Scenario C: fallback ok (version=1)" +fi + +if want_scenario "S"; then + if [[ "$RAM_CODE" == "1" ]]; then + log "Scenario S: self-update enabled (RAM_CODE=1)" + log "Scenario S: not enabled in this script yet" + else + log "Scenario S: RAM_CODE disabled, skipping" + fi +fi + +log "ok: $TARGET emu tests passed" diff --git a/tools/test-update-server/server.c b/tools/test-update-server/server.c index 15c2eb700b..6ba617a7bc 100644 --- a/tools/test-update-server/server.c +++ b/tools/test-update-server/server.c @@ -129,7 +129,17 @@ int main(int argc, char** argv) struct stat st; union usb_ack ack; struct termios tty; - sigset(SIGALRM, alarm_handler); + { + struct sigaction sa; + sigset_t mask; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = alarm_handler; + sigemptyset(&sa.sa_mask); + (void)sigaction(SIGALRM, &sa, NULL); + sigemptyset(&mask); + sigaddset(&mask, SIGALRM); + (void)sigprocmask(SIG_UNBLOCK, &mask, NULL); + } if (argc != 2) { printf("Usage: %s firmware_filename\n", argv[0]);