aboutsummaryrefslogtreecommitdiff
path: root/test/lib
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-06-07 19:12:04 -0400
committerTom Rini <trini@konsulko.com>2021-06-07 19:12:04 -0400
commit24e1e8841c59956aaf0bd65720d0dbdd61aa3632 (patch)
tree09d104dbed9bf79b7e4d05a799e18cc9485836ff /test/lib
parente3b64beda5dd1a6b6bedfd1fe0e50be1ddea7044 (diff)
parentade4e0428f4d85454fdb3818702facc7728a274a (diff)
Merge branch '2021-06-07-arm-cache-cp15-improvements' into next
To quote the series author, Patrick Delaunay: On STM32MP15x platform we can use OP-TEE, loaded in DDR in a region protected by a firewall. This region is reserved in the device with the "no-map" property as defined in the binding file doc/device-tree-bindings/reserved-memory/reserved-memory.txt. Sometime the platform boot failed in U-Boot on a Cortex A7 access to this region (depending of the binary and the issue can change with compiler version or with code alignment), then the firewall raise an error, for example: E/TC:0 tzc_it_handler:19 TZC permission failure E/TC:0 dump_fail_filter:420 Permission violation on filter 0 E/TC:0 dump_fail_filter:425 Violation @0xde5c6bf0, non-secure privileged read, AXI ID 5c0 E/TC:0 Panic After investigation, the forbidden access is a speculative request performed by the Cortex A7 because all the DDR is mapped as MEMORY with CACHEABLE property. The issue is solved only when the region reserved by OP-TEE is no more mapped in U-Boot as it is already done in Linux kernel. Tested on DK2 board with OP-TEE 3.12 / TF-A 2.4: With hard-coded address for OP-TEE reserved memory, the error doesn't occur. void dram_bank_mmu_setup(int bank) { .... for (i = start >> MMU_SECTION_SHIFT; i < (start >> MMU_SECTION_SHIFT) + (size >> MMU_SECTION_SHIFT); i++) { option = DCACHE_DEFAULT_OPTION; if (i >= 0xde0) option = INVALID_ENTRY; set_section_dcache(i, option); } } Just by modifying the test on 0xde0 to 0xdf0, the OP-TEE memory protected by firewall is mapped cacheable and the error occurs. I think that it can be a general issue for ARM architecture: the "no-map" tag of reserved memory in device should be respected by U-Boot if firewall is configured before U-Boot execution. But I don't propose a generic solution in arm/lib/cache-cp15.c:dram_bank_mmu_setup() because the device tree parsing done in lmb_init_and_reserve() takes a long time when it is executed without data cache.
Diffstat (limited to 'test/lib')
-rw-r--r--test/lib/lmb.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/test/lib/lmb.c b/test/lib/lmb.c
index 0d8963fcbf..b2c2b99ef1 100644
--- a/test/lib/lmb.c
+++ b/test/lib/lmb.c
@@ -723,3 +723,92 @@ static int lib_test_lmb_max_regions(struct unit_test_state *uts)
DM_TEST(lib_test_lmb_max_regions,
UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+static int lib_test_lmb_flags(struct unit_test_state *uts)
+{
+ const phys_addr_t ram = 0x40000000;
+ const phys_size_t ram_size = 0x20000000;
+ struct lmb lmb;
+ long ret;
+
+ lmb_init(&lmb);
+
+ ret = lmb_add(&lmb, ram, ram_size);
+ ut_asserteq(ret, 0);
+
+ /* reserve, same flag */
+ ret = lmb_reserve_flags(&lmb, 0x40010000, 0x10000, LMB_NOMAP);
+ ut_asserteq(ret, 0);
+ ASSERT_LMB(&lmb, ram, ram_size, 1, 0x40010000, 0x10000,
+ 0, 0, 0, 0);
+
+ /* reserve again, same flag */
+ ret = lmb_reserve_flags(&lmb, 0x40010000, 0x10000, LMB_NOMAP);
+ ut_asserteq(ret, 0);
+ ASSERT_LMB(&lmb, ram, ram_size, 1, 0x40010000, 0x10000,
+ 0, 0, 0, 0);
+
+ /* reserve again, new flag */
+ ret = lmb_reserve_flags(&lmb, 0x40010000, 0x10000, LMB_NONE);
+ ut_asserteq(ret, -1);
+ ASSERT_LMB(&lmb, ram, ram_size, 1, 0x40010000, 0x10000,
+ 0, 0, 0, 0);
+
+ ut_asserteq(lmb_is_nomap(&lmb.reserved.region[0]), 1);
+
+ /* merge after */
+ ret = lmb_reserve_flags(&lmb, 0x40020000, 0x10000, LMB_NOMAP);
+ ut_asserteq(ret, 1);
+ ASSERT_LMB(&lmb, ram, ram_size, 1, 0x40010000, 0x20000,
+ 0, 0, 0, 0);
+
+ /* merge before */
+ ret = lmb_reserve_flags(&lmb, 0x40000000, 0x10000, LMB_NOMAP);
+ ut_asserteq(ret, 1);
+ ASSERT_LMB(&lmb, ram, ram_size, 1, 0x40000000, 0x30000,
+ 0, 0, 0, 0);
+
+ ut_asserteq(lmb_is_nomap(&lmb.reserved.region[0]), 1);
+
+ ret = lmb_reserve_flags(&lmb, 0x40030000, 0x10000, LMB_NONE);
+ ut_asserteq(ret, 0);
+ ASSERT_LMB(&lmb, ram, ram_size, 2, 0x40000000, 0x30000,
+ 0x40030000, 0x10000, 0, 0);
+
+ ut_asserteq(lmb_is_nomap(&lmb.reserved.region[0]), 1);
+ ut_asserteq(lmb_is_nomap(&lmb.reserved.region[1]), 0);
+
+ /* test that old API use LMB_NONE */
+ ret = lmb_reserve(&lmb, 0x40040000, 0x10000);
+ ut_asserteq(ret, 1);
+ ASSERT_LMB(&lmb, ram, ram_size, 2, 0x40000000, 0x30000,
+ 0x40030000, 0x20000, 0, 0);
+
+ ut_asserteq(lmb_is_nomap(&lmb.reserved.region[0]), 1);
+ ut_asserteq(lmb_is_nomap(&lmb.reserved.region[1]), 0);
+
+ ret = lmb_reserve_flags(&lmb, 0x40070000, 0x10000, LMB_NOMAP);
+ ut_asserteq(ret, 0);
+ ASSERT_LMB(&lmb, ram, ram_size, 3, 0x40000000, 0x30000,
+ 0x40030000, 0x20000, 0x40070000, 0x10000);
+
+ ret = lmb_reserve_flags(&lmb, 0x40050000, 0x10000, LMB_NOMAP);
+ ut_asserteq(ret, 0);
+ ASSERT_LMB(&lmb, ram, ram_size, 4, 0x40000000, 0x30000,
+ 0x40030000, 0x20000, 0x40050000, 0x10000);
+
+ /* merge with 2 adjacent regions */
+ ret = lmb_reserve_flags(&lmb, 0x40060000, 0x10000, LMB_NOMAP);
+ ut_asserteq(ret, 2);
+ ASSERT_LMB(&lmb, ram, ram_size, 3, 0x40000000, 0x30000,
+ 0x40030000, 0x20000, 0x40050000, 0x30000);
+
+ ut_asserteq(lmb_is_nomap(&lmb.reserved.region[0]), 1);
+ ut_asserteq(lmb_is_nomap(&lmb.reserved.region[1]), 0);
+ ut_asserteq(lmb_is_nomap(&lmb.reserved.region[2]), 1);
+
+ return 0;
+}
+
+DM_TEST(lib_test_lmb_flags,
+ UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);