diff --git a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c new file mode 100644 index 000000000..92414b905 --- /dev/null +++ b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c @@ -0,0 +1,289 @@ +/* + * Texas Instruments K3 Secure Proxy Driver + * Based on Linux and U-Boot implementation + * + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sec_proxy.h" + +/* SEC PROXY RT THREAD STATUS */ +#define RT_THREAD_STATUS (0x0) +#define RT_THREAD_STATUS_ERROR_SHIFT (31) +#define RT_THREAD_STATUS_ERROR_MASK BIT(31) +#define RT_THREAD_STATUS_CUR_CNT_SHIFT (0) +#define RT_THREAD_STATUS_CUR_CNT_MASK GENMASK(7, 0) + +/* SEC PROXY SCFG THREAD CTRL */ +#define SCFG_THREAD_CTRL (0x1000) +#define SCFG_THREAD_CTRL_DIR_SHIFT (31) +#define SCFG_THREAD_CTRL_DIR_MASK BIT(31) + +#define SEC_PROXY_THREAD(base, x) ((base) + (0x1000 * (x))) +#define THREAD_IS_RX (1) +#define THREAD_IS_TX (0) + +/** + * struct k3_sec_proxy_desc - Description of secure proxy integration + * @timeout_us: Timeout for communication (in Microseconds) + * @max_msg_size: Message size in bytes + * @data_start_offset: Offset of the First data register of the thread + * @data_end_offset: Offset of the Last data register of the thread + */ +struct k3_sec_proxy_desc { + uint32_t timeout_us; + uint16_t max_msg_size; + uint16_t data_start_offset; + uint16_t data_end_offset; +}; + +/** + * struct k3_sec_proxy_thread - Description of a secure proxy Thread + * @id: Thread ID + * @data: Thread Data path region for target + * @scfg: Secure Config Region for Thread + * @rt: RealTime Region for Thread + */ +struct k3_sec_proxy_thread { + uint32_t id; + uintptr_t data; + uintptr_t scfg; + uintptr_t rt; +}; + +/** + * struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance + * @desc: Description of the SoC integration + * @chans: Array for valid thread instances + */ +struct k3_sec_proxy_mbox { + const struct k3_sec_proxy_desc desc; + struct k3_sec_proxy_thread threads[]; +}; + +/* + * Thread ID #0: DMSC notify + * Thread ID #1: DMSC request response + * Thread ID #2: DMSC request high priority + * Thread ID #3: DMSC request low priority + * Thread ID #4: DMSC notify response + */ +#define SP_THREAD(_x) \ + [_x] = { \ + .id = _x, \ + .data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, _x), \ + .scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, _x), \ + .rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, _x), \ + } + +static struct k3_sec_proxy_mbox spm = { + .desc = { + .timeout_us = SEC_PROXY_TIMEOUT_US, + .max_msg_size = SEC_PROXY_MAX_MESSAGE_SIZE, + .data_start_offset = 0x4, + .data_end_offset = 0x3C, + }, + .threads = { + SP_THREAD(SP_NOTIFY), + SP_THREAD(SP_RESPONSE), + SP_THREAD(SP_HIGH_PRIORITY), + SP_THREAD(SP_LOW_PRIORITY), + SP_THREAD(SP_NOTIFY_RESP), + }, +}; + +/** + * struct sec_msg_hdr - Message header for secure messages and responses + * @checksum: CRC of message for integrity checking + */ +union sec_msg_hdr { + struct { + uint16_t checksum; + uint16_t reserved; + } __packed; + uint32_t data; +}; + +/** + * k3_sec_proxy_verify_thread() - Verify thread status before + * sending/receiving data + * @spt: Pointer to Secure Proxy thread description + * @dir: Direction of the thread + * + * Return: 0 if all goes well, else appropriate error message + */ +static inline int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt, + uint32_t dir) +{ + /* Check for any errors already available */ + if (mmio_read_32(spt->rt + RT_THREAD_STATUS) & + RT_THREAD_STATUS_ERROR_MASK) { + ERROR("Thread %d is corrupted, cannot send data\n", spt->id); + return -EINVAL; + } + + /* Make sure thread is configured for right direction */ + if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK) + != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) { + if (dir) + ERROR("Trying to receive data on tx Thread %d\n", + spt->id); + else + ERROR("Trying to send data on rx Thread %d\n", + spt->id); + return -EINVAL; + } + + /* Check the message queue before sending/receiving data */ + uint32_t tick_start = (uint32_t)read_cntpct_el0(); + uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000; + while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) { + VERBOSE("Waiting for thread %d to clear\n", spt->id); + if (((uint32_t)read_cntpct_el0() - tick_start) > + (spm.desc.timeout_us * ticks_per_us)) { + ERROR("Timeout waiting for thread %d to clear\n", spt->id); + return -ETIMEDOUT; + } + } + + return 0; +} + +/** + * k3_sec_proxy_send() - Send data over a Secure Proxy thread + * @id: Channel Identifier + * @msg: Pointer to k3_sec_proxy_msg + * + * Return: 0 if all goes well, else appropriate error message + */ +int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg) +{ + struct k3_sec_proxy_thread *spt = &spm.threads[id]; + union sec_msg_hdr secure_header; + int num_words, trail_bytes, i, ret; + uintptr_t data_reg; + + ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX); + if (ret) { + ERROR("Thread %d verification failed (%d)\n", spt->id, ret); + return ret; + } + + /* Check the message size */ + if (msg->len + sizeof(secure_header) > spm.desc.max_msg_size) { + ERROR("Thread %d message length %lu > max msg size\n", + spt->id, msg->len); + return -EINVAL; + } + + /* TODO: Calculate checksum */ + secure_header.checksum = 0; + + /* Send the secure header */ + data_reg = spm.desc.data_start_offset; + mmio_write_32(spt->data + data_reg, secure_header.data); + data_reg += sizeof(uint32_t); + + /* Send whole words */ + num_words = msg->len / sizeof(uint32_t); + for (i = 0; i < num_words; i++) { + mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]); + data_reg += sizeof(uint32_t); + } + + /* Send remaining bytes */ + trail_bytes = msg->len % sizeof(uint32_t); + if (trail_bytes) { + uint32_t data_trail = 0; + + i = msg->len - trail_bytes; + while (trail_bytes--) { + data_trail <<= 8; + data_trail |= msg->buf[i++]; + } + + mmio_write_32(spt->data + data_reg, data_trail); + data_reg += sizeof(uint32_t); + } + /* + * 'data_reg' indicates next register to write. If we did not already + * write on tx complete reg(last reg), we must do so for transmit + */ + if (data_reg <= spm.desc.data_end_offset) + mmio_write_32(spt->data + spm.desc.data_end_offset, 0); + + VERBOSE("Message successfully sent on thread %ud\n", id); + + return 0; +} + +/** + * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread + * @id: Channel Identifier + * @msg: Pointer to k3_sec_proxy_msg + * + * Return: 0 if all goes well, else appropriate error message + */ +int k3_sec_proxy_recv(uint32_t id, struct k3_sec_proxy_msg *msg) +{ + struct k3_sec_proxy_thread *spt = &spm.threads[id]; + union sec_msg_hdr secure_header; + uintptr_t data_reg; + int num_words, trail_bytes, i, ret; + + ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX); + if (ret) { + ERROR("Thread %d verification failed (%d)\n", spt->id, ret); + return ret; + } + + /* Read secure header */ + data_reg = spm.desc.data_start_offset; + secure_header.data = mmio_read_32(spt->data + data_reg); + data_reg += sizeof(uint32_t); + + /* Read whole words */ + num_words = msg->len / sizeof(uint32_t); + for (i = 0; i < num_words; i++) { + ((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg); + data_reg += sizeof(uint32_t); + } + + /* Read remaining bytes */ + trail_bytes = msg->len % sizeof(uint32_t); + if (trail_bytes) { + uint32_t data_trail = mmio_read_32(spt->data + data_reg); + data_reg += sizeof(uint32_t); + + i = msg->len - trail_bytes; + while (trail_bytes--) { + msg->buf[i] = data_trail & 0xff; + data_trail >>= 8; + } + } + + /* + * 'data_reg' indicates next register to read. If we did not already + * read on rx complete reg(last reg), we must do so for receive + */ + if (data_reg <= spm.desc.data_end_offset) + mmio_read_32(spt->data + spm.desc.data_end_offset); + + /* TODO: Verify checksum */ + (void)secure_header.checksum; + + VERBOSE("Message successfully received from thread %ud\n", id); + + return 0; +} diff --git a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h new file mode 100644 index 000000000..facfd1988 --- /dev/null +++ b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h @@ -0,0 +1,58 @@ +/* + * Texas Instruments K3 Secure Proxy Driver + * Based on Linux and U-Boot implementation + * + * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef K3_SEC_PROXY_H +#define K3_SEC_PROXY_H + +#include + +/** + * enum k3_sec_proxy_chan_id - Secure Proxy thread IDs + * + * These the available IDs used in k3_sec_proxy_{send,recv}() + */ +enum k3_sec_proxy_chan_id { + SP_NOTIFY = 0, + SP_RESPONSE, + SP_HIGH_PRIORITY, + SP_LOW_PRIORITY, + SP_NOTIFY_RESP, +}; + +/** + * struct k3_sec_proxy_msg - Secure proxy message structure + * @len: Length of data in the Buffer + * @buf: Buffer pointer + * + * This is the structure for data used in k3_sec_proxy_{send,recv}() + */ +struct k3_sec_proxy_msg { + size_t len; + uint8_t *buf; +}; + +/** + * k3_sec_proxy_send() - Send data over a Secure Proxy thread + * @id: Channel Identifier + * @msg: Pointer to k3_sec_proxy_msg + * + * Return: 0 if all goes well, else appropriate error message + */ +int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg); + +/** + * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread + * @id: Channel Identifier + * @msg: Pointer to k3_sec_proxy_msg + * + * Return: 0 if all goes well, else appropriate error message + */ +int k3_sec_proxy_recv(enum k3_sec_proxy_chan_id id, struct k3_sec_proxy_msg *msg); + +#endif /* K3_SEC_PROXY_H */ diff --git a/plat/ti/k3/common/k3_bl31_setup.c b/plat/ti/k3/common/k3_bl31_setup.c index 3de57a7c4..19816a71b 100644 --- a/plat/ti/k3/common/k3_bl31_setup.c +++ b/plat/ti/k3/common/k3_bl31_setup.c @@ -21,6 +21,9 @@ const mmap_region_t plat_arm_mmap[] = { MAP_REGION_FLAT(K3_USART_BASE_ADDRESS, K3_USART_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(K3_GICD_BASE, K3_GICD_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(K3_GICR_BASE, K3_GICR_SIZE, MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(SEC_PROXY_RT_BASE, SEC_PROXY_RT_SIZE, MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(SEC_PROXY_SCFG_BASE, SEC_PROXY_SCFG_SIZE, MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(SEC_PROXY_DATA_BASE, SEC_PROXY_DATA_SIZE, MT_DEVICE | MT_RW | MT_SECURE), { /* sentinel */ } }; diff --git a/plat/ti/k3/common/plat_common.mk b/plat/ti/k3/common/plat_common.mk index 7cb6eb78e..5f19127d0 100644 --- a/plat/ti/k3/common/plat_common.mk +++ b/plat/ti/k3/common/plat_common.mk @@ -36,6 +36,7 @@ PLAT_INCLUDES += \ -I${PLAT_PATH}/include \ -Iinclude/plat/arm/common/ \ -Iinclude/plat/arm/common/aarch64/ \ + -I${PLAT_PATH}/common/drivers/sec_proxy \ K3_CONSOLE_SOURCES += \ drivers/console/aarch64/console.S \ @@ -53,6 +54,9 @@ K3_PSCI_SOURCES += \ plat/common/plat_psci_common.c \ ${PLAT_PATH}/common/k3_psci.c \ +K3_SEC_PROXY_SOURCES += \ + ${PLAT_PATH}/common/drivers/sec_proxy/sec_proxy.c \ + PLAT_BL_COMMON_SOURCES += \ plat/arm/common/arm_common.c \ lib/cpus/aarch64/cortex_a53.S \ @@ -65,3 +69,4 @@ BL31_SOURCES += \ ${PLAT_PATH}/common/k3_topology.c \ ${K3_GIC_SOURCES} \ ${K3_PSCI_SOURCES} \ + ${K3_SEC_PROXY_SOURCES} \ diff --git a/plat/ti/k3/include/platform_def.h b/plat/ti/k3/include/platform_def.h index ebc9c4770..7159328ac 100644 --- a/plat/ti/k3/include/platform_def.h +++ b/plat/ti/k3/include/platform_def.h @@ -106,7 +106,7 @@ * runtime memory used, choose the smallest value needed to register the * required regions for each BL stage. */ -#define MAX_MMAP_REGIONS 8 +#define MAX_MMAP_REGIONS 11 /* * Defines the total size of the address space in bytes. For example, for a 32 @@ -193,4 +193,14 @@ #define K3_GICR_BASE 0x01880000 #define K3_GICR_SIZE 0x100000 +#define SEC_PROXY_DATA_BASE 0x32C00000 +#define SEC_PROXY_DATA_SIZE 0x80000 +#define SEC_PROXY_SCFG_BASE 0x32800000 +#define SEC_PROXY_SCFG_SIZE 0x80000 +#define SEC_PROXY_RT_BASE 0x32400000 +#define SEC_PROXY_RT_SIZE 0x80000 + +#define SEC_PROXY_TIMEOUT_US 1000000 +#define SEC_PROXY_MAX_MESSAGE_SIZE 56 + #endif /* __PLATFORM_DEF_H__ */