[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 3/6] xen/riscv: fix A/D bit handling in G-stage mappings



There are two schemes for managing the PTE A/D bits: either a page fault is
raised when an access requires A or D to be set (ratified as Svade), or
hardware updates the bits itself (ratified as Svadu).

p2m_set_pte_flags() presets the A/D bits in G-stage PTEs only when Svade is
present in the device tree. When neither Svade nor Svadu is present, this
causes an unhandled page fault.

The four possible Svade/Svadu combinations in the device tree mean (see
[1]):
- neither present: the scheme is unknown, so the A/D bits have to be
  preset. This is harmless if hardware actually updates them itself.
- only Svade present: page faults, so the A/D bits have to be preset.
- only Svadu present: hardware updates the A/D bits.
- both present: hardware updating is off at boot and has to be enabled
  through the SBI FWFT extension, which Xen doesn't support yet, so the A/D
  bits have to be preset.

Hence preset the A/D bits in p2m_set_pte_flags() unless only Svadu is
present, i.e. when (!svadu || svade). Add riscv_resolve_ad_scheme(), called
once from riscv_fill_hwcap(), to warn when both are present but SBI FWFT is
missing, as dropping 'svade' from the DT is then the only way to get Svadu.

[1] https://lwn.net/Articles/980016/

Fixes: ff14053983b0 ("xen/riscv: Implement p2m_pte_from_mfn() and support PBMT 
configuration")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Baptiste Le Duc <baptiste.le-duc@xxxxxxxxxx>
---
Changes since v2:
- change commit title.
- preset A/D bits in p2m_set_pte_flags() if (!svadu || svade), instead of
setting RISCV_ISA_EXT_svade in the riscv_isa bitmap for cases 1, 2 and 4.
- riscv_resolve_ad_scheme() now only warns when both Svade and Svadu are
present and SBI FWFT is missing; drop the dead 'svadu && svade' operand.
- repeat XENLOG_WARNING on each line of the warning.
- drop ASSERT(svade != svadu) from p2m_set_pte_flags().
- only add the sbi_probe_extension() declaration to sbi.h.
- rework the comment in p2m_set_pte_flags().
---
Changes since v1:
- change commit title
- expose RISCV_ISA_EXT_svadu so the two extensions can be told apart.
- move the Svade/Svadu resolution to a new riscv_resolve_ad_scheme(),
  called once from riscv_fill_hwcap().
- expose sbi_probe_extension() (was static) to probe for SBI FWFT.
- stop presetting A/D bits unconditionally in p2m_set_permission(), do it
  only when Svade is present.
---
 xen/arch/riscv/cpufeature.c             | 43 +++++++++++++++++++++++++++++++++
 xen/arch/riscv/include/asm/cpufeature.h |  1 +
 xen/arch/riscv/include/asm/sbi.h        |  8 ++++++
 xen/arch/riscv/p2m.c                    | 40 +++++++++---------------------
 4 files changed, 63 insertions(+), 29 deletions(-)

diff --git a/xen/arch/riscv/cpufeature.c b/xen/arch/riscv/cpufeature.c
index 2d12dffae7..ee35c7a17c 100644
--- a/xen/arch/riscv/cpufeature.c
+++ b/xen/arch/riscv/cpufeature.c
@@ -20,6 +20,7 @@
 
 #include <asm/cpufeature.h>
 #include <asm/csr.h>
+#include <asm/sbi.h>
 
 #ifdef CONFIG_ACPI
 # error "cpufeature.c functions should be updated to support ACPI"
@@ -200,6 +201,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),
 };
 
@@ -500,6 +502,45 @@ static void __init riscv_fill_hwcap_from_isa_string(void)
     }
 }
 
+/*
+ * Svade and Svadu extensions represent two schemes for managing the PTE A/D
+ * bits. When the PTE A/D bits need to be set, the Svade extension indicates
+ * that a page fault will be raised. In contrast, the Svadu extension supports
+ * hardware updating of the PTE A/D bits.
+ *
+ * There are 4 possible combinations of these extensions in the device tree.
+ * The default hardware behavior for each is:
+ *
+ * 1) Neither Svade nor Svadu present in DT => It is technically unknown
+ *    whether the platform uses Svade or Svadu. Xen should be prepared to
+ *    handle either hardware updating of the PTE A/D bits or page faults when
+ *    they need updating.
+ *
+ * 2) Only Svade present in DT => Xen must assume Svade to be always enabled.
+ *
+ * 3) Only Svadu present in DT => Xen must assume Svadu to be always enabled.
+ *
+ * 4) Both Svade and Svadu present in DT => Xen must assume Svadu is turned off
+ *    at boot time, so it presets the A/D bits. To use Svadu, the supervisor
+ *    must explicitly enable it using the SBI FWFT extension.
+ *
+ * The Svade extension is mandatory and the Svadu extension is optional in the
+ * RVA23 profile. Platforms wanting to take advantage of Svadu can choose
+ * option 3. Platforms aware of the profile can choose option 4, and Xen won't
+ * get the benefit of Svadu until the SBI FWFT extension is available.
+ */
+static void __init riscv_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);
+
+    if ( svadu && svade )
+        if ( sbi_probe_extension(SBI_EXT_FWFT) <= 0 )
+            printk(XENLOG_WARNING "RISC-V: Both Svade and Svadu detected, but 
SBI FWFT is missing.\n"
+                XENLOG_WARNING "RISC-V: Defaulting to software A/D updates 
(Svade).\n"
+                XENLOG_WARNING "RISC-V: To force hardware A/D updates (Svadu), 
remove 'svade' from DT.\n");
+}
+
 static bool __init has_isa_extensions_property(void)
 {
     const struct dt_device_node *cpus = dt_find_node_by_path("/cpus");
@@ -664,6 +705,8 @@ void __init riscv_fill_hwcap(void)
         __set_bit(RISCV_ISA_EXT_sstc, riscv_isa);
     }
 
+    riscv_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..7a448d6111 100644
--- a/xen/arch/riscv/include/asm/cpufeature.h
+++ b/xen/arch/riscv/include/asm/cpufeature.h
@@ -41,6 +41,7 @@ enum riscv_isa_ext_id {
     RISCV_ISA_EXT_ssaia,
     RISCV_ISA_EXT_sstc,
     RISCV_ISA_EXT_svade,
+    RISCV_ISA_EXT_svadu,
     RISCV_ISA_EXT_svpbmt,
     RISCV_ISA_EXT_MAX
 };
diff --git a/xen/arch/riscv/include/asm/sbi.h b/xen/arch/riscv/include/asm/sbi.h
index 1952868e96..4efa166603 100644
--- a/xen/arch/riscv/include/asm/sbi.h
+++ b/xen/arch/riscv/include/asm/sbi.h
@@ -30,6 +30,7 @@
 #define SBI_EXT_BASE                    0x10
 #define SBI_EXT_RFENCE                  0x52464E43
 #define SBI_EXT_TIME                    0x54494D45
+#define SBI_EXT_FWFT                    0x46574654
 
 /* SBI function IDs for BASE extension */
 #define SBI_EXT_BASE_GET_SPEC_VERSION   0x0
@@ -138,6 +139,13 @@ int sbi_remote_hfence_gvma(const cpumask_t *cpu_mask, 
vaddr_t start,
 int sbi_remote_hfence_gvma_vmid(const cpumask_t *cpu_mask, vaddr_t start,
                                 size_t size, unsigned long vmid);
 
+/*
+ * Check if an SBI extension ID is supported or not.
+ *
+ * @return: > 0 if supported, 0 if not, negative errno on SBI error.
+ */
+int sbi_probe_extension(long extid);
+
 /*
  * Initialize SBI library
  *
diff --git a/xen/arch/riscv/p2m.c b/xen/arch/riscv/p2m.c
index f7b380b90a..5c8e480050 100644
--- a/xen/arch/riscv/p2m.c
+++ b/xen/arch/riscv/p2m.c
@@ -586,42 +586,24 @@ static inline void p2m_clean_pte(pte_t *p, bool 
clean_cache)
 
 static void p2m_set_pte_flags(pte_t *e, p2m_type_t t)
 {
+    bool svade = riscv_isa_extension_available(NULL, RISCV_ISA_EXT_svade);
+    bool svadu = riscv_isa_extension_available(NULL, RISCV_ISA_EXT_svadu);
+
     e->pte &= ~PTE_ACCESS_MASK;
 
     e->pte |= PTE_USER;
 
     /*
-     * Two schemes to manage the A and D bits are defined:
-     *   • The Svade extension: when a virtual page is accessed and the A bit
-     *     is clear, or is written and the D bit is clear, a page-fault
-     *     exception is raised.
-     *   • When the Svade extension is not implemented, the following scheme
-     *     applies.
-     *     When a virtual page is accessed and the A bit is clear, the PTE is
-     *     updated to set the A bit. When the virtual page is written and the
-     *     D bit is clear, the PTE is updated to set the D bit. When G-stage
-     *     address translation is in use and is not Bare, the G-stage virtual
-     *     pages may be accessed or written by implicit accesses to VS-level
-     *     memory management data structures, such as page tables.
-     * Thereby to avoid a page-fault in case of Svade is available, it is
-     * necessary to set A and D bits.
-     *
-     * TODO: For now, it’s fine to simply set the A/D bits, since OpenSBI
-     *       delegates page faults to a lower privilege mode and so OpenSBI
-     *       isn't expect to handle page-faults occured in lower modes.
-     *       By setting the A/D bits here, page faults that would otherwise
-     *       be generated due to unset A/D bits will not occur in Xen.
-     *
-     *       Currently, Xen on RISC-V does not make use of the information
-     *       that could be obtained from handling such page faults, which
-     *       could otherwise be useful for several use cases such as demand
-     *       paging, cache-flushing optimizations, memory access tracking,etc.
+     * A RISC-V implementation can choose to either:
+     * 1) Update 'A' and 'D' PTE bits in hardware.
+     * 2) Generate page fault when 'A' and/or 'D' PTE bits are not set so that
+     *    software can update these bits.
      *
-     *       To support the more general case and the optimizations mentioned
-     *       above, it would be better to stop setting the A/D bits here and
-     *       instead handle page faults that occur due to unset A/D bits.
+     * Xen supports both options mentioned above: unless the platform 
guarantees
+     * (1), i.e. only Svadu is present, set 'A' and 'D' so that (2) never
+     * faults.
      */
-    if ( riscv_isa_extension_available(NULL, RISCV_ISA_EXT_svade) )
+    if ( !svadu || svade )
         e->pte |= PTE_ACCESSED | PTE_DIRTY;
 
     switch ( t )

-- 
2.55.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.