cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H5: Getting the provisioned state from within the firmware

peter7
Associate II

Hello,

 

we are using a STM32H5 with TZ disabled. In firmware, we are doing the following:

- set the product state to provisioning (0x17)

- provision the debug authentication

This already works fine. Afterwards, we can do a discovery an see the validity of the DA ( we read 0xeaeaeaea). Regression afterwards works fine.

However, we would like to check this validity from within the firmware.

1) where does this 0xeaeaeaea comes from? Can we also access it?

2) reading back the storage area of the DA (0x0ffd0100) is not reliable. Sometimes, we can read the data we just wrote, sometime we just read 0xff... This depends on the code we execute after writing. It is not a timing issue, should we maybe set a certain flag or something like that?

 

The code we used is based on the github project https://github.com/stm32-hotspot/STM32H5_DA_EmbeddedProvisioning

 

Best regards

Peter

2 REPLIES 2
Jocelyn RICARD
ST Employee

Hello @peter7 ,

The 0xeaeaeaea code comes from STDA component that you activate when requesting a discovery.

This status is basically the result of the hash check done on DA OBK.

Regarding the reliability of writing the OBK from firmware, I have never seen any issue.

Especially, this is used by secure boot OEMiROT to write firmware hash and version.

What you see may be related to reading timing, I need to reproduce to understand what happens.

By the way, did you have any time a DA configuration written by firmware that couldn't be used to perform the regression ?

Best regards

Jocelyn

peter7
Associate II

Hello Jocelyn,

 

thanks for the reply. I'm doing the following in firmware:

  • Read the DA-storage area -> 0xFF...
  • Write DA-data -> ok
  • Read the DA-storage area -> 0xFF...
  • Reset
  • Read the DA-storage area -> provisioned data

Please see the attached code. During my tests, provisioning always works.

When I execute certain code between the writing and the reading, I can directly read back the provisioned data. This behaviour is reproducible, some intermediate code works, some does not, but I could not narrow it down to a certain instruction. I have the impression that a function call is needed, so maybe it has something to do with the accessing other memory banks.

 

We would like to close the device on the first start of the firmware. This requires provisioning, setting to provisioned, checking the provisioned state first. Obviously, we don't want to close a device, before we are sure the the provisioning was successful. 

The planned production process does not permit to do these steps with the flasher.

 

I'm hoping that you can help me figure out what to do to allow reading back without executing a reset.

 

/**********************************************************************************************************************/
/** Main function and initialization
 **********************************************************************************************************************/
#include "stm32h5xx_hal.h"
#include "main.h"

extern "C" int main(void);

/**********************************************************************************************************************/
static void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct {};
  RCC_ClkInitTypeDef RCC_ClkInitStruct {};

  /** Configure the main internal regulator output voltage */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Initializes the RCC Oscillators according to the specified parameters in the RCC_OscInitTypeDef structure. */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_PCLK3;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) {
    Error_Handler();
  }
}

/**********************************************************************************************************************/
static void MX_ICACHE_Init(void) {
  if (HAL_ICACHE_ConfigAssociativityMode(ICACHE_1WAY) != HAL_OK) {
    Error_Handler();
  }
  if (HAL_ICACHE_Enable() != HAL_OK) {
    Error_Handler();
  }
}

/**********************************************************************************************************************/
static void MX_GPIO_Init(void) {

  GPIO_InitTypeDef GPIO_InitStruct {};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();

  __HAL_RCC_USART3_CLK_ENABLE();

  /*Configure GPIO pins : PD8 PD9 */
  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  // Initialize UART
  UART_HandleTypeDef uartHandle;

  uartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

  uartHandle.Instance = USART3;
  uartHandle.Init.BaudRate = 1000000;
  uartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  uartHandle.Init.Mode = UART_MODE_TX;
  uartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
  uartHandle.Init.Parity = UART_PARITY_NONE;
  uartHandle.Init.StopBits = UART_STOPBITS_1;
  uartHandle.Init.WordLength = UART_WORDLENGTH_8B;
  uartHandle.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  uartHandle.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED;

  HAL_UART_Init(&uartHandle);
}

