Skip to content

Commit

Permalink
flash/stm32h5: add product state transition (Open to Close or Locked)
Browse files Browse the repository at this point in the history
add all possible transition for STM32 product state for H5:
* Open to Provisioning
* Write key in OBK area using RSS_Lib function.
* Provisioning to TZclosed.
* Provisioning or TZclosed to Closed or Locked.

Signed-off-by: bouzazif <[email protected]>
Reviewed-by: Tarek BOCHKATI <[email protected]>
  • Loading branch information
FBOSTM authored and tarek-bochkati committed Dec 3, 2024
1 parent b3fe75f commit 0de861e
Show file tree
Hide file tree
Showing 2 changed files with 286 additions and 11 deletions.
190 changes: 189 additions & 1 deletion src/flash/nor/stm32h5x.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
#include "imp.h"
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/breakpoints.h>
#include <target/cortex_m.h>
#include <target/arm_adi_v5.h>
#include "stm32h5x.h"

#include <target/image.h>

enum stm32h5x_bank_id {
STM32_BANK1 = 1,
Expand Down Expand Up @@ -58,6 +59,14 @@ static const char *stm32h5x_product_state_str(enum stm32h5x_pstate pstate)
return "Unknown";
}

struct rsslib_data_provisioning_conf {
uint32_t p_source; /* Address of the Data to be provisioned, shall be in SRAM3 */
uint32_t p_destination; /* Address in OBKeys sections where to provision Data */
uint32_t size; /* Size in bytes of the Data to be provisioned */
uint32_t do_encryption; /* Notifies RSSLIB_DataProvisioning to encrypt or not Data */
uint32_t crc; /* CRC over full Data buffer and previous field in the structure */
};

enum stm32h5x_tzen {
TZEN_DISABLED = 0xC3,
TZEN_ENABLED = 0xB4
Expand Down Expand Up @@ -92,6 +101,7 @@ struct stm32h5x_flash_bank {
enum stm32h5x_pstate pstate;
enum stm32h5x_tzen tzen;
uint32_t optsr_cur, optsr2_cur; /* options cache to trigger re-probing */
uint32_t available_rm_addr, rss_lib_addr;
};

/* Human readable list of families this drivers supports (sorted alphabetically) */
Expand Down Expand Up @@ -207,6 +217,23 @@ static const uint32_t stm32h5x_s_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
[STM32_FLASH_WRP2_PRG_INDEX] = 0x1EC,
};

uint32_t crc32_func(uint32_t *buff, size_t len)
{
uint32_t crc = 0xFFFFFFFF;
const uint32_t poly = 0x04C11DB7U;
for (size_t i = 0; i < len; i++) {
crc ^= buff[i];
for (size_t j = 0; j < 32; j++) {
if (crc & 0x80000000)
crc = (crc << 1) ^ poly;
else
crc <<= 1;
}
}

return crc;
}

/* Usage: flash bank stm32h5x <base> <size> 0 0 <target#> */
FLASH_BANK_COMMAND_HANDLER(stm32h5x_flash_bank_command)
{
Expand Down Expand Up @@ -1365,6 +1392,152 @@ COMMAND_HANDLER(stm32h5x_handle_option_load_command)
return ERROR_FLASH_OPER_UNSUPPORTED;
}

