.. _west_atmotp-tool: Atmosic OTP Tool ################ ========================== Building with Secure Debug ========================== Secure Debug is a collection of hardware and software features to limit access to the debug port for devices in production. It is not intended to be used in development because once security measures are enabled many steps in the normal development flow will no longer function. ===================== Managing the OTP bits ===================== At a hardware level, the debug security state at power-on is defined by two OTP bits (``ATM_OTP_MASK_SEC_DBG_DEBUG_SECURED`` and ``ATM_OTP_MASK_SEC_DBG_DEBUG_DISABLED``). Hardware applies the debug security state prior to the CPU booting. No intervention is required by software to enforce the security state. When secure debug is either SECURED or DISABLED, access through SWD is disallowed even if benign boot is enabled. When the port is SECURED (rather than DISABLED), the state can be cleared by software after a software challenge to prove the identity of the debug access requester. The authenticator is implemented in the MCUboot image that monitors a UART console port. To check the state of the OTP bits, users can use the atmotp west extension by issuing the following command:: west atmotp get --board --device --otp SEC_DBG_CONFIG.DEBUG_DISABLED <--jlink or --dl> or:: west atmotp get --board --device --otp SEC_DBG_CONFIG.DEBUG_SECURED <--jlink or --dl> To completely disable secure debug, users can issue the following command (this is irreversible):: west atmotp burn --board --device --otp SEC_DBG_CONFIG.DEBUG_DISABLED <--jlink or --dl> To enable secure debug, users can issue the following command:: west atmotp burn --board --device --otp SEC_DBG_CONFIG.DEBUG_SECURED <--jlink or --dl> The authenticator software component runs during the boot sequence of MCUboot. Secure debug is not accessible in Non-MCUboot builds. If no authentication occurs, the software will sticky lock the debug port until reset. A Python script is provided to demonstrate communications with the MCUboot authenticator to unlock the debug port. The challenge/authentication process must be performed on each boot. The challenge consists of a unique hash of per-device data stored in the secure journal. This is computed by the MCUboot image and provided as a base64 encoded text output on the UART console port. The hash will be unique for each manufactured device. The challenge must be signed with the private ECDSA key and the resulting signature provided back to the authenticator to verify it using its local public ECDSA key. The signature is unique for the device and can be used for every challenge response. The ``atmotp`` west extension can also be used to inspect and configure other OTP bits. Use ``list_otp`` to display the OTP definitions supported by the target platform:: west atmotp list_otp --board --device <--jlink or --dl> The output includes the absolute bit index for each OTP definition. A definition that spans multiple bits is shown as a range. The ``get`` command returns the value of a definition or of an individual bit, while ``burn`` programs one bit at a time. Every definition shown by ``list_otp`` is supported by the selected platform's OTP map. OTP programming is irreversible; check the current value before burning a bit. Use ``dump`` to read and display the complete OTP contents, including the raw OTP value and the value of every definition:: west atmotp dump --board --device <--jlink or --dl> The ``--otp`` argument accepted by ``get`` and ``burn`` supports the following addressing forms: * An absolute bit index, such as ``23`` * A definition followed by a relative bit index, such as ``BATT_TYPE_LATCH.0`` * A definition followed by a named sub-field, such as ``SEC_DBG_CONFIG.DEBUG_SECURED`` For example, read an absolute bit or a named sub-field with:: west atmotp get --board --device --otp 23 <--jlink or --dl> west atmotp get --board --device --otp SEC_DBG_CONFIG.DEBUG_SECURED <--jlink or --dl> Reading a multi-bit definition without a suffix returns the complete value. A multi-bit definition cannot be burned as a whole; specify its relative index or named sub-field instead. The ``burn`` command displays the current and new values, then asks for confirmation. Enter ``yes`` to program the bit or ``no`` to cancel. An already-programmed bit is rejected and cannot be re-burned. For example:: west atmotp burn --board --device --otp 23 <--jlink or --dl> west atmotp burn --board --device --otp SEC_DBG_CONFIG.DEBUG_SECURED <--jlink or --dl> All subcommands require a board and device. Use ``--jlink`` for a J-Link connection or ``--dl`` for a DL board. If a non-default OpenOCD configuration is needed, provide it with ``--openocd_config``:: west atmotp get --board --device --otp 23 --openocd_config <--jlink or --dl> ------------------------------- Platform OTP Bit Definitions ------------------------------- The OTP bit definitions below are taken from the following ``atm_otp.tcl`` OpenOCD configurations: * ATM33xx-5: ``modules/hal_atmosic/ATM33xx-5/openocd/atm_otp.tcl`` * ATM34xx-rev-5: ``modules/hal_atmosic/ATM34xx/rev-5/openocd/atm_otp.tcl`` * ATM5xxx-rev-2: ``modules/hal_atmosic/ATM5xxx/rev-2/openocd/atm_otp.tcl`` The three platforms use the same bit positions for the brownout-related definitions: .. list-table:: Common OTP definitions :header-rows: 1 :widths: 35 20 * - OTP definition - Absolute bit(s) * - ``NABG_TRIM_LATCH`` - 0-8 * - ``USE_LDO_LATCH`` - 9 * - ``DISABLE_CHPU_LATCH`` - 10 * - ``HARV_DISABLED_LATCH`` - 11 * - ``RECT_CTUNE_LATCH`` - 12-14 * - ``INTERNAL_SPARE_LATCH`` - 15-18 * - ``DISABLE_XTAL32K_LATCH`` - 19 * - ``NOIND_LATCH`` - 20 * - ``DISABLE_VDDIOGEN_LATCH`` - 21 * - ``DISABLE_VDDGEN_LATCH`` - 22 * - ``DISABLE_5V_LATCH`` - 23 * - ``VBATT_LEVEL_LATCH`` - 24 * - ``BATT_TYPE_LATCH`` - 25-26 * - ``VBATT_GOOD_LATCH`` - 27-29 * - ``VBATT_BROWNOUT_LATCH`` - 30-36 * - ``MPPT_TYPE_LATCH`` - 37-38 * - ``DISABLE_RFHARV_LATCH`` - 39 * - ``VHARV_START_LATCH`` - 40-41 * - ``VSTORE_GOOD_LATCH`` - 42-43 * - ``VSTORE_MAX_LATCH`` - 44-46 * - ``RRAM_WRITE_LOCK`` - 48-54 * - ``SEC_DBG_CONFIG`` - 60-61 * - ``RRAM_JTAG_BYPASS`` - 62 The platform-specific definitions are: .. list-table:: Platform-specific OTP definitions :header-rows: 1 :widths: 15 28 28 28 * - Absolute bit(s) - ATM33xx-5 - ATM34xx-rev-5 - ATM5xxx-rev-2 * - 47 - ``SPARE_LATCH`` - No named definition - ``SPARE_LATCH`` * - 55 - ``SPARE_2_LATCH`` - No named definition - ``SPARE_2_LATCH`` * - 56 - Part of ``RESERVED_1`` - ``UART1_RX_DISABLE`` - Part of ``RESERVED_1`` * - 57-59 - ``RESERVED_1`` - No named definition - ``RESERVED_1`` An unlisted bit position has no named definition in that platform's OpenOCD OTP configuration. Run ``list_otp`` for the selected board before using a definition, because the output is platform-specific and can depend on the installed SDK version. The ``SPARE`` and ``RESERVED`` entries are included for map completeness; do not program them unless instructed by the applicable hardware specification. On all three platforms, ``VBATT_LEVEL_LATCH`` and ``BATT_TYPE_LATCH`` affect the brownout voltage calculation: * ``VBATT_LEVEL_LATCH`` is a one-bit field at absolute bit 24. A value of ``0`` selects a battery level of 1.8 V or less; a value of ``1`` selects a battery level above 1.8 V. * ``BATT_TYPE_LATCH`` is a two-bit field at absolute bits 25-26. Its value is ``1`` for a rechargeable battery and ``3`` for a non-rechargeable battery. For example, read the two fields with:: west atmotp get --board --device --otp VBATT_LEVEL_LATCH <--jlink or --dl> west atmotp get --board --device --otp BATT_TYPE_LATCH <--jlink or --dl> For a multi-bit definition, the suffix after the period is a zero-based index relative to the definition. For ``BATT_TYPE_LATCH``, ``.0`` addresses absolute bit 25 and ``.1`` addresses absolute bit 26. A multi-bit definition cannot be burned as a whole; specify one relative index for each bit. The following commands show how to address both bits:: west atmotp burn --board --device --otp VBATT_LEVEL_LATCH <--jlink or --dl> west atmotp burn --board --device --otp BATT_TYPE_LATCH.0 <--jlink or --dl> west atmotp burn --board --device --otp BATT_TYPE_LATCH.1 <--jlink or --dl> Burn ``BATT_TYPE_LATCH.0`` only to produce a value of ``01`` (decimal ``1``), or burn ``BATT_TYPE_LATCH.1`` only to produce ``10`` (decimal ``2``). Burn both bits to produce ``11`` (decimal ``3``). Only values defined for the target platform and battery configuration should be programmed. Because OTP bits can only change from 0 to 1, read the current value and plan the desired two-bit value before programming; burning a bit cannot be undone. The brownout-related multi-bit definitions, such as ``VBATT_GOOD_LATCH`` and ``VBATT_BROWNOUT_LATCH``, can be inspected in the same way. Use the complete definition with ``get`` to read its value, or append ``.0``, ``.1``, and so on to read or burn one bit. Refer to the brownout configuration documentation for the voltage represented by each field value. ``RRAM_WRITE_LOCK`` is another seven-bit definition in the OpenOCD map. Its named sub-fields are ``BOOT_BLOCK_0``, ``BOOT_BLOCK_1``, ``BOOT_BLOCK_2``, ``BOOT_BLOCK_3``, ``PROTECTED_DATA``, ``SECURE_COUNTERS``, and ``PRIVATE_KEY_STORAGE`` at absolute bits 48-54. If the selected platform's ``list_otp`` output exposes these named sub-fields, one sub-field can be programmed with:: west atmotp burn --board --device --otp RRAM_WRITE_LOCK.PROTECTED_DATA <--jlink or --dl> ``SEC_DBG_CONFIG`` also has the named sub-fields ``DEBUG_DISABLED`` at bit 60 and ``DEBUG_SECURED`` at bit 61, as shown by the Secure Debug examples above. ----------------------------------- Compiling MCUboot with Secure Debug ----------------------------------- To build with secure debug, add the following additional flags:: -DCONFIG_ATM_MCUBOOT_SECURE_DEBUG=y -DDTS_EXTRA_CPPFLAGS="-DUSE_ATM_SECURE_DEBUG" The DTS option ``-DUSE_ATM_SECURE_DEBUG`` will enable UART0 as a bi-directional console port for authentication use. The MCUboot extension for secure debug will use a default private ECC-P256 key to generate the public ECC-P256 key stored in the image. This is a widely distributed key and should not be used in production. At this time the authenticator implements a 500ms default timeout through ``CONFIG_ATM_MCUBOOT_UART_DEBUG_AUTH_TIMEOUT_MS`` while monitoring the console port for characters. You can adjust as needed ``-DCONFIG_ATM_MCUBOOT_UART_DEBUG_AUTH_TIMEOUT_MS=`` to extend the timeout. A future update will support monitoring the UART RX pin for a logic high state to detect the presence of a host UART connection. ----------------------------- Using the Debug Unlock Script ----------------------------- A debug unlock Python script is provided in ``openair/tools/scripts/sec_debug_unlock.py``. This tool requires PySerial. :: python sec_debug_unlock.py -v -k -p To unlock using the default private key in ``openair/lib/atm_debug_auth/`` :: python sec_debug_unlock.py -v -k openair/lib/atm_debug_auth/root-debug-ec-p256.pem -p The unlocking script using the ``-v`` option will verbosely output:: Sending: b'DBG REQUEST\n' Received: b'Static Challenge: o9H3wvgqOfAi/mvTV/qvvdNjBqzGILIai3G4OBURjhE=\n' Unlock Static Challenge Sending: b'DBG STATIC_RESPONSE sMdx+QFewpAt3Dnqy9BrjSLNxgtObtu3IKhSvpuvbG7J9IClpt/zJL4XRlo9rt7KCCw6orjUIyBdaWWM657aRw==\n' Received: b'Debug unlocked\n' The SWD port will be unlocked and MCUboot will remain in a benign state with the processor halted at a WFI instruction (Wait For Interrupt). The developer can freely attach a debugger such as GDB and inspect the target (read memory, set breakpoints). If the debugger allows the CPU to continue then MCUboot will continue its boot from the point at which WFI was entered.