blob: ad86240190d3acb14ea965dad406b0ee0e4475e8 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <debug.h>
9#include <errno.h>
10#include <platform_def.h>
11#include <secure_partition.h>
12#include <sp_helpers.h>
13#include <spm_svc.h>
14#include <stdio.h>
15#include <types.h>
16#include <xlat_tables_defs.h>
17
18#include "cactus.h"
Antonio Nino Diaz1486f3b2018-06-26 10:30:10 +010019#include "cactus_def.h"
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020020#include "cactus_tests.h"
21
22/* This is filled at runtime. */
23static uintptr_t cactus_tests_start;
24static uintptr_t cactus_tests_end;
25static uintptr_t cactus_tests_size;
26
27/*
28 * Given the required instruction and data access permissions,
29 * create a memory access controls value that is formatted as expected
30 * by the SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC.
31 */
32static inline uint32_t mem_access_perm(int instr_access_perm,
33 int data_access_perm)
34{
35 return instr_access_perm |
36 ((data_access_perm & SP_MEMORY_ATTRIBUTES_ACCESS_MASK)
37 << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT);
38}
39
40/*
41 * Send an SP_MEMORY_ATTRIBUTES_SET_AARCH64 SVC with the given arguments.
42 * Return the return value of the SVC.
43 */
44static int32_t request_mem_attr_changes(uintptr_t base_address,
45 int pages_count,
46 uint32_t memory_access_controls)
47{
48 INFO("Requesting memory attributes change\n");
49 INFO(" Start address : %p\n", (void *) base_address);
50 INFO(" Number of pages: %i\n", pages_count);
51 INFO(" Attributes : 0x%x\n", memory_access_controls);
52
53 svc_args svc_values = { SP_MEMORY_ATTRIBUTES_SET_AARCH64,
54 base_address,
55 pages_count,
56 memory_access_controls };
57 return sp_svc(&svc_values);
58}
59
60/*
61 * Send an SP_MEMORY_ATTRIBUTES_GET_AARCH64 SVC with the given arguments.
62 * Return the return value of the SVC.
63 */
64static int32_t request_get_mem_attr(uintptr_t base_address)
65{
66 INFO("Requesting memory attributes\n");
67 INFO(" Base address : %p\n", (void *) base_address);
68
69 svc_args svc_values = { SP_MEMORY_ATTRIBUTES_GET_AARCH64,
70 base_address };
71 return sp_svc(&svc_values);
72}
73
74/*
75 * This function expects a base address and number of pages identifying the
76 * extents of some memory region mapped as non-executable, read-only.
77 *
78 * 1) It changes its data access permissions to read-write.
79 * 2) It checks this memory can now be written to.
80 * 3) It restores the original data access permissions.
81 *
82 * If any check fails, it loops forever. It could also trigger a permission
83 * fault while trying to write to the memory.
84 */
85static void mem_attr_changes_unittest(uintptr_t addr, int pages_count)
86{
87 int32_t ret;
88 uintptr_t end_addr = addr + pages_count * PAGE_SIZE;
89 uint32_t old_attr, new_attr;
90
91 char test_desc[50];
92
93 snprintf(test_desc, sizeof(test_desc),
94 "RO -> RW (%i page(s) from address 0x%lx)", pages_count, addr);
95 announce_test_start(test_desc);
96
97 /*
98 * Ensure we don't change the attributes of some random memory
99 * location
100 */
101 assert(addr >= cactus_tests_start);
102 assert(end_addr < (cactus_tests_start + cactus_tests_size));
103
104 old_attr = mem_access_perm(SP_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_ACCESS_RO);
105 /* Memory was read-only, let's try changing that to RW */
106 new_attr = mem_access_perm(SP_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_ACCESS_RW);
107
108 ret = request_mem_attr_changes(addr, pages_count, new_attr);
109 expect(ret, SPM_SUCCESS);
110 printf("Successfully changed memory attributes\n");
111
112 /* The attributes should be the ones we have just written. */
113 ret = request_get_mem_attr(addr);
114 expect(ret, new_attr);
115
116 /* If it worked, we should be able to write to this memory now! */
117 for (unsigned char *data = (unsigned char *) addr;
118 (uintptr_t) data != end_addr;
119 ++data) {
120 *data = 42;
121 }
122 printf("Successfully wrote to the memory\n");
123
124 /* Let's revert back to the original attributes for the next test */
125 ret = request_mem_attr_changes(addr, pages_count, old_attr);
126 expect(ret, SPM_SUCCESS);
127 printf("Successfully restored the old attributes\n");
128
129 /* The attributes should be the original ones again. */
130 ret = request_get_mem_attr(addr);
131 expect(ret, old_attr);
132
133 announce_test_end(test_desc);
134}
135
136/*
137 * Exercise the ability of the Trusted Firmware to change the data access
138 * permissions and instruction execution permissions of some memory region.
139 */
Antonio Nino Diaz1486f3b2018-06-26 10:30:10 +0100140void mem_attr_changes_tests(void)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200141{
142 uint32_t attributes;
143 int32_t ret;
144 uintptr_t addr;
145
Antonio Nino Diaz1486f3b2018-06-26 10:30:10 +0100146 cactus_tests_start = CACTUS_TEST_MEM_BASE;
147 cactus_tests_size = CACTUS_TEST_MEM_SIZE;
148 cactus_tests_end = cactus_tests_start + cactus_tests_size;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200149
150 const char *test_sect_desc = "memory attributes changes";
151
152 announce_test_section_start(test_sect_desc);
153 /*
154 * Start with error cases, i.e. requests that are expected to be denied
155 */
156 const char *test_desc1 = "Read-write, executable";
157
158 announce_test_start(test_desc1);
159 attributes = mem_access_perm(SP_MEMORY_ATTRIBUTES_EXEC, SP_MEMORY_ATTRIBUTES_ACCESS_RW);
Antonio Nino Diaz54287c82018-12-05 15:37:33 +0000160 ret = request_mem_attr_changes(cactus_tests_start, 1, attributes);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200161 expect(ret, SPM_INVALID_PARAMETER);
162 announce_test_end(test_desc1);
163
164 const char *test_desc2 = "Size == 0";
165
166 announce_test_start(test_desc2);
167 attributes = mem_access_perm(SP_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_ACCESS_RW);
Antonio Nino Diaz54287c82018-12-05 15:37:33 +0000168 ret = request_mem_attr_changes(cactus_tests_start, 0, attributes);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200169 expect(ret, SPM_INVALID_PARAMETER);
170 announce_test_end(test_desc2);
171
172 const char *test_desc3 = "Unaligned address";
173
174 announce_test_start(test_desc3);
175 attributes = mem_access_perm(SP_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_ACCESS_RW);
176 /* Choose an address not aligned to a page boundary. */
177 addr = cactus_tests_start + 5;
178 ret = request_mem_attr_changes(addr, 1, attributes);
179 expect(ret, SPM_INVALID_PARAMETER);
180 announce_test_end(test_desc3);
181
182 const char *test_desc4 = "Unmapped memory region";
183
184 announce_test_start(test_desc4);
Antonio Nino Diaz1486f3b2018-06-26 10:30:10 +0100185 addr = cactus_tests_end + 2 * PAGE_SIZE;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200186 attributes = mem_access_perm(SP_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_ACCESS_RW);
187 ret = request_mem_attr_changes(addr, 3, attributes);
188 expect(ret, SPM_INVALID_PARAMETER);
189 announce_test_end(test_desc4);
190
191 const char *test_desc5 = "Partially unmapped memory region";
192
193 announce_test_start(test_desc5);
Antonio Nino Diaz1486f3b2018-06-26 10:30:10 +0100194 addr = cactus_tests_end - 2 * PAGE_SIZE;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200195 attributes = mem_access_perm(SP_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_ACCESS_RW);
196 ret = request_mem_attr_changes(addr, 6, attributes);
197 expect(ret, SPM_INVALID_PARAMETER);
198 announce_test_end(test_desc5);
199
200 const char *test_desc6 = "Memory region mapped with the wrong granularity";
201
202 announce_test_start(test_desc6);
203 /*
204 * This address is usually mapped at a 2 MiB granularity. By using as
205 * test address the block after the console we make sure that in case
206 * the attributes of the block actually changed, the console would work
207 * and we would get the error message.
208 */
209 addr = ((uintptr_t)PLAT_ARM_UART_BASE + 0x200000ULL) & ~(0x200000ULL - 1ULL);
210 attributes = mem_access_perm(SP_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_ACCESS_RW);
211 ret = request_mem_attr_changes(addr, 1, attributes);
212 expect(ret, SPM_INVALID_PARAMETER);
213 announce_test_end(test_desc6);
214
215 const char *test_desc7 = "Try some valid memory change requests";
216
217 announce_test_start(test_desc7);
218 for (unsigned int i = 0; i < 20; ++i) {
219 /*
220 * Choose some random address in the pool of memory reserved
221 * for these tests.
222 */
223 const int pages_max = cactus_tests_size / PAGE_SIZE;
224 int pages_count = bound_rand(1, pages_max);
225
226 addr = bound_rand(
227 cactus_tests_start,
228 cactus_tests_end - (pages_count * PAGE_SIZE));
229 /* Align to PAGE_SIZE. */
230 addr &= ~(PAGE_SIZE - 1);
231
232 mem_attr_changes_unittest(addr, pages_count);
233 }
234 announce_test_end(test_desc7);
235
236 announce_test_section_end(test_sect_desc);
237}