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

Re: [PATCH v2 1/6] xen/riscv: fix Svade/Svadu A/D bit handling



On 2026-09-22 17:29 +0200, Oleksii Kurochko wrote:
> 
> 
> On 9/10/26 11:34 AM, Baptiste Le Duc wrote:
> > p2m_set_permission() only presets the PTE A/D bits when the Svade extension
> > is present in the device tree. This causes an unhandled page fault when
> > neither Svade nor Svadu is present (the platform's actual behaviour is then
> > unknown), and when both are present in the device tree.
> 
> When both are present, RISCV_ISA_EXT_svade is set, so the current code 
> does preset the A/D bits and no fault happens. The only broken case is 
> when neither extension is present, so shouldn't "both present" be dropped?
Yes i agree, I'll fix that in v3.
> 
> > 
> > Move the Svade/Svadu resolution out of p2m_set_permission() and into a new
> > riscv_resolve_ad_scheme(), called once from riscv_fill_hwcap(). For each of
> > the four possible Svade/Svadu combinations (inspired by [1]), it decides
> > whether software has to preset the A/D bits and, if so, sets
> > RISCV_ISA_EXT_svade to record that decision:
> > - neither present: assume Svade, since assuming Svade is harmless on real
> >    Svadu hardware, while assuming Svadu on real Svade hardware risks an
> >    unhandled page fault
> > - only Svade present: assume Svade
> > - only Svadu present: leave A/D management to hardware
> > - both present: Svade wins until Xen supports the SBI FWFT call needed to
> >    enable hardware updating of A/D bits, so assume Svade and warn that
> >    dropping 'svade' from the DT is 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 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.
> 
> sbi_probe_extension() is already non-static in staging, only the prototype
> is missing. What base is this patch against?
> 
> > - stop presetting A/D bits unconditionally in p2m_set_permission(), do it
> >    only when Svade is present.
> 
> What is the gain from not presetting them? Presetting A/D is correct 
> with both Svade and Svadu: with Svadu it just saves the hardware an 
> atomic PTE update on first access. Xen doesn't consume G-stage A/D bits 
> (no dirty tracking, no demand paging), and pt.c already presets A/D 
> unconditionally for Xen's own mappings. Always setting PTE_ACCESSED | 
> PTE_DIRTY in p2m_set_permission() fixes the bug in one line, with no 
> need for the resolver, the new ISA bit, FWFT probing or the ASSERT. 
> Handling A/D differently only makes sense once Xen actually wants that 
> information, and at that point FWFT support and a fault handler are 
> needed anyway.
I agree that presetting them is the right way, it is also the way linux
is working. If Jan agree, I will to in that way in v3.