COMMAND_HANDLER(stm32h5x_write_obk)
{
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (retval != ERROR_OK)
return retval;
struct target *target = bank->target;
struct armv7m_algorithm armv7m_info = {
.common_magic = ARMV7M_COMMON_MAGIC,
.core_mode = ARM_MODE_THREAD
};
struct stm32h5x_flash_bank *stm32h5x_bank = bank->driver_priv;
if (CMD_ARGC < 2)
return ERROR_COMMAND_SYNTAX_ERROR;

/* open file in binary mode */
FILE *fp = fopen(CMD_ARGV[1], "rb");
if (!fp) {
LOG_ERROR("Error opening file\n");
return ERROR_FAIL;
}

/* read 12 bytes from file into buffer */
uint32_t buffer[3];
if (fread(buffer, sizeof(uint32_t), 3, fp) != 3) {
LOG_ERROR("Error Reading Cert info");
return ERROR_FAIL;
}

if (!stm32h5x_bank->available_rm_addr) {
LOG_ERROR("You should enter an available ram addr using write_obk_options command");
return ERROR_FAIL;
}

if (!stm32h5x_bank->rss_lib_addr) {
LOG_ERROR("You should enter the addr of Rss_lib_privisioning function using write_obk_options command");
return ERROR_FAIL;
}

struct rsslib_data_provisioning_conf pconf = {
.p_source = stm32h5x_bank->available_rm_addr + 0x18,
.p_destination = buffer[0], /* extract the first 32 bits into pDestination (OBK area) */
.size = buffer[1], /* extract the second 32 bits into Size (Size of data to be provisioned) */
.do_encryption = buffer[2] == 1 ? 0xF5F5A0AA : 0xCACA0AA0, /* extract the third 32 bits
(1 : do encryption else do not encrypt data) */
.crc = 0 /* will be computed later */
};

uint8_t *data = malloc(pconf.size);
if (fread(data, sizeof(uint32_t), pconf.size / 4, fp) != pconf.size / 4) {
LOG_ERROR("Can't read certfication data");
free(data);
return ERROR_FAIL;
}
fclose(fp); /* close the file */

/* reorganize the certification to calculate the CRC */
uint8_t *crc_buffer = malloc(12 + pconf.size);
memcpy(crc_buffer, data, pconf.size);
memcpy(crc_buffer + pconf.size, &pconf.p_destination, 4);
memcpy(crc_buffer + pconf.size + 4, &pconf.size, 4);
memcpy(crc_buffer + pconf.size + 8, &pconf.do_encryption, 4);
uint32_t crc_buffer32[(12 + pconf.size) / 4];
memcpy(crc_buffer32, crc_buffer, (12 + pconf.size));
pconf.crc = crc32_func(crc_buffer32, (12 + pconf.size) / 4);

retval = target_write_buffer(target, pconf.p_source, pconf.size, data);
if (retval != ERROR_OK) {
LOG_ERROR("Can't write certification data in RAM");
free(data);
free(crc_buffer);
return retval;
}

const uint32_t return_addr = stm32h5x_bank->available_rm_addr;
target_write_u32(target, stm32h5x_bank->available_rm_addr + 0x4, stm32h5x_bank->available_rm_addr + 0x18);
target_write_u32(target, stm32h5x_bank->available_rm_addr + 0x8, pconf.p_destination);
target_write_u32(target, stm32h5x_bank->available_rm_addr + 0xC, pconf.size);
target_write_u32(target, stm32h5x_bank->available_rm_addr + 0x10, pconf.do_encryption);
target_write_u32(target, stm32h5x_bank->available_rm_addr + 0x14, pconf.crc);

/* write function parameters */
struct reg_param reg_params[3];
init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
init_reg_param(&reg_params[2], "lr", 32, PARAM_OUT);
buf_set_u32(reg_params[2].value, 0, 32, return_addr | 0x1);

buf_set_u32(reg_params[0].value, 0, 32, stm32h5x_bank->available_rm_addr + 0x4);

breakpoint_add(target, return_addr, 2, BKPT_SOFT);
retval = target_run_algorithm(target,
0, NULL,
ARRAY_SIZE(reg_params), reg_params,
stm32h5x_bank->rss_lib_addr,
return_addr, 10000, &armv7m_info);
breakpoint_remove(target, return_addr);
if (retval != ERROR_OK) {
LOG_ERROR("Error running RSS_Lib_Provisioning function");
free(data);
free(crc_buffer);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
return retval;
}
uint32_t returned_res = buf_get_u32(reg_params[0].value, 0, 32);
LOG_DEBUG("RSSLIB_DataProvisioning returned 0x%" PRIx32 "", returned_res);

if (returned_res == 0xEAEAEAEA)
LOG_INFO("RSSLIB_DataProvisioning executed successfully");
else if (returned_res == 0xF5F5E0E0)
LOG_ERROR(" Error: provided RAM addr is not in SRAM3, "
"obk addr is not aligned on 16 bytes, "
"privisioned data does not fit within an OBKey section");
else
LOG_ERROR("Error executing RSS_Lib_Provisioning function");

/* free allocation */
free(crc_buffer);
free(data);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);

return ERROR_OK;
}

COMMAND_HANDLER(stm32h5x_write_obk_options)
{
if (CMD_ARGC < 2) {
command_print(CMD, "stm32hx obk_options <Available_Ram_addr> <RSS_Lib_Provisioning addr>");
return ERROR_COMMAND_SYNTAX_ERROR;
}
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (retval != ERROR_OK)
return retval;
struct stm32h5x_flash_bank *stm32h5x_bank = bank->driver_priv;

COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], stm32h5x_bank->available_rm_addr);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], stm32h5x_bank->rss_lib_addr);

return ERROR_OK;
}

