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