|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v6 1/4] xen/riscv: probe the PTE A/D bits update scheme at boot
p2m_set_pte_flags() presets the A/D bits of G-stage PTEs only when
RISCV_ISA_EXT_svade is set, which today only reflects the device tree.
Platforms that fault on clear A/D bits without advertising Svade, such as
the HiFive Premier P550, then leave A/D clear and take guest-page faults
that Xen does not handle. The device tree cannot be trusted alone to tell
which scheme is in effect.
Introduce probe_hw_ad_update(): map a scratch page through the FIX_MISC
fixmap slot with a PTE whose A bit is clear, and read from it under an
exception table fixup. The read succeeds if hardware updates A/D bits and
faults otherwise.
Introduce resolve_ad_scheme(), called from riscv_fill_hwcap(), to check the
probe against what the device tree advertises, following the DT binding:
- Svade and Svadu: if the probe faults, Svade applies. Warn that hardware
updating can be used by dropping Svade from the device tree, or through
SBI FWFT once Xen supports it. Otherwise hardware updating applies and
nothing is needed.
- Svadu only: firmware must have enabled hardware updating. Panic if the
probe faults.
- Svade only: the hart must not update A/D bits. Assert the probe faults.
- Neither: record the probed scheme by setting RISCV_ISA_EXT_svadu or
RISCV_ISA_EXT_svade.
Add Svadu to the known ISA extensions so it can be told apart from Svade.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Baptiste Le Duc <baptiste.le-duc@xxxxxxxxxx>
---
Changes since v5:
- new patch, probe the A/D bits update scheme instead of trusting the
device tree alone.
---
xen/arch/riscv/cpufeature.c | 97 +++++++++++++++++++++++++++++++++
xen/arch/riscv/include/asm/cpufeature.h | 1 +
2 files changed, 98 insertions(+)
diff --git a/xen/arch/riscv/cpufeature.c b/xen/arch/riscv/cpufeature.c
index 3d5bbd2228..60e48652a6 100644
--- a/xen/arch/riscv/cpufeature.c
+++ b/xen/arch/riscv/cpufeature.c
@@ -20,6 +20,8 @@
#include <asm/cpufeature.h>
#include <asm/csr.h>
+#include <asm/fixmap.h>
+#include <asm/pmap.h>
#ifdef CONFIG_ACPI
# error "cpufeature.c functions should be updated to support ACPI"
@@ -200,6 +202,7 @@ static const struct riscv_isa_ext_entry __initconstrel
riscv_isa_ext[] = {
RISCV_ISA_EXT_ENTRY(ssaia, ANY),
RISCV_ISA_EXT_ENTRY(sstc, NONE),
RISCV_ISA_EXT_ENTRY(svade, NONE),
+ RISCV_ISA_EXT_ENTRY(svadu, NONE),
RISCV_ISA_EXT_ENTRY(svpbmt, NONE),
};
@@ -620,6 +623,98 @@ static void __init compute_guest_isa(void)
panic("Failed to build guest \"riscv,isa\" string\n");
}
+static bool __init probe_hw_ad_update(void)
+{
+ bool updated = false;
+ unsigned int slot = FIX_MISC;
+ vaddr_t va = FIXMAP_ADDR(slot);
+ struct page_info *pg;
+ pte_t *entry, pte;
+ mfn_t mfn;
+ unsigned long tmp;
+
+ pg = alloc_domheap_page(NULL, 0);
+ if ( !pg )
+ return false;
+
+ mfn = page_to_mfn(pg);
+
+ arch_pmap_map(FIX_MISC, mfn);
+ entry = &xen_fixmap[slot];
+ pte = pte_from_mfn(mfn, PTE_VALID | PTE_READABLE);
+ write_pte(entry, pte);
+
+ flush_tlb_one_local(va);
+
+ asm_inline volatile (
+ "1: ld %[tmp], 0(%[va])\n"
+ " li %[updated], 1\n"
+ "2:\n"
+ ASM_EXTABLE(1b, 2b)
+ : [tmp] "=&r" (tmp), [updated] "+r" (updated)
+ : [va] "r" (va)
+ : "memory" );
+
+ arch_pmap_unmap(slot);
+ free_domheap_page(pg);
+
+ return updated;
+}
+
+/*
+ * The privileged spec allows exactly two schemes for the PTE A and D bits:
+ * 1) hardware sets them on access and on write.
+ * 2) accessing a page whose A and/or D bit is clear raises a page fault,
+ * so that software can set them (ratified as Svade).
+ *
+ * Hence an implementation without Svade uses the hardware scheme (1), and one
+ * that faults on clear A/D bits implements Svade, whether or not it says so.
+ *
+ * Svadu isn't itself a scheme: it adds menvcfg.ADUE, selecting between the
+ * two for S-mode and G-stage translation, and henvcfg.ADUE, doing the same
+ * for VS-stage translation (read-only zero when menvcfg.ADUE is zero).
+ *
+ * Rather than trusting the DTS alone, probe the scheme in effect with a read
+ * through a PTE whose A bit is clear, and check it against what the DTS
+ * advertises, as described by the DT binding. Panic on a mismatch Xen cannot
+ * run with, and record the probed scheme when the DTS advertises neither.
+ */
+static void __init resolve_ad_scheme(void)
+{
+ bool svade = riscv_isa_extension_available(NULL, RISCV_ISA_EXT_svade);
+ bool svadu = riscv_isa_extension_available(NULL, RISCV_ISA_EXT_svadu);
+ bool has_hw_update = probe_hw_ad_update();
+
+ /* Both advertised: Svade applies until FWFT enables hardware updating. */
+ if ( svade && svadu )
+ {
+ if ( !has_hw_update )
+ printk(XENLOG_WARNING
+ "Svade and Svadu are both advertised, but software updates
A/D bits. "
+ "To use hardware updating, drop Svade from the DTS or use
FWFT (not implemented yet)\n");
+ return;
+ }
+
+ /* Only Svadu advertised: firmware must have enabled hardware updating. */
+ if ( svadu )
+ {
+ if ( !has_hw_update )
+ panic("Svadu is advertised but A/D bits are not updated by
hardware\n");
+ return;
+ }
+
+ /* Only Svade advertised: the hart must not update A/D bits. */
+ if ( svade )
+ {
+ ASSERT(!has_hw_update);
+ return;
+ }
+
+ /* Neither advertised: trust the probe. */
+ __set_bit(has_hw_update ? RISCV_ISA_EXT_svadu : RISCV_ISA_EXT_svade,
+ riscv_isa);
+}
+
void init_guest_isa(struct domain *d)
{
d->arch.isa = guest_isa;
@@ -674,6 +769,8 @@ void __init riscv_fill_hwcap(void)
"Zihintpause unavailable: cpu_relax() gives the CPU no hint; "
"wire up this platform's pause equivalent in cpu_relax()\n");
+ resolve_ad_scheme();
+
for ( i = 0; i < req_extns_amount; i++ )
{
const struct riscv_isa_ext_data ext = required_extensions[i];
diff --git a/xen/arch/riscv/include/asm/cpufeature.h
b/xen/arch/riscv/include/asm/cpufeature.h
index 2973eb13a5..6fb8ad4b9c 100644
--- a/xen/arch/riscv/include/asm/cpufeature.h
+++ b/xen/arch/riscv/include/asm/cpufeature.h
@@ -42,6 +42,7 @@ enum riscv_isa_ext_id {
RISCV_ISA_EXT_sstc,
RISCV_ISA_EXT_svade,
RISCV_ISA_EXT_svpbmt,
+ RISCV_ISA_EXT_svadu,
RISCV_ISA_EXT_MAX
};
--
2.55.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |