All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property
@ 2021-05-07 12:50 Patrick Delaunay
  2021-05-07 12:50 ` [PATCH v4 1/7] lmb: Add support of flags for no-map properties Patrick Delaunay
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Patrick Delaunay @ 2021-05-07 12:50 UTC (permalink / raw)
  To: u-boot


Hi,

It it the v4 serie of [1].

This v4 serie is rebased on top of master branch with update after Simon
Glass review and added tags.

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.

=> the previous path 7/7 of v2 series is dropped to avoid
  performance issue on other ARM target.

To avoid this performance issue on stm32mp32mp platform, the lmb
initialization is done in enable_caches() when dcache is still enable.

This v3 series is composed by 7 patches
- 1..3/7: preliminary steps to support flags in library in lmb
  (as it is done in memblock.c in Linux)
- 4/7: unitary test on the added feature in lmb lib
- 5/7: save the no-map flags in lmb when the device tree is parsed
- 6/7: solve issue for the size of cacheable area in pre-reloc case
- 7/7: update the stm32mp mmu support

See also [2] which handle same speculative access on armv8 for area
with Executable attribute.

[1] http://patchwork.ozlabs.org/project/uboot/list/?series=241122&state=*
[2] http://patchwork.ozlabs.org/project/uboot/patch/20200903000106.5016-1-marek.bykowski at gmail.com/

Regards
Patrick

Changes in v4:
- Add comment for lmb_reserve_flags and remove extern
- Remove unnecessary !! on return of boolean in lmb_is_nomap
- Add comment for lmb_is_reserved_flags and remove extern
- Remove unnecessary !! on return of boolean in lmb_is_reserved_flags
- map the end of the DDR only before relocation, in board_f.c;
  this test avoid issue when board_get_usable_ram_top() is called
  in efi_loader function efi_add_known_memory()

Changes in v3:
- NEW: solve performance issue as relocated DT is not marked cacheable
- call lmb_init_and_reserve when data cache is activated in enable_caches()
- drop v2 patch "arm: cache: cp15: don't map the reserved region
  with no-map property"

Changes in v2:
- remove unnecessary comments in lmb.h
- rebase on latest lmb patches
- NEW: update in stm32mp specific MMU setup functions

Patrick Delaunay (7):
  lmb: Add support of flags for no-map properties
  lmb: add lmb_is_reserved_flags
  lmb: add lmb_dump_region() function
  test: lmb: add test for lmb_reserve_flags
  image-fdt: save no-map parameter of reserve-memory
  stm32mp: Increase the reserved memory in board_get_usable_ram_top
  stm32mp: don't map the reserved region with no-map property

 arch/arm/mach-stm32mp/cpu.c       | 17 +++++-
 arch/arm/mach-stm32mp/dram_init.c |  7 ++-
 common/image-fdt.c                | 23 +++++---
 include/lmb.h                     | 38 +++++++++++++
 lib/lmb.c                         | 93 ++++++++++++++++++++++---------
 test/lib/lmb.c                    | 89 +++++++++++++++++++++++++++++
 6 files changed, 228 insertions(+), 39 deletions(-)

-- 
2.17.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v4 1/7] lmb: Add support of flags for no-map properties
  2021-05-07 12:50 [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property Patrick Delaunay
@ 2021-05-07 12:50 ` Patrick Delaunay
  2021-05-07 12:50 ` [PATCH v4 2/7] lmb: add lmb_is_reserved_flags Patrick Delaunay
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Patrick Delaunay @ 2021-05-07 12:50 UTC (permalink / raw)
  To: u-boot

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 <patrick.delaunay@foss.st.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---

Changes in v4:
- Add comment for lmb_reserve_flags and remove extern
- Remove unnecessary !! on return of boolean in lmb_is_nomap

Changes in v2:
- remove unnecessary comments in lmb.h
- rebase on latest lmb patches

 include/lmb.h | 29 ++++++++++++++++++++++++++++
 lib/lmb.c     | 52 ++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 72 insertions(+), 9 deletions(-)

diff --git a/include/lmb.h b/include/lmb.h
index 541e17093c..e900b3dd65 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 c08c4d942b..69700bf9ba 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(struct lmb *lmb, phys_addr_t base, phys_size_t size)
+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(_rgn, base, size);
+	return lmb_add_region_flags(_rgn, base, size, flags);
+}
+
+long lmb_reserve(struct lmb *lmb, phys_addr_t base, phys_size_t size)
+{
+	return lmb_reserve_flags(lmb, base, size, LMB_NONE);
 }
 
 static long lmb_overlaps_region(struct lmb_region *rgn, phys_addr_t base,
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v4 2/7] lmb: add lmb_is_reserved_flags
  2021-05-07 12:50 [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property Patrick Delaunay
  2021-05-07 12:50 ` [PATCH v4 1/7] lmb: Add support of flags for no-map properties Patrick Delaunay
@ 2021-05-07 12:50 ` Patrick Delaunay
  2021-05-07 12:50 ` [PATCH v4 3/7] lmb: add lmb_dump_region() function Patrick Delaunay
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Patrick Delaunay @ 2021-05-07 12:50 UTC (permalink / raw)
  To: u-boot

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 <patrick.delaunay@foss.st.com>
---

Changes in v4:
- Add comment for lmb_is_reserved_flags and remove extern
- Remove unnecessary !! on return of boolean in lmb_is_reserved_flags

 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 e900b3dd65..3c4afdf9f0 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 69700bf9ba..a0fb8c7e88 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() */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v4 3/7] lmb: add lmb_dump_region() function
  2021-05-07 12:50 [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property Patrick Delaunay
  2021-05-07 12:50 ` [PATCH v4 1/7] lmb: Add support of flags for no-map properties Patrick Delaunay
  2021-05-07 12:50 ` [PATCH v4 2/7] lmb: add lmb_is_reserved_flags Patrick Delaunay
@ 2021-05-07 12:50 ` Patrick Delaunay
  2021-05-07 12:50 ` [PATCH v4 4/7] test: lmb: add test for lmb_reserve_flags Patrick Delaunay
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Patrick Delaunay @ 2021-05-07 12:50 UTC (permalink / raw)
  To: u-boot

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 <patrick.delaunay@foss.st.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 lib/lmb.c | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/lib/lmb.c b/lib/lmb.c
index a0fb8c7e88..7bd1255f7a 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -14,32 +14,32 @@
 
 #define LMB_ALLOC_ANYWHERE	0
 
-void lmb_dump_all_force(struct lmb *lmb)
+static void lmb_dump_region(struct lmb_region *rgn, char *name)
 {
-	unsigned long i;
+	unsigned long long base, size, end;
+	enum lmb_flags flags;
+	int 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(" %s.cnt  = 0x%lx\n", name, rgn->cnt);
 
-	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);
+	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)
+{
+	printf("lmb_dump_all:\n");
+	lmb_dump_region(&lmb->memory, "memory");
+	lmb_dump_region(&lmb->reserved, "reserved");
+}
+
 void lmb_dump_all(struct lmb *lmb)
 {
 #ifdef DEBUG
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v4 4/7] test: lmb: add test for lmb_reserve_flags
  2021-05-07 12:50 [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property Patrick Delaunay
                   ` (2 preceding siblings ...)
  2021-05-07 12:50 ` [PATCH v4 3/7] lmb: add lmb_dump_region() function Patrick Delaunay
@ 2021-05-07 12:50 ` Patrick Delaunay
  2021-05-07 12:50 ` [PATCH v4 5/7] image-fdt: save no-map parameter of reserve-memory Patrick Delaunay
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Patrick Delaunay @ 2021-05-07 12:50 UTC (permalink / raw)
  To: u-boot

Add a test to check the management of reserved region with flags.

Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---

(no changes since v1)

 test/lib/lmb.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

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);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v4 5/7] image-fdt: save no-map parameter of reserve-memory
  2021-05-07 12:50 [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property Patrick Delaunay
                   ` (3 preceding siblings ...)
  2021-05-07 12:50 ` [PATCH v4 4/7] test: lmb: add test for lmb_reserve_flags Patrick Delaunay
@ 2021-05-07 12:50 ` Patrick Delaunay
  2021-05-07 12:50 ` [PATCH v4 6/7] stm32mp: Increase the reserved memory in board_get_usable_ram_top Patrick Delaunay
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Patrick Delaunay @ 2021-05-07 12:50 UTC (permalink / raw)
  To: u-boot

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 <patrick.delaunay@foss.st.com>
---

(no changes since v1)

 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 d50e1ba3fe..06dce92a28 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);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v4 6/7] stm32mp: Increase the reserved memory in board_get_usable_ram_top
  2021-05-07 12:50 [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property Patrick Delaunay
                   ` (4 preceding siblings ...)
  2021-05-07 12:50 ` [PATCH v4 5/7] image-fdt: save no-map parameter of reserve-memory Patrick Delaunay
@ 2021-05-07 12:50 ` Patrick Delaunay
  2021-05-07 12:50 ` [PATCH v4 7/7] stm32mp: don't map the reserved region with no-map property Patrick Delaunay
  2021-06-07 23:16 ` [PATCH v4 0/7] arm: cache: cp15: don't map " Tom Rini
  7 siblings, 0 replies; 9+ messages in thread
From: Patrick Delaunay @ 2021-05-07 12:50 UTC (permalink / raw)
  To: u-boot

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 <patrick.delaunay@foss.st.com>
---

Changes in v4:
- map the end of the DDR only before relocation, in board_f.c;
  this test avoid issue when board_get_usable_ram_top() is called
  in efi_loader function efi_add_known_memory()

Changes in v3:
- NEW: solve performance issue as relocated DT is not marked cacheable

 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 66e81bacca..3c097029bd 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;
 }
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v4 7/7] stm32mp: don't map the reserved region with no-map property
  2021-05-07 12:50 [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property Patrick Delaunay
                   ` (5 preceding siblings ...)
  2021-05-07 12:50 ` [PATCH v4 6/7] stm32mp: Increase the reserved memory in board_get_usable_ram_top Patrick Delaunay
@ 2021-05-07 12:50 ` Patrick Delaunay
  2021-06-07 23:16 ` [PATCH v4 0/7] arm: cache: cp15: don't map " Tom Rini
  7 siblings, 0 replies; 9+ messages in thread
From: Patrick Delaunay @ 2021-05-07 12:50 UTC (permalink / raw)
  To: u-boot

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 at gmail.com
  Series-cc: Ard Biesheuvel <ardb@kernel.org>
  Series-cc: Etienne Carriere <etienne.carriere@linaro.org>

Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com>
---

(no changes since v3)

Changes in v3:
- call lmb_init_and_reserve when data cache is activated in enable_caches()
- drop v2 patch "arm: cache: cp15: don't map the reserved region
  with no-map property"

Changes in v2:
- NEW: update in stm32mp specific MMU setup functions

 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 8115d58b19..592bfd413d 100644
--- a/arch/arm/mach-stm32mp/cpu.c
+++ b/arch/arm/mach-stm32mp/cpu.c
@@ -12,6 +12,7 @@
 #include <env.h>
 #include <init.h>
 #include <log.h>
+#include <lmb.h>
 #include <misc.h>
 #include <net.h>
 #include <asm/io.h>
@@ -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() */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property
  2021-05-07 12:50 [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property Patrick Delaunay
                   ` (6 preceding siblings ...)
  2021-05-07 12:50 ` [PATCH v4 7/7] stm32mp: don't map the reserved region with no-map property Patrick Delaunay
@ 2021-06-07 23:16 ` Tom Rini
  7 siblings, 0 replies; 9+ messages in thread
From: Tom Rini @ 2021-06-07 23:16 UTC (permalink / raw)
  To: Patrick Delaunay
  Cc: u-boot, Andy Shevchenko, Etienne Carriere, Masahiro Yamada,
	Pali Rohár, Patrice Chotard, Patrick Delaunay, Simon Glass,
	Stefan Roese, Tero Kristo, U-Boot STM32, Wasim Khan, chenshuo

[-- Attachment #1: Type: text/plain, Size: 3419 bytes --]

On Fri, May 07, 2021 at 02:50:28PM +0200, Patrick Delaunay wrote:

> Hi,
> 
> It it the v4 serie of [1].
> 
> This v4 serie is rebased on top of master branch with update after Simon
> Glass review and added tags.
> 
> 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.
> 
> => the previous path 7/7 of v2 series is dropped to avoid
>   performance issue on other ARM target.
> 
> To avoid this performance issue on stm32mp32mp platform, the lmb
> initialization is done in enable_caches() when dcache is still enable.
> 
> This v3 series is composed by 7 patches
> - 1..3/7: preliminary steps to support flags in library in lmb
>   (as it is done in memblock.c in Linux)
> - 4/7: unitary test on the added feature in lmb lib
> - 5/7: save the no-map flags in lmb when the device tree is parsed
> - 6/7: solve issue for the size of cacheable area in pre-reloc case
> - 7/7: update the stm32mp mmu support
> 
> See also [2] which handle same speculative access on armv8 for area
> with Executable attribute.
> 
> [1] http://patchwork.ozlabs.org/project/uboot/list/?series=241122&state=*
> [2] http://patchwork.ozlabs.org/project/uboot/patch/20200903000106.5016-1-marek.bykowski@gmail.com/

For the series, applied to u-boot/next, and I've taken the above and
reworked it slightly to use as the merge commit message.  Thanks!

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2021-06-07 23:17 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-07 12:50 [PATCH v4 0/7] arm: cache: cp15: don't map reserved region with no-map property Patrick Delaunay
2021-05-07 12:50 ` [PATCH v4 1/7] lmb: Add support of flags for no-map properties Patrick Delaunay
2021-05-07 12:50 ` [PATCH v4 2/7] lmb: add lmb_is_reserved_flags Patrick Delaunay
2021-05-07 12:50 ` [PATCH v4 3/7] lmb: add lmb_dump_region() function Patrick Delaunay
2021-05-07 12:50 ` [PATCH v4 4/7] test: lmb: add test for lmb_reserve_flags Patrick Delaunay
2021-05-07 12:50 ` [PATCH v4 5/7] image-fdt: save no-map parameter of reserve-memory Patrick Delaunay
2021-05-07 12:50 ` [PATCH v4 6/7] stm32mp: Increase the reserved memory in board_get_usable_ram_top Patrick Delaunay
2021-05-07 12:50 ` [PATCH v4 7/7] stm32mp: don't map the reserved region with no-map property Patrick Delaunay
2021-06-07 23:16 ` [PATCH v4 0/7] arm: cache: cp15: don't map " Tom Rini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.