Merge pull request #1109 from robertovargas-arm/mem_protect

Mem protect
This commit is contained in:
davidcunado-arm 2017-10-04 16:23:59 +01:00 committed by GitHub
commit c64d1345a8
22 changed files with 349 additions and 14 deletions

View File

@ -65,6 +65,9 @@
#define PSCI_STAT_RESIDENCY_AARCH64 U(0xc4000010)
#define PSCI_STAT_COUNT_AARCH32 U(0x84000011)
#define PSCI_STAT_COUNT_AARCH64 U(0xc4000011)
#define PSCI_MEM_PROTECT U(0x84000013)
#define PSCI_MEM_CHK_RANGE_AARCH32 U(0x84000014)
#define PSCI_MEM_CHK_RANGE_AARCH64 U(0xc4000014)
/* Macro to help build the psci capabilities bitfield */
#define define_psci_cap(x) (U(1) << (x & U(0x1f)))
@ -288,6 +291,9 @@ typedef struct plat_psci_ops {
unsigned int power_state,
psci_power_state_t *output_state);
int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);
int (*mem_protect_chk)(uintptr_t base, u_register_t length);
int (*read_mem_protect)(int *val);
int (*write_mem_protect)(int val);
} plat_psci_ops_t;
/*******************************************************************************

View File

@ -19,6 +19,25 @@
#include <types.h>
typedef struct mem_region_t {
uintptr_t base;
size_t nbytes;
} mem_region_t;
/*
* zero_normalmem all the regions defined in tbl.
*/
void clear_mem_regions(mem_region_t *tbl, size_t nregions);
/*
* checks that a region (addr + nbytes-1) of memory is totally covered by
* one of the regions defined in tbl. Caller must ensure that (addr+nbytes-1)
* doesn't overflow.
*/
int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
uintptr_t addr, size_t nbytes);
/*
* Fill a region of normal memory of size "length" in bytes with zero bytes.
*

View File

@ -89,11 +89,26 @@
#define PLAT_ARM_TRUSTED_SRAM_SIZE 0x00040000 /* 256 KB */
/* Reserve the last block of flash for PSCI MEM PROTECT flag */
#define PLAT_ARM_FIP_BASE V2M_FLASH0_BASE
#define PLAT_ARM_FIP_MAX_SIZE V2M_FLASH0_SIZE
#define PLAT_ARM_FIP_MAX_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
#define PLAT_ARM_NVM_BASE V2M_FLASH0_BASE
#define PLAT_ARM_NVM_SIZE V2M_FLASH0_SIZE
#define PLAT_ARM_NVM_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
/* PSCI memory protect definitions:
* This variable is stored in a non-secure flash because some ARM reference
* platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT
* support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions.
*/
#define PLAT_ARM_MEM_PROT_ADDR (V2M_FLASH0_BASE + \
V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE)
/*
* Map mem_protect flash region with read and write permissions
*/
#define ARM_V2M_MAP_MEM_PROTECT MAP_REGION_FLAT(PLAT_ARM_MEM_PROT_ADDR, \
V2M_FLASH_BLOCK_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
#endif /* __BOARD_ARM_DEF_H__ */

View File

@ -69,6 +69,7 @@
/* NOR Flash */
#define V2M_FLASH0_BASE 0x08000000
#define V2M_FLASH0_SIZE 0x04000000
#define V2M_FLASH_BLOCK_SIZE 0x00040000 /* 256 KB */
#define V2M_IOFPGA_BASE 0x1c000000
#define V2M_IOFPGA_SIZE 0x03000000

View File