/**********************************************************************************************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
  if (htim->Instance == TIM3) {
    HAL_IncTick();
  }
}

/**********************************************************************************************************************/
void Error_Handler(void) {
  __disable_irq();
  while (1){}
}

/**********************************************************************************************************************/
static void PrintLn(uint8_t count, uint8_t * data) {
  for(uint8_t pos = 0; pos < count; pos++) {
    while((USART3->ISR & USART_ISR_TXE) == 0);
    USART3->TDR = data[pos];
  }
  while((USART3->ISR & USART_ISR_TXE) == 0);
  USART3->TDR = '\n';
}

/**********************************************************************************************************************/
static bool IsProvisioned() {
  if ((*(uint32_t *)(0x0FFD0100)) != 0xFFFFFFFF) {
    PrintLn(11,(uint8_t *)"provisioned");
    return true;
  }
  else {
    PrintLn(15,(uint8_t *)"not provisioned");
    return false;
  }
}

/**********************************************************************************************************************/
const unsigned char DA_Config[] = {

    // addr
    0x00, 0x01, 0xfd, 0x0f,
    // size
    0x60, 0x00, 0x00, 0x00,
    // enc
    0x00, 0x00, 0x00, 0x00,
    // integrity
    0x42, 0x09, 0x02, 0x43,
    0x9c, 0x31, 0x95, 0x3b, 0x6a, 0x8b, 0xff, 0xdd,   0xab, 0x06, 0x19, 0x95, 0x81, 0x29, 0xe2, 0xb5,
    0x2c, 0x51, 0xb0, 0x0f, 0x13, 0x91, 0x27, 0x4c,   0xe7, 0xdd, 0xb3, 0x53,

    // sha256
    0x18, 0x4a, 0xa4, 0x6d,
    0x81, 0x34, 0x11, 0x72, 0x7d, 0xa0, 0xdc, 0x9e,   0x64, 0x18, 0x6b, 0xb9, 0x90, 0x72, 0x89, 0xb5,
    0xaa, 0xb4, 0xb3, 0x20, 0xd2, 0x6f, 0xff, 0x5e,   0xa4, 0x5d, 0x8e, 0x3d,
    // perm
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    // reserved
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

/**********************************************************************************************************************/
static void OBKProvisioning_ProvisionDA(void) {
  __HAL_RCC_SBS_CLK_ENABLE();

  /* Unlock  Flash area */
  (void) HAL_FLASH_Unlock();
  (void) HAL_FLASHEx_OBK_Unlock();

  /* Force use of EPOCH_S value for DHUK */
  WRITE_REG(SBS_S->EPOCHSELCR, (1U << SBS_EPOCHSELCR_EPOCH_SEL_Pos));

  /* Erase OBKeys */
  FLASH_EraseInitTypeDef FLASH_EraseInitStruct = {0U};
  uint32_t sector_error = 0U;
  FLASH_EraseInitStruct.TypeErase = FLASH_TYPEERASE_OBK_ALT;
  if (HAL_FLASHEx_Erase(&FLASH_EraseInitStruct, &sector_error) != HAL_OK) {
    PrintLn(11, (uint8_t *)"Error Erase");
  }

  /* Program OBKeys */
  for (uint32_t i = 0U; i < 0x60; i += 16) {
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD_OBK_ALT, (0x0FFD0100 + i), ((uint32_t)&(DA_Config[12 + i]))) != HAL_OK) {
      PrintLn(11, (uint8_t *)"Error Flash");
    }
  }

  /* Swap all OBKeys */
  if (HAL_FLASHEx_OBK_Swap(0x1FFU) != HAL_OK) {
    PrintLn(10, (uint8_t *)"Error Swap");
  }

  /* Lock the User Flash area */
  (void) HAL_FLASH_Lock();
  (void) HAL_FLASHEx_OBK_Lock();
}

/** Main function *****************************************************************************************************/
int main(void)
{
  // Reset of all peripherals, Initializes the Flash interface and the Systick.
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  // Initialize all configured peripherals
  MX_GPIO_Init();
  MX_ICACHE_Init();

  if(IsProvisioned() == false) {
    // Write provisioning data
    PrintLn(13,(uint8_t *)"do provision");
  }
    OBKProvisioning_ProvisionDA();

  IsProvisioned();

  while (true){}
}

 

Best regards,

Peter