xref: /arm-trusted-firmware/plat/arm/common/arm_nor_psci_mem_protect.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <platform_def.h>
8*91f16700Schasinglulu 
9*91f16700Schasinglulu #include <common/debug.h>
10*91f16700Schasinglulu #include <drivers/cfi/v2m_flash.h>
11*91f16700Schasinglulu #include <lib/psci/psci.h>
12*91f16700Schasinglulu #include <lib/utils.h>
13*91f16700Schasinglulu #include <plat/arm/common/plat_arm.h>
14*91f16700Schasinglulu 
15*91f16700Schasinglulu /*
16*91f16700Schasinglulu  * DRAM1 is used also to load the NS boot loader. For this reason we
17*91f16700Schasinglulu  * cannot clear the full DRAM1, because in that case we would clear
18*91f16700Schasinglulu  * the NS images (especially for RESET_TO_BL31 and RESET_TO_SPMIN cases).
19*91f16700Schasinglulu  * For this reason we reserve 64 MB for the NS images and protect the RAM
20*91f16700Schasinglulu  * until the end of DRAM1.
21*91f16700Schasinglulu  * We limit the size of DRAM2 to 1 GB to avoid big delays while booting
22*91f16700Schasinglulu  */
23*91f16700Schasinglulu #define DRAM1_NS_IMAGE_LIMIT  (PLAT_ARM_NS_IMAGE_BASE + (32 << TWO_MB_SHIFT))
24*91f16700Schasinglulu #define DRAM1_PROTECTED_SIZE  (ARM_NS_DRAM1_END+1u - DRAM1_NS_IMAGE_LIMIT)
25*91f16700Schasinglulu 
26*91f16700Schasinglulu static mem_region_t arm_ram_ranges[] = {
27*91f16700Schasinglulu 	{DRAM1_NS_IMAGE_LIMIT, DRAM1_PROTECTED_SIZE},
28*91f16700Schasinglulu #ifdef __aarch64__
29*91f16700Schasinglulu 	{ARM_DRAM2_BASE, 1u << ONE_GB_SHIFT},
30*91f16700Schasinglulu #endif
31*91f16700Schasinglulu };
32*91f16700Schasinglulu 
33*91f16700Schasinglulu /*******************************************************************************
34*91f16700Schasinglulu  * Function that reads the content of the memory protect variable that
35*91f16700Schasinglulu  * enables clearing of non secure memory when system boots. This variable
36*91f16700Schasinglulu  * should be stored in a secure NVRAM.
37*91f16700Schasinglulu  ******************************************************************************/
38*91f16700Schasinglulu int arm_psci_read_mem_protect(int *enabled)
39*91f16700Schasinglulu {
40*91f16700Schasinglulu 	int tmp;
41*91f16700Schasinglulu 
42*91f16700Schasinglulu 	tmp = *(int *) PLAT_ARM_MEM_PROT_ADDR;
43*91f16700Schasinglulu 	*enabled = (tmp == 1) ? 1 : 0;
44*91f16700Schasinglulu 	return 0;
45*91f16700Schasinglulu }
46*91f16700Schasinglulu 
47*91f16700Schasinglulu /*******************************************************************************
48*91f16700Schasinglulu  * Function that writes the content of the memory protect variable that
49*91f16700Schasinglulu  * enables overwritten of non secure memory when system boots.
50*91f16700Schasinglulu  ******************************************************************************/
51*91f16700Schasinglulu int arm_nor_psci_write_mem_protect(int val)
52*91f16700Schasinglulu {
53*91f16700Schasinglulu 	unsigned long enable = (val != 0) ? 1UL : 0UL;
54*91f16700Schasinglulu 
55*91f16700Schasinglulu 	if (nor_unlock(PLAT_ARM_MEM_PROT_ADDR) != 0) {
56*91f16700Schasinglulu 		ERROR("unlocking memory protect variable\n");
57*91f16700Schasinglulu 		return -1;
58*91f16700Schasinglulu 	}
59*91f16700Schasinglulu 
60*91f16700Schasinglulu 	if (enable == 1UL) {
61*91f16700Schasinglulu 		/*
62*91f16700Schasinglulu 		 * If we want to write a value different than 0
63*91f16700Schasinglulu 		 * then we have to erase the full block because
64*91f16700Schasinglulu 		 * otherwise we cannot ensure that the value programmed
65*91f16700Schasinglulu 		 * into the flash is going to be the same than the value
66*91f16700Schasinglulu 		 * requested by the caller
67*91f16700Schasinglulu 		 */
68*91f16700Schasinglulu 		if (nor_erase(PLAT_ARM_MEM_PROT_ADDR) != 0) {
69*91f16700Schasinglulu 			ERROR("erasing block containing memory protect variable\n");
70*91f16700Schasinglulu 			return -1;
71*91f16700Schasinglulu 		}
72*91f16700Schasinglulu 	}
73*91f16700Schasinglulu 
74*91f16700Schasinglulu 	if (nor_word_program(PLAT_ARM_MEM_PROT_ADDR, enable) != 0) {
75*91f16700Schasinglulu 		ERROR("programming memory protection variable\n");
76*91f16700Schasinglulu 		return -1;
77*91f16700Schasinglulu 	}
78*91f16700Schasinglulu 	return 0;
79*91f16700Schasinglulu }
80*91f16700Schasinglulu 
81*91f16700Schasinglulu /*******************************************************************************
82*91f16700Schasinglulu  * Function used for required psci operations performed when
83*91f16700Schasinglulu  * system boots
84*91f16700Schasinglulu  ******************************************************************************/
85*91f16700Schasinglulu /*
86*91f16700Schasinglulu  * PLAT_MEM_PROTECT_VA_FRAME is a address specifically
87*91f16700Schasinglulu  * selected in a way that is not needed an additional
88*91f16700Schasinglulu  * translation table for memprotect. It happens because
89*91f16700Schasinglulu  * we use a chunk of size 2MB and it means that it can
90*91f16700Schasinglulu  * be mapped in a level 2 table and the level 2 table
91*91f16700Schasinglulu  * for 0xc0000000 is already used and the entry for
92*91f16700Schasinglulu  * 0xc0000000 is not used.
93*91f16700Schasinglulu  */
94*91f16700Schasinglulu #if defined(PLAT_XLAT_TABLES_DYNAMIC)
95*91f16700Schasinglulu void arm_nor_psci_do_dyn_mem_protect(void)
96*91f16700Schasinglulu {
97*91f16700Schasinglulu 	int enable;
98*91f16700Schasinglulu 
99*91f16700Schasinglulu 	arm_psci_read_mem_protect(&enable);
100*91f16700Schasinglulu 	if (enable == 0)
101*91f16700Schasinglulu 		return;
102*91f16700Schasinglulu 
103*91f16700Schasinglulu 	INFO("PSCI: Overwriting non secure memory\n");
104*91f16700Schasinglulu 	clear_map_dyn_mem_regions(arm_ram_ranges,
105*91f16700Schasinglulu 				  ARRAY_SIZE(arm_ram_ranges),
106*91f16700Schasinglulu 				  PLAT_ARM_MEM_PROTEC_VA_FRAME,
107*91f16700Schasinglulu 				  1 << TWO_MB_SHIFT);
108*91f16700Schasinglulu }
109*91f16700Schasinglulu #endif
110*91f16700Schasinglulu 
111*91f16700Schasinglulu /*******************************************************************************
112*91f16700Schasinglulu  * Function used for required psci operations performed when
113*91f16700Schasinglulu  * system boots and dynamic memory is not used.
114*91f16700Schasinglulu  ******************************************************************************/
115*91f16700Schasinglulu void arm_nor_psci_do_static_mem_protect(void)
116*91f16700Schasinglulu {
117*91f16700Schasinglulu 	int enable;
118*91f16700Schasinglulu 
119*91f16700Schasinglulu 	(void) arm_psci_read_mem_protect(&enable);
120*91f16700Schasinglulu 	if (enable == 0)
121*91f16700Schasinglulu 		return;
122*91f16700Schasinglulu 
123*91f16700Schasinglulu 	INFO("PSCI: Overwriting non secure memory\n");
124*91f16700Schasinglulu 	clear_mem_regions(arm_ram_ranges,
125*91f16700Schasinglulu 			  ARRAY_SIZE(arm_ram_ranges));
126*91f16700Schasinglulu 	(void) arm_nor_psci_write_mem_protect(0);
127*91f16700Schasinglulu }
128*91f16700Schasinglulu 
129*91f16700Schasinglulu /*******************************************************************************
130*91f16700Schasinglulu  * Function that checks if a region is protected by the memory protect
131*91f16700Schasinglulu  * mechanism
132*91f16700Schasinglulu  ******************************************************************************/
133*91f16700Schasinglulu int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length)
134*91f16700Schasinglulu {
135*91f16700Schasinglulu 	return mem_region_in_array_chk(arm_ram_ranges,
136*91f16700Schasinglulu 				       ARRAY_SIZE(arm_ram_ranges),
137*91f16700Schasinglulu 				       base, length);
138*91f16700Schasinglulu }
139