From 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 11:13:47 +0200 Subject: Adding upstream version 2.8.0+dfsg. Signed-off-by: Daniel Baumann --- plat/nxp/common/sip_svc/aarch64/sipsvc.S | 152 ++++++++++++++++++++++++ plat/nxp/common/sip_svc/include/sipsvc.h | 80 +++++++++++++ plat/nxp/common/sip_svc/sip_svc.c | 194 +++++++++++++++++++++++++++++++ plat/nxp/common/sip_svc/sipsvc.mk | 35 ++++++ 4 files changed, 461 insertions(+) create mode 100644 plat/nxp/common/sip_svc/aarch64/sipsvc.S create mode 100644 plat/nxp/common/sip_svc/include/sipsvc.h create mode 100644 plat/nxp/common/sip_svc/sip_svc.c create mode 100644 plat/nxp/common/sip_svc/sipsvc.mk (limited to 'plat/nxp/common/sip_svc') diff --git a/plat/nxp/common/sip_svc/aarch64/sipsvc.S b/plat/nxp/common/sip_svc/aarch64/sipsvc.S new file mode 100644 index 0000000..6a47cbf --- /dev/null +++ b/plat/nxp/common/sip_svc/aarch64/sipsvc.S @@ -0,0 +1,152 @@ +/* + * Copyright 2018-2020 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include + +.global el2_2_aarch32 +.global prefetch_disable + +#define SPSR_EL3_M4 0x10 +#define SPSR_EL_MASK 0xC +#define SPSR_EL2 0x8 +#define SCR_EL3_4_EL2_AARCH32 0x131 +#define SPSR32_EL2_LE 0x1DA + +#define MIDR_PARTNUM_START 4 +#define MIDR_PARTNUM_WIDTH 12 +#define MIDR_PARTNUM_A53 0xD03 +#define MIDR_PARTNUM_A57 0xD07 +#define MIDR_PARTNUM_A72 0xD08 + +/* + * uint64_t el2_2_aarch32(u_register_t smc_id, + * u_register_t start_addr, + * u_register_t parm1, + * u_register_t parm2) + * this function allows changing the execution width of EL2 from Aarch64 + * to Aarch32 + * Note: MUST be called from EL2 @ Aarch64 + * in: x0 = smc function id + * x1 = start address for EL2 @ Aarch32 + * x2 = first parameter to pass to EL2 @ Aarch32 + * x3 = second parameter to pass to EL2 @ Aarch32 + * out: x0 = 0, on success + * x0 = -1, on failure + * uses x0, x1, x2, x3 + */ +func el2_2_aarch32 + + /* check that caller is EL2 @ Aarch64 - err return if not */ + mrs x0, spsr_el3 + /* see if we were called from Aarch32 */ + tst x0, #SPSR_EL3_M4 + b.ne 2f + + /* see if we were called from EL2 */ + and x0, x0, SPSR_EL_MASK + cmp x0, SPSR_EL2 + b.ne 2f + + /* set ELR_EL3 */ + msr elr_el3, x1 + + /* set scr_el3 */ + mov x0, #SCR_EL3_4_EL2_AARCH32 + msr scr_el3, x0 + + /* set sctlr_el2 */ + ldr x1, =SCTLR_EL2_RES1 + msr sctlr_el2, x1 + + /* set spsr_el3 */ + ldr x0, =SPSR32_EL2_LE + msr spsr_el3, x0 + + /* x2 = parm 1 + * x3 = parm2 + */ + + /* set the parameters to be passed-thru to EL2 @ Aarch32 */ + mov x1, x2 + mov x2, x3 + + /* x1 = parm 1 + * x2 = parm2 + */ + + mov x0, xzr + /* invalidate the icache */ + ic iallu + dsb sy + isb + b 1f +2: + /* error return */ + mvn x0, xzr + ret +1: + eret +endfunc el2_2_aarch32 + +/* + * int prefetch_disable(u_register_t smc_id, u_register_t mask) + * this function marks cores which need to have the prefetch disabled - + * secondary cores have prefetch disabled when they are released from reset - + * the bootcore has prefetch disabled when this call is made + * in: x0 = function id + * x1 = core mask, where bit[0]=core0, bit[1]=core1, etc + * if a bit in the mask is set, then prefetch is disabled for that + * core + * out: x0 = SMC_SUCCESS + */ +func prefetch_disable + stp x4, x30, [sp, #-16]! + + mov x3, x1 + + /* x1 = core prefetch disable mask */ + /* x3 = core prefetch disable mask */ + + /* store the mask */ + mov x0, #PREFETCH_DIS_OFFSET + bl _set_global_data + + /* x3 = core prefetch disable mask */ + + /* see if we need to disable prefetch on THIS core */ + bl plat_my_core_mask + + /* x0 = core mask lsb */ + /* x3 = core prefetch disable mask */ + + tst x3, x0 + b.eq 1f + + /* read midr_el1 */ + mrs x1, midr_el1 + + /* x1 = midr_el1 */ + + mov x0, xzr + bfxil x0, x1, #MIDR_PARTNUM_START, #MIDR_PARTNUM_WIDTH + + /* x0 = part number (a53, a57, a72, etc) */ + + /* branch on cpu-specific */ + cmp x0, #MIDR_PARTNUM_A57 + b.eq 1f + cmp x0, #MIDR_PARTNUM_A72 + b.ne 1f + + bl _disable_ldstr_pfetch_A72 + b 1f +1: + ldp x4, x30, [sp], #16 + mov x0, xzr + ret +endfunc prefetch_disable diff --git a/plat/nxp/common/sip_svc/include/sipsvc.h b/plat/nxp/common/sip_svc/include/sipsvc.h new file mode 100644 index 0000000..d9e61e9 --- /dev/null +++ b/plat/nxp/common/sip_svc/include/sipsvc.h @@ -0,0 +1,80 @@ +/* + * Copyright 2018-2020 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef SIPSVC_H +#define SIPSVC_H + +#include + +#define SMC_FUNC_MASK 0x0000ffff +#define SMC32_PARAM_MASK 0xffffffff + +/* SMC function IDs for SiP Service queries */ +#define SIP_SVC_CALL_COUNT 0xff00 +#define SIP_SVC_UID 0xff01 +#define SIP_SVC_VERSION 0xff03 +#define SIP_SVC_PRNG 0xff10 +#define SIP_SVC_RNG 0xff11 +#define SIP_SVC_MEM_BANK 0xff12 +#define SIP_SVC_PREFETCH_DIS 0xff13 +#define SIP_SVC_HUK 0xff14 +#define SIP_SVC_ALLOW_L1L2_ERR 0xff15 +#define SIP_SVC_ALLOW_L2_CLR 0xff16 +#define SIP_SVC_2_AARCH32 0xff17 +#define SIP_SVC_PORSR1 0xff18 + +/* Layerscape SiP Service Calls version numbers */ +#define LS_SIP_SVC_VERSION_MAJOR 0x0 +#define LS_SIP_SVC_VERSION_MINOR 0x1 + +/* Number of Layerscape SiP Calls implemented */ +#define LS_COMMON_SIP_NUM_CALLS 10 + +/* Parameter Type Constants */ +#define SIP_PARAM_TYPE_NONE 0x0 +#define SIP_PARAM_TYPE_VALUE_INPUT 0x1 +#define SIP_PARAM_TYPE_VALUE_OUTPUT 0x2 +#define SIP_PARAM_TYPE_VALUE_INOUT 0x3 +#define SIP_PARAM_TYPE_MEMREF_INPUT 0x5 +#define SIP_PARAM_TYPE_MEMREF_OUTPUT 0x6 +#define SIP_PARAM_TYPE_MEMREF_INOUT 0x7 + +#define SIP_PARAM_TYPE_MASK 0xF + +/* + * The macro SIP_PARAM_TYPES can be used to construct a value that you can + * compare against an incoming paramTypes to check the type of all the + * parameters in one comparison. + */ +#define SIP_PARAM_TYPES(t0, t1, t2, t3) \ + ((t0) | ((t1) << 4) | ((t2) << 8) | ((t3) << 12)) + +/* + * The macro SIP_PARAM_TYPE_GET can be used to extract the type of a given + * parameter from paramTypes if you need more fine-grained type checking. + */ +#define SIP_PARAM_TYPE_GET(t, i) ((((uint32_t)(t)) >> ((i) * 4)) & 0xF) + +/* + * The macro SIP_PARAM_TYPE_SET can be used to load the type of a given + * parameter from paramTypes without specifying all types (SIP_PARAM_TYPES) + */ +#define SIP_PARAM_TYPE_SET(t, i) (((uint32_t)(t) & 0xF) << ((i) * 4)) + +#define SIP_SVC_RNG_PARAMS (SIP_PARAM_TYPE_VALUE_INPUT, \ + SIP_PARAM_TYPE_MEMREF_OUTPUT, \ + SIP_PARAM_TYPE_NONE, \ + SIP_PARAM_TYPE_NONE) + +/* Layerscape SiP Calls error code */ +enum { + LS_SIP_SUCCESS = 0, + LS_SIP_INVALID_PARAM = -1, + LS_SIP_NOT_SUPPORTED = -2, +}; + +#endif /* SIPSVC_H */ diff --git a/plat/nxp/common/sip_svc/sip_svc.c b/plat/nxp/common/sip_svc/sip_svc.c new file mode 100644 index 0000000..1c8668e --- /dev/null +++ b/plat/nxp/common/sip_svc/sip_svc.c @@ -0,0 +1,194 @@ +/* + * Copyright 2018-2021 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/* Layerscape SiP Service UUID */ +DEFINE_SVC_UUID2(nxp_sip_svc_uid, + 0x871de4ef, 0xedfc, 0x4209, 0xa4, 0x23, + 0x8d, 0x23, 0x75, 0x9d, 0x3b, 0x9f); + +#pragma weak nxp_plat_sip_handler +static uintptr_t nxp_plat_sip_handler(unsigned int smc_fid, + u_register_t x1, + u_register_t x2, + u_register_t x3, + u_register_t x4, + void *cookie, + void *handle, + u_register_t flags) +{ + ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); + SMC_RET1(handle, SMC_UNK); +} + +uint64_t el2_2_aarch32(u_register_t smc_id, u_register_t start_addr, + u_register_t parm1, u_register_t parm2); + +uint64_t prefetch_disable(u_register_t smc_id, u_register_t mask); +uint64_t bl31_get_porsr1(void); + +static void clean_top_32b_of_param(uint32_t smc_fid, + u_register_t *px1, + u_register_t *px2, + u_register_t *px3, + u_register_t *px4) +{ + /* if parameters from SMC32. Clean top 32 bits */ + if (GET_SMC_CC(smc_fid) == SMC_32) { + *px1 = *px1 & SMC32_PARAM_MASK; + *px2 = *px2 & SMC32_PARAM_MASK; + *px3 = *px3 & SMC32_PARAM_MASK; + *px4 = *px4 & SMC32_PARAM_MASK; + } +} + +/* This function handles Layerscape defined SiP Calls */ +static uintptr_t nxp_sip_handler(unsigned int smc_fid, + u_register_t x1, + u_register_t x2, + u_register_t x3, + u_register_t x4, + void *cookie, + void *handle, + u_register_t flags) +{ + uint32_t ns; + uint64_t ret; + dram_regions_info_t *info_dram_regions; + + /* if parameter is sent from SMC32. Clean top 32 bits */ + clean_top_32b_of_param(smc_fid, &x1, &x2, &x3, &x4); + + /* Determine which security state this SMC originated from */ + ns = is_caller_non_secure(flags); + if (ns == 0) { + /* SiP SMC service secure world's call */ + ; + } else { + /* SiP SMC service normal world's call */ + ; + } + + switch (smc_fid & SMC_FUNC_MASK) { + case SIP_SVC_RNG: + if (is_sec_enabled() == false) { + NOTICE("SEC is disabled.\n"); + SMC_RET1(handle, SMC_UNK); + } + + /* Return zero on failure */ + ret = get_random((int)x1); + if (ret != 0) { + SMC_RET2(handle, SMC_OK, ret); + } else { + SMC_RET1(handle, SMC_UNK); + } + /* break is not required as SMC_RETx return */ + case SIP_SVC_HUK: + if (is_sec_enabled() == false) { + NOTICE("SEC is disabled.\n"); + SMC_RET1(handle, SMC_UNK); + } + ret = get_hw_unq_key_blob_hw((uint8_t *) x1, (uint32_t) x2); + + if (ret == SMC_OK) { + SMC_RET1(handle, SMC_OK); + } else { + SMC_RET1(handle, SMC_UNK); + } + /* break is not required as SMC_RETx return */ + case SIP_SVC_MEM_BANK: + VERBOSE("Handling SMC SIP_SVC_MEM_BANK.\n"); + info_dram_regions = get_dram_regions_info(); + + if (x1 == -1) { + SMC_RET2(handle, SMC_OK, + info_dram_regions->total_dram_size); + } else if (x1 >= info_dram_regions->num_dram_regions) { + SMC_RET1(handle, SMC_UNK); + } else { + SMC_RET3(handle, SMC_OK, + info_dram_regions->region[x1].addr, + info_dram_regions->region[x1].size); + } + /* break is not required as SMC_RETx return */ + case SIP_SVC_PREFETCH_DIS: + VERBOSE("In SIP_SVC_PREFETCH_DIS call\n"); + ret = prefetch_disable(smc_fid, x1); + if (ret == SMC_OK) { + SMC_RET1(handle, SMC_OK); + } else { + SMC_RET1(handle, SMC_UNK); + } + /* break is not required as SMC_RETx return */ + case SIP_SVC_2_AARCH32: + ret = el2_2_aarch32(smc_fid, x1, x2, x3); + + /* In success case, control should not reach here. */ + NOTICE("SMC: SIP_SVC_2_AARCH32 Failed.\n"); + SMC_RET1(handle, SMC_UNK); + /* break is not required as SMC_RETx return */ + case SIP_SVC_PORSR1: + ret = bl31_get_porsr1(); + SMC_RET2(handle, SMC_OK, ret); + /* break is not required as SMC_RETx return */ + default: + return nxp_plat_sip_handler(smc_fid, x1, x2, x3, x4, + cookie, handle, flags); + } +} + +/* This function is responsible for handling all SiP calls */ +static uintptr_t sip_smc_handler(unsigned int smc_fid, + u_register_t x1, + u_register_t x2, + u_register_t x3, + u_register_t x4, + void *cookie, + void *handle, + u_register_t flags) +{ + switch (smc_fid & SMC_FUNC_MASK) { + case SIP_SVC_CALL_COUNT: + /* Return the number of Layerscape SiP Service Calls. */ + SMC_RET1(handle, LS_COMMON_SIP_NUM_CALLS); + break; + case SIP_SVC_UID: + /* Return UID to the caller */ + SMC_UUID_RET(handle, nxp_sip_svc_uid); + break; + case SIP_SVC_VERSION: + /* Return the version of current implementation */ + SMC_RET2(handle, LS_SIP_SVC_VERSION_MAJOR, + LS_SIP_SVC_VERSION_MINOR); + break; + default: + return nxp_sip_handler(smc_fid, x1, x2, x3, x4, + cookie, handle, flags); + } +} + +/* Define a runtime service descriptor for fast SMC calls */ +DECLARE_RT_SVC( + nxp_sip_svc, + OEN_SIP_START, + OEN_SIP_END, + SMC_TYPE_FAST, + NULL, + sip_smc_handler +); diff --git a/plat/nxp/common/sip_svc/sipsvc.mk b/plat/nxp/common/sip_svc/sipsvc.mk new file mode 100644 index 0000000..c3a57de --- /dev/null +++ b/plat/nxp/common/sip_svc/sipsvc.mk @@ -0,0 +1,35 @@ +# +# Copyright 2018-2020 NXP +# +# SPDX-License-Identifier: BSD-3-Clause +# +# +#------------------------------------------------------------------------------ +# +# Select the SIP SVC files +# +# ----------------------------------------------------------------------------- + +ifeq (${ADD_SIPSVC},) + +ADD_SIPSVC := 1 + +PLAT_SIPSVC_PATH := $(PLAT_COMMON_PATH)/sip_svc + +SIPSVC_SOURCES := ${PLAT_SIPSVC_PATH}/sip_svc.c \ + ${PLAT_SIPSVC_PATH}/$(ARCH)/sipsvc.S + +PLAT_INCLUDES += -I${PLAT_SIPSVC_PATH}/include + +ifeq (${BL_COMM_SIPSVC_NEEDED},yes) +BL_COMMON_SOURCES += ${SIPSVC_SOURCES} +else +ifeq (${BL2_SIPSVC_NEEDED},yes) +BL2_SOURCES += ${SIPSVC_SOURCES} +endif +ifeq (${BL31_SIPSVC_NEEDED},yes) +BL31_SOURCES += ${SIPSVC_SOURCES} +endif +endif +endif +# ----------------------------------------------------------------------------- -- cgit v1.2.3