* [PATCH v2 0/2] arm: cpu: Add optional CMOs by VA
@ 2023-02-08 20:54 Ying-Chun Liu (PaulLiu)
2023-02-08 20:54 ` [PATCH v2 1/2] " Ying-Chun Liu (PaulLiu)
2023-02-08 20:54 ` [PATCH v2 2/2] arm64: Initialize TLB memory if CMO_BY_VA_ONLY Ying-Chun Liu (PaulLiu)
0 siblings, 2 replies; 5+ messages in thread
From: Ying-Chun Liu (PaulLiu) @ 2023-02-08 20:54 UTC (permalink / raw)
To: u-boot; +Cc: Ying-Chun Liu (PaulLiu)
Exposing set/way cache maintenance to a virtual machine is unsafe, not
least because the instructions are not permission-checked but also
because they are not broadcast between CPUs. Consequently, KVM traps and
emulates such maintenance in the host kernel using by-VA operations and
looping over the stage-2 page-tables. However, when running under
protected KVM, these instructions are not able to be emulated and will
instead result in an exception being delivered to the guest.
Introduce CONFIG_CMO_BY_VA_ONLY so that virtual platforms can select
this option and perform by-VA cache maintenance instead of using the
set/way instructions.
Marc Zyngier (1):
arm: cpu: Add optional CMOs by VA
Pierre-Clément Tosi (1):
arm64: Initialize TLB memory if CMO_BY_VA_ONLY
v2: Fix the Signed-off-by list.
arch/arm/cpu/armv8/Kconfig | 4 ++
arch/arm/cpu/armv8/cache.S | 50 +++++++++++++-----
arch/arm/cpu/armv8/cache_v8.c | 97 ++++++++++++++++++++++++++++++++++-
arch/arm/cpu/armv8/cpu.c | 30 +++++++----
arch/arm/lib/cache.c | 9 ++++
5 files changed, 164 insertions(+), 26 deletions(-)
--
2.39.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] arm: cpu: Add optional CMOs by VA
2023-02-08 20:54 [PATCH v2 0/2] arm: cpu: Add optional CMOs by VA Ying-Chun Liu (PaulLiu)
@ 2023-02-08 20:54 ` Ying-Chun Liu (PaulLiu)
2023-03-07 17:52 ` Tom Rini
2023-02-08 20:54 ` [PATCH v2 2/2] arm64: Initialize TLB memory if CMO_BY_VA_ONLY Ying-Chun Liu (PaulLiu)
1 sibling, 1 reply; 5+ messages in thread
From: Ying-Chun Liu (PaulLiu) @ 2023-02-08 20:54 UTC (permalink / raw)
To: u-boot
Cc: Marc Zyngier, Will Deacon, Pierre-Clément Tosi,
Ying-Chun Liu, Tom Rini
From: Marc Zyngier <maz@kernel.org>
Exposing set/way cache maintenance to a virtual machine is unsafe, not
least because the instructions are not permission-checked but also
because they are not broadcast between CPUs. Consequently, KVM traps and
emulates such maintenance in the host kernel using by-VA operations and
looping over the stage-2 page-tables. However, when running under
protected KVM, these instructions are not able to be emulated and will
instead result in an exception being delivered to the guest.
Introduce CONFIG_CMO_BY_VA_ONLY so that virtual platforms can select
this option and perform by-VA cache maintenance instead of using the
set/way instructions.
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Will Deacon <willdeacon@google.com>
Signed-off-by: Pierre-Clément Tosi <ptosi@google.com>
[ Paul: pick from the Android tree. Fixup Pierre's commit. And fix some
checkpatch warnings. Rebased to upstream. ]
Signed-off-by: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
Cc: Tom Rini <trini@konsulko.com>
Link: https://android.googlesource.com/platform/external/u-boot/+/db5507f47f4f57f766d52f753ff2cc761afc213b
Link: https://android.googlesource.com/platform/external/u-boot/+/2baf54e743380a1e4a6bc2dbdde020a2e783ff67
---
v2: Fix the Signed-off-by list.
---
arch/arm/cpu/armv8/Kconfig | 4 ++
arch/arm/cpu/armv8/cache.S | 50 +++++++++++++-----
arch/arm/cpu/armv8/cache_v8.c | 97 ++++++++++++++++++++++++++++++++++-
arch/arm/cpu/armv8/cpu.c | 30 +++++++----
4 files changed, 155 insertions(+), 26 deletions(-)
diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig
index 1305238c9d..7d5cf1594d 100644
--- a/arch/arm/cpu/armv8/Kconfig
+++ b/arch/arm/cpu/armv8/Kconfig
@@ -1,5 +1,9 @@
if ARM64
+config CMO_BY_VA_ONLY
+ bool "Force cache maintenance to be exclusively by VA"
+ depends on !SYS_DISABLE_DCACHE_OPS
+
config ARMV8_SPL_EXCEPTION_VECTORS
bool "Install crash dump exception vectors"
depends on SPL
diff --git a/arch/arm/cpu/armv8/cache.S b/arch/arm/cpu/armv8/cache.S
index d1cee23437..3fe935cf28 100644
--- a/arch/arm/cpu/armv8/cache.S
+++ b/arch/arm/cpu/armv8/cache.S
@@ -12,6 +12,7 @@
#include <asm/system.h>
#include <linux/linkage.h>
+#ifndef CONFIG_CMO_BY_VA_ONLY
/*
* void __asm_dcache_level(level)
*
@@ -116,6 +117,41 @@ ENTRY(__asm_invalidate_dcache_all)
ENDPROC(__asm_invalidate_dcache_all)
.popsection
+.pushsection .text.__asm_flush_l3_dcache, "ax"
+WEAK(__asm_flush_l3_dcache)
+ mov x0, #0 /* return status as success */
+ ret
+ENDPROC(__asm_flush_l3_dcache)
+.popsection
+
+.pushsection .text.__asm_invalidate_l3_icache, "ax"
+WEAK(__asm_invalidate_l3_icache)
+ mov x0, #0 /* return status as success */
+ ret
+ENDPROC(__asm_invalidate_l3_icache)
+.popsection
+
+#else /* CONFIG_CMO_BY_VA */
+
+/*
+ * Define these so that they actively clash with in implementation
+ * accidentally selecting CONFIG_CMO_BY_VA
+ */
+
+.pushsection .text.__asm_invalidate_l3_icache, "ax"
+ENTRY(__asm_invalidate_l3_icache)
+ mov x0, xzr
+ ret
+ENDPROC(__asm_invalidate_l3_icache)
+.popsection
+.pushsection .text.__asm_flush_l3_dcache, "ax"
+ENTRY(__asm_flush_l3_dcache)
+ mov x0, xzr
+ ret
+ENDPROC(__asm_flush_l3_dcache)
+.popsection
+#endif /* CONFIG_CMO_BY_VA */
+
/*
* void __asm_flush_dcache_range(start, end)
*
@@ -189,20 +225,6 @@ WEAK(__asm_invalidate_l3_dcache)
ENDPROC(__asm_invalidate_l3_dcache)
.popsection
-.pushsection .text.__asm_flush_l3_dcache, "ax"
-WEAK(__asm_flush_l3_dcache)
- mov x0, #0 /* return status as success */
- ret
-ENDPROC(__asm_flush_l3_dcache)
-.popsection
-
-.pushsection .text.__asm_invalidate_l3_icache, "ax"
-WEAK(__asm_invalidate_l3_icache)
- mov x0, #0 /* return status as success */
- ret
-ENDPROC(__asm_invalidate_l3_icache)
-.popsection
-
/*
* void __asm_switch_ttbr(ulong new_ttbr)
*
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
index 2a226fd063..f333ad8889 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -163,6 +163,83 @@ static u64 *find_pte(u64 addr, int level)
return NULL;
}
+#ifdef CONFIG_CMO_BY_VA_ONLY
+static void __cmo_on_leaves(void (*cmo_fn)(unsigned long, unsigned long),
+ u64 pte, int level, u64 base)
+{
+ u64 *ptep;
+ int i;
+
+ ptep = (u64 *)(pte & GENMASK_ULL(47, PAGE_SHIFT));
+ for (i = 0; i < PAGE_SIZE / sizeof(u64); i++) {
+ u64 end, va = base + i * BIT(level2shift(level));
+ u64 type, attrs;
+
+ pte = ptep[i];
+ type = pte & PTE_TYPE_MASK;
+ attrs = pte & PMD_ATTRINDX_MASK;
+ debug("PTE %llx at level %d VA %llx\n", pte, level, va);
+
+ /* Not valid? next! */
+ if (!(type & PTE_TYPE_VALID))
+ continue;
+
+ /* Not a leaf? Recurse on the next level */
+ if (!(type == PTE_TYPE_BLOCK ||
+ (level == 3 && type == PTE_TYPE_PAGE))) {
+ __cmo_on_leaves(cmo_fn, pte, level + 1, va);
+ continue;
+ }
+
+ /*
+ * From this point, this must be a leaf.
+ *
+ * Start excluding non memory mappings
+ */
+ if (attrs != PTE_BLOCK_MEMTYPE(MT_NORMAL) &&
+ attrs != PTE_BLOCK_MEMTYPE(MT_NORMAL_NC))
+ continue;
+
+ end = va + BIT(level2shift(level)) - 1;
+
+ /* No intersection with RAM? */
+ if (end < gd->ram_base ||
+ va >= (gd->ram_base + gd->ram_size))
+ continue;
+
+ /*
+ * OK, we have a partial RAM mapping. However, this
+ * can cover *more* than the RAM. Yes, u-boot is
+ * *that* braindead. Compute the intersection we care
+ * about, and not a byte more.
+ */
+ va = max(va, (u64)gd->ram_base);
+ end = min(end, gd->ram_base + gd->ram_size);
+
+ debug("Flush PTE %llx at level %d: %llx-%llx\n",
+ pte, level, va, end);
+ cmo_fn(va, end);
+ }
+}
+
+static void apply_cmo_to_mappings(void (*cmo_fn)(unsigned long, unsigned long))
+{
+ u64 va_bits;
+ int sl = 0;
+
+ if (!gd->arch.tlb_addr)
+ return;
+
+ get_tcr(NULL, &va_bits);
+ if (va_bits < 39)
+ sl = 1;
+
+ __cmo_on_leaves(cmo_fn, gd->arch.tlb_addr, sl, 0);
+}
+#else
+static inline void apply_cmo_to_mappings(void *dummy) {}
+#endif
+
/* Returns and creates a new full table (512 entries) */
static u64 *create_table(void)
{
@@ -447,8 +524,12 @@ __weak void mmu_setup(void)
*/
void invalidate_dcache_all(void)
{
+#ifndef CONFIG_CMO_BY_VA_ONLY
__asm_invalidate_dcache_all();
__asm_invalidate_l3_dcache();
+#else
+ apply_cmo_to_mappings(invalidate_dcache_range);
+#endif
}
/*
@@ -458,6 +539,7 @@ void invalidate_dcache_all(void)
*/
inline void flush_dcache_all(void)
{
+#ifndef CONFIG_CMO_BY_VA_ONLY
int ret;
__asm_flush_dcache_all();
@@ -466,6 +548,9 @@ inline void flush_dcache_all(void)
debug("flushing dcache returns 0x%x\n", ret);
else
debug("flushing dcache successfully.\n");
+#else
+ apply_cmo_to_mappings(flush_dcache_range);
+#endif
}
#ifndef CONFIG_SYS_DISABLE_DCACHE_OPS
@@ -520,9 +605,19 @@ void dcache_disable(void)
if (!(sctlr & CR_C))
return;
+ if (IS_ENABLED(CONFIG_CMO_BY_VA_ONLY)) {
+ /*
+ * When invalidating by VA, do it *before* turning the MMU
+ * off, so that at least our stack is coherent.
+ */
+ flush_dcache_all();
+ }
+
set_sctlr(sctlr & ~(CR_C|CR_M));
- flush_dcache_all();
+ if (!IS_ENABLED(CONFIG_CMO_BY_VA_ONLY))
+ flush_dcache_all();
+
__asm_invalidate_tlb_all();
}
diff --git a/arch/arm/cpu/armv8/cpu.c b/arch/arm/cpu/armv8/cpu.c
index db5d460eb4..3c7f36ad8d 100644
--- a/arch/arm/cpu/armv8/cpu.c
+++ b/arch/arm/cpu/armv8/cpu.c
@@ -48,18 +48,26 @@ int cleanup_before_linux(void)
disable_interrupts();
- /*
- * Turn off I-cache and invalidate it
- */
- icache_disable();
- invalidate_icache_all();
+ if (IS_ENABLED(CONFIG_CMO_BY_VA_ONLY)) {
+ /*
+ * Disable D-cache.
+ */
+ dcache_disable();
+ } else {
+ /*
+ * Turn off I-cache and invalidate it
+ */
+ icache_disable();
+ invalidate_icache_all();
- /*
- * turn off D-cache
- * dcache_disable() in turn flushes the d-cache and disables MMU
- */
- dcache_disable();
- invalidate_dcache_all();
+ /*
+ * turn off D-cache
+ * dcache_disable() in turn flushes the d-cache and disables
+ * MMU
+ */
+ dcache_disable();
+ invalidate_dcache_all();
+ }
return 0;
}
--
2.39.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] arm64: Initialize TLB memory if CMO_BY_VA_ONLY
2023-02-08 20:54 [PATCH v2 0/2] arm: cpu: Add optional CMOs by VA Ying-Chun Liu (PaulLiu)
2023-02-08 20:54 ` [PATCH v2 1/2] " Ying-Chun Liu (PaulLiu)
@ 2023-02-08 20:54 ` Ying-Chun Liu (PaulLiu)
2023-03-07 17:52 ` Tom Rini
1 sibling, 1 reply; 5+ messages in thread
From: Ying-Chun Liu (PaulLiu) @ 2023-02-08 20:54 UTC (permalink / raw)
To: u-boot; +Cc: Pierre-Clément Tosi, Ying-Chun Liu, Tom Rini
From: Pierre-Clément Tosi <ptosi@google.com>
Memory used to hold the page tables is allocated from the top of RAM
with no prior initialization and could therefore hold invalid data. As
invalidate_dcache_all() will be called before the MMU has been
initialized and as that function relies indirectly on the page tables
when using CMO_BY_VA_ONLY, these must be in a valid state from their
allocation.
Signed-off-by: Pierre-Clément Tosi <ptosi@google.com>
[ Paul: pick from the Android tree. Fix checkpatch warnings, and rebased
to the upstream. ]
Signed-off-by: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
Cc: Tom Rini <trini@konsulko.com>
Link: https://android.googlesource.com/platform/external/u-boot/+/e3ceef4230b772186c6853cace4a676a407e6ab7
---
v2: Fix the Signed-off-by list.
---
arch/arm/lib/cache.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c
index 1a589c7e2a..7a16015867 100644
--- a/arch/arm/lib/cache.c
+++ b/arch/arm/lib/cache.c
@@ -159,6 +159,15 @@ __weak int arm_reserve_mmu(void)
*/
gd->arch.tlb_allocated = gd->arch.tlb_addr;
#endif
+
+ if (IS_ENABLED(CONFIG_CMO_BY_VA_ONLY)) {
+ /*
+ * As invalidate_dcache_all() will be called before
+ * mmu_setup(), we should make sure that the PTs are
+ * already in a valid state.
+ */
+ memset((void *)gd->arch.tlb_addr, 0, gd->arch.tlb_size);
+ }
#endif
return 0;
--
2.39.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/2] arm: cpu: Add optional CMOs by VA
2023-02-08 20:54 ` [PATCH v2 1/2] " Ying-Chun Liu (PaulLiu)
@ 2023-03-07 17:52 ` Tom Rini
0 siblings, 0 replies; 5+ messages in thread
From: Tom Rini @ 2023-03-07 17:52 UTC (permalink / raw)
To: Ying-Chun Liu (PaulLiu)
Cc: u-boot, Marc Zyngier, Will Deacon, Pierre-Clément Tosi
[-- Attachment #1: Type: text/plain, Size: 1449 bytes --]
On Thu, Feb 09, 2023 at 04:54:27AM +0800, Ying-Chun Liu (PaulLiu) wrote:
> From: Marc Zyngier <maz@kernel.org>
>
> Exposing set/way cache maintenance to a virtual machine is unsafe, not
> least because the instructions are not permission-checked but also
> because they are not broadcast between CPUs. Consequently, KVM traps and
> emulates such maintenance in the host kernel using by-VA operations and
> looping over the stage-2 page-tables. However, when running under
> protected KVM, these instructions are not able to be emulated and will
> instead result in an exception being delivered to the guest.
>
> Introduce CONFIG_CMO_BY_VA_ONLY so that virtual platforms can select
> this option and perform by-VA cache maintenance instead of using the
> set/way instructions.
>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> Signed-off-by: Will Deacon <willdeacon@google.com>
> Signed-off-by: Pierre-Clément Tosi <ptosi@google.com>
> [ Paul: pick from the Android tree. Fixup Pierre's commit. And fix some
> checkpatch warnings. Rebased to upstream. ]
> Signed-off-by: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
> Cc: Tom Rini <trini@konsulko.com>
> Link: https://android.googlesource.com/platform/external/u-boot/+/db5507f47f4f57f766d52f753ff2cc761afc213b
> Link: https://android.googlesource.com/platform/external/u-boot/+/2baf54e743380a1e4a6bc2dbdde020a2e783ff67
Applied to u-boot/next, thanks!
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/2] arm64: Initialize TLB memory if CMO_BY_VA_ONLY
2023-02-08 20:54 ` [PATCH v2 2/2] arm64: Initialize TLB memory if CMO_BY_VA_ONLY Ying-Chun Liu (PaulLiu)
@ 2023-03-07 17:52 ` Tom Rini
0 siblings, 0 replies; 5+ messages in thread
From: Tom Rini @ 2023-03-07 17:52 UTC (permalink / raw)
To: Ying-Chun Liu (PaulLiu); +Cc: u-boot, Pierre-Clément Tosi
[-- Attachment #1: Type: text/plain, Size: 919 bytes --]
On Thu, Feb 09, 2023 at 04:54:28AM +0800, Ying-Chun Liu (PaulLiu) wrote:
> From: Pierre-Clément Tosi <ptosi@google.com>
>
> Memory used to hold the page tables is allocated from the top of RAM
> with no prior initialization and could therefore hold invalid data. As
> invalidate_dcache_all() will be called before the MMU has been
> initialized and as that function relies indirectly on the page tables
> when using CMO_BY_VA_ONLY, these must be in a valid state from their
> allocation.
>
> Signed-off-by: Pierre-Clément Tosi <ptosi@google.com>
> [ Paul: pick from the Android tree. Fix checkpatch warnings, and rebased
> to the upstream. ]
> Signed-off-by: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
> Cc: Tom Rini <trini@konsulko.com>
> Link: https://android.googlesource.com/platform/external/u-boot/+/e3ceef4230b772186c6853cace4a676a407e6ab7
Applied to u-boot/next, thanks!
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-03-07 17:53 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-02-08 20:54 [PATCH v2 0/2] arm: cpu: Add optional CMOs by VA Ying-Chun Liu (PaulLiu)
2023-02-08 20:54 ` [PATCH v2 1/2] " Ying-Chun Liu (PaulLiu)
2023-03-07 17:52 ` Tom Rini
2023-02-08 20:54 ` [PATCH v2 2/2] arm64: Initialize TLB memory if CMO_BY_VA_ONLY Ying-Chun Liu (PaulLiu)
2023-03-07 17:52 ` Tom Rini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox