Merge changes from topic "msm8916-spmin" into integration
* changes:
docs(msm8916): document new build options
feat(msm8916): allow selecting which UART to use
feat(msm8916): add SP_MIN port for AArch32
refactor(msm8916): detect cold boot in plat_get_my_entrypoint
feat(msm8916): add Test Secure Payload (TSP) port
build(msm8916): place bl32 directly after bl31
refactor(msm8916): separate common platform setup code
diff --git a/bl32/tsp/tsp_ffa_main.c b/bl32/tsp/tsp_ffa_main.c
index 268d329..1c8c68f 100644
--- a/bl32/tsp/tsp_ffa_main.c
+++ b/bl32/tsp/tsp_ffa_main.c
@@ -91,7 +91,7 @@
smc_args_t ffa_forward_result;
ffa_endpoint_id16_t receiver = arg5;
- ffa_forward_result = ffa_msg_send_direct_req(ffa_endpoint_source(arg1),
+ ffa_forward_result = ffa_msg_send_direct_req(tsp_id,
receiver,
FF_A_ECHO_MESSAGE, arg4,
0, 0, 0);
diff --git a/lib/cpus/aarch64/dsu_helpers.S b/lib/cpus/aarch64/dsu_helpers.S
index b7e028a..a34b9a6 100644
--- a/lib/cpus/aarch64/dsu_helpers.S
+++ b/lib/cpus/aarch64/dsu_helpers.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2022, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -44,11 +44,11 @@
/* --------------------------------------------------
* Errata Workaround for DSU erratum #798953.
*
- * Can clobber only: x0-x17
+ * Can clobber only: x0-x8
* --------------------------------------------------
*/
func errata_dsu_798953_wa
- mov x17, x30
+ mov x8, x30
bl check_errata_dsu_798953
cbz x0, 1f
@@ -58,7 +58,7 @@
msr CLUSTERACTLR_EL1, x0
isb
1:
- ret x17
+ ret x8
endfunc errata_dsu_798953_wa
/* -----------------------------------------------------------------------
@@ -72,7 +72,7 @@
* This function is called from both assembly and C environment. So it
* follows AAPCS.
*
- * Clobbers: x0-x15
+ * Clobbers: x0-x4
* -----------------------------------------------------------------------
*/
.globl check_errata_dsu_936184
@@ -83,7 +83,7 @@
* Default behaviour respresents SCU is always present with DSU.
* CPUs can override this definition if required.
*
- * Can clobber only: x0-x14
+ * Can clobber only: x0-x3
* --------------------------------------------------------------------
*/
func is_scu_present_in_dsu
@@ -92,7 +92,7 @@
endfunc is_scu_present_in_dsu
func check_errata_dsu_936184
- mov x15, x30
+ mov x4, x30
bl is_scu_present_in_dsu
cmp x0, xzr
/* Default error status */
@@ -116,17 +116,17 @@
b.hs 1f
mov x0, #ERRATA_APPLIES
1:
- ret x15
+ ret x4
endfunc check_errata_dsu_936184
/* --------------------------------------------------
* Errata Workaround for DSU erratum #936184.
*
- * Can clobber only: x0-x17
+ * Can clobber only: x0-x8
* --------------------------------------------------
*/
func errata_dsu_936184_wa
- mov x17, x30
+ mov x8, x30
bl check_errata_dsu_936184
cbz x0, 1f
@@ -137,7 +137,7 @@
msr CLUSTERACTLR_EL1, x0
isb
1:
- ret x17
+ ret x8
endfunc errata_dsu_936184_wa
/* -----------------------------------------------------------------------
@@ -176,11 +176,11 @@
/* --------------------------------------------------
* Errata Workaround for DSU erratum #2313941.
*
- * Can clobber only: x0-x17
+ * Can clobber only: x0-x8
* --------------------------------------------------
*/
func errata_dsu_2313941_wa
- mov x17, x30
+ mov x8, x30
bl check_errata_dsu_2313941
cbz x0, 1f
@@ -190,6 +190,5 @@
msr CLUSTERACTLR_EL1, x0
isb
1:
- ret x17
+ ret x8
endfunc errata_dsu_2313941_wa
-
diff --git a/plat/arm/board/fvp/fvp_el3_spmc_logical_sp.c b/plat/arm/board/fvp/fvp_el3_spmc_logical_sp.c
index b9e4f86..72dfa30 100644
--- a/plat/arm/board/fvp/fvp_el3_spmc_logical_sp.c
+++ b/plat/arm/board/fvp/fvp_el3_spmc_logical_sp.c
@@ -27,6 +27,7 @@
void *handle, uint64_t flags)
{
uint64_t ret;
+ uint32_t src_dst;
/* Determine if we have a 64 or 32 direct request. */
if (smc_fid == FFA_MSG_SEND_DIRECT_REQ_SMC32) {
@@ -36,18 +37,22 @@
} else {
panic(); /* Unknown SMC. */
}
+
/*
* Handle the incoming request. For testing purposes we echo the
* incoming message.
*/
- INFO("Logical Partition: Received Direct Request from %s world!\n",
- secure_origin ? "Secure" : "Normal");
+ INFO("LSP: Received Direct Request from %s world (0x%x)\n",
+ secure_origin ? "Secure" : "Normal", ffa_endpoint_source(x1));
+ /* Populate the source and destination IDs. */
+ src_dst = (uint32_t) LP_PARTITION_ID << FFA_DIRECT_MSG_SOURCE_SHIFT |
+ ffa_endpoint_source(x1) << FFA_DIRECT_MSG_DESTINATION_SHIFT;
/*
* Logical SP's must always send a direct response so we can populate
* our response directly.
*/
- SMC_RET8(handle, ret, 0, 0, x4, 0, 0, 0, 0);
+ SMC_RET8(handle, ret, src_dst, 0, x4, 0, 0, 0, 0);
}
/* Register logical partition */
diff --git a/plat/qemu/common/qemu_sdei.c b/plat/qemu/common/qemu_sdei.c
new file mode 100644
index 0000000..820567e
--- /dev/null
+++ b/plat/qemu/common/qemu_sdei.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* SDEI configuration for ARM platforms */
+
+#include <bl31/ehf.h>
+#include <common/debug.h>
+#include <lib/utils_def.h>
+#include <services/sdei.h>
+#include <platform_def.h>
+
+/* Private event mappings */
+static sdei_ev_map_t qemu_sdei_private[] = {
+ SDEI_DEFINE_EVENT_0(PLAT_SDEI_SGI_PRIVATE),
+};
+
+/* Shared event mappings */
+static sdei_ev_map_t qemu_sdei_shared[] = {
+};
+
+void plat_sdei_setup(void)
+{
+ INFO("SDEI platform setup\n");
+}
+
+/* Export Arm SDEI events */
+REGISTER_SDEI_MAP(qemu_sdei_private, qemu_sdei_shared);
diff --git a/plat/qemu/qemu/include/platform_def.h b/plat/qemu/qemu/include/platform_def.h
index 98b8254..93a3ce8 100644
--- a/plat/qemu/qemu/include/platform_def.h
+++ b/plat/qemu/qemu/include/platform_def.h
@@ -244,8 +244,7 @@
* interrupts.
*****************************************************************************/
#define PLATFORM_G1S_PROPS(grp) \
- INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, \
- grp, GIC_INTR_CFG_EDGE), \
+ DESC_G1S_IRQ_SEC_SGI_0(grp) \
INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_EDGE), \
INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, \
@@ -261,7 +260,19 @@
INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_EDGE)
-#define PLATFORM_G0_PROPS(grp)
+#if SDEI_SUPPORT
+#define DESC_G0_IRQ_SEC_SGI(grp) \
+ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI, (grp), \
+ GIC_INTR_CFG_EDGE)
+#define DESC_G1S_IRQ_SEC_SGI_0(grp)
+#else
+#define DESC_G0_IRQ_SEC_SGI(grp)
+#define DESC_G1S_IRQ_SEC_SGI_0(grp) \
+ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI, (grp), \
+ GIC_INTR_CFG_EDGE),
+#endif
+
+#define PLATFORM_G0_PROPS(grp) DESC_G0_IRQ_SEC_SGI(grp)
/*
* DT related constants
@@ -270,6 +281,14 @@
#define PLAT_QEMU_DT_MAX_SIZE 0x100000
/*
+ * Platforms macros to support SDEI
+ */
+#define PLAT_PRI_BITS U(3)
+#define PLAT_SDEI_CRITICAL_PRI 0x60
+#define PLAT_SDEI_NORMAL_PRI 0x70
+#define PLAT_SDEI_SGI_PRIVATE QEMU_IRQ_SEC_SGI_0
+
+/*
* System counter
*/
#define SYS_COUNTER_FREQ_IN_TICKS ((1000 * 1000 * 1000) / 16)
diff --git a/plat/qemu/qemu/platform.mk b/plat/qemu/qemu/platform.mk
index 3a0e1c0..7a1dccd 100644
--- a/plat/qemu/qemu/platform.mk
+++ b/plat/qemu/qemu/platform.mk
@@ -230,6 +230,10 @@
${PLAT_QEMU_COMMON_PATH}/qemu_bl31_setup.c \
${QEMU_GIC_SOURCES}
+ifeq (${SDEI_SUPPORT}, 1)
+BL31_SOURCES += plat/qemu/common/qemu_sdei.c
+endif
+
# Pointer Authentication sources
ifeq (${ENABLE_PAUTH}, 1)
PLAT_BL_COMMON_SOURCES += plat/arm/common/aarch64/arm_pauth.c \
@@ -323,3 +327,7 @@
ifneq (${BL33},)
all: qemu_fw.bios qemu_fw.rom
endif
+
+ifeq (${EL3_EXCEPTION_HANDLING},1)
+BL31_SOURCES += plat/common/aarch64/plat_ehf.c
+endif
diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h
index 61afee3..13875b9 100644
--- a/services/std_svc/spm/el3_spmc/spmc.h
+++ b/services/std_svc/spm/el3_spmc/spmc.h
@@ -131,6 +131,9 @@
/* Track the current runtime model of the SP. */
enum sp_runtime_model rt_model;
+
+ /* Track the source partition ID to validate a direct response. */
+ uint16_t dir_req_origin_id;
};
/*
diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c
index 08e7218..ada6f45 100644
--- a/services/std_svc/spm/el3_spmc/spmc_main.c
+++ b/services/std_svc/spm/el3_spmc/spmc_main.c
@@ -260,6 +260,65 @@
}
/*******************************************************************************
+ * Helper function to validate the destination ID of a direct response.
+ ******************************************************************************/
+static bool direct_msg_validate_dst_id(uint16_t dst_id)
+{
+ struct secure_partition_desc *sp;
+
+ /* Check if we're targeting a normal world partition. */
+ if (ffa_is_normal_world_id(dst_id)) {
+ return true;
+ }
+
+ /* Or directed to the SPMC itself.*/
+ if (dst_id == FFA_SPMC_ID) {
+ return true;
+ }
+
+ /* Otherwise ensure the SP exists. */
+ sp = spmc_get_sp_ctx(dst_id);
+ if (sp != NULL) {
+ return true;
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ * Helper function to validate the response from a Logical Partition.
+ ******************************************************************************/
+static bool direct_msg_validate_lp_resp(uint16_t origin_id, uint16_t lp_id,
+ void *handle)
+{
+ /* Retrieve populated Direct Response Arguments. */
+ uint64_t x1 = SMC_GET_GP(handle, CTX_GPREG_X1);
+ uint64_t x2 = SMC_GET_GP(handle, CTX_GPREG_X2);
+ uint16_t src_id = ffa_endpoint_source(x1);
+ uint16_t dst_id = ffa_endpoint_destination(x1);
+
+ if (src_id != lp_id) {
+ ERROR("Invalid EL3 LP source ID (0x%x).\n", src_id);
+ return false;
+ }
+
+ /*
+ * Check the destination ID is valid and ensure the LP is responding to
+ * the original request.
+ */
+ if ((!direct_msg_validate_dst_id(dst_id)) || (dst_id != origin_id)) {
+ ERROR("Invalid EL3 LP destination ID (0x%x).\n", dst_id);
+ return false;
+ }
+
+ if (!direct_msg_validate_arg2(x2)) {
+ ERROR("Invalid EL3 LP message encoding.\n");
+ return false;
+ }
+ return true;
+}
+
+/*******************************************************************************
* Handle direct request messages and route to the appropriate destination.
******************************************************************************/
static uint64_t direct_req_smc_handler(uint32_t smc_fid,
@@ -272,6 +331,7 @@
void *handle,
uint64_t flags)
{
+ uint16_t src_id = ffa_endpoint_source(x1);
uint16_t dst_id = ffa_endpoint_destination(x1);
struct el3_lp_desc *el3_lp_descs;
struct secure_partition_desc *sp;
@@ -283,14 +343,29 @@
FFA_ERROR_INVALID_PARAMETER);
}
+ /* Validate Sender is either the current SP or from the normal world. */
+ if ((secure_origin && src_id != spmc_get_current_sp_ctx()->sp_id) ||
+ (!secure_origin && !ffa_is_normal_world_id(src_id))) {
+ ERROR("Invalid direct request source ID (0x%x).\n", src_id);
+ return spmc_ffa_error_return(handle,
+ FFA_ERROR_INVALID_PARAMETER);
+ }
+
el3_lp_descs = get_el3_lp_array();
/* Check if the request is destined for a Logical Partition. */
for (unsigned int i = 0U; i < MAX_EL3_LP_DESCS_COUNT; i++) {
if (el3_lp_descs[i].sp_id == dst_id) {
- return el3_lp_descs[i].direct_req(
- smc_fid, secure_origin, x1, x2, x3, x4,
- cookie, handle, flags);
+ uint64_t ret = el3_lp_descs[i].direct_req(
+ smc_fid, secure_origin, x1, x2,
+ x3, x4, cookie, handle, flags);
+ if (!direct_msg_validate_lp_resp(src_id, dst_id,
+ handle)) {
+ panic();
+ }
+
+ /* Message checks out. */
+ return ret;
}
}
@@ -332,6 +407,7 @@
*/
sp->ec[idx].rt_state = RT_STATE_RUNNING;
sp->ec[idx].rt_model = RT_MODEL_DIR_REQ;
+ sp->ec[idx].dir_req_origin_id = src_id;
return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
handle, cookie, flags, dst_id);
}
@@ -370,7 +446,7 @@
* Check that the response is either targeted to the Normal world or the
* SPMC e.g. a PM response.
*/
- if ((dst_id != FFA_SPMC_ID) && ffa_is_secure_world_id(dst_id)) {
+ if (!direct_msg_validate_dst_id(dst_id)) {
VERBOSE("Direct response to invalid partition ID (0x%x).\n",
dst_id);
return spmc_ffa_error_return(handle,
@@ -397,9 +473,18 @@
return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
}
+ if (sp->ec[idx].dir_req_origin_id != dst_id) {
+ WARN("Invalid direct resp partition ID 0x%x != 0x%x on core%u.\n",
+ dst_id, sp->ec[idx].dir_req_origin_id, idx);
+ return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+ }
+
/* Update the state of the SP execution context. */
sp->ec[idx].rt_state = RT_STATE_WAITING;
+ /* Clear the ongoing direct request ID. */
+ sp->ec[idx].dir_req_origin_id = INV_SP_ID;
+
/*
* If the receiver is not the SPMC then forward the response to the
* Normal world.
diff --git a/services/std_svc/spm/el3_spmc/spmc_pm.c b/services/std_svc/spm/el3_spmc/spmc_pm.c
index d25344c..c7e864f 100644
--- a/services/std_svc/spm/el3_spmc/spmc_pm.c
+++ b/services/std_svc/spm/el3_spmc/spmc_pm.c
@@ -83,6 +83,7 @@
/* Update the runtime model and state of the partition. */
ec->rt_model = RT_MODEL_INIT;
ec->rt_state = RT_STATE_RUNNING;
+ ec->dir_req_origin_id = INV_SP_ID;
INFO("SP (0x%x) init start on core%u.\n", sp->sp_id, linear_id);
@@ -132,6 +133,7 @@
/* Update the runtime model and state of the partition. */
ec->rt_model = RT_MODEL_DIR_REQ;
ec->rt_state = RT_STATE_RUNNING;
+ ec->dir_req_origin_id = FFA_SPMC_ID;
rc = spmc_sp_synchronous_entry(ec);
if (rc != 0ULL) {
diff --git a/services/std_svc/spm/el3_spmc/spmc_shared_mem.c b/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
index 15c7e91..5c3d580 100644
--- a/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
+++ b/services/std_svc/spm/el3_spmc/spmc_shared_mem.c
@@ -777,16 +777,16 @@
static int spmc_shmem_check_obj(struct spmc_shmem_obj *obj,
uint32_t ffa_version)
{
- uint64_t total_page_count;
+ unsigned long long total_page_count;
const struct ffa_emad_v1_0 *first_emad;
const struct ffa_emad_v1_0 *end_emad;
size_t emad_size;
- uint32_t comp_mrd_offset = 0;
+ uint32_t comp_mrd_offset;
size_t header_emad_size;
size_t size;
size_t count;
size_t expected_size;
- struct ffa_comp_mrd *comp;
+ const struct ffa_comp_mrd *comp;
if (obj->desc_filled != obj->desc_size) {
ERROR("BUG: %s called on incomplete object (%zu != %zu)\n",
@@ -807,9 +807,7 @@
comp_mrd_offset = first_emad->comp_mrd_offset;
/* Loop through the endpoint descriptors, validating each of them. */
- for (const struct ffa_emad_v1_0 *emad = first_emad;
- emad < end_emad;
- emad = emad_advance(emad, emad_size)) {
+ for (const struct ffa_emad_v1_0 *emad = first_emad; emad < end_emad;) {
ffa_endpoint_id16_t ep_id;
/*
@@ -836,6 +834,23 @@
__func__, emad->comp_mrd_offset, comp_mrd_offset);
return FFA_ERROR_INVALID_PARAMETER;
}
+
+ /* Advance to the next endpoint descriptor */
+ emad = emad_advance(emad, emad_size);
+
+ /*
+ * Ensure neither this emad nor any subsequent emads have
+ * the same partition ID as the previous emad.
+ */
+ for (const struct ffa_emad_v1_0 *other_emad = emad;
+ other_emad < end_emad;
+ other_emad = emad_advance(other_emad, emad_size)) {
+ if (ep_id == other_emad->mapd.endpoint_id) {
+ WARN("%s: Duplicated endpoint id 0x%x\n",
+ __func__, emad->mapd.endpoint_id);
+ return FFA_ERROR_INVALID_PARAMETER;
+ }
+ }
}
header_emad_size = (size_t)((const uint8_t *)end_emad -
@@ -869,16 +884,18 @@
}
size -= comp_mrd_offset;
+ /* Check that there is enough space for the composite descriptor. */
if (size < sizeof(struct ffa_comp_mrd)) {
WARN("%s: invalid object, offset %u, total size %zu, no header space.\n",
__func__, comp_mrd_offset, obj->desc_size);
return FFA_ERROR_INVALID_PARAMETER;
}
- size -= sizeof(struct ffa_comp_mrd);
+ size -= sizeof(*comp);
count = size / sizeof(struct ffa_cons_mrd);
- comp = spmc_shmem_obj_get_comp_mrd(obj, ffa_version);
+ comp = (const struct ffa_comp_mrd *)
+ ((const uint8_t *)(&obj->desc) + comp_mrd_offset);
if (comp->address_range_count != count) {
WARN("%s: invalid object, desc count %u != %zu\n",
@@ -886,6 +903,7 @@
return FFA_ERROR_INVALID_PARAMETER;
}
+ /* Ensure that the expected and actual sizes are equal. */
expected_size = comp_mrd_offset + sizeof(*comp) +
count * sizeof(struct ffa_cons_mrd);
@@ -897,14 +915,30 @@
total_page_count = 0;
+ /*
+ * comp->address_range_count is 32-bit, so 'count' must fit in a
+ * uint32_t at this point.
+ */
for (size_t i = 0; i < count; i++) {
- total_page_count +=
- comp->address_range_array[i].page_count;
+ const struct ffa_cons_mrd *mrd = comp->address_range_array + i;
+
+ if (!is_aligned(mrd->address, PAGE_SIZE)) {
+ WARN("%s: invalid object, address in region descriptor "
+ "%zu not 4K aligned (got 0x%016llx)",
+ __func__, i, (unsigned long long)mrd->address);
+ }
+
+ /*
+ * No overflow possible: total_page_count can hold at
+ * least 2^64 - 1, but will be have at most 2^32 - 1.
+ * values added to it, each of which cannot exceed 2^32 - 1.
+ */
+ total_page_count += mrd->page_count;
}
+
if (comp->total_page_count != total_page_count) {
- WARN("%s: invalid object, desc total_page_count %u != %" PRIu64 "\n",
- __func__, comp->total_page_count,
- total_page_count);
+ WARN("%s: invalid object, desc total_page_count %u != %llu\n",
+ __func__, comp->total_page_count, total_page_count);
return FFA_ERROR_INVALID_PARAMETER;
}
@@ -970,11 +1004,8 @@
void *smc_handle)
{
int ret;
- size_t emad_size;
uint32_t handle_low;
uint32_t handle_high;
- struct ffa_emad_v1_0 *emad;
- struct ffa_emad_v1_0 *other_emad;
if (mbox->rxtx_page_count == 0U) {
WARN("%s: buffer pair not registered.\n", __func__);
@@ -1057,26 +1088,6 @@
goto err_bad_desc;
}
- /* Ensure partition IDs are not duplicated. */
- for (size_t i = 0; i < obj->desc.emad_count; i++) {
- emad = spmc_shmem_obj_get_emad(&obj->desc, i, ffa_version,
- &emad_size);
-
- for (size_t j = i + 1; j < obj->desc.emad_count; j++) {
- other_emad = spmc_shmem_obj_get_emad(&obj->desc, j,
- ffa_version,
- &emad_size);
-
- if (emad->mapd.endpoint_id ==
- other_emad->mapd.endpoint_id) {
- WARN("%s: Duplicated endpoint id 0x%x\n",
- __func__, emad->mapd.endpoint_id);
- ret = FFA_ERROR_INVALID_PARAMETER;
- goto err_bad_desc;
- }
- }
- }
-
ret = spmc_shmem_check_state_obj(obj, ffa_version);
if (ret) {
ERROR("%s: invalid memory region descriptor.\n", __func__);