From 59c0ea5df33fc4d9b62226d29e3b5c61d639303f Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 May 2021 14:50:29 +0200 Subject: [PATCH 1/7] lmb: Add support of flags for no-map properties Add "flags" in lmb_property to save the "no-map" property of reserved region and a new function lmb_reserve_flags() to check this flag. The default allocation use flags = LMB_NONE. The adjacent reserved memory region are merged only when they have the same flags value. This patch is partially based on flags support done in Linux kernel mm/memblock .c (previously lmb.c); it is why LMB_NOMAP = 0x4, it is aligned with MEMBLOCK_NOMAP value. Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- include/lmb.h | 29 +++++++++++++++++++++++++++ lib/lmb.c | 54 +++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/include/lmb.h b/include/lmb.h index 541e17093c6..e900b3dd65c 100644 --- a/include/lmb.h +++ b/include/lmb.h @@ -12,6 +12,16 @@ * Copyright (C) 2001 Peter Bergner, IBM Corp. */ +/** + * enum lmb_flags - definition of memory region attributes + * @LMB_NONE: no special request + * @LMB_NOMAP: don't add to mmu configuration + */ +enum lmb_flags { + LMB_NONE = 0x0, + LMB_NOMAP = 0x4, +}; + /** * struct lmb_property - Description of one region. * @@ -21,6 +31,7 @@ struct lmb_property { phys_addr_t base; phys_size_t size; + enum lmb_flags flags; }; /** @@ -69,6 +80,17 @@ extern void lmb_init_and_reserve_range(struct lmb *lmb, phys_addr_t base, phys_size_t size, void *fdt_blob); extern long lmb_add(struct lmb *lmb, phys_addr_t base, phys_size_t size); extern long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size); +/** + * lmb_reserve_flags - Reserve one region with a specific flags bitfield. + * + * @lmb the logical memory block struct + * @base base address of the memory region + * @size size of the memory region + * @flags flags for the memory region + * @return 0 if OK, > 0 for coalesced region or a negative error code. + */ +long lmb_reserve_flags(struct lmb *lmb, phys_addr_t base, + phys_size_t size, enum lmb_flags flags); extern phys_addr_t lmb_alloc(struct lmb *lmb, phys_size_t size, ulong align); extern phys_addr_t lmb_alloc_base(struct lmb *lmb, phys_size_t size, ulong align, phys_addr_t max_addr); @@ -92,6 +114,13 @@ lmb_size_bytes(struct lmb_region *type, unsigned long region_nr) void board_lmb_reserve(struct lmb *lmb); void arch_lmb_reserve(struct lmb *lmb); +/* Low level functions */ + +static inline bool lmb_is_nomap(struct lmb_property *m) +{ + return m->flags & LMB_NOMAP; +} + #endif /* __KERNEL__ */ #endif /* _LINUX_LMB_H */ diff --git a/lib/lmb.c b/lib/lmb.c index c08c4d942b7..69700bf9baf 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -25,6 +25,8 @@ void lmb_dump_all_force(struct lmb *lmb) (unsigned long long)lmb->memory.region[i].base); printf(" .size = 0x%llx\n", (unsigned long long)lmb->memory.region[i].size); + printf(" .flags = 0x%x\n", + lmb->memory.region[i].flags); } printf("\n reserved.cnt = 0x%lx\n", lmb->reserved.cnt); @@ -33,6 +35,8 @@ void lmb_dump_all_force(struct lmb *lmb) (unsigned long long)lmb->reserved.region[i].base); printf(" .size = 0x%llx\n", (unsigned long long)lmb->reserved.region[i].size); + printf(" .flags = 0x%x\n", + lmb->reserved.region[i].flags); } } @@ -81,6 +85,7 @@ static void lmb_remove_region(struct lmb_region *rgn, unsigned long r) for (i = r; i < rgn->cnt - 1; i++) { rgn->region[i].base = rgn->region[i + 1].base; rgn->region[i].size = rgn->region[i + 1].size; + rgn->region[i].flags = rgn->region[i + 1].flags; } rgn->cnt--; } @@ -144,7 +149,8 @@ void lmb_init_and_reserve_range(struct lmb *lmb, phys_addr_t base, } /* This routine called with relocation disabled. */ -static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t size) +static long lmb_add_region_flags(struct lmb_region *rgn, phys_addr_t base, + phys_size_t size, enum lmb_flags flags) { unsigned long coalesced = 0; long adjacent, i; @@ -152,6 +158,7 @@ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t if (rgn->cnt == 0) { rgn->region[0].base = base; rgn->region[0].size = size; + rgn->region[0].flags = flags; rgn->cnt = 1; return 0; } @@ -160,18 +167,27 @@ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t for (i = 0; i < rgn->cnt; i++) { phys_addr_t rgnbase = rgn->region[i].base; phys_size_t rgnsize = rgn->region[i].size; + phys_size_t rgnflags = rgn->region[i].flags; - if ((rgnbase == base) && (rgnsize == size)) - /* Already have this region, so we're done */ - return 0; + if (rgnbase == base && rgnsize == size) { + if (flags == rgnflags) + /* Already have this region, so we're done */ + return 0; + else + return -1; /* regions with new flags */ + } adjacent = lmb_addrs_adjacent(base, size, rgnbase, rgnsize); if (adjacent > 0) { + if (flags != rgnflags) + break; rgn->region[i].base -= size; rgn->region[i].size += size; coalesced++; break; } else if (adjacent < 0) { + if (flags != rgnflags) + break; rgn->region[i].size += size; coalesced++; break; @@ -182,8 +198,10 @@ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t } if ((i < rgn->cnt - 1) && lmb_regions_adjacent(rgn, i, i + 1)) { - lmb_coalesce_regions(rgn, i, i + 1); - coalesced++; + if (rgn->region[i].flags == rgn->region[i + 1].flags) { + lmb_coalesce_regions(rgn, i, i + 1); + coalesced++; + } } if (coalesced) @@ -196,9 +214,11 @@ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t if (base < rgn->region[i].base) { rgn->region[i + 1].base = rgn->region[i].base; rgn->region[i + 1].size = rgn->region[i].size; + rgn->region[i + 1].flags = rgn->region[i].flags; } else { rgn->region[i + 1].base = base; rgn->region[i + 1].size = size; + rgn->region[i + 1].flags = flags; break; } } @@ -206,6 +226,7 @@ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t if (base < rgn->region[0].base) { rgn->region[0].base = base; rgn->region[0].size = size; + rgn->region[0].flags = flags; } rgn->cnt++; @@ -213,6 +234,12 @@ static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, phys_size_t return 0; } +static long lmb_add_region(struct lmb_region *rgn, phys_addr_t base, + phys_size_t size) +{ + return lmb_add_region_flags(rgn, base, size, LMB_NONE); +} + /* This routine may be called with relocation disabled. */ long lmb_add(struct lmb *lmb, phys_addr_t base, phys_size_t size) { @@ -267,14 +294,21 @@ long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size) * beginging of the hole and add the region after hole. */ rgn->region[i].size = base - rgn->region[i].base; - return lmb_add_region(rgn, end + 1, rgnend - end); + return lmb_add_region_flags(rgn, end + 1, rgnend - end, + rgn->region[i].flags); +} + +long lmb_reserve_flags(struct lmb *lmb, phys_addr_t base, phys_size_t size, + enum lmb_flags flags) +{ + struct lmb_region *_rgn = &(lmb->reserved); + + return lmb_add_region_flags(_rgn, base, size, flags); } long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size) { - struct lmb_region *_rgn = &(lmb->reserved); - - return lmb_add_region(_rgn, base, size); + return lmb_reserve_flags(lmb, base, size, LMB_NONE); } static long lmb_overlaps_region(struct lmb_region *rgn, phys_addr_t base, From e359a4a5c1f01add83b8f39f5da0c61ce51e918a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 May 2021 14:50:30 +0200 Subject: [PATCH 2/7] lmb: add lmb_is_reserved_flags Add a new function lmb_is_reserved_flags to check if an address is reserved with a specific flags. This function can be used to check if an address was reserved with no-map flags with: lmb_is_reserved_flags(lmb, addr, LMB_NOMAP); Signed-off-by: Patrick Delaunay --- include/lmb.h | 9 +++++++++ lib/lmb.c | 9 +++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/lmb.h b/include/lmb.h index e900b3dd65c..3c4afdf9f06 100644 --- a/include/lmb.h +++ b/include/lmb.h @@ -100,6 +100,15 @@ extern phys_addr_t lmb_alloc_addr(struct lmb *lmb, phys_addr_t base, phys_size_t size); extern phys_size_t lmb_get_free_size(struct lmb *lmb, phys_addr_t addr); extern int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr); +/** + * lmb_is_reserved_flags - test if tha address is in reserved region with a bitfield flag + * + * @lmb the logical memory block struct + * @addr address to be tested + * @flags flags bitfied to be tested + * @return 0 if not reserved or reserved without the requested flag else 1 + */ +int lmb_is_reserved_flags(struct lmb *lmb, phys_addr_t addr, int flags); extern long lmb_free(struct lmb *lmb, phys_addr_t base, phys_size_t size); extern void lmb_dump_all(struct lmb *lmb); diff --git a/lib/lmb.c b/lib/lmb.c index 69700bf9baf..a0fb8c7e88d 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -443,7 +443,7 @@ phys_size_t lmb_get_free_size(struct lmb *lmb, phys_addr_t addr) return 0; } -int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr) +int lmb_is_reserved_flags(struct lmb *lmb, phys_addr_t addr, int flags) { int i; @@ -451,11 +451,16 @@ int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr) phys_addr_t upper = lmb->reserved.region[i].base + lmb->reserved.region[i].size - 1; if ((addr >= lmb->reserved.region[i].base) && (addr <= upper)) - return 1; + return (lmb->reserved.region[i].flags & flags) == flags; } return 0; } +int lmb_is_reserved(struct lmb *lmb, phys_addr_t addr) +{ + return lmb_is_reserved_flags(lmb, addr, LMB_NONE); +} + __weak void board_lmb_reserve(struct lmb *lmb) { /* please define platform specific board_lmb_reserve() */ From 358c7789afb8b1723be596040fbfb4964cc3f703 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 May 2021 14:50:31 +0200 Subject: [PATCH 3/7] lmb: add lmb_dump_region() function Add lmb_dump_region() function, to simplify lmb_dump_all_force(). This patch is based on Linux memblock dump function. An example of bdinfo output is: ..... fdt_size = 0x000146a0 FB base = 0xfdd00000 lmb_dump_all: memory.cnt = 0x1 memory[0] [0xc0000000-0xffffffff], 0x40000000 bytes flags: 0 reserved.cnt = 0x6 reserved[0] [0x10000000-0x10045fff], 0x00046000 bytes flags: 4 reserved[1] [0x30000000-0x3003ffff], 0x00040000 bytes flags: 4 reserved[2] [0x38000000-0x3800ffff], 0x00010000 bytes flags: 4 reserved[3] [0xe8000000-0xefffffff], 0x08000000 bytes flags: 4 reserved[4] [0xfbaea344-0xfdffffff], 0x02515cbc bytes flags: 0 reserved[5] [0xfe000000-0xffffffff], 0x02000000 bytes flags: 4 arch_number = 0x00000000 TLB addr = 0xfdff0000 .... Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- lib/lmb.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/lmb.c b/lib/lmb.c index a0fb8c7e88d..7bd1255f7a4 100644 --- a/lib/lmb.c +++ b/lib/lmb.c @@ -14,30 +14,30 @@ #define LMB_ALLOC_ANYWHERE 0 +static void lmb_dump_region(struct lmb_region *rgn, char *name) +{ + unsigned long long base, size, end; + enum lmb_flags flags; + int i; + + printf(" %s.cnt = 0x%lx\n", name, rgn->cnt); + + for (i = 0; i < rgn->cnt; i++) { + base = rgn->region[i].base; + size = rgn->region[i].size; + end = base + size - 1; + flags = rgn->region[i].flags; + + printf(" %s[%d]\t[0x%llx-0x%llx], 0x%08llx bytes flags: %x\n", + name, i, base, end, size, flags); + } +} + void lmb_dump_all_force(struct lmb *lmb) { - unsigned long i; - printf("lmb_dump_all:\n"); - printf(" memory.cnt = 0x%lx\n", lmb->memory.cnt); - for (i = 0; i < lmb->memory.cnt; i++) { - printf(" memory.reg[0x%lx].base = 0x%llx\n", i, - (unsigned long long)lmb->memory.region[i].base); - printf(" .size = 0x%llx\n", - (unsigned long long)lmb->memory.region[i].size); - printf(" .flags = 0x%x\n", - lmb->memory.region[i].flags); - } - - printf("\n reserved.cnt = 0x%lx\n", lmb->reserved.cnt); - for (i = 0; i < lmb->reserved.cnt; i++) { - printf(" reserved.reg[0x%lx].base = 0x%llx\n", i, - (unsigned long long)lmb->reserved.region[i].base); - printf(" .size = 0x%llx\n", - (unsigned long long)lmb->reserved.region[i].size); - printf(" .flags = 0x%x\n", - lmb->reserved.region[i].flags); - } + lmb_dump_region(&lmb->memory, "memory"); + lmb_dump_region(&lmb->reserved, "reserved"); } void lmb_dump_all(struct lmb *lmb) From 7d08a3dd02125f2d2a49c0f99ad901e2c3db3389 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 May 2021 14:50:32 +0200 Subject: [PATCH 4/7] test: lmb: add test for lmb_reserve_flags Add a test to check the management of reserved region with flags. Signed-off-by: Patrick Delaunay Reviewed-by: Simon Glass --- test/lib/lmb.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/test/lib/lmb.c b/test/lib/lmb.c index 0d8963fcbf3..b2c2b99ef19 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); From f46959cef4360960103d84467b82a56d56152fe4 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 May 2021 14:50:33 +0200 Subject: [PATCH 5/7] image-fdt: save no-map parameter of reserve-memory Save the 'no-map' information present in 'reserved-memory' node to allow correct handling when the MMU is configured in board to avoid speculative access. This binding is defined in doc/device-tree-bindings/reserved-memory/reserved-memory.txt Additional properties: ... no-map (optional) - empty property - Indicates the operating system must not create a virtual mapping of the region as part of its standard mapping of system memory, nor permit speculative access to it under any circumstances other than under the control of the device driver using the region. Signed-off-by: Patrick Delaunay --- common/image-fdt.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/common/image-fdt.c b/common/image-fdt.c index d50e1ba3feb..06dce92a28a 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -75,18 +75,20 @@ static const image_header_t *image_get_fdt(ulong fdt_addr) #endif static void boot_fdt_reserve_region(struct lmb *lmb, uint64_t addr, - uint64_t size) + uint64_t size, enum lmb_flags flags) { long ret; - ret = lmb_reserve(lmb, addr, size); + ret = lmb_reserve_flags(lmb, addr, size, flags); if (ret >= 0) { - debug(" reserving fdt memory region: addr=%llx size=%llx\n", - (unsigned long long)addr, (unsigned long long)size); + debug(" reserving fdt memory region: addr=%llx size=%llx flags=%x\n", + (unsigned long long)addr, + (unsigned long long)size, flags); } else { puts("ERROR: reserving fdt memory region failed "); - printf("(addr=%llx size=%llx)\n", - (unsigned long long)addr, (unsigned long long)size); + printf("(addr=%llx size=%llx flags=%x)\n", + (unsigned long long)addr, + (unsigned long long)size, flags); } } @@ -106,6 +108,7 @@ void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob) int i, total, ret; int nodeoffset, subnode; struct fdt_resource res; + enum lmb_flags flags; if (fdt_check_header(fdt_blob) != 0) return; @@ -115,7 +118,7 @@ void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob) for (i = 0; i < total; i++) { if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0) continue; - boot_fdt_reserve_region(lmb, addr, size); + boot_fdt_reserve_region(lmb, addr, size, LMB_NONE); } /* process reserved-memory */ @@ -127,9 +130,13 @@ void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob) ret = fdt_get_resource(fdt_blob, subnode, "reg", 0, &res); if (!ret && fdtdec_get_is_enabled(fdt_blob, subnode)) { + flags = LMB_NONE; + if (fdtdec_get_bool(fdt_blob, subnode, + "no-map")) + flags = LMB_NOMAP; addr = res.start; size = res.end - res.start + 1; - boot_fdt_reserve_region(lmb, addr, size); + boot_fdt_reserve_region(lmb, addr, size, flags); } subnode = fdt_next_subnode(fdt_blob, subnode); From 7dc6068fc10d699558176da364a3e7a6cfccdaa1 Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 May 2021 14:50:34 +0200 Subject: [PATCH 6/7] stm32mp: Increase the reserved memory in board_get_usable_ram_top Add 8M for the U-Boot reserved memory (display, fdt, gd, ...) mapped cacheable before relocation. Without this patch the device tree, located before the MALLOC area is not tagged cacheable just after relocation, before mmu reconfiguration. This patch reduces the duration for device tree parsing in lmb_init_and_reserve. Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/dram_init.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-stm32mp/dram_init.c b/arch/arm/mach-stm32mp/dram_init.c index 66e81baccaf..3c097029bda 100644 --- a/arch/arm/mach-stm32mp/dram_init.c +++ b/arch/arm/mach-stm32mp/dram_init.c @@ -50,13 +50,16 @@ ulong board_get_usable_ram_top(ulong total_size) lmb_init(&lmb); lmb_add(&lmb, gd->ram_base, gd->ram_size); boot_fdt_add_mem_rsv_regions(&lmb, (void *)gd->fdt_blob); - size = ALIGN(CONFIG_SYS_MALLOC_LEN + total_size, MMU_SECTION_SIZE), + /* add 8M for reserved memory for display, fdt, gd,... */ + size = ALIGN(SZ_8M + CONFIG_SYS_MALLOC_LEN + total_size, MMU_SECTION_SIZE), reg = lmb_alloc(&lmb, size, MMU_SECTION_SIZE); if (!reg) reg = gd->ram_top - size; - mmu_set_region_dcache_behaviour(reg, size, DCACHE_DEFAULT_OPTION); + /* before relocation, mark the U-Boot memory as cacheable by default */ + if (!(gd->flags & GD_FLG_RELOC)) + mmu_set_region_dcache_behaviour(reg, size, DCACHE_DEFAULT_OPTION); return reg + size; } From ade4e0428f4d85454fdb3818702facc7728a274a Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Fri, 7 May 2021 14:50:35 +0200 Subject: [PATCH 7/7] stm32mp: don't map the reserved region with no-map property No more map the reserved region with "no-map" property by marking the corresponding TLB entries with invalid entry (=0) to avoid speculative access. The device tree parsing done in lmb_init_and_reserve() takes a long time when it is executed without data cache, so it is called in enable_caches() before to disable it. This patch fixes an issue where predictive read access on secure DDR OP-TEE reserved area are caught by firewall. Series-cc: marex Series-cc: pch Series-cc: marek.bykowski@gmail.com Series-cc: Ard Biesheuvel Series-cc: Etienne Carriere Signed-off-by: Patrick Delaunay --- arch/arm/mach-stm32mp/cpu.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c index 8115d58b199..592bfd413df 100644 --- a/arch/arm/mach-stm32mp/cpu.c +++ b/arch/arm/mach-stm32mp/cpu.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -90,6 +91,8 @@ */ u8 early_tlb[PGTABLE_SIZE] __section(".data") __aligned(0x4000); +struct lmb lmb; + #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD) #ifndef CONFIG_TFABOOT static void security_init(void) @@ -221,6 +224,8 @@ void dram_bank_mmu_setup(int bank) int i; phys_addr_t start; phys_size_t size; + bool use_lmb = false; + enum dcache_option option; if (IS_ENABLED(CONFIG_SPL_BUILD)) { start = ALIGN_DOWN(STM32_SYSRAM_BASE, MMU_SECTION_SIZE); @@ -229,6 +234,7 @@ void dram_bank_mmu_setup(int bank) /* bd->bi_dram is available only after relocation */ start = bd->bi_dram[bank].start; size = bd->bi_dram[bank].size; + use_lmb = true; } else { /* mark cacheable and executable the beggining of the DDR */ start = STM32_DDR_BASE; @@ -237,8 +243,12 @@ void dram_bank_mmu_setup(int bank) for (i = start >> MMU_SECTION_SHIFT; i < (start >> MMU_SECTION_SHIFT) + (size >> MMU_SECTION_SHIFT); - i++) - set_section_dcache(i, DCACHE_DEFAULT_OPTION); + i++) { + option = DCACHE_DEFAULT_OPTION; + if (use_lmb && lmb_is_reserved_flags(&lmb, i << MMU_SECTION_SHIFT, LMB_NOMAP)) + option = 0; /* INVALID ENTRY in TLB */ + set_section_dcache(i, option); + } } /* * initialize the MMU and activate cache in SPL or in U-Boot pre-reloc stage @@ -302,6 +312,9 @@ int arch_cpu_init(void) void enable_caches(void) { + /* parse device tree when data cache is still activated */ + lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob); + /* I-cache is already enabled in start.S: icache_enable() not needed */ /* deactivate the data cache, early enabled in arch_cpu_init() */