Commit 3a5830cc authored by Lionel Debieve's avatar Lionel Debieve
Browse files

stm32mp: ssp: Add secure secret provisioning feature



This patch adds changes to support the secure secret
provisioning (SSP).
Main changes are:
    - Add SSP library which includes OTP fusing services
    - Change TF-A binary layout for SSP binary to embed only BL2
      and device tree.
    - Modify some generic drivers to embed only needed functions
    - Add read functionality for UART/USB programmer mode to receive
      the encrypted binary.

Signed-off-by: default avatarLionel Debieve <lionel.debieve@st.com>
Change-Id: Ie5cdc173c3e924c466ce9a66a98c679a9ace08d4
parent e587179e
......@@ -698,20 +698,24 @@ static unsigned int gate_refcounts[NB_GATES];
static struct spinlock refcount_lock;
static struct stm32mp1_pll_settings pll1_settings;
static uint32_t current_opp_khz;
#if !STM32MP_SSP
static uint32_t pll3cr;
static uint32_t pll4cr;
static uint32_t mssckselr;
static uint32_t mcudivr;
#endif
static const struct stm32mp1_clk_gate *gate_ref(unsigned int idx)
{
return &stm32mp1_clk_gate[idx];
}
#if !STM32MP_SSP
static bool gate_is_non_secure(const struct stm32mp1_clk_gate *gate)
{
return gate->secure == N_S;
}
#endif
static const struct stm32mp1_clk_sel *clk_sel_ref(unsigned int idx)
{
......@@ -2848,6 +2852,7 @@ unsigned long stm32mp1_clk_rcc2id(unsigned int offset, unsigned int bit)
return get_id_from_rcc_bit(offset, bit);
}
#if !STM32MP_SSP
#ifdef IMAGE_BL32
/*
* Get the parent ID of the target parent clock, for tagging as secure
......@@ -3449,6 +3454,7 @@ static void sync_earlyboot_clocks_state(void)
stm32mp_clk_enable(RTCAPB);
}
#endif /* !STM32MP_SSP */
int stm32mp1_clk_probe(void)
{
......@@ -3458,7 +3464,9 @@ int stm32mp1_clk_probe(void)
stm32mp1_osc_init();
#if !STM32MP_SSP
sync_earlyboot_clocks_state();
#endif
/* Save current CPU operating point value */
freq_khz = udiv_round_nearest(stm32mp_clk_get_rate(CK_MPU), 1000UL);
......
......@@ -17,6 +17,7 @@
#include <drivers/st/io_programmer_st_usb.h>
#include <drivers/st/io_stm32image.h>
#include <drivers/st/stm32_iwdg.h>
#include <lib/ssp_lib.h>
#include <lib/usb/usb_st_dfu.h>
#define USB_STATE_READY 0
......@@ -89,13 +90,22 @@ static uint16_t usb_callback_write_done(uint32_t *written_in, uint32_t len)
}
/* Call back to notify that a read memory is requested */
static uint8_t *usb_callback_read(uint8_t *src, uint8_t *dest, uint32_t len)
static uint16_t usb_callback_read(uint8_t *src, uint8_t *dest, uint32_t len)
{
#if STM32MP_SSP
if (current_phase.phase_id == SSP_PHASE) {
const size_t size = SSP_KEY_CERTIFICATE_SIZE * sizeof(uint32_t);
if (len >= size) {
memcpy(dest, src, size);
return size;
}
}
#else
ERROR("%s read is not supported src 0x%lx dest 0x%lx len %i\n",
__func__, (uintptr_t)src, (uintptr_t)dest, len);
/* Return a valid address to avoid HardFault */
return (uint8_t *)(dest);
#endif
return 0;
}
/* Get the status to know if written operation has been checked */
......@@ -173,10 +183,11 @@ static int usb_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
io_entity_t *entity)
{
int result;
#if !STM32MP_SSP
uint32_t length = 0;
boot_api_image_header_t *header =
(boot_api_image_header_t *)first_usb_buffer;
#endif
const struct stm32image_part_info *partition_spec =
(struct stm32image_part_info *)spec;
......@@ -186,7 +197,7 @@ static int usb_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
assert(entity);
current_phase.current_packet = 0;
#if !STM32MP_SSP
if (!strcmp(partition_spec->name, BL33_IMAGE_NAME)) {
/* read flash layout first for U-boot */
current_phase.phase_id = PHASE_FLASHLAYOUT;
......@@ -221,6 +232,16 @@ static int usb_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
current_phase.phase_id = PHASE_SSBL;
current_phase.max_size = dt_get_ddr_size();
}
#else
if (!strcmp(partition_spec->name, "SSP")) {
current_phase.phase_id = SSP_PHASE;
current_phase.keep_header = 1;
}
if (!strcmp(partition_spec->name, "SSP_INIT")) {
current_phase.phase_id = RESET_PHASE;
}
#endif
entity->info = (uintptr_t)&current_phase;
result = 0;
} else {
......@@ -267,6 +288,64 @@ static int usb_block_seek(io_entity_t *entity, int mode,
}
/* Read data from a file on the usb device */
#if STM32MP_SSP
static int usb_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read)
{
uint64_t timeout;
uint32_t detach_timeout = DETACH_TIMEOUT;
ssp_exchange_t *exchange = (ssp_exchange_t *)buffer;
if (current_phase.phase_id == RESET_PHASE) {
usb_dfu_set_phase_id(RESET_PHASE);
usb_dfu_set_upload_addr(buffer);
usb_dfu_error_msg_size(length);
} else {
usb_dfu_set_upload_addr((uint32_t)exchange->msg);
usb_dfu_set_download_addr((uint32_t)exchange->blob);
/* Use flashlayout partition for SSP exchange */
usb_dfu_set_phase_id(PHASE_FLASHLAYOUT);
INFO("Start Download partition SSP address 0x%lx length %i\n",
(uintptr_t)exchange->blob, length);
}
while (!usb_dfu_download_is_completed()) {
/* Reload watchdog */
stm32_iwdg_refresh();
usb_core_handle_it((usb_handle_t *)usb_dev_info.info);
}
/* Wait Detach in case */
usb_dfu_set_phase_id(0x0);
usb_dfu_set_upload_addr(UNDEFINE_DOWN_ADDR);
usb_dfu_request_detach();
timeout = timeout_init_us(IO_USB_TIMEOUT_10_SEC);
while (detach_timeout != 0U) {
usb_core_handle_it((usb_handle_t *)usb_dev_info.info);
if (usb_dfu_detach_req() == 0U) {
/*
* Continue to handle usb core IT to assure
* complete data transmission.
*/
detach_timeout--;
}
if (timeout_elapsed(timeout)) {
return -EIO;
}
}
/* STOP the USB Handler */
usb_core_stop((usb_handle_t *)usb_dev_info.info);
*length_read = length;
return 0;
}
#else /* STM32MP_SSP */
static int usb_block_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read)
{
......@@ -355,6 +434,7 @@ static int usb_block_read(io_entity_t *entity, uintptr_t buffer,
return 0;
}
#endif /* STM32MP_SSP */
/* Close a file on the usb device */
static int usb_block_close(io_entity_t *entity)
......
......@@ -18,6 +18,7 @@
#include <drivers/st/io_stm32image.h>
#include <drivers/st/io_uart.h>
#include <drivers/st/stm32_iwdg.h>
#include <lib/ssp_lib.h>
/* USART bootloader protocol version V4.0*/
#define USART_BL_VERSION 0x40
......@@ -31,6 +32,9 @@ static const uint8_t command_tab[] = {
GET_VER_COMMAND,
GET_ID_COMMAND,
PHASE_COMMAND,
#if STM32MP_SSP
READ_PART_COMMAND,
#endif
START_COMMAND,
DOWNLOAD_COMMAND
};
......@@ -195,8 +199,10 @@ static int uart_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
int result = -EIO;
const struct stm32image_part_info *partition_spec =
(struct stm32image_part_info *)spec;
#if !STM32MP_SSP
uint32_t length = 0;
uint32_t layout_length = 0;
#endif
/* Use PHASE_FSBL1 like init value*/
if (current_phase.phase_id == PHASE_FSBL1) {
......@@ -205,6 +211,7 @@ static int uart_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
current_phase.current_packet = 0;
#if !STM32MP_SSP
if (!strcmp(partition_spec->name, BL33_IMAGE_NAME)) {
/* read flashlayout first for U-boot */
current_phase.phase_id = PHASE_FLASHLAYOUT;
......@@ -224,6 +231,18 @@ static int uart_block_open(io_dev_info_t *dev_info, const uintptr_t spec,
current_phase.max_size = dt_get_ddr_size();
current_phase.keep_header = 0;
}
#else
if (!strcmp(partition_spec->name, "SSP")) {
current_phase.phase_id = SSP_PHASE;
header_length_read = 0;
}
if (!strcmp(partition_spec->name, "SSP_INIT")) {
current_phase.phase_id = RESET_PHASE;
header_length_read = 0;
}
#endif
entity->info = (uintptr_t)&current_phase;
result = 0;
} else {
......@@ -303,17 +322,128 @@ static int get_id_command(void)
return 0;
}
static int uart_send_phase(uint32_t address)
static int uart_send_phase(uint32_t address, size_t length)
{
uart_write_byte(0x05); /* length of data - 1 */
size_t local_length = 0;
uint32_t i;
if (current_phase.phase_id == RESET_PHASE) {
local_length = length;
}
if ((local_length + 5U) > UINT8_MAX) {
return -EINVAL;
}
uart_write_byte(local_length + 5U); /* length of data - 1 */
/* Send the ID of next partition */
uart_write_byte(current_phase.phase_id); /* partition ID */
uart_write_uint32(address); /* destination address */
uart_write_byte(0x00); /* length of extra data */
uart_write_byte(local_length); /* length of extra data */
for (i = 0; i < local_length; i++) {
uart_write_byte(((char *)address)[i]);
}
return 0;
}
#if STM32MP_SSP
static int uart_read_part(uint8_t *buffer, size_t length, size_t *length_read)
{
uint8_t byte = 0U;
uint8_t xor = 0U;
uint8_t partid = 0U;
uint16_t size = 0U;
uint32_t start_address = 0U;
uint32_t i;
/* Get partition id */
if (uart_read_byte(&partid) != 0) {
return -EIO;
}
if (partid != SSP_PART_ID) {
return -EPERM;
}
xor = partid;
/* Get address */
for (i = 4U; i > 0U; i--) {
if (uart_read_byte(&byte) != 0) {
return -EIO;
}
xor ^= byte;
start_address = (start_address << 8) | byte;
}
/* Checksum */
if (uart_read_byte(&byte) != 0) {
return -EIO;
}
if (xor != byte) {
WARN("UART: Start cmd: address checksum: %x != %x\n",
xor, byte);
return -EPROTO;
}
uart_write_byte(ACK_BYTE);
/* Get number of bytes to send */
if (uart_read_byte(&byte) != 0) {
return -EIO;
}
xor = byte;
/* Send Size + 1 */
size = byte++;
/* Checksum */
if (uart_read_byte(&byte) != 0) {
return -EIO;
}
if ((xor ^ byte) != 0xFF) {
WARN("UART: Start cmd: length checksum: %x != %x\n", xor, byte);
return -EPROTO;
}
uart_write_byte(ACK_BYTE);
switch (partid) {
case SSP_PART_ID:
if ((start_address != 0U) ||
(size < (SSP_KEY_CERTIFICATE_SIZE * sizeof(uint32_t)))) {
return -EIO;
}
for (i = 0U;
i < (SSP_KEY_CERTIFICATE_SIZE * sizeof(uint32_t));
i++, buffer++) {
uart_write_byte(*buffer);
}
for (; i < size; i++) {
uart_write_byte(0x0);
}
break;
default:
WARN("Not supported\n");
return -EPROTO;
}
return 0;
}
#endif /* STM32MP_SSP */
static int uart_download_part(uint8_t *buffer, uint32_t *length_read)
{
......@@ -325,15 +455,23 @@ static int uart_download_part(uint8_t *buffer, uint32_t *length_read)
int i = 0;
volatile uint8_t *ptr = (uint8_t *)buffer;
/* get operation number */
if (uart_read_byte(&operation))
/* Get operation number */
if (uart_read_byte(&operation) != 0) {
return -EIO;
}
xor = operation;
/* get packet Number */
for (i = 3, byte = 0; i > 0; i--) {
if (uart_read_byte(&byte))
if ((operation != 0x0) && (operation != 0xF3)) {
return -EPERM;
}
/* Get packet number */
for (i = 3; i > 0; i--) {
if (uart_read_byte(&byte) != 0) {
return -EIO;
}
xor ^= byte;
packet_number = (packet_number << 8) | byte;
}
......@@ -430,6 +568,12 @@ static int uart_start_cmd(boot_api_image_header_t *header, uintptr_t buffer)
return stm32mp_check_header(header, buffer);
#if STM32MP_SSP
case SSP_PHASE:
current_phase.phase_id = RESET_PHASE;
break;
#endif
default:
ERROR("Invalid phase ID : %i\n", current_phase.phase_id);
return -EINVAL;
......@@ -447,6 +591,9 @@ static int uart_block_read(io_entity_t *entity, uintptr_t buffer,
uint32_t ptr_offset = 0;
uint8_t command = 0;
uint8_t all_commands_done = 0;
#if STM32MP_SSP
ssp_exchange_t *exchange = (ssp_exchange_t *)buffer;
#endif
boot_api_image_header_t *header =
(boot_api_image_header_t *)&header_buffer[0];
......@@ -508,12 +655,44 @@ static int uart_block_read(io_entity_t *entity, uintptr_t buffer,
break;
case PHASE_COMMAND:
result = uart_send_phase((uint32_t)buffer);
result = uart_send_phase((uint32_t)buffer, length);
#if STM32MP_SSP
if (current_phase.phase_id == RESET_PHASE) {
all_commands_done = 1;
}
#endif
break;
#if STM32MP_SSP
case READ_PART_COMMAND:
result = uart_read_part((uint8_t *)(buffer), length,
length_read);
if (result == 0) {
/* No ACK_BYTE needed */
continue;
}
break;
#endif
case DOWNLOAD_COMMAND:
result = uart_download_part((uint8_t *)(buffer +
ptr_offset),
#if STM32MP_SSP
result = uart_download_part((uint8_t *)
(exchange->blob +
ptr_offset),
&read_length);
if (!result) {
ptr_offset += read_length;
total_length += read_length;
if (total_length > length) {
/* Buffer too long */
all_commands_done = 1;
}
}
#else
result = uart_download_part((uint8_t *)
(buffer + ptr_offset),
&read_length);
if (!result) {
ptr_offset += read_length;
......@@ -524,6 +703,7 @@ static int uart_block_read(io_entity_t *entity, uintptr_t buffer,
all_commands_done = 1;
}
}
#endif
break;
......@@ -531,7 +711,6 @@ static int uart_block_read(io_entity_t *entity, uintptr_t buffer,
result = uart_start_cmd(header, buffer);
if (!result)
all_commands_done = 1;
break;
default:
......@@ -557,8 +736,7 @@ static int uart_block_read(io_entity_t *entity, uintptr_t buffer,
*length_read = total_length;
INFO("Read block in buffer 0x%lx size 0x%x phase ID %i\n",
buffer, length, current_phase.phase_id);
buffer, *length_read, current_phase.phase_id);
return 0;
}
......
......@@ -41,7 +41,12 @@
<&nand_otp>,
<&uid_otp>,
<&package_otp>,
<&hw2_otp>;
<&hw2_otp>,
<&pkh_otp>,
<&cfg2_otp>,
<&ssp_otp>,
<&chip_otp>,
<&rma_otp>;
nvmem-cell-names = "cfg0_otp",
"part_number_otp",
......@@ -49,7 +54,12 @@
"nand_otp",
"uid_otp",
"package_otp",
"hw2_otp";
"hw2_otp",
"pkh_otp",
"cfg2_otp",
"ssp_otp",
"chip_otp",
"rma_otp";
};
psci {
......@@ -456,9 +466,15 @@
part_number_otp: part_number_otp@4 {
reg = <0x4 0x1>;
};
cfg2_otp: cfg2_otp@8 {
reg = <0x8 0x4>;
};
monotonic_otp: monotonic_otp@10 {
reg = <0x10 0x4>;
};
ssp_otp: ssp_otp@20 {
reg = <0x20 0x4>;
};
nand_otp: nand_otp@24 {
reg = <0x24 0x4>;
};
......@@ -480,6 +496,12 @@
pkh_otp: pkh_otp@60 {
reg = <0x60 0x20>;
};
chip_otp: chip_otp@a0 {
reg = <0xa0 0x40>;
};
rma_otp: rma_otp@e0 {
reg = <0xe0 0x4>;
};
mac_addr: mac_addr@e4 {
reg = <0xe4 0x8>;
st,non-secure-otp;
......
......@@ -289,7 +289,11 @@
<&package_otp>,
<&hw2_otp>,
<&pkh_otp>,
<&board_id>;
<&board_id>,
<&cfg2_otp>,
<&ssp_otp>,
<&chip_otp>,
<&rma_otp>;
nvmem-cell-names = "cfg0_otp",
"part_number_otp",
......@@ -299,7 +303,11 @@
"package_otp",
"hw2_otp",
"pkh_otp",
"board_id";
"board_id",
"cfg2_otp",
"ssp_otp",
"chip_otp",
"rma_otp";
};
&pwr_regulators {
......
......@@ -296,7 +296,11 @@
<&package_otp>,
<&hw2_otp>,
<&pkh_otp>,
<&board_id>;
<&board_id>,
<&cfg2_otp>,
<&ssp_otp>,
<&chip_otp>,
<&rma_otp>;
nvmem-cell-names = "cfg0_otp",
"part_number_otp",
......@@ -306,7 +310,11 @@
"package_otp",
"hw2_otp",
"pkh_otp",
"board_id";
"board_id",
"cfg2_otp",
"ssp_otp",
"chip_otp",
"rma_otp";
};
&pwr_regulators {
......
/*
* Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved
* Copyright (c) 2015-2020, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
......@@ -12,12 +12,18 @@
#define PHASE_FSBL1 1
#define PHASE_FSBL2 2
#define PHASE_SSBL 3
#define RESET_PHASE 0xFF
#if STM32MP_SSP
#define SSP_PHASE 0xF3
#endif