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