static const struct command_registration stm32h5x_exec_command_handlers[] = {
{
.name = "mass_erase",
Expand Down Expand Up @@ -1401,6 +1574,21 @@ static const struct command_registration stm32h5x_exec_command_handlers[] = {
.usage = "bank_id",
.help = "Force re-load of device options (will cause device reset).",
},
{
.name = "write_obk",
.handler = stm32h5x_write_obk,
.mode = COMMAND_EXEC,
.usage = "bank_id <path/to/cert>",
.help = "program data in OBKey-area",
},
{
.name = "write_obk_options",
.handler = stm32h5x_write_obk_options,
.mode = COMMAND_EXEC,
.usage = "bank_id Available_RAM_addr RSSLIB_DataProvisioning address",
.help = "provide Available RAM address and RSSLIB_DataProvisioning address"
" before write on obk area",
},
COMMAND_REGISTRATION_DONE
};

Expand Down
107 changes: 97 additions & 10 deletions tcl/target/stm32h5x.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,19 @@
#
# stm32h5 devices support both JTAG and SWD transports.
#

source [find target/swj-dp.tcl]
source [find mem_helper.tcl]

set PSTATE_OPEN 0xED
set PSTATE_PROVISIONING 0x17
set PSTATE_IROT_PROVISIONED 0x2E
set PSTATE_TZ_CLOSED 0xC6
set PSTATE_CLOSED 0x72
set PSTATE_LOCKED 0x5C
set PSTATE_REGRESSION 0x9A
set PSTATE_NS_REGRESSION 0xA3

if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
Expand All @@ -17,11 +27,11 @@ if { [info exists CHIPNAME] } {
set _ENDIAN little

# Work-area is a space in RAM used for flash programming
# By default use 16kB at address 0x20000000
# By default use 32kB at address 0x20000000
if { [info exists WORKAREASIZE] } {
set _WORKAREASIZE $WORKAREASIZE
} else {
set _WORKAREASIZE 0x4000
set _WORKAREASIZE 0x8000
}

if { [info exists WORKAREAADDR] } {
Expand Down Expand Up @@ -165,14 +175,14 @@ proc stm32h5x_enter_debug {} {
# read product state
set pstate [expr {($optsr >> 8) & 0xFF}]

set PSATE_OPEN 0xED
set PSTATE_PROVISIONING 0x17
set PSTATE_IROT_PROVISIONED 0x2E
set PSTATE_TZ_CLOSED 0xC6
set PSTATE_CLOSED 0x72
set PSTATE_LOCKED 0x5C
set PSTATE_REGRESSION 0x9A
set PSTATE_NS_REGRESSION 0xA3
global PSATE_OPEN
global PSTATE_PROVISIONING
global PSTATE_IROT_PROVISIONED
global PSTATE_TZ_CLOSED
global PSTATE_CLOSED
global PSTATE_LOCKED
global PSTATE_REGRESSION
global PSTATE_NS_REGRESSION

# ensure that workarea is correctly configured if there is a change in tz or pstate
global $_CHIPNAME.tz $_CHIPNAME.pstate
Expand Down Expand Up @@ -262,3 +272,80 @@ $_CHIPNAME.cpu configure -event trace-config {
# change this value accordingly to configure trace pins assignment
stm32h5x_mmw $_CHIPNAME.ap0 0xE0044004 0x00000030 0
}

proc get_pstate {} {
set optsr [mrw 0x40022050]
set pstate [expr {($optsr >> 8) & 0xFF}]
return $pstate
}

proc set_pstate {bank_id pstate} {
stm32h5x option_write $bank_id 0x54 [expr {$pstate << 8}] 0xFF00
}

proc enter_provisionning_pstate {bank_id crt_path} {
global PSTATE_OPEN
global PSTATE_PROVISIONING
set current_pstate [get_pstate]
if { $current_pstate != $PSTATE_OPEN } {
echo "Your current state should be OPEN to pass to PROVISIONING"
return 0
}
set_pstate $bank_id $PSTATE_PROVISIONING
reset
flash probe $bank_id
halt
stm32h5x write_obk $bank_id $crt_path
}

proc enter_tz_closed_pstate {bank_id} {
global PSTATE_PROVISIONING
global PSTATE_TZ_CLOSED
set optsr2 [mrw 0x40022070]
# read TrustZone state
set tzen [expr {($optsr2 >> 24) & 0xFF}]
set tz [expr {$tzen == 0xB4}]
set current_pstate [get_pstate]
if { $current_pstate != $PSTATE_PROVISIONING && $tz == 1 } {
echo "Your current state should be PROVESIONING and TZ enabled to pass to TZ_CLOSED"
return 0
}
set_pstate $bank_id $PSTATE_TZ_CLOSED
reset
flash probe $bank_id
}

proc enter_closed_pstate {bank_id} {
global PSTATE_PROVISIONING
global PSTATE_CLOSED
global PSTATE_TZ_CLOSED
set current_pstate [get_pstate]
if { $current_pstate != $PSTATE_PROVISIONING || $current_pstate != $PSTATE_TZ_CLOSED} {
echo "Your current state should be PROVESIONING or TZ_CLOSED to pass to CLOSED"
return 0
}
set_pstate $bank_id $PSTATE_CLOSED
reset
flash probe $bank_id
}

proc enter_locked_pstate {bank_id} {
global PSTATE_PROVISIONING
global PSTATE_LOCKED
global PSTATE_TZ_CLOSED
set current_pstate [get_pstate]
set input 0
while {$input ne 'Y' or $input ne 'N'} {
echo "Are you sure to enter LOCKED state? this state is irreversible (Y\N)"
set input [gets stdin]
if {$input eq 'N'}
return 0
}
if { $current_pstate != $PSTATE_PROVISIONING || $current_pstate != $PSTATE_TZ_CLOSED} {
echo "Your current state should be PROVESIONING or TZ_CLOSED to pass to CLOSED"
return 0
}
set_pstate $bank_id $PSTATE_LOCKED
reset
flash probe $bank_id
}

0 comments on commit 0de861e

Please sign in to comment.