Can't use CONFIG_FPROTECT=y in MCUBOOT+APP (with TFM), compilation results in "No fprotect backend selected." CMake error

Hi all,

I wanted to enable read/write protection for MCUBOOT partition in my firmware from the application and encountered a strange problem. The build (build system - default, device nrf9160, SDK v2.7.0) for nrf9160dk_nrf9160_ns with MCUBOOT(child image) and TFM results with error:

CMake Error at C:/ncs/v2.7.0/nrf/lib/fprotect/CMakeLists.txt:15 (message):
No fprotect backend selected.

My research showed that the device tree for NS board has no SPU, ficr and uicr peripherals (why??). And if I try to add these peripherals in a device tree overlay file I get following compilation errors:

In file included from C:/ncs/v2.7.0/zephyr/include/zephyr/toolchain.h:50,
from C:/ncs/v2.7.0/zephyr/include/zephyr/kernel_includes.h:23,
from C:/ncs/v2.7.0/zephyr/include/zephyr/kernel.h:17,
from C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:7:
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:176:20: error: 'NRF_FICR' undeclared here (not in a function); did you mean 'NRF_FICR_S'?
176 | CHECK_DT_REG(ficr, NRF_FICR);
| ^~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/toolchain/gcc.h:87:51: note: in definition of macro 'BUILD_ASSERT'
87 | #define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG)
| ^~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:69:53: note: in expansion of macro '__DEBRACKET'
69 | #define __GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET val
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:64:9: note: in expansion of macro '__GET_ARG2_DEBRACKET'
64 | __GET_ARG2_DEBRACKET(one_or_two_args _if_code, _else_code)
| ^~~~~~~~~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:59:9: note: in expansion of macro '__COND_CODE'
59 | __COND_CODE(_XXXX##_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:180:9: note: in expansion of macro 'Z_COND_CODE_1'
180 | Z_COND_CODE_1(_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:378:23: note: in expansion of macro 'COND_CODE_1'
378 | #define UTIL_OR(a, b) COND_CODE_1(UTIL_BOOL(a), (a), (b))
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:101:17: note: in expansion of macro 'UTIL_OR'
101 | UTIL_OR(UTIL_NOT(DT_REG_HAS_IDX(DT_NODELABEL(lbl), 0)), \
| ^~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:176:1: note: in expansion of macro 'CHECK_DT_REG'
176 | CHECK_DT_REG(ficr, NRF_FICR);
| ^~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:102:25: error: expression in static assertion is not an integer
102 | (DT_REG_ADDR(DT_NODELABEL(lbl)) == (uint32_t)(mdk_addr))))
| ^
C:/ncs/v2.7.0/zephyr/include/zephyr/toolchain/gcc.h:87:51: note: in definition of macro 'BUILD_ASSERT'
87 | #define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG)
| ^~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:69:53: note: in expansion of macro '__DEBRACKET'
69 | #define __GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET val
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:64:9: note: in expansion of macro '__GET_ARG2_DEBRACKET'
64 | __GET_ARG2_DEBRACKET(one_or_two_args _if_code, _else_code)
| ^~~~~~~~~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:59:9: note: in expansion of macro '__COND_CODE'
59 | __COND_CODE(_XXXX##_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:180:9: note: in expansion of macro 'Z_COND_CODE_1'
180 | Z_COND_CODE_1(_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:378:23: note: in expansion of macro 'COND_CODE_1'
378 | #define UTIL_OR(a, b) COND_CODE_1(UTIL_BOOL(a), (a), (b))
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:101:17: note: in expansion of macro 'UTIL_OR'
101 | UTIL_OR(UTIL_NOT(DT_REG_HAS_IDX(DT_NODELABEL(lbl), 0)), \
| ^~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:176:1: note: in expansion of macro 'CHECK_DT_REG'
176 | CHECK_DT_REG(ficr, NRF_FICR);
| ^~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:275:19: error: 'NRF_SPU' undeclared here (not in a function); did you mean 'NRF_FPU'?
275 | CHECK_DT_REG(spu, NRF_SPU);
| ^~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/toolchain/gcc.h:87:51: note: in definition of macro 'BUILD_ASSERT'
87 | #define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG)
| ^~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:69:53: note: in expansion of macro '__DEBRACKET'
69 | #define __GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET val
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:64:9: note: in expansion of macro '__GET_ARG2_DEBRACKET'
64 | __GET_ARG2_DEBRACKET(one_or_two_args _if_code, _else_code)
| ^~~~~~~~~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:59:9: note: in expansion of macro '__COND_CODE'
59 | __COND_CODE(_XXXX##_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:180:9: note: in expansion of macro 'Z_COND_CODE_1'
180 | Z_COND_CODE_1(_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:378:23: note: in expansion of macro 'COND_CODE_1'
378 | #define UTIL_OR(a, b) COND_CODE_1(UTIL_BOOL(a), (a), (b))
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:101:17: note: in expansion of macro 'UTIL_OR'
101 | UTIL_OR(UTIL_NOT(DT_REG_HAS_IDX(DT_NODELABEL(lbl), 0)), \
| ^~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:275:1: note: in expansion of macro 'CHECK_DT_REG'
275 | CHECK_DT_REG(spu, NRF_SPU);
| ^~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:102:25: error: expression in static assertion is not an integer
102 | (DT_REG_ADDR(DT_NODELABEL(lbl)) == (uint32_t)(mdk_addr))))
| ^
C:/ncs/v2.7.0/zephyr/include/zephyr/toolchain/gcc.h:87:51: note: in definition of macro 'BUILD_ASSERT'
87 | #define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG)
| ^~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:69:53: note: in expansion of macro '__DEBRACKET'
69 | #define __GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET val
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:64:9: note: in expansion of macro '__GET_ARG2_DEBRACKET'
64 | __GET_ARG2_DEBRACKET(one_or_two_args _if_code, _else_code)
| ^~~~~~~~~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:59:9: note: in expansion of macro '__COND_CODE'
59 | __COND_CODE(_XXXX##_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:180:9: note: in expansion of macro 'Z_COND_CODE_1'
180 | Z_COND_CODE_1(_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:378:23: note: in expansion of macro 'COND_CODE_1'
378 | #define UTIL_OR(a, b) COND_CODE_1(UTIL_BOOL(a), (a), (b))
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:101:17: note: in expansion of macro 'UTIL_OR'
101 | UTIL_OR(UTIL_NOT(DT_REG_HAS_IDX(DT_NODELABEL(lbl), 0)), \
| ^~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:275:1: note: in expansion of macro 'CHECK_DT_REG'
275 | CHECK_DT_REG(spu, NRF_SPU);
| ^~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:326:20: error: 'NRF_UICR' undeclared here (not in a function); did you mean 'NRF_UICR_S'?
326 | CHECK_DT_REG(uicr, NRF_UICR);
| ^~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/toolchain/gcc.h:87:51: note: in definition of macro 'BUILD_ASSERT'
87 | #define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG)
| ^~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:69:53: note: in expansion of macro '__DEBRACKET'
69 | #define __GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET val
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:64:9: note: in expansion of macro '__GET_ARG2_DEBRACKET'
64 | __GET_ARG2_DEBRACKET(one_or_two_args _if_code, _else_code)
| ^~~~~~~~~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:59:9: note: in expansion of macro '__COND_CODE'
59 | __COND_CODE(_XXXX##_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:180:9: note: in expansion of macro 'Z_COND_CODE_1'
180 | Z_COND_CODE_1(_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:378:23: note: in expansion of macro 'COND_CODE_1'
378 | #define UTIL_OR(a, b) COND_CODE_1(UTIL_BOOL(a), (a), (b))
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:101:17: note: in expansion of macro 'UTIL_OR'
101 | UTIL_OR(UTIL_NOT(DT_REG_HAS_IDX(DT_NODELABEL(lbl), 0)), \
| ^~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:326:1: note: in expansion of macro 'CHECK_DT_REG'
326 | CHECK_DT_REG(uicr, NRF_UICR);
| ^~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:102:25: error: expression in static assertion is not an integer
102 | (DT_REG_ADDR(DT_NODELABEL(lbl)) == (uint32_t)(mdk_addr))))
| ^
C:/ncs/v2.7.0/zephyr/include/zephyr/toolchain/gcc.h:87:51: note: in definition of macro 'BUILD_ASSERT'
87 | #define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG)
| ^~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:69:53: note: in expansion of macro '__DEBRACKET'
69 | #define __GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET val
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:64:9: note: in expansion of macro '__GET_ARG2_DEBRACKET'
64 | __GET_ARG2_DEBRACKET(one_or_two_args _if_code, _else_code)
| ^~~~~~~~~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_internal.h:59:9: note: in expansion of macro '__COND_CODE'
59 | __COND_CODE(_XXXX##_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:180:9: note: in expansion of macro 'Z_COND_CODE_1'
180 | Z_COND_CODE_1(_flag, _if_1_code, _else_code)
| ^~~~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/include/zephyr/sys/util_macro.h:378:23: note: in expansion of macro 'COND_CODE_1'
378 | #define UTIL_OR(a, b) COND_CODE_1(UTIL_BOOL(a), (a), (b))
| ^~~~~~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:101:17: note: in expansion of macro 'UTIL_OR'
101 | UTIL_OR(UTIL_NOT(DT_REG_HAS_IDX(DT_NODELABEL(lbl), 0)), \
| ^~~~~~~
C:/ncs/v2.7.0/zephyr/soc/nordic/validate_base_addresses.c:326:1: note: in expansion of macro 'CHECK_DT_REG'
326 | CHECK_DT_REG(uicr, NRF_UICR);
| ^~~~~~~~~~~~

 Are there any examples of how to apply readout flash protection in nrf9160 ns builds?

Best regards, Valerii

Parents Reply Children
  • Hi,

    no, I'm using "Build system default" in the build configuration (I assume in the v2.7.0 SDK and toolchain this means usage of an older "Multi-image build" approach with parent and child images).

    Best regards, Valerii

  • valerii7 said:
    no, I'm using "Build system default" in the build configuration (I assume in the v2.7.0 SDK and toolchain this means usage of an older "Multi-image build" approach with parent and child images).

    I have experienced that it can vary. I recommend explicitly selecting either with or without sysbuild. This way you will know for sure and we wont have to guess.

    Anyhow, for Multi-image builds:

    valerii7 said:
    2) I want to protect my bootloader from read/write over SWD interface, I also would like to protect my application in the same way;

    Let us start by protecting the bootloader.

    Then set CONFIG_FPROTECT in child_image/mcuboot.conf only.

    Does this work as expected?

  • Not completely, it fails with the same CMake error if I add only CONFIG_FPROTECT in child_image/mcuboot.conf But if I also add CONFIG_NORDIC_SECURITY_BACKEND it will compile ok.

  • valerii7 said:
    Not completely, it fails with the same CMake error if I add only CONFIG_FPROTECT in child_image/mcuboot.conf But if I also add CONFIG_NORDIC_SECURITY_BACKEND it will compile ok.

    I guess that makes sense.

    Nice, then we got protection the bootloader it seems.

    My research showed that the device tree for NS board has no SPU, ficr and uicr peripherals (why??). And if I try to add these peripherals in a device tree overlay file I get following compilation errors:

    With TF-M (_ns), your application is split in two:

    NSPE and SPE. See  An Introduction to Trusted Firmware-M (TF-M) .

    Your Zephyr application is NSPE, while the SPE has access to the SPU. I guess that the same would be true for FICR and UICR as well.  This is why the application cannot access the SPU.

    To use FPROTECT from TF-M, you can for an custom secure service. See the TF-M secure peripheral partition sample for how this can be done. This does not support Zephyr, so you would have to use nrfx libraries directly to write to the SPU.

    Did this make sense?

  • Ok, thank you for the answers. I have a couple more questions now:

    1) MCUBOOT with activated FPROTECT will do only write protection, I'm curious, why not both read and write? Is there any reason not to protect the bootloader from reading as well?

    2) "... This is why the application cannot access the SPU... " - that's a bit confusing, AFAIK MCUBOOT also belongs to NSPE but still has access to SPU. So why it works for mcuboot, but doesn't work for the app?

    3) "you would have to use nrfx libraries directly to write to the SPU." - do I understand this correctly, that the proposed solution is basically to use SPU registers "directly", without involving device tree and FPROTECT library?

    4) one more question - would it be possible to program protection mode over SWD, without bootloader/app code? Something like in STM32 where read/write flash protection can be enabled without any dedicated code, only through a JTAG/SWD. If yes, what would be the tool/command for that?

    Best regards, Valerii

Related