Then, it seems there is no need to register Svade/Svadu at all in
cpufeature.c, am I right?
> > ---
> >   xen/arch/riscv/cpufeature.c             | 59 
> > +++++++++++++++++++++++++++++++++
> >   xen/arch/riscv/include/asm/cpufeature.h |  1 +
> >   xen/arch/riscv/include/asm/sbi.h        |  8 +++++
> >   xen/arch/riscv/p2m.c                    | 47 ++++++++++----------------
> >   4 files changed, 86 insertions(+), 29 deletions(-)
> > 
> > diff --git a/xen/arch/riscv/cpufeature.c b/xen/arch/riscv/cpufeature.c
> > index 92235fdfd5..19454544a7 100644
> > --- a/xen/arch/riscv/cpufeature.c
> > +++ b/xen/arch/riscv/cpufeature.c
> > @@ -18,6 +18,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"
> > @@ -468,6 +469,62 @@ static bool __init has_isa_extensions_property(void)
> >       return false;
> >   }
> >   
> > +/*
> > + * 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. In that case, Xen assumes Svade because it's
> > + *    harmless if the platform is actually Svadu, while assuming Svadu on 
> > real
> > + *    Svade hardware risks an unhandled page fault.
> > + *
> > + * 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 by setting 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.
> > + *
> > + * In other words, hardware manages the A/D bits on its own only in case 
> > 3, in
> > + * all the other cases software has to preset them. Instead of open coding 
> > this
> > + * in every A/D bits user, RISCV_ISA_EXT_svade is used to mean "software is
> > + * responsible for the A/D bits" and is set here for the cases 1, 2 and 4.
> > + */
> > +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);
> 
> svadu is always false here: the patch doesn't add 
> RISCV_ISA_EXT_ENTRY(svadu, NONE) to riscv_isa_ext[], so match_isa_ext()
> never sets this bit. Cases 3 and 4 are dead code. Am I missing something?
> 
> > +
> > +    /* Case 3: leave the A/D bits management to hardware. */
> > +    if ( svadu && !svade )
> > +        return;
> > +
> > +    /* Case 4 */
> > +    if ( svadu && svade ){
> > +        if ( !sbi_probe_extension(SBI_EXT_FWFT) ){
> > +          printk(XENLOG_WARNING "RISC-V: Both Svade and Svadu detected, 
> > but SBI FWFT is missing.\n"
> > +                  "RISC-V: Defaulting to software A/D updates (Svade).\n"
> > +                  "RISC-V: To force hardware A/D updates (Svadu), remove 
> > 'svade' from DT.\n");
> > +        }
> > +    }
> 
> sbi_probe_extension() returns a negative errno on SBI failure, so
> !sbi_probe_extension() is false in that case and an error is treated as
> "FWFT present". The existing callers check "> 0", so this should be
> "<= 0".
> 
> > +
> > +    /* Cases 1, 2: Xen assume Svade to be enabled */
> 
> s/assume/assumes.
> 
> > +    __set_bit(RISCV_ISA_EXT_svade, riscv_isa);
> 
> In case 4 RISCV_ISA_EXT_svadu stays set, so both bits are set and the
> ASSERT() in p2m_set_permission() fires (once svadu is actually parsed).
> This contradicts the "mutually exclusive" statement there.
> 
> > +}
> > +
> >   bool riscv_isa_extension_available(const unsigned long *isa_bitmap,
> >                                      enum riscv_isa_ext_id id)
> >   {
> > @@ -513,6 +570,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 0c48d57a03..74200ce7c9 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_sstc,
> >       RISCV_ISA_EXT_svade,
> >       RISCV_ISA_EXT_svpbmt,
> > +    RISCV_ISA_EXT_svadu,
> 
> Please keep the same order as riscv_isa_ext[], i.e. between svade and
> svpbmt, and add the matching riscv_isa_ext[] entry there as well.
> 
> >       RISCV_ISA_EXT_MAX
> >   };
> >   
> > diff --git a/xen/arch/riscv/include/asm/sbi.h 
> > b/xen/arch/riscv/include/asm/sbi.h
> > index 1952868e96..4f13e8c7a0 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.
> > + * @extid: The extension ID to be probed.
> > + *
> > + * @return: 1 or an extension specific nonzero value if yes, 0 otherwise.
> > + */
> 
> This is incorrect: on failure the function returns a negative errno, not
> 0. Also, the rest of the file uses /* */ and not kernel-doc /**.
> 
> > +int sbi_probe_extension(long extid);
> 
> A blank line is missing before the next comment block.
> 
> >   /*
> >    * Initialize SBI library
> >    *
> > diff --git a/xen/arch/riscv/p2m.c b/xen/arch/riscv/p2m.c
> > index 1cea86512c..22ad4a2aee 100644
> > --- a/xen/arch/riscv/p2m.c
> > +++ b/xen/arch/riscv/p2m.c
> > @@ -586,42 +586,31 @@ static inline void p2m_clean_pte(pte_t *p, bool 
> > clean_cache)
> >   
> >   static void p2m_set_permission(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);
> 
> This runs for every p2m PTE. The second test_bit() exists only for the
> ASSERT().
> 
> > +
> >       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.
> > +     * riscv_fill_hwcap() sets either RISCV_ISA_EXT_svade or
> > +     * RISCV_ISA_EXT_svadu (mutually exclusive) depending on the 
> > Svade/Svadu
> > +     * device tree combination (see riscv_resolve_ad_scheme()):
> 
> This isn't true, see the comment on riscv_resolve_ad_scheme(): in case 4 
> both bits end up set.
> 
> > +     * - RISCV_ISA_EXT_svade means that software is responsible for the A/D
> > +     *   bits.
> > +     * - RISCV_ISA_EXT_svadu means the hardware is responsible for the A/D
> > +     *   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.
> > +     * Currently, when RISCV_ISA_EXT_svade is set, Xen doesn't track A/D
> > +     * bits, so it does not make use of the information that could be
> > +     * obtained from handling the resulting page faults, which could
> > +     * otherwise be useful for several use cases such as demand paging,
> > +     * cache-flushing optimizations, memory access tracking, etc. To avoid
> > +     * such a page fault, Xen presets the A and D bits instead.
> >        */
> > -    if ( riscv_isa_extension_available(NULL, RISCV_ISA_EXT_svade) )
> > +    ASSERT(svade != svadu); /* exactly one of svade/svadu must be set by 
> > riscv_fill_hwcap() */
> 
> The line is over 80 columns, and the trailing comment just repeats the 
> block comment above.
> 
> > +    if ( svade )
> >           e->pte |= PTE_ACCESSED | PTE_DIRTY;
> >   
> >       switch ( t )
> > 
> 
> ~ Oleksii
> 
> 
> 





 


Rackspace

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