@ -177,7 +177,12 @@
ARM_NS_DRAM1_SIZE, \
MT_MEMORY | MT_RW | MT_NS)
#define ARM_MAP_DRAM2 MAP_REGION_FLAT( \
ARM_DRAM2_BASE, \
ARM_DRAM2_SIZE, \
MT_MEMORY | MT_RW | MT_NS)
#ifdef SPD_tspd
#define ARM_MAP_TSP_SEC_MEM MAP_REGION_FLAT( \
TSP_SEC_MEM_BASE, \
TSP_SEC_MEM_SIZE, \
@ -224,8 +229,18 @@
* Required platform porting definitions common to all ARM standard platforms
*****************************************************************************/
/*
* We need to access DRAM2 from BL2 for PSCI_MEM_PROTECT for
* AArch64 builds
*/
#ifdef AARCH64
#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 36)
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 36)
#else
#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32)
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32)
#endif
/*
* This macro defines the deepest retention state possible. A higher state

View File

@ -122,6 +122,10 @@ int arm_validate_power_state(unsigned int power_state,
int arm_validate_ns_entrypoint(uintptr_t entrypoint);
void arm_system_pwr_domain_resume(void);
void arm_program_trusted_mailbox(uintptr_t address);
int arm_psci_read_mem_protect(int *val);
int arm_nor_psci_write_mem_protect(int val);
void arm_nor_psci_do_mem_protect(void);
int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length);
/* Topology utility function */
int arm_check_mpidr(u_register_t mpidr);

View File

@ -17,6 +17,7 @@ PSCI_LIB_SOURCES := lib/el3_runtime/cpu_data_array.c \
lib/psci/psci_main.c \
lib/psci/psci_setup.c \
lib/psci/psci_system_off.c \
lib/psci/psci_mem_protect.c \
lib/psci/${ARCH}/psci_helpers.S
ifeq (${ARCH}, aarch64)

View File

@ -408,6 +408,11 @@ u_register_t psci_smc_handler(uint32_t smc_fid,
case PSCI_STAT_COUNT_AARCH32:
return psci_stat_count(x1, x2);
#endif
case PSCI_MEM_PROTECT:
return psci_mem_protect(x1);
case PSCI_MEM_CHK_RANGE_AARCH32:
return psci_mem_chk_range(x1, x2);
default:
break;
@ -445,6 +450,10 @@ u_register_t psci_smc_handler(uint32_t smc_fid,
return psci_stat_count(x1, x2);
#endif
case PSCI_MEM_CHK_RANGE_AARCH64:
return psci_mem_chk_range(x1, x2);
default:
break;
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <limits.h>
#include <utils.h>
#include "psci_private.h"
int psci_mem_protect(unsigned int enable)
{
int val;
assert(psci_plat_pm_ops->read_mem_protect);
assert(psci_plat_pm_ops->write_mem_protect);
if (psci_plat_pm_ops->read_mem_protect(&val) < 0)
return PSCI_E_NOT_SUPPORTED;
if (psci_plat_pm_ops->write_mem_protect(enable) < 0)
return PSCI_E_NOT_SUPPORTED;
return val != 0;
}
int psci_mem_chk_range(uintptr_t base, u_register_t length)
{
int ret;
assert(psci_plat_pm_ops->mem_protect_chk);
if (length == 0 || check_uptr_overflow(base, length-1))
return PSCI_E_DENIED;
ret = psci_plat_pm_ops->mem_protect_chk(base, length);
return (ret < 0) ? PSCI_E_DENIED : PSCI_E_SUCCESS;
}

View File

@ -269,4 +269,8 @@ u_register_t psci_stat_residency(u_register_t target_cpu,
u_register_t psci_stat_count(u_register_t target_cpu,
unsigned int power_state);
/* Private exported functions from psci_mem_protect.c */
int psci_mem_protect(unsigned int enable);
int psci_mem_chk_range(uintptr_t base, u_register_t length);
#endif /* __PSCI_PRIVATE_H__ */

View File

@ -243,6 +243,11 @@ int psci_setup(const psci_lib_args_t *lib_args)
psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET);
if (psci_plat_pm_ops->get_node_hw_state)
psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64);
if (psci_plat_pm_ops->read_mem_protect &&
psci_plat_pm_ops->write_mem_protect)
psci_caps |= define_psci_cap(PSCI_MEM_PROTECT);
if (psci_plat_pm_ops->mem_protect_chk)
psci_caps |= define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64);
#if ENABLE_PSCI_STAT
psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64);

78
lib/utils/mem_region.c Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <utils.h>
/*
* All the regions defined in mem_region_t must have the following properties
*
* - Any contiguous regions must be merged into a single entry.
* - The number of bytes of each region must be greater than zero.
* - The calculation of the highest address within the region (base + nbytes-1)
* doesn't produce an overflow.
*
* These conditions must be fulfilled by the caller and they aren't checked
* at runtime.
*/
/*
* zero_normalmem all the regions defined in tbl.
* It assumes that MMU is enabled and the memory is Normal memory.
* tbl must be a valid pointer to a memory mem_region_t array,
* nregions is the size of the array.
*/
void clear_mem_regions(mem_region_t *tbl, size_t nregions)
{
size_t i;
assert(tbl);
assert(nregions > 0);
for (i = 0; i < nregions; i++) {
assert(tbl->nbytes > 0);
assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
zero_normalmem((void *) (tbl->base), tbl->nbytes);
tbl++;
}
}
/*
* This function checks that a region (addr + nbytes-1) of memory is totally
* covered by one of the regions defined in tbl.
* tbl must be a valid pointer to a memory mem_region_t array, nregions
* is the size of the array and the region described by addr and nbytes must
* not generate an overflow.
* Returns:
* -1 means that the region is not covered by any of the regions
* described in tbl.
* 0 the region (addr + nbytes-1) is covered by one of the regions described
* in tbl
*/
int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
uintptr_t addr, size_t nbytes)
{
uintptr_t region_start, region_end, start, end;
size_t i;
assert(tbl);
assert(nbytes > 0);
assert(!check_uptr_overflow(addr, nbytes-1));
region_start = addr;
region_end = addr + (nbytes - 1);
for (i = 0; i < nregions; i++) {
assert(tbl->nbytes > 0);
assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
start = tbl->base;
end = start + (tbl->nbytes - 1);
if (region_start >= start && region_end <= end)
return 0;
tbl++;
}
return -1;
}

View File

@ -12,9 +12,13 @@ PLAT_BL_COMMON_SOURCES += drivers/arm/pl011/${ARCH}/pl011_console.S \
BL1_SOURCES += plat/arm/board/common/drivers/norflash/norflash.c
BL2_SOURCES += plat/arm/board/common/drivers/norflash/norflash.c
BL2_SOURCES += lib/utils/mem_region.c \
plat/arm/common/arm_nor_psci_mem_protect.c \
plat/arm/board/common/drivers/norflash/norflash.c
#BL31_SOURCES +=
BL31_SOURCES += lib/utils/mem_region.c \
plat/arm/board/common/drivers/norflash/norflash.c \
plat/arm/common/arm_nor_psci_mem_protect.c
ifneq (${TRUSTED_BOARD_BOOT},0)
ifneq (${ARM_CRYPTOCELL_INTEG}, 1)

View File

@ -29,10 +29,16 @@ const mmap_region_t plat_arm_mmap[] = {
const mmap_region_t plat_arm_mmap[] = {
ARM_MAP_SHARED_RAM,
V2M_MAP_FLASH0_RO,
#ifdef PLAT_ARM_MEM_PROT_ADDR
ARM_V2M_MAP_MEM_PROTECT,
#endif
V2M_MAP_IOFPGA,
CSS_MAP_DEVICE,
SOC_CSS_MAP_DEVICE,
ARM_MAP_NS_DRAM1,
#ifdef AARCH64
ARM_MAP_DRAM2,
#endif
#ifdef SPD_tspd
ARM_MAP_TSP_SEC_MEM,
#endif
@ -56,6 +62,9 @@ const mmap_region_t plat_arm_mmap[] = {
ARM_MAP_SHARED_RAM,
V2M_MAP_IOFPGA,
CSS_MAP_DEVICE,
#ifdef PLAT_ARM_MEM_PROT_ADDR
ARM_V2M_MAP_MEM_PROTECT,
#endif
SOC_CSS_MAP_DEVICE,
{0}
};

View File

@ -79,6 +79,9 @@ const mmap_region_t plat_arm_mmap[] = {
MAP_DEVICE0,
MAP_DEVICE1,
ARM_MAP_NS_DRAM1,
#ifdef AARCH64
ARM_MAP_DRAM2,
#endif
#ifdef SPD_tspd
ARM_MAP_TSP_SEC_MEM,
#endif
@ -109,6 +112,7 @@ const mmap_region_t plat_arm_mmap[] = {
V2M_MAP_IOFPGA,
MAP_DEVICE0,
MAP_DEVICE1,
ARM_V2M_MAP_MEM_PROTECT,
{0}
};
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -324,5 +324,14 @@ plat_psci_ops_t plat_arm_psci_pm_ops = {
.system_reset = fvp_system_reset,
.validate_power_state = arm_validate_power_state,
.validate_ns_entrypoint = arm_validate_ns_entrypoint,
.get_node_hw_state = fvp_node_hw_state
.get_node_hw_state = fvp_node_hw_state,
/*
* mem_protect is not supported in RESET_TO_BL31 and RESET_TO_SP_MIN,
* as that would require mapping in all of NS DRAM into BL31 or BL32.
*/
#if !RESET_TO_BL31 && !RESET_TO_SP_MIN
.mem_protect_chk = arm_psci_mem_protect_chk,
.read_mem_protect = arm_psci_read_mem_protect,
.write_mem_protect = arm_nor_psci_write_mem_protect,
#endif
};

View File

@ -5,11 +5,14 @@
#
# SP_MIN source files specific to FVP platform
BL32_SOURCES += plat/arm/board/fvp/aarch32/fvp_helpers.S \
BL32_SOURCES += lib/utils/mem_region.c \
plat/arm/board/fvp/aarch32/fvp_helpers.S \
plat/arm/board/fvp/drivers/pwrc/fvp_pwrc.c \
plat/arm/board/fvp/fvp_pm.c \
plat/arm/board/fvp/fvp_topology.c \
plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c \
plat/arm/board/common/drivers/norflash/norflash.c \
plat/arm/common/arm_nor_psci_mem_protect.c \
${FVP_CPU_LIBS} \
${FVP_GIC_SOURCES} \
${FVP_INTERCONNECT_SOURCES} \

View File

@ -68,11 +68,11 @@
#ifdef IMAGE_BL2
#ifdef SPD_opteed
# define PLAT_ARM_MMAP_ENTRIES 9
# define MAX_XLAT_TABLES 4
# define PLAT_ARM_MMAP_ENTRIES 11
# define MAX_XLAT_TABLES 5
#else
# define PLAT_ARM_MMAP_ENTRIES 8
# define MAX_XLAT_TABLES 3
# define PLAT_ARM_MMAP_ENTRIES 10
# define MAX_XLAT_TABLES 4
#endif
#endif
@ -82,8 +82,8 @@
#endif
#ifdef IMAGE_BL31
# define PLAT_ARM_MMAP_ENTRIES 5
# define MAX_XLAT_TABLES 2
# define PLAT_ARM_MMAP_ENTRIES 7
# define MAX_XLAT_TABLES 3
#endif
#ifdef IMAGE_BL32

View File

@ -8,7 +8,10 @@
BL32_SOURCES += lib/cpus/aarch32/cortex_a53.S \
lib/cpus/aarch32/cortex_a57.S \
lib/cpus/aarch32/cortex_a72.S \
lib/utils/mem_region.c \
plat/arm/board/common/drivers/norflash/norflash.c \
plat/arm/board/juno/juno_topology.c \
plat/arm/common/arm_nor_psci_mem_protect.c \
plat/arm/soc/common/soc_css_security.c \
${JUNO_GIC_SOURCES} \
${JUNO_INTERCONNECT_SOURCES} \

View File

@ -193,6 +193,10 @@ void arm_bl2_platform_setup(void)
{
/* Initialize the secure environment */
plat_arm_security_setup();
#if defined(PLAT_ARM_MEM_PROT_ADDR)
arm_nor_psci_do_mem_protect();
#endif
}
void bl2_platform_setup(void)

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include <mmio.h>
#include <norflash.h>
#include <plat_arm.h>
#include <platform_def.h>
#include <psci.h>
#include <utils.h>
mem_region_t arm_ram_ranges[] = {
{ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_SIZE},
#ifdef AARCH64
{ARM_DRAM2_BASE, ARM_DRAM2_SIZE},
#endif
};
/*******************************************************************************
* Function that reads the content of the memory protect variable that
* enables clearing of non secure memory when system boots. This variable
* should be stored in a secure NVRAM.
******************************************************************************/
int arm_psci_read_mem_protect(int *enabled)
{
int tmp;
tmp = *(int *) PLAT_ARM_MEM_PROT_ADDR;
*enabled = (tmp == 1);
return 0;
}
/*******************************************************************************
* Function that writes the content of the memory protect variable that
* enables overwritten of non secure memory when system boots.
******************************************************************************/
int arm_nor_psci_write_mem_protect(int val)
{
int enable = (val != 0);
if (nor_unlock(PLAT_ARM_MEM_PROT_ADDR) != 0) {
ERROR("unlocking memory protect variable\n");
return -1;
}
if (enable) {
/*
* If we want to write a value different than 0
* then we have to erase the full block because
* otherwise we cannot ensure that the value programmed
* into the flash is going to be the same than the value
* requested by the caller
*/
if (nor_erase(PLAT_ARM_MEM_PROT_ADDR) != 0) {
ERROR("erasing block containing memory protect variable\n");
return -1;
}
}
if (nor_word_program(PLAT_ARM_MEM_PROT_ADDR, enable) != 0) {
ERROR("programming memory protection variable\n");
return -1;
}
return 0;
}
/*******************************************************************************
* Function used for required psci operations performed when
* system boots
******************************************************************************/
void arm_nor_psci_do_mem_protect(void)
{
int enable;
arm_psci_read_mem_protect(&enable);
if (!enable)
return;
INFO("PSCI: Overwritting non secure memory\n");
clear_mem_regions(arm_ram_ranges, ARRAY_SIZE(arm_ram_ranges));
arm_nor_psci_write_mem_protect(0);
}
/*******************************************************************************
* Function that checks if a region is protected by the memory protect
* mechanism
******************************************************************************/
int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length)
{
return mem_region_in_array_chk(arm_ram_ranges,
ARRAY_SIZE(arm_ram_ranges),
base, length);
}

View File

@ -290,5 +290,14 @@ plat_psci_ops_t plat_arm_psci_pm_ops = {
.validate_ns_entrypoint = arm_validate_ns_entrypoint,
.translate_power_state_by_mpidr = css_translate_power_state_by_mpidr,
.get_node_hw_state = css_node_hw_state,
.get_sys_suspend_power_state = css_get_sys_suspend_power_state
.get_sys_suspend_power_state = css_get_sys_suspend_power_state,
/*
* mem_protect is not supported in RESET_TO_BL31 and RESET_TO_SP_MIN,
* as that would require mapping in all of NS DRAM into BL31 or BL32.
*/
#if defined(PLAT_ARM_MEM_PROT_ADDR) && !RESET_TO_BL31 && !RESET_TO_SP_MIN
.mem_protect_chk = arm_psci_mem_protect_chk,
.read_mem_protect = arm_psci_read_mem_protect,
.write_mem_protect = arm_nor_psci_write_mem_protect,
#endif
};