blob: c4ffbf9ac19166af3df8ebd46fd8da7f058ef2c6 [file] [log] [blame]
Antonio Nino Diaz54959b02019-03-29 12:59:35 +00001/*
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -06002 * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
Antonio Nino Diaz54959b02019-03-29 12:59:35 +00003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch.h>
8#include <arch_helpers.h>
9#include <debug.h>
10#include <errno.h>
11#include <platform_def.h>
12#include <stdlib.h>
13#include <string.h>
14#include <tftf_lib.h>
15#include <xlat_tables_v2.h>
16
17/*
18 * NOTE: In order to make the tests as generic as possible, the tests don't
19 * actually access the mapped memory, the instruction AT is used to verify that
20 * the mapping is correct. It is likely that the memory that ends up being
21 * mapped isn't physically there, so the memory is mapped as device memory to
22 * prevent the CPU from speculatively reading from it.
23 *
24 * Also, it is very likely that a failure in any of the tests would leave the
25 * translation tables in a state from which the system can't be recovered. This
26 * is why in some cases the tests don't try to unmap regions that have been
27 * successfully mapped.
28 */
29
Antonio Nino Diaz402b2692018-10-05 15:11:38 +010030#define STRESS_TEST_ITERATIONS 1000
31
Antonio Nino Diaz54959b02019-03-29 12:59:35 +000032#define SIZE_L1 XLAT_BLOCK_SIZE(1)
33#define SIZE_L2 XLAT_BLOCK_SIZE(2)
34#define SIZE_L3 XLAT_BLOCK_SIZE(3) /* PAGE_SIZE */
35
36#define MASK_L1 XLAT_BLOCK_MASK(1)
37#define MASK_L2 XLAT_BLOCK_MASK(2)
38#define MASK_L3 XLAT_BLOCK_MASK(3)
39
Antonio Nino Diazf152f8f2018-10-05 15:18:45 +010040static const struct {
41 size_t size;
42 size_t expected_va_mask;
43} mem_tests[] = {
44 { SIZE_L1 + 2 * SIZE_L2 + 2 * SIZE_L3, MASK_L3 },
45 { SIZE_L1 + SIZE_L2 + SIZE_L3, MASK_L3 },
46 { SIZE_L1 + 2 * SIZE_L2, MASK_L2 },
47 { SIZE_L1 + SIZE_L2, MASK_L2 },
48 { SIZE_L1 + 2 * SIZE_L3, MASK_L3 },
49 { SIZE_L1 + SIZE_L3, MASK_L3 },
50 { SIZE_L1, MASK_L1 },
51 { SIZE_L2 + 2 * SIZE_L3, MASK_L3 },
52 { SIZE_L2 + SIZE_L3, MASK_L3 },
53 { SIZE_L2, MASK_L2 },
54 { SIZE_L3, MASK_L3 }
55};
56
Antonio Nino Diaz54959b02019-03-29 12:59:35 +000057/*
58 * Translate the given virtual address into a physical address in the current
59 * translation regime. Returns the resulting physical address on success,
60 * otherwise UINT64_MAX.
61 */
62static unsigned long long va2pa(uintptr_t base_va)
63{
64 uint64_t par;
65
66 /*
67 * Performs stage 1 address translation for the current EL, with
68 * read permissions.
69 */
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -060070#ifndef __aarch64__
Antonio Nino Diaz54959b02019-03-29 12:59:35 +000071 if (IS_IN_HYP())
72 write_ats1hr(base_va);
73 else
74 write_ats1cpr(base_va);
75 isb();
76 par = read64_par();
77#else
78 if (IS_IN_EL2())
79 ats1e2r(base_va);
80 else
81 ats1e1r(base_va);
82 isb();
83 par = read_par_el1();
84#endif
85
86 /*
87 * If PAR_EL1.F == 1 then the address translation was aborted.
88 * In this case, return an invalid VA.
89 */
90 if (par & PAR_F_MASK)
91 return UINT64_MAX;
92
93 /*
94 * If PAR_EL1.F == 0 then the address translation completed
95 * successfully. In this case, bits 47-12 hold bits 47-12 of the
96 * resulting physical address.
97 */
98 return par & (PAR_ADDR_MASK << PAR_ADDR_SHIFT);
99}
100
101/*
102 * Checks that the given region has been mapped correctly. Returns 0 on success,
103 * 1 otherwise.
104 */
105static int verify_region_mapped(unsigned long long base_pa, uintptr_t base_va,
106 size_t size)
107{
108 uintptr_t end_va = base_va + size;
109 unsigned long long addr;
110
111 VERBOSE("Checking: PA = 0x%llx, VA = 0x%lx, size = 0x%zx\n",
112 base_pa, base_va, size);
113
114 while (base_va < end_va) {
115 addr = va2pa(base_va);
116
117 if (base_pa != addr) {
118 ERROR("Error: 0x%lx => 0x%llx (expected 0x%llx)\n",
119 base_va, addr, base_pa);
120 return 1;
121 }
122
123 base_va += PAGE_SIZE;
124 base_pa += PAGE_SIZE;
125 }
126
127 return 0;
128}
129
130/*
131 * Checks that the given region has been unmapped correctly. Returns 0 on
132 * success, 1 otherwise.
133 */
134static int verify_region_unmapped(uintptr_t base_va, size_t size)
135{
136 uintptr_t end_va = base_va + size;
137
138 VERBOSE("Checking: VA = 0x%lx, size = 0x%zx\n", base_va, size);
139
140 while (base_va < end_va) {
141 unsigned long long phys_addr = va2pa(base_va);
142
143 if (phys_addr != UINT64_MAX) {
144 ERROR("Error: 0x%lx => 0x%llx (expected UINT64_MAX)\n",
145 base_va, phys_addr);
146 return 1;
147 }
148
149 base_va += PAGE_SIZE;
150 }
151
152 return 0;
153}
154
155/*
156 * Ask to map a given region of physical memory with a given set of memory
157 * attributes. Returns 0 on success, otherwise an error code returned by
158 * mmap_add_dynamic_region(). On success, it also verifies that the mapping has
159 * been done correctly.
160 */
161static int add_region(unsigned long long base_pa, uintptr_t base_va,
162 size_t size, unsigned int attr)
163{
164 int ret;
165
Shruti Gupta92b99ee2023-10-10 14:23:48 +0100166 if (size == 0U) {
167 return -EPERM;
168 }
Antonio Nino Diaz54959b02019-03-29 12:59:35 +0000169 VERBOSE("mmap_add_dynamic_region(0x%llx, 0x%lx, 0x%zx, 0x%x)\n",
170 base_pa, base_va, size, attr);
171
172 ret = mmap_add_dynamic_region(base_pa, base_va, size, attr);
173
174 VERBOSE(" = %d\n", ret);
175
176 if (ret == 0) {
177 return verify_region_mapped(base_pa, base_va, size);
178 }
179
180 return ret;
181}
182
183/*
184 * Ask to map a given region of physical memory with a given set of memory
185 * attributes. On success it returns a VA with the VA allocated for the new
186 * region and 0 as error code. Otherwise, the error code returned by
187 * mmap_add_dynamic_region_alloc_va().
188 */
189static int add_region_alloc_va(unsigned long long base_pa, uintptr_t *base_va,
190 size_t size, unsigned int attr)
191{
192 int ret;
193
194 VERBOSE("mmap_add_dynamic_region_alloc_va(0x%llx, 0x%zx, 0x%x)\n",
195 base_pa, size, attr);
196
197 ret = mmap_add_dynamic_region_alloc_va(base_pa, base_va, size, attr);
198
199 VERBOSE(" = %d VA=0x%lx\n", ret, *base_va);
200
201 if (ret == 0) {
202 return verify_region_mapped(base_pa, *base_va, size);
203 }
204
205 return ret;
206}
207
208/*
209 * Unmap a given memory region given its virtual address and size.
210 */
211static int remove_region(uintptr_t base_va, size_t size)
212{
213 int ret;
214
215 VERBOSE("mmap_remove_dynamic_region(0x%lx, 0x%zx)\n", base_va, size);
216
217 ret = mmap_remove_dynamic_region(base_va, size);
218
219 VERBOSE(" = %d\n", ret);
220
221 if (ret == 0) {
222 return verify_region_unmapped(base_va, size);
223 }
224
225 return ret;
226}
227
Antonio Nino Diaz402b2692018-10-05 15:11:38 +0100228/*
229 * Number of individual chunks of memory that can be mapped and unmaped in the
230 * region that we use for testing. The size of each block is total_size /
231 * num_blocks. The test tries to allocate as much memory as possible.
232 */
233#define STRESS_TEST_NUM_BLOCKS 1024
234
235/* Memory region to be used by the stress test */
236static uintptr_t memory_base_va;
237static size_t memory_size;
238/* Block size to be used by the stress test */
239static size_t block_size;
240/*
241 * Each element of the array can have one of the following states:
242 * - 0: Free
243 * - 1: Used
244 * - 2: Used, and it is the start of a region
245 */
246static int block_used[STRESS_TEST_NUM_BLOCKS];
247
248/* Returns -1 if error, 1 if chunk added, 0 if not added */
249static int alloc_random_chunk(void)
250{
251 int rc;
252 int start = rand() % STRESS_TEST_NUM_BLOCKS;
253 int blocks = rand() % STRESS_TEST_NUM_BLOCKS;
254 bool is_free = true;
255
256 if (start + blocks > STRESS_TEST_NUM_BLOCKS) {
257 blocks = STRESS_TEST_NUM_BLOCKS - start;
258 }
259
260 /* Check if it's free */
261 for (int i = start; i < start + blocks; i++) {
262 if (block_used[i] != 0) {
263 is_free = false;
264 break;
265 }
266 }
267
268 uintptr_t base_va = memory_base_va + start * block_size;
269 unsigned long long base_pa = base_va;
270 size_t size = blocks * block_size;
271
272 if (is_free) {
273 /*
274 * Allocate a region, it should succeed. Use a non 1:1 mapping
275 * by adding an arbitrary offset to the base PA.
276 */
277 rc = add_region(base_pa + 0x20000U, base_va, size, MT_DEVICE);
278 if ((rc == -ENOMEM) || (rc == -EPERM)) {
279 /*
280 * Not enough memory or partial overlap, don't consider
281 * this a hard failure.
282 */
283 return 0;
284 } else if (rc != 0) {
285 tftf_testcase_printf("%d: add_region failed: %d\n",
286 __LINE__, rc);
287 return -1;
288 }
289
290 /* Flag as used */
291 block_used[start] = 2;
292 for (int i = start + 1; i < start + blocks; i++)
293 block_used[i] = 1;
294
295 return 1;
296 } else {
297 /* Allocate, it should fail */
298 rc = add_region(base_pa, base_va, size, MT_DEVICE);
299 if (rc == 0) {
300 tftf_testcase_printf("%d: add_region succeeded\n",
301 __LINE__);
302 return -1;
303 }
304
305 return 0;
306 }
307}
308
309/* Returns -1 if error, 1 if chunk removed, 0 if not removed */
310static int free_random_chunk(void)
311{
312 int start = -1;
313 int end = -1;
314 int seek = rand() % STRESS_TEST_NUM_BLOCKS;
315 int i = seek;
316
317 for (;;) {
318 if (start == -1) { /* Look for the start of a block */
319
320 /* Search the start of a chunk */
321 if (block_used[i] == 2) {
322 start = i;
323 }
324
325 } else { /* Look for the end of the block */
326
327 /* Search free space or the start of another chunk */
328 if (block_used[i] != 1) {
329 end = i;
330 break;
331 }
332 }
333
334 i++;
335
336 if (start == -1) { /* Look for the start of a block */
337
338 /* Looking for the start of a block so wrap around */
339 if (i == STRESS_TEST_NUM_BLOCKS) {
340 i = 0;
341 }
342
343 } else { /* Look for the end of the block */
344
345 /* If the end of the region is reached, this must be
346 * the end of the chunk as well.*/
347 if (i == STRESS_TEST_NUM_BLOCKS) {
348 end = i;
349 break;
350 }
351 }
352
353 /* Back to the starting point of the search: no chunk found */
354 if (i == seek) {
355 break;
356 }
357 }
358
359 /* No chunks found */
360 if ((start == -1) || (end == -1)) {
361 return 0;
362 }
363
364 int blocks = end - start;
365
366 bool is_correct_size = true;
367
368 if ((rand() % 5) == 0) { /* Make it fail sometimes */
369 blocks++;
370 is_correct_size = false;
371 }
372
373 uintptr_t base_va = memory_base_va + start * block_size;
374 size_t size = blocks * block_size;
375
376 if (is_correct_size) {
377 /* Remove, it should succeed */
378 int rc = remove_region(base_va, size);
379 if (rc != 0) {
380 tftf_testcase_printf("%d: remove_region failed: %d\n",
381 __LINE__, rc);
382 return 1;
383 }
384
385 /* Flag as unused */
386 for (int i = start; i < start + blocks; i++) {
387 block_used[i] = 0;
388 }
389
390 return 1;
391 } else {
392 /* Remove, it should fail */
393 int rc = remove_region(base_va, size);
394 if (rc == 0) {
395 tftf_testcase_printf("%d: remove_region succeeded\n",
396 __LINE__);
397 return 1;
398 }
399
400 return 0;
401 }
402}
403
404/* Returns number of allocated chunks */
405static int get_num_chunks(void)
406{
407 int count = 0;
408
409 for (int i = 0; i < STRESS_TEST_NUM_BLOCKS; i++) {
410 if (block_used[i] == 2) {
411 count++;
412 }
413 }
414
415 return count;
416}
417
Antonio Nino Diaz54959b02019-03-29 12:59:35 +0000418/**
419 * @Test_Aim@ Perform dynamic translation tables API basic tests
420 *
421 * This test checks for invalid uses of the dynamic translation tables library.
422 */
423test_result_t xlat_lib_v2_basic_test(void)
424{
425 uintptr_t memory_base_va;
426 int rc, i;
427
428 /*
429 * 1) Try to allocate a region with size 0.
430 *
431 * The allocation should "succeed" but not allocate anything, and it
432 * still should return the top VA.
433 */
434 rc = add_region_alloc_va(0, &memory_base_va, 0, 0);
435 if (rc != 0) {
436 tftf_testcase_printf("%d: add_region_alloc_va: %d\n",
437 __LINE__, rc);
438 return TEST_RESULT_FAIL;
439 }
440
441 /*
442 * Try do deallocate this region. It should fail because it hasn't been
443 * allocated in the first place.
444 */
445 rc = remove_region(memory_base_va, 0);
446 if (rc != -EINVAL) {
447 if (rc == 0) {
448 tftf_testcase_printf("%d: Deallocation should have failed.\n",
449 __LINE__);
450 } else {
451 tftf_testcase_printf("%d: remove_region: %d\n",
452 __LINE__, rc);
453 }
454 return TEST_RESULT_FAIL;
455 }
456
457 /* 2) Allocate and deallocate a small region */
458
459 rc = add_region_alloc_va(0, &memory_base_va, SIZE_L3, MT_DEVICE);
460 if (rc != 0) {
461 tftf_testcase_printf("%d: add_region_alloc_va: %d\n",
462 __LINE__, rc);
463 return TEST_RESULT_FAIL;
464 }
465
466 rc = remove_region(memory_base_va, SIZE_L3);
467 if (rc != 0) {
468 tftf_testcase_printf("%d: remove_region: %d\n", __LINE__, rc);
469 return TEST_RESULT_FAIL;
470 }
471
472 /*
473 * 3) Try to allocate the last page of the virtual address space, which
474 * can lead to wraparound problems (specially in AArch32).
475 */
476 rc = add_region(PLAT_VIRT_ADDR_SPACE_SIZE - PAGE_SIZE,
477 PLAT_VIRT_ADDR_SPACE_SIZE - PAGE_SIZE,
478 PAGE_SIZE, MT_DEVICE);
479 if (rc != 0) {
480 tftf_testcase_printf("%d: add_region: %d\n", __LINE__, rc);
481 return TEST_RESULT_FAIL;
482 }
483
484 rc = remove_region(PLAT_VIRT_ADDR_SPACE_SIZE - PAGE_SIZE, PAGE_SIZE);
485 if (rc != 0) {
486 tftf_testcase_printf("%d: remove_region: %d\n", __LINE__, rc);
487 return TEST_RESULT_FAIL;
488 }
489
490 /*
491 * 4) Try to allocate an invalid region. It should fail, but it will
492 * return the address of memory that can be used for the following
493 * tests.
494 */
495 rc = add_region_alloc_va(0, &memory_base_va, SIZE_MAX, MT_DEVICE);
496 if (rc == 0) {
497 tftf_testcase_printf("%d: add_region_alloc_va() didn't fail\n",
498 __LINE__);
499
500 return TEST_RESULT_FAIL;
501 }
502
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -0600503#ifdef __aarch64__
Antonio Nino Diaz54959b02019-03-29 12:59:35 +0000504 unsigned long long memory_base_pa;
505
506 /*
507 * Get address of memory region over the max used VA that is aligned to
508 * a L1 block for the next tests.
509 */
510 memory_base_pa = (memory_base_va + SIZE_L1 - 1ULL) & ~MASK_L1;
511
512 INFO("Using 0x%llx as base address for tests.\n", memory_base_pa);
513
514 /*
515 * 5) Try to allocate memory over the virtual address space limit. This
516 * test can't run in AArch32 because size_t is 32-bit wide, and the
517 * address space used by the TFTF is also 32-bit wide, so it is not
518 * possible to go over the limit.
519 */
520
521 rc = add_region(memory_base_pa, memory_base_va,
522 PLAT_VIRT_ADDR_SPACE_SIZE + PAGE_SIZE - memory_base_pa,
523 MT_DEVICE);
524 if (rc != -ERANGE) {
525 tftf_testcase_printf("%d: Allocation succeeded: %d\n",
526 __LINE__, rc);
527 return TEST_RESULT_FAIL;
528 }
529
530 /* Try to wrap around 64 bit */
531 rc = add_region(1ULL << 32, 1ULL << 32,
532 UINT64_MAX - PAGE_SIZE + 1ULL,
533 MT_DEVICE);
534 if (rc != -ERANGE) {
535 tftf_testcase_printf("%d: Allocation succeeded: %d\n",
536 __LINE__, rc);
537 return TEST_RESULT_FAIL;
538 }
539#else
540 /* Try to wrap around 32 bit */
541 rc = add_region((1ULL << 32) - PAGE_SIZE, (1ULL << 32) - PAGE_SIZE,
542 2 * PAGE_SIZE, MT_DEVICE);
543 if (rc != -ERANGE) {
544 tftf_testcase_printf("%d: Allocation succeeded: %d\n",
545 __LINE__, rc);
546 return TEST_RESULT_FAIL;
547 }
548#endif
549
550 /*
551 * 6) Try to allocate too many regions. There is only room for at most
552 * MAX_MMAP_REGIONS, and some of the regions are already used for
553 * devices, code, BSS, etc. Trying to allocate MAX_MMAP_REGIONS here
554 * should fail.
555 */
556 for (i = 0; i < MAX_MMAP_REGIONS; i++) {
557 uintptr_t addr = memory_base_va + PAGE_SIZE * i;
558
559 rc = add_region(addr, addr, PAGE_SIZE, MT_DEVICE);
560 if (rc == -ENOMEM) {
561 /* The limit has been reached as expected */
562 break;
563 } else if (rc != 0) {
564 tftf_testcase_printf("%d: add_region: %d\n",
565 __LINE__, rc);
566 return TEST_RESULT_FAIL;
567 }
568 }
569
570 if (i == MAX_MMAP_REGIONS) {
571 tftf_testcase_printf("%d: Too many regions allocated\n",
572 __LINE__);
573 return TEST_RESULT_FAIL;
574 }
575
576 i--;
577
578 /* Cleanup */
579 for (; i >= 0; i--) {
580 uintptr_t addr = memory_base_va + PAGE_SIZE * i;
581
582 rc = remove_region(addr, PAGE_SIZE);
583 if (rc != 0) {
584 tftf_testcase_printf("%d: remove_region: %d\n",
585 __LINE__, rc);
586 return TEST_RESULT_FAIL;
587 }
588 }
589
590 return TEST_RESULT_SUCCESS;
591}
Antonio Nino Diaz402b2692018-10-05 15:11:38 +0100592
593/**
Antonio Nino Diazf152f8f2018-10-05 15:18:45 +0100594 * @Test_Aim@ Perform dynamic translation tables API alignment tests
595 *
596 * This test makes sure that the alloc VA APIs return addresses aligned as
597 * expected.
598 */
599test_result_t xlat_lib_v2_alignment_test(void)
600{
601 uintptr_t memory_base_va;
602 unsigned long long memory_base_pa;
603 int rc, i;
604
605 /*
606 * 1) Try to allocate an invalid region. It should fail, but it will
607 * return the address of memory that can be used for the following
608 * tests.
609 */
610
611 rc = add_region_alloc_va(0, &memory_base_va, SIZE_MAX, MT_DEVICE);
612 if (rc == 0) {
613 tftf_testcase_printf("%d: add_region_alloc_va() didn't fail\n",
614 __LINE__);
615
616 return TEST_RESULT_FAIL;
617 }
618
619 /*
620 * Get address of memory region over the max used VA that is aligned to
621 * a L1 block for the next tests.
622 */
623 memory_base_pa = (memory_base_va + SIZE_L1 - 1ULL) & ~MASK_L1;
624
625 INFO("Using 0x%llx as base address for tests.\n", memory_base_pa);
626
627 /*
628 * 2) Try to allocate regions that have an unaligned base VA or PA, or
629 * a size that isn't multiple of PAGE_SIZE.
630 */
631
632 rc = add_region(memory_base_va + 1, memory_base_va, PAGE_SIZE, MT_DEVICE);
633 if (rc != -EINVAL) {
634 tftf_testcase_printf("%d: add_region: %d\n", __LINE__, rc);
635 return TEST_RESULT_FAIL;
636 }
637
638 rc = add_region(memory_base_va, memory_base_va + 1, PAGE_SIZE, MT_DEVICE);
639 if (rc != -EINVAL) {
640 tftf_testcase_printf("%d: add_region: %d\n", __LINE__, rc);
641 return TEST_RESULT_FAIL;
642 }
643
644 rc = add_region(memory_base_va, memory_base_va, PAGE_SIZE + 1, MT_DEVICE);
645 if (rc != -EINVAL) {
646 tftf_testcase_printf("%d: add_region: %d\n", __LINE__, rc);
647 return TEST_RESULT_FAIL;
648 }
649
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -0600650#ifdef __aarch64__
Antonio Nino Diazf152f8f2018-10-05 15:18:45 +0100651 /*
652 * 3) Try to allocate at least 1 GB aligned. There is only room for this
653 * in AArch64.
654 */
655
656 rc = add_region_alloc_va(memory_base_pa, &memory_base_va, SIZE_L1,
657 MT_DEVICE);
658 if (rc == -ENOMEM) {
659 tftf_testcase_printf("%d: Not enough memory\n", __LINE__);
660 return TEST_RESULT_FAIL;
661 } else if (rc != 0) {
662 tftf_testcase_printf("%d: add_region_alloc_va: %d\n",
663 __LINE__, rc);
664 return TEST_RESULT_FAIL;
665 }
666
667 rc = remove_region(memory_base_va, SIZE_L1);
668 if (rc != 0) {
669 tftf_testcase_printf("%d: remove_region: %d\n", __LINE__, rc);
670 return TEST_RESULT_FAIL;
671 }
672#else
673 /*
674 * 4) Try to allocate an absurdly large amount of misaligned memory,
675 * which should fail. In AArch64 there's enough memory to map 4GB of
676 * virtual memory so skip it.
677 */
678 rc = add_region_alloc_va(memory_base_pa + PAGE_SIZE, &memory_base_va,
679 PLAT_VIRT_ADDR_SPACE_SIZE - (memory_base_pa + PAGE_SIZE),
680 MT_DEVICE);
681 if (rc != -ENOMEM) {
682 tftf_testcase_printf("%d: add_region_alloc_va: %d\n",
683 __LINE__, rc);
684 return TEST_RESULT_FAIL;
685 }
686#endif
687
688 /*
689 * 5) Try to allocate hand-picked regions of different sizes and make
690 * sure that the resulting address is aligned to the correct boundary.
691 */
692
693 for (i = 0; i < ARRAY_SIZE(mem_tests); i++) {
694 /* Allocate to a correct PA boundary. */
695
696 unsigned long long base_pa = memory_base_pa;
697
698 rc = add_region_alloc_va(base_pa, &memory_base_va,
699 mem_tests[i].size, MT_DEVICE);
700 if ((rc == -ENOMEM) || (rc == -ERANGE)) {
701 /*
702 * Skip regions that are too big for the address space.
703 * This is a problem specially in AArch32, when the max
704 * virtual address space width is 32 bit.
705 */
706 WARN("%d: Not enough memory for case %d\n",
707 __LINE__, i);
708 continue;
709 } else if (rc != 0) {
710 tftf_testcase_printf("%d: add_region_alloc_va: %d\n",
711 __LINE__, rc);
712 return TEST_RESULT_FAIL;
713 }
714
715 rc = remove_region(memory_base_va, mem_tests[i].size);
716 if (rc != 0) {
717 tftf_testcase_printf("%d: remove_region: %d\n",
718 __LINE__, rc);
719 return TEST_RESULT_FAIL;
720 }
721
722 if (memory_base_va & mem_tests[i].expected_va_mask) {
723 tftf_testcase_printf("%d: Invalid alignment for case %d\n",
724 __LINE__, i);
725 return TEST_RESULT_FAIL;
726 }
727
728 /*
729 * Try to allocate to an incorrect PA boundary (a smaller one).
730 * This only makes sense for regions that are aligned to
731 * boundaries bigger than 4 KB, as there cannot be an incorrect
732 * alignment for 4 KB aligned regions.
733 */
734
735 if (mem_tests[i].expected_va_mask != MASK_L3) {
736
737 base_pa = memory_base_pa;
738
739 if (mem_tests[i].expected_va_mask == MASK_L1) {
740 base_pa += SIZE_L2;
741 } else if (mem_tests[i].expected_va_mask == MASK_L2) {
742 base_pa += SIZE_L3;
743 }
744
745 rc = add_region_alloc_va(base_pa, &memory_base_va,
746 mem_tests[i].size, MT_DEVICE);
747 if (rc == 0) {
748
749 rc = remove_region(memory_base_va,
750 mem_tests[i].size);
751 if (rc != 0) {
752 tftf_testcase_printf("%d: remove_region: %d\n",
753 __LINE__, rc);
754 return TEST_RESULT_FAIL;
755 }
756
757 } else if ((rc != -ENOMEM) && (rc != -ERANGE)) {
758 /*
759 * It could happen that we run out of memory, so
760 * it doesn't make sense to fail because of
761 * that. However, any other error is a
762 * legitimate error.
763 */
764 tftf_testcase_printf("%d: add_region_alloc_va: %d\n",
765 __LINE__, rc);
766 return TEST_RESULT_FAIL;
767 }
768 }
769 }
770
771 return TEST_RESULT_SUCCESS;
772}
773
774/**
Antonio Nino Diaz402b2692018-10-05 15:11:38 +0100775 * @Test_Aim@ Perform dynamic translation tables API stress tests
776 *
777 * This test performs a stress test in the library APIs.
778 */
779test_result_t xlat_lib_v2_stress_test(void)
780{
781 test_result_t test_result = TEST_RESULT_SUCCESS;
782 uintptr_t memory_base;
783 int rc;
784
785 /*
786 * 1) Try to allocate an invalid region. It should fail, but it will
787 * return the address of memory that can be used for the following
788 * tests.
789 */
790 rc = add_region_alloc_va(0, &memory_base, SIZE_MAX, MT_DEVICE);
791 if (rc == 0) {
792 tftf_testcase_printf("%d: add_region_alloc_va() didn't fail\n",
793 __LINE__);
794 return TEST_RESULT_FAIL;
795 }
796
797 /*
798 * Get address of memory region over the max used VA that is aligned to
799 * a L1 block for the next tests.
800 */
801 memory_base = (memory_base + SIZE_L1 - 1UL) & ~MASK_L1;
802
803 INFO("Using 0x%lx as base address for tests.\n", memory_base);
804
805 /* 2) Get a region of memory that we can use for testing. */
806
807 /*
808 * Try with blocks 64 times the size of a page and reduce the size until
809 * it fits. PAGE_SIZE can only be 4, 16 or 64KB.
810 */
811 block_size = PAGE_SIZE * 64;
812 for (;;) {
813 memory_size = block_size * STRESS_TEST_NUM_BLOCKS;
814 rc = add_region(memory_base, memory_base, memory_size,
815 MT_DEVICE);
816 if (rc == 0) {
817 break;
818 }
819
820 block_size >>= 1;
821 if (block_size < PAGE_SIZE) {
822 tftf_testcase_printf("%d: Couldn't allocate enough memory\n",
823 __LINE__);
824 return TEST_RESULT_FAIL;
825 }
826 }
827
828 rc = remove_region(memory_base, memory_size);
829 if (rc != 0) {
830 tftf_testcase_printf("%d: remove_region: %d\n", __LINE__, rc);
831 return TEST_RESULT_FAIL;
832 }
833
834 /* 3) Start stress test with the calculated top VA and space */
835
836 memset(block_used, 0, sizeof(block_used));
837
838 for (int i = 0; i < STRESS_TEST_ITERATIONS; i++) {
839 if ((rand() % 4) > 0) {
840 rc = alloc_random_chunk();
841 } else {
842 rc = free_random_chunk();
843 }
844
845 if (rc == -1) {
846 test_result = TEST_RESULT_FAIL;
847 break;
848 }
849 }
850
851 /* Cleanup of regions left allocated by the stress test */
852 while (get_num_chunks() > 0) {
853 rc = free_random_chunk();
854 if (rc == -1) {
855 test_result = TEST_RESULT_FAIL;
856 }
857 }
858
859 return test_result;
860}