From 879c08c9f17fb4681031412ec8c637d2de9dfe3b Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Wed, 5 Mar 2025 10:27:36 +0100 Subject: [PATCH] feat(core/prodtest): support writing device ID into OTP memory --- core/embed/models/otp_layout.h | 1 + .../projects/prodtest/.changelog.d/4735.added | 1 + core/embed/projects/prodtest/README.md | 34 ++++++++++++++ .../prodtest/cmd/prodtest_otp_batch.c | 46 +++++++++++++++---- 4 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 core/embed/projects/prodtest/.changelog.d/4735.added diff --git a/core/embed/models/otp_layout.h b/core/embed/models/otp_layout.h index 401fffc72c..4faa4d5c69 100644 --- a/core/embed/models/otp_layout.h +++ b/core/embed/models/otp_layout.h @@ -26,3 +26,4 @@ #define FLASH_OTP_BLOCK_RANDOMNESS 3 #define FLASH_OTP_BLOCK_DEVICE_VARIANT 4 #define FLASH_OTP_BLOCK_FIRMWARE_VERSION 5 +#define FLASH_OTP_BLOCK_DEVICE_ID 6 diff --git a/core/embed/projects/prodtest/.changelog.d/4735.added b/core/embed/projects/prodtest/.changelog.d/4735.added new file mode 100644 index 0000000000..5dc85b7489 --- /dev/null +++ b/core/embed/projects/prodtest/.changelog.d/4735.added @@ -0,0 +1 @@ +Added device ID write/read commands. diff --git a/core/embed/projects/prodtest/README.md b/core/embed/projects/prodtest/README.md index e94f0bc537..a45e615d61 100644 --- a/core/embed/projects/prodtest/README.md +++ b/core/embed/projects/prodtest/README.md @@ -469,6 +469,7 @@ If the OTP memory has not been written yet, it returns error code `no-data`. Example: ``` +otp-batch-read # Reading device OTP memory... # Bytes read: ERROR no-data "OTP block is empty." @@ -493,6 +494,39 @@ otp-batch-write T2B1-231231 --dry-run # Locking OTP block... ``` + +### otp-device-id-read +Retrieves the device ID string from the device's OTP memory. The device ID string is unique for each device. + +If the OTP memory has not been written yet, it returns error code `no-data`. + +Example: +``` +otp-device-id-read +# Reading device OTP memory... +# Bytes read: +ERROR no-data "OTP block is empty." +``` + +### otp-device-id-write +Writes the device ID string to the device's OTP memory. The device ID string is unique for each device. + +The batch string can be up to 31 characters in length. + +In non-production firmware, you must include `--execute` as the last parameter to write the data to the OTP memory. Conversely, in production firmware, you can use `--dry-run` as the last parameter to simulate the command without actually writing to the OTP memory. + +Example: +``` +otp-device-id-write 123456ABCD --dry-run +# +# !!! It's a dry run, OTP will be left unchanged. +# !!! Use '--execute' switch to write to OTP memory. +# +# Writing device batch info into OTP memory... +# Bytes written: 3132333435364142434400000000000000000000000000000000000000000000 +# Locking OTP block... +``` + ### otp-variant-write Writes up to 31 decimal values, each representing device variant options, to device's OTP memory. Each value must range from 0 to 255. diff --git a/core/embed/projects/prodtest/cmd/prodtest_otp_batch.c b/core/embed/projects/prodtest/cmd/prodtest_otp_batch.c index 4f0167393a..a762baa46d 100644 --- a/core/embed/projects/prodtest/cmd/prodtest_otp_batch.c +++ b/core/embed/projects/prodtest/cmd/prodtest_otp_batch.c @@ -23,7 +23,7 @@ #include #include -static void prodtest_otp_batch_read(cli_t* cli) { +static void prodtest_otp_read(cli_t* cli, uint8_t block_num) { if (cli_arg_count(cli) > 0) { cli_error_arg_count(cli); return; @@ -33,8 +33,7 @@ static void prodtest_otp_batch_read(cli_t* cli) { cli_trace(cli, "Reading device OTP memory..."); - if (sectrue != - flash_otp_read(FLASH_OTP_BLOCK_BATCH, 0, block, sizeof(block))) { + if (sectrue != flash_otp_read(block_num, 0, block, sizeof(block))) { cli_error(cli, CLI_ERROR, "Failed to read OTP memory."); return; } @@ -64,7 +63,7 @@ static void prodtest_otp_batch_read(cli_t* cli) { } } -static void prodtest_otp_batch_write(cli_t* cli) { +static void prodtest_otp_write(cli_t* cli, uint8_t block_num) { const char* data = cli_arg(cli, "text"); if (strlen(data) == 0 || strlen(data) > FLASH_OTP_BLOCK_SIZE - 1) { @@ -111,18 +110,17 @@ static void prodtest_otp_batch_write(cli_t* cli) { return; } - if (sectrue == flash_otp_is_locked(FLASH_OTP_BLOCK_BATCH)) { + if (sectrue == flash_otp_is_locked(block_num)) { cli_error(cli, CLI_ERROR_LOCKED, "OTP block is locked and cannot be written again."); return; } - cli_trace(cli, "Writing device batch info into OTP memory..."); + cli_trace(cli, "Writing info into OTP memory..."); cli_trace(cli, "Bytes written: %s", block_hex); if (!dry_run) { - if (sectrue != - flash_otp_write(FLASH_OTP_BLOCK_BATCH, 0, block, sizeof(block))) { + if (sectrue != flash_otp_write(block_num, 0, block, sizeof(block))) { cli_error(cli, CLI_ERROR, "Failed to write OTP block."); return; } @@ -131,7 +129,7 @@ static void prodtest_otp_batch_write(cli_t* cli) { cli_trace(cli, "Locking OTP block..."); if (!dry_run) { - if (sectrue != flash_otp_lock(FLASH_OTP_BLOCK_BATCH)) { + if (sectrue != flash_otp_lock(block_num)) { cli_error(cli, CLI_ERROR, "Failed to lock the OTP block."); return; } @@ -141,6 +139,22 @@ static void prodtest_otp_batch_write(cli_t* cli) { cli_ok(cli, ""); } +static void prodtest_otp_batch_read(cli_t* cli) { + prodtest_otp_read(cli, FLASH_OTP_BLOCK_BATCH); +} + +static void prodtest_otp_batch_write(cli_t* cli) { + prodtest_otp_write(cli, FLASH_OTP_BLOCK_BATCH); +} + +static void prodtest_otp_device_id_read(cli_t* cli) { + prodtest_otp_read(cli, FLASH_OTP_BLOCK_DEVICE_ID); +} + +static void prodtest_otp_device_id_write(cli_t* cli) { + prodtest_otp_write(cli, FLASH_OTP_BLOCK_DEVICE_ID); +} + // clang-format off PRODTEST_CLI_CMD( @@ -156,3 +170,17 @@ PRODTEST_CLI_CMD( .info = "Write the device batch info into OTP memory", .args = " [--execute | --dry-run]" ); + +PRODTEST_CLI_CMD( + .name = "otp-device-id-read", + .func = prodtest_otp_device_id_read, + .info = "Read the device ID from OTP memory", + .args = "" +); + +PRODTEST_CLI_CMD( + .name = "otp-device-id-write", + .func = prodtest_otp_device_id_write, + .info = "Write the device ID into OTP memory", + .args = " [--execute | --dry-run]" +);