diff --git a/include/plat/arm/common/arm_spm_def.h b/include/plat/arm/common/arm_spm_def.h index 83277a6..6aa8ce8 100644 --- a/include/plat/arm/common/arm_spm_def.h +++ b/include/plat/arm/common/arm_spm_def.h @@ -7,7 +7,6 @@ #define __ARM_SPM_DEF_H__ #include -#include #include #include @@ -73,12 +72,11 @@ /* * RW memory, which uses the remaining Trusted DRAM. Placed after the memory - * shared between Secure and Non-secure worlds. First there is the stack memory - * for all CPUs and then there is the common heap memory. Both are mapped with - * RW permissions. + * shared between Secure and Non-secure worlds, or after the platform specific + * buffers, if defined. First there is the stack memory for all CPUs and then + * there is the common heap memory. Both are mapped with RW permissions. */ -#define PLAT_SP_IMAGE_STACK_BASE (ARM_SP_IMAGE_NS_BUF_BASE + \ - ARM_SP_IMAGE_NS_BUF_SIZE) +#define PLAT_SP_IMAGE_STACK_BASE PLAT_ARM_SP_IMAGE_STACK_BASE #define PLAT_SP_IMAGE_STACK_PCPU_SIZE ULL(0x2000) #define ARM_SP_IMAGE_STACK_TOTAL_SIZE (PLATFORM_CORE_COUNT * \ PLAT_SP_IMAGE_STACK_PCPU_SIZE) diff --git a/lib/extensions/ras/ras_common.c b/lib/extensions/ras/ras_common.c index 0335a7b..5a2b43c 100644 --- a/lib/extensions/ras/ras_common.c +++ b/lib/extensions/ras/ras_common.c @@ -114,9 +114,10 @@ panic(); } - - ret = selected->err_record->probe(selected->err_record, &probe_data); - assert(ret != 0); + if (selected->err_record->probe) { + ret = selected->err_record->probe(selected->err_record, &probe_data); + assert(ret != 0); + } /* Call error handler for the record group */ assert(selected->err_record->handler != NULL); diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h index b1adbee..f22a8ec 100644 --- a/plat/arm/board/fvp/include/platform_def.h +++ b/plat/arm/board/fvp/include/platform_def.h @@ -163,4 +163,7 @@ #define PLAT_ARM_PRIVATE_SDEI_EVENTS ARM_SDEI_PRIVATE_EVENTS #define PLAT_ARM_SHARED_SDEI_EVENTS ARM_SDEI_SHARED_EVENTS +#define PLAT_ARM_SP_IMAGE_STACK_BASE (ARM_SP_IMAGE_NS_BUF_BASE + \ + ARM_SP_IMAGE_NS_BUF_SIZE) + #endif /* __PLATFORM_DEF_H__ */ diff --git a/plat/arm/common/arm_err.c b/plat/arm/common/arm_err.c index 59c5861..66568e7 100644 --- a/plat/arm/common/arm_err.c +++ b/plat/arm/common/arm_err.c @@ -5,12 +5,12 @@ */ #include -#include #include #include #include #include #include +#include #include /* diff --git a/plat/arm/css/sgi/include/platform_def.h b/plat/arm/css/sgi/include/platform_def.h index 7a2a6bd..169ae1b 100644 --- a/plat/arm/css/sgi/include/platform_def.h +++ b/plat/arm/css/sgi/include/platform_def.h @@ -8,12 +8,14 @@ #define PLATFORM_DEF_H #include +#include #include #include #include #include #include #include +#include #define CSS_SGI_MAX_CPUS_PER_CLUSTER 4 @@ -85,6 +87,55 @@ #define PLAT_ARM_GICC_BASE 0x2C000000 #define PLAT_ARM_GICR_BASE 0x300C0000 +/* Map the secure region for access from S-EL0 */ +#define PLAT_ARM_SECURE_MAP_DEVICE MAP_REGION_FLAT( \ + SOC_CSS_DEVICE_BASE, \ + SOC_CSS_DEVICE_SIZE, \ + MT_DEVICE | MT_RW | MT_SECURE | MT_USER) + +#if RAS_EXTENSION +/* Allocate 128KB for CPER buffers */ +#define PLAT_SP_BUF_BASE ULL(0x20000) + +#define PLAT_ARM_SP_IMAGE_STACK_BASE (ARM_SP_IMAGE_NS_BUF_BASE + \ + ARM_SP_IMAGE_NS_BUF_SIZE + \ + PLAT_SP_BUF_BASE) + +/* Platform specific SMC FID's used for RAS */ +#define SP_DMC_ERROR_INJECT_EVENT_AARCH64 0xC4000042 +#define SP_DMC_ERROR_INJECT_EVENT_AARCH32 0x84000042 + +#define SP_DMC_ERROR_OVERFLOW_EVENT_AARCH64 0xC4000043 +#define SP_DMC_ERROR_OVERFLOW_EVENT_AARCH32 0x84000043 + +#define SP_DMC_ERROR_ECC_EVENT_AARCH64 0xC4000044 +#define SP_DMC_ERROR_ECC_EVENT_AARCH32 0x84000044 + +/* ARM SDEI dynamic shared event numbers */ +#define SGI_SDEI_DS_EVENT_0 804 +#define SGI_SDEI_DS_EVENT_1 805 + +#define PLAT_ARM_PRIVATE_SDEI_EVENTS \ + SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI), \ + SDEI_EXPLICIT_EVENT(SGI_SDEI_DS_EVENT_0, SDEI_MAPF_CRITICAL), \ + SDEI_EXPLICIT_EVENT(SGI_SDEI_DS_EVENT_1, SDEI_MAPF_CRITICAL), +#define PLAT_ARM_SHARED_SDEI_EVENTS + +#define ARM_SP_CPER_BUF_BASE (ARM_SP_IMAGE_NS_BUF_BASE + \ + ARM_SP_IMAGE_NS_BUF_SIZE) +#define ARM_SP_CPER_BUF_SIZE ULL(0x20000) +#define ARM_SP_CPER_BUF_MMAP MAP_REGION2( \ + ARM_SP_CPER_BUF_BASE, \ + ARM_SP_CPER_BUF_BASE, \ + ARM_SP_CPER_BUF_SIZE, \ + MT_RW_DATA | MT_NS | MT_USER, \ + PAGE_SIZE) + +#else +#define PLAT_ARM_SP_IMAGE_STACK_BASE (ARM_SP_IMAGE_NS_BUF_BASE + \ + ARM_SP_IMAGE_NS_BUF_SIZE) +#endif /* RAS_EXTENSION */ + /* Platform ID address */ #define SSC_VERSION (SSC_REG_BASE + SSC_VERSION_OFFSET) #ifndef __ASSEMBLY__ diff --git a/plat/arm/css/sgi/include/sgi_ras.h b/plat/arm/css/sgi/include/sgi_ras.h new file mode 100644 index 0000000..b307b9c --- /dev/null +++ b/plat/arm/css/sgi/include/sgi_ras.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __SGI_RAS__ +#define __SGI_RAS__ + +/* + * Mapping the RAS interrupt with SDEI event number and the event + * id used with Standalone MM code + */ +struct sgi_ras_ev_map { + int ras_ev_num; /* RAS Event number */ + int sdei_ev_num; /* SDEI Event number */ + int intr; /* Physical intr number */ +}; + +int sgi_ras_intr_handler_setup(void); + +#endif /* __SGI_RAS__ */ diff --git a/plat/arm/css/sgi/sgi-common.mk b/plat/arm/css/sgi/sgi-common.mk index f4092f3..e0996c7 100644 --- a/plat/arm/css/sgi/sgi-common.mk +++ b/plat/arm/css/sgi/sgi-common.mk @@ -8,6 +8,16 @@ CSS_ENT_BASE := plat/arm/css/sgi +RAS_EXTENSION := 0 + +ENABLE_SPM := 0 + +SDEI_SUPPORT := 0 + +EL3_EXCEPTION_HANDLING := 0 + +HANDLE_EA_EL3_FIRST := 0 + INTERCONNECT_SOURCES := ${CSS_ENT_BASE}/sgi_interconnect.c PLAT_INCLUDES += -I${CSS_ENT_BASE}/include @@ -40,6 +50,10 @@ ${CSS_ENT_BASE}/sgi_topology.c \ ${CSS_ENT_BASE}/sgi_plat_config.c +ifeq (${RAS_EXTENSION},1) +BL31_SOURCES += ${CSS_ENT_BASE}/sgi_ras.c +endif + # Add the FDT_SOURCES and options for Dynamic Config FDT_SOURCES += ${CSS_ENT_BASE}/fdts/${PLAT}_tb_fw_config.dts TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb diff --git a/plat/arm/css/sgi/sgi_bl31_setup.c b/plat/arm/css/sgi/sgi_bl31_setup.c index 2090846..09f493e 100644 --- a/plat/arm/css/sgi/sgi_bl31_setup.c +++ b/plat/arm/css/sgi/sgi_bl31_setup.c @@ -8,6 +8,7 @@ #include #include #include +#include void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) @@ -17,3 +18,12 @@ arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); } + +void bl31_platform_setup(void) +{ + arm_bl31_platform_setup(); + +#if RAS_EXTENSION + sgi_ras_intr_handler_setup(); +#endif +} diff --git a/plat/arm/css/sgi/sgi_plat.c b/plat/arm/css/sgi/sgi_plat.c index 7e1d4e2..6aa76ef 100644 --- a/plat/arm/css/sgi/sgi_plat.c +++ b/plat/arm/css/sgi/sgi_plat.c @@ -5,11 +5,14 @@ */ #include +#include #include #include #include #include +#include #include +#include #include "../../../../bl1/bl1_private.h" #if USE_COHERENT_MEM @@ -58,6 +61,9 @@ #if ARM_BL31_IN_DRAM ARM_MAP_BL31_SEC_DRAM, #endif +#if ENABLE_SPM + ARM_SP_IMAGE_MMAP, +#endif {0} }; #endif @@ -67,8 +73,73 @@ V2M_MAP_IOFPGA, CSS_SGI_MAP_DEVICE, SOC_CSS_MAP_DEVICE, +#if ENABLE_SPM + ARM_SPM_BUF_EL3_MMAP, +#endif {0} }; + +#if ENABLE_SPM && defined(IMAGE_BL31) +const mmap_region_t plat_arm_secure_partition_mmap[] = { + PLAT_ARM_SECURE_MAP_DEVICE, + ARM_SP_IMAGE_MMAP, + ARM_SP_IMAGE_NS_BUF_MMAP, + ARM_SP_CPER_BUF_MMAP, + ARM_SP_IMAGE_RW_MMAP, + ARM_SPM_BUF_EL0_MMAP, + {0} +}; +#endif /* ENABLE_SPM && defined(IMAGE_BL31) */ #endif ARM_CASSERT_MMAP + +#if ENABLE_SPM && defined(IMAGE_BL31) +/* + * Boot information passed to a secure partition during initialisation. Linear + * indices in MP information will be filled at runtime. + */ +static secure_partition_mp_info_t sp_mp_info[] = { + [0] = {0x81000000, 0}, + [1] = {0x81000100, 0}, + [2] = {0x81000200, 0}, + [3] = {0x81000300, 0}, + [4] = {0x81010000, 0}, + [5] = {0x81010100, 0}, + [6] = {0x81010200, 0}, + [7] = {0x81010300, 0}, +}; + +const secure_partition_boot_info_t plat_arm_secure_partition_boot_info = { + .h.type = PARAM_SP_IMAGE_BOOT_INFO, + .h.version = VERSION_1, + .h.size = sizeof(secure_partition_boot_info_t), + .h.attr = 0, + .sp_mem_base = ARM_SP_IMAGE_BASE, + .sp_mem_limit = ARM_SP_IMAGE_LIMIT, + .sp_image_base = ARM_SP_IMAGE_BASE, + .sp_stack_base = PLAT_SP_IMAGE_STACK_BASE, + .sp_heap_base = ARM_SP_IMAGE_HEAP_BASE, + .sp_ns_comm_buf_base = ARM_SP_IMAGE_NS_BUF_BASE, + .sp_shared_buf_base = PLAT_SPM_BUF_BASE, + .sp_image_size = ARM_SP_IMAGE_SIZE, + .sp_pcpu_stack_size = PLAT_SP_IMAGE_STACK_PCPU_SIZE, + .sp_heap_size = ARM_SP_IMAGE_HEAP_SIZE, + .sp_ns_comm_buf_size = ARM_SP_IMAGE_NS_BUF_SIZE, + .sp_shared_buf_size = PLAT_SPM_BUF_SIZE, + .num_sp_mem_regions = ARM_SP_IMAGE_NUM_MEM_REGIONS, + .num_cpus = PLATFORM_CORE_COUNT, + .mp_info = &sp_mp_info[0], +}; + +const struct mmap_region *plat_get_secure_partition_mmap(void *cookie) +{ + return plat_arm_secure_partition_mmap; +} + +const struct secure_partition_boot_info *plat_get_secure_partition_boot_info( + void *cookie) +{ + return &plat_arm_secure_partition_boot_info; +} +#endif /* ENABLE_SPM && defined(IMAGE_BL31) */ diff --git a/plat/arm/css/sgi/sgi_ras.c b/plat/arm/css/sgi/sgi_ras.c new file mode 100644 index 0000000..ac4610d --- /dev/null +++ b/plat/arm/css/sgi/sgi_ras.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int sgi_ras_intr_handler(const struct err_record_info *err_rec, + int probe_data, + const struct err_handler_data *const data); +struct efi_guid { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; +}; + +typedef struct mm_communicate_header { + struct efi_guid header_guid; + size_t message_len; + uint8_t data[8]; +} mm_communicate_header_t; + +struct sgi_ras_ev_map sgi575_ras_map[] = { + + /* DMC620 error overflow interrupt*/ + {SP_DMC_ERROR_OVERFLOW_EVENT_AARCH64, SGI_SDEI_DS_EVENT_1, 33}, + + /* DMC620 error ECC error interrupt*/ + {SP_DMC_ERROR_ECC_EVENT_AARCH64, SGI_SDEI_DS_EVENT_0, 35}, +}; + +#define SGI575_RAS_MAP_SIZE ARRAY_SIZE(sgi575_ras_map) + +struct err_record_info sgi_err_records[] = { + { + .handler = &sgi_ras_intr_handler, + }, +}; + +struct ras_interrupt sgi_ras_interrupts[] = { + { + .intr_number = 33, + .err_record = &sgi_err_records[0], + }, + { + .intr_number = 35, + .err_record = &sgi_err_records[0], + } +}; + +REGISTER_ERR_RECORD_INFO(sgi_err_records); +REGISTER_RAS_INTERRUPTS(sgi_ras_interrupts); + +static struct sgi_ras_ev_map *plat_sgi_get_ras_ev_map(void) +{ + return sgi575_ras_map; +} + +static int plat_sgi_get_ras_ev_map_size(void) +{ + return SGI575_RAS_MAP_SIZE; +} + +/* + * Find event mapping for a given interrupt number: On success, returns pointer + * to the event mapping. On error, returns NULL. + */ +static struct sgi_ras_ev_map *find_ras_event_map_by_intr(uint32_t intr_num) +{ + struct sgi_ras_ev_map *map = plat_sgi_get_ras_ev_map(); + int i; + int size = plat_sgi_get_ras_ev_map_size(); + + for (i = 0; i < size; i++) { + if (map->intr == intr_num) + return map; + + map++; + } + + return NULL; +} + +static void sgi_ras_intr_configure(int intr) +{ + plat_ic_set_interrupt_type(intr, INTR_TYPE_EL3); + plat_ic_set_interrupt_priority(intr, PLAT_RAS_PRI); + plat_ic_clear_interrupt_pending(intr); + plat_ic_set_spi_routing(intr, INTR_ROUTING_MODE_ANY, + (u_register_t)read_mpidr_el1()); + plat_ic_enable_interrupt(intr); +} + +static int sgi_ras_intr_handler(const struct err_record_info *err_rec, + int probe_data, + const struct err_handler_data *const data) +{ + struct sgi_ras_ev_map *ras_map; + mm_communicate_header_t *header; + uint32_t intr; + + cm_el1_sysregs_context_save(NON_SECURE); + intr = data->interrupt; + + /* + * Find if this is a RAS interrupt. There must be an event against + * this interrupt + */ + ras_map = find_ras_event_map_by_intr(intr); + assert(ras_map); + + /* + * Populate the MM_COMMUNICATE payload to share the + * event info with StandaloneMM code. This allows us to use + * MM_COMMUNICATE as a common entry mechanism into S-EL0. The + * header data will be parsed in StandaloneMM to process the + * corresponding event. + * + * TBD - Currently, the buffer allocated by SPM for communication + * between EL3 and S-EL0 is being used(PLAT_SPM_BUF_BASE). But this + * should happen via a dynamic mem allocation, which should be + * managed by SPM -- the individual platforms then call the mem + * alloc api to get memory for the payload. + */ + header = (void *) PLAT_SPM_BUF_BASE; + memset(header, 0, sizeof(*header)); + memcpy(&header->data, &ras_map->ras_ev_num, + sizeof(ras_map->ras_ev_num)); + header->message_len = 4; + + spm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0, + plat_my_core_pos()); + + /* + * Do an EOI of the RAS interuupt. This allows the + * sdei event to be dispatched at the SDEI event's + * priority. + */ + plat_ic_end_of_interrupt(intr); + + /* Dispatch the event to the SDEI client */ + sdei_dispatch_event(ras_map->sdei_ev_num); + + return 0; +} + +int sgi_ras_intr_handler_setup(void) +{ + int i; + struct sgi_ras_ev_map *map = plat_sgi_get_ras_ev_map(); + int size = plat_sgi_get_ras_ev_map_size(); + + for (i = 0; i < size; i++) { + sgi_ras_intr_configure(map->intr); + map++; + } + + INFO("SGI: RAS Interrupt Handler successfully registered\n"); + + return 0; +}