* [PATCH v4 1/3] dt-bindings: riscv: describe Svadu as disabled at boot
2026-06-18 6:44 [PATCH v4 0/3] riscv: support effective hardware PTE A/D updates Yunhui Cui
@ 2026-06-18 6:44 ` Yunhui Cui
2026-06-18 16:37 ` Conor Dooley
2026-06-18 6:44 ` [PATCH v4 2/3] riscv: track effective hardware PTE A/D updating Yunhui Cui
2026-06-18 6:44 ` [PATCH v4 3/3] riscv: preserve A/D and soft-dirty state across PTE updates Yunhui Cui
2 siblings, 1 reply; 7+ messages in thread
From: Yunhui Cui @ 2026-06-18 6:44 UTC (permalink / raw)
To: akpm, alex, andrew+kernel, aou, apatel, apopple, atishp,
baolin.wang, cleger, conor+dt, cuiyunhui, debug, devicetree,
guodong, hui.wang, krzk+dt, linux-kernel, linux-riscv,
liu.xuemei1, namcao, nick.hu, palmer, pincheng.plct, pjw,
qingwei.hu, ritesh.list, rmclure, robh, wangruikang, zhangchunyan,
zong.li
When both Svade and Svadu are advertised, Svadu is not active at boot and
must be enabled through SBI FWFT before supervisor software can rely on
hardware PTE A/D updates.
Use "disabled" instead of "turned-off" to describe that boot-time state.
This matches the FWFT terminology more closely and avoids the informal
"turned-off" wording without changing the binding semantics.
Signed-off-by: Yunhui Cui <cuiyunhui@bytedance.com>
Reviewed-by: Qingwei Hu <qingwei.hu@bytedance.com>
---
Documentation/devicetree/bindings/riscv/extensions.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 2b0a8a93bb214..f1e6b0d79486b 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -297,7 +297,7 @@ properties:
3) Only Svadu present in DT => Supervisor must assume Svadu to be
always enabled.
4) Both Svade and Svadu present in DT => Supervisor must assume
- Svadu turned-off at boot time. To use Svadu, supervisor must
+ Svadu is disabled at boot time. To use Svadu, supervisor must
explicitly enable it using the SBI FWFT extension.
- const: svadu
--
2.39.5
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v4 1/3] dt-bindings: riscv: describe Svadu as disabled at boot
2026-06-18 6:44 ` [PATCH v4 1/3] dt-bindings: riscv: describe Svadu as disabled at boot Yunhui Cui
@ 2026-06-18 16:37 ` Conor Dooley
0 siblings, 0 replies; 7+ messages in thread
From: Conor Dooley @ 2026-06-18 16:37 UTC (permalink / raw)
To: Yunhui Cui
Cc: akpm, alex, andrew+kernel, aou, apatel, apopple, atishp,
baolin.wang, cleger, conor+dt, debug, devicetree, guodong,
hui.wang, krzk+dt, linux-kernel, linux-riscv, liu.xuemei1, namcao,
nick.hu, palmer, pincheng.plct, pjw, qingwei.hu, ritesh.list,
rmclure, robh, wangruikang, zhangchunyan, zong.li
[-- Attachment #1: Type: text/plain, Size: 75 bytes --]
Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 2/3] riscv: track effective hardware PTE A/D updating
2026-06-18 6:44 [PATCH v4 0/3] riscv: support effective hardware PTE A/D updates Yunhui Cui
2026-06-18 6:44 ` [PATCH v4 1/3] dt-bindings: riscv: describe Svadu as disabled at boot Yunhui Cui
@ 2026-06-18 6:44 ` Yunhui Cui
2026-06-18 7:02 ` sashiko-bot
2026-06-18 6:44 ` [PATCH v4 3/3] riscv: preserve A/D and soft-dirty state across PTE updates Yunhui Cui
2 siblings, 1 reply; 7+ messages in thread
From: Yunhui Cui @ 2026-06-18 6:44 UTC (permalink / raw)
To: akpm, alex, andrew+kernel, aou, apatel, apopple, atishp,
baolin.wang, cleger, conor+dt, cuiyunhui, debug, devicetree,
guodong, hui.wang, krzk+dt, linux-kernel, linux-riscv,
liu.xuemei1, namcao, nick.hu, palmer, pincheng.plct, pjw,
qingwei.hu, ritesh.list, rmclure, robh, wangruikang, zhangchunyan,
zong.li
Svadu being present in the ISA does not always mean that hardware PTE A/D
updating is active. When Svade and Svadu are both advertised, Svadu starts
disabled and must be enabled through SBI FWFT before the kernel can rely on
hardware A/D updates.
Track that effective runtime state with a static key. During init, enable
FWFT for all online harts before setting the key; if that fails, leave the
system in software-managed A/D mode. Secondary harts must match the global
A/D update mode before they are marked online.
The full state flow is:
boot init
|
v
do all CPUs have Svadu?
|
+------+------+
| |
no yes
| |
v v
hw_ad key = false does any CPU have Svade?
requires_fwft = false |
| +-----+-----+
| | |
| no yes
| | |
| v v
| hw_ad key = true requires_fwft = true
| requires_fwft = false |
| v
| FWFT on online CPUs
| |
| +------+------+
| | |
| success failure
| | |
| v v
| hw_ad key = true requires_fwft = false
| requires_fwft = true hw_ad key = false
| fallback to software A/D
|
+--------------+-----------+
|
v
hotplug CPU
|
v
if (!hw_ad_key || !requires_fwft)
|
+------+------+
| |
true false
| |
v v
return 0 enable local FWFT
| |
| +-----+-----+
| | |
| success failure
| | |
v v v
continue continue return error
| | |
v v v
set_cpu_online() do not set CPU online
| |
v v
CPU online CPU bringup fails
Thus, an online CPU never runs with an A/D update mode different from the
global kernel state.
Signed-off-by: Yunhui Cui <cuiyunhui@bytedance.com>
Reviewed-by: Qingwei Hu <qingwei.hu@bytedance.com>
---
arch/riscv/include/asm/cpufeature.h | 8 +++
arch/riscv/kernel/cpufeature.c | 101 ++++++++++++++++++++++++++--
arch/riscv/kernel/smpboot.c | 4 ++
3 files changed, 107 insertions(+), 6 deletions(-)
diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 739fcc84bf7b2..ba3d74f6006a6 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -128,6 +128,14 @@ struct riscv_isa_ext_data {
extern const struct riscv_isa_ext_data riscv_isa_ext[];
extern const size_t riscv_isa_ext_count;
extern bool riscv_isa_fallback;
+DECLARE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
+
+static __always_inline bool riscv_has_hw_pte_ad_updating(void)
+{
+ return static_branch_unlikely(&riscv_hw_pte_ad_updating);
+}
+
+int riscv_enable_hw_pte_ad_updating(void);
unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index f46aa5602d74d..c0ac7ab39d4e0 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -15,6 +15,7 @@
#include <linux/memory.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/smp.h>
#include <asm/acpi.h>
#include <asm/alternative.h>
#include <asm/bugs.h>
@@ -35,6 +36,9 @@
static bool any_cpu_has_zicboz;
static bool any_cpu_has_zicbop;
static bool any_cpu_has_zicbom;
+DEFINE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
+EXPORT_SYMBOL_GPL(riscv_hw_pte_ad_updating);
+static bool riscv_hw_pte_ad_updating_requires_fwft __read_mostly;
unsigned long elf_hwcap __read_mostly;
@@ -287,15 +291,100 @@ static int riscv_ext_zvfbfwma_validate(const struct riscv_isa_ext_data *data,
return -EPROBE_DEFER;
}
-static int riscv_ext_svadu_validate(const struct riscv_isa_ext_data *data,
- const unsigned long *isa_bitmap)
+static void riscv_set_hw_pte_ad_updating(void)
+{
+ static_branch_enable(&riscv_hw_pte_ad_updating);
+}
+
+static int riscv_enable_local_hw_pte_ad_updating(void)
{
- /* SVADE has already been detected, use SVADE only */
- if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_SVADE))
- return -EOPNOTSUPP;
+ return sbi_fwft_set(SBI_FWFT_PTE_AD_HW_UPDATING, 1, 0);
+}
+
+static int riscv_set_online_hw_pte_ad_updating(bool enable)
+{
+ return sbi_fwft_set_online_cpus(SBI_FWFT_PTE_AD_HW_UPDATING,
+ enable, 0);
+}
+
+static bool __init riscv_any_cpu_has_svade(void)
+{
+ unsigned int cpu;
+ for_each_possible_cpu(cpu) {
+ if (riscv_cpu_has_extension_unlikely(cpu, RISCV_ISA_EXT_SVADE))
+ return true;
+ }
+
+ return false;
+}
+
+int riscv_enable_hw_pte_ad_updating(void)
+{
+ unsigned int cpu;
+ int ret;
+
+ if (!riscv_has_hw_pte_ad_updating() ||
+ !riscv_hw_pte_ad_updating_requires_fwft)
+ return 0;
+
+ cpu = smp_processor_id();
+ ret = riscv_enable_local_hw_pte_ad_updating();
+ if (ret)
+ pr_err("CPU%u failed to enable hardware PTE A/D updating: %d\n",
+ cpu, ret);
+
+ return ret;
+}
+
+static void __init riscv_disable_hw_pte_ad_updating(int error)
+{
+ int ret;
+
+ riscv_hw_pte_ad_updating_requires_fwft = false;
+ if (error != -EOPNOTSUPP)
+ pr_err("Failed to enable hardware PTE A/D updating: %d\n",
+ error);
+
+ ret = riscv_set_online_hw_pte_ad_updating(false);
+ if (ret && ret != -EOPNOTSUPP)
+ pr_err("Failed to rollback hardware PTE A/D updating: %d\n",
+ ret);
+
+ pr_info("riscv: leave PTE A/D updates software-managed (%d)\n",
+ error);
+}
+
+static int __init riscv_hw_pte_ad_updating_init(void)
+{
+ bool requires_fwft, has_svadu;
+ int ret;
+
+ has_svadu = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
+ requires_fwft = riscv_any_cpu_has_svade();
+
+ if (!has_svadu)
+ return 0;
+
+ if (requires_fwft) {
+ riscv_hw_pte_ad_updating_requires_fwft = true;
+ ret = riscv_set_online_hw_pte_ad_updating(true);
+ if (ret) {
+ riscv_disable_hw_pte_ad_updating(ret);
+ return 0;
+ }
+ }
+
+ /*
+ * At this point hardware PTE A/D updating is active for all online
+ * harts, either from boot or from the FWFT setup above. Later harts
+ * must do the same in secondary startup before they are marked online.
+ */
+ riscv_set_hw_pte_ad_updating();
+ pr_debug("riscv: hardware PTE A/D updating enabled\n");
return 0;
}
+arch_initcall(riscv_hw_pte_ad_updating_init);
static int riscv_cfilp_validate(const struct riscv_isa_ext_data *data,
const unsigned long *isa_bitmap)
@@ -584,7 +673,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
__RISCV_ISA_EXT_DATA(svade, RISCV_ISA_EXT_SVADE),
- __RISCV_ISA_EXT_DATA_VALIDATE(svadu, RISCV_ISA_EXT_SVADU, riscv_ext_svadu_validate),
+ __RISCV_ISA_EXT_DATA(svadu, RISCV_ISA_EXT_SVADU),
__RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
__RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
index 8b628580fe118..4fe62f96bcca2 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -27,6 +27,7 @@
#include <linux/sched/mm.h>
#include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
#include <asm/cpu_ops.h>
#include <asm/irq.h>
#include <asm/mmu_context.h>
@@ -221,6 +222,9 @@ asmlinkage __visible void smp_callin(void)
struct mm_struct *mm = &init_mm;
unsigned int curr_cpuid = smp_processor_id();
+ if (riscv_enable_hw_pte_ad_updating())
+ return;
+
if (has_vector()) {
/*
* Return as early as possible so the hart with a mismatching
--
2.39.5
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v4 2/3] riscv: track effective hardware PTE A/D updating
2026-06-18 6:44 ` [PATCH v4 2/3] riscv: track effective hardware PTE A/D updating Yunhui Cui
@ 2026-06-18 7:02 ` sashiko-bot
2026-06-18 8:53 ` [External] " yunhui cui
0 siblings, 1 reply; 7+ messages in thread
From: sashiko-bot @ 2026-06-18 7:02 UTC (permalink / raw)
To: Yunhui Cui; +Cc: devicetree, conor+dt, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] A hotplugged CPU lacking the Svadu extension is incorrectly allowed to come online when hardware PTE A/D updating is globally enabled but FWFT is not required, leading to silent data corruption.
--
commit e238566a69f2ecd235872518a759dd75d54f71af
Author: Yunhui Cui <cuiyunhui@bytedance.com>
riscv: track effective hardware PTE A/D updating
This commit tracks the runtime state of hardware PTE A/D updating using a
static key. It attempts to enable FWFT for all online harts, falling back
to software A/D if that fails, and ensures hotplugged CPUs match the global
state before coming online.
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
[ ... ]
> +int riscv_enable_hw_pte_ad_updating(void)
> +{
> + unsigned int cpu;
> + int ret;
> +
> + if (!riscv_has_hw_pte_ad_updating() ||
> + !riscv_hw_pte_ad_updating_requires_fwft)
> + return 0;
[Severity: High]
Does this code allow a hotplugged CPU to come online without the Svadu
extension when hardware A/D updating is globally enabled?
If the boot CPUs have Svadu but lack Svade, the flag
riscv_hw_pte_ad_updating_requires_fwft is set to false and the global
static key riscv_hw_pte_ad_updating is enabled.
When a new CPU is later hotplugged, it calls this function via
smp_callin(). Since riscv_hw_pte_ad_updating_requires_fwft is false, it
returns 0 and bypasses any capability checks for the local CPU.
If the hotplugged CPU does not actually support Svadu (e.g., in an
asymmetric SoC or due to firmware misconfiguration), it successfully
comes online. Because the kernel globally assumes hardware A/D updating
is active, it skips software A/D fault handling.
Could this lead to the hotplugged CPU silently failing to update
accessed/dirty bits, causing data corruption when dirty data is dropped
during reclaim?
> +
> + cpu = smp_processor_id();
> + ret = riscv_enable_local_hw_pte_ad_updating();
> + if (ret)
> + pr_err("CPU%u failed to enable hardware PTE A/D updating: %d\n",
> + cpu, ret);
> +
> + return ret;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618064406.14508-1-cuiyunhui@bytedance.com?part=2
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [External] Re: [PATCH v4 2/3] riscv: track effective hardware PTE A/D updating
2026-06-18 7:02 ` sashiko-bot
@ 2026-06-18 8:53 ` yunhui cui
0 siblings, 0 replies; 7+ messages in thread
From: yunhui cui @ 2026-06-18 8:53 UTC (permalink / raw)
To: sashiko-reviews; +Cc: devicetree, conor+dt, robh
Hi sashiko,
On Thu, Jun 18, 2026 at 3:03 PM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] A hotplugged CPU lacking the Svadu extension is incorrectly allowed to come online when hardware PTE A/D updating is globally enabled but FWFT is not required, leading to silent data corruption.
> --
>
> commit e238566a69f2ecd235872518a759dd75d54f71af
> Author: Yunhui Cui <cuiyunhui@bytedance.com>
>
> riscv: track effective hardware PTE A/D updating
>
> This commit tracks the runtime state of hardware PTE A/D updating using a
> static key. It attempts to enable FWFT for all online harts, falling back
> to software A/D if that fails, and ensures hotplugged CPUs match the global
> state before coming online.
>
> > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> > --- a/arch/riscv/kernel/cpufeature.c
> > +++ b/arch/riscv/kernel/cpufeature.c
>
> [ ... ]
>
> > +int riscv_enable_hw_pte_ad_updating(void)
> > +{
> > + unsigned int cpu;
> > + int ret;
> > +
> > + if (!riscv_has_hw_pte_ad_updating() ||
> > + !riscv_hw_pte_ad_updating_requires_fwft)
> > + return 0;
>
> [Severity: High]
> Does this code allow a hotplugged CPU to come online without the Svadu
> extension when hardware A/D updating is globally enabled?
>
> If the boot CPUs have Svadu but lack Svade, the flag
> riscv_hw_pte_ad_updating_requires_fwft is set to false and the global
> static key riscv_hw_pte_ad_updating is enabled.
No, a hotplugged CPU should not be able to bypass this in the normal
RISC-V hotplug path. A CPU reaching smp_callin() must already be in
cpu_possible_mask, and the
global Svadu state is computed from the ISA intersection of all
possible CPUs. Therefore, if any possible hotplug CPU lacks Svadu,
riscv_has_extension_unlikely(SVADU)
is false and the HW A/D static key is never enabled.
>
> When a new CPU is later hotplugged, it calls this function via
> smp_callin(). Since riscv_hw_pte_ad_updating_requires_fwft is false, it
> returns 0 and bypasses any capability checks for the local CPU.
>
> If the hotplugged CPU does not actually support Svadu (e.g., in an
> asymmetric SoC or due to firmware misconfiguration), it successfully
> comes online. Because the kernel globally assumes hardware A/D updating
> is active, it skips software A/D fault handling.
>
> Could this lead to the hotplugged CPU silently failing to update
> accessed/dirty bits, causing data corruption when dirty data is dropped
> during reclaim?
>
> > +
> > + cpu = smp_processor_id();
> > + ret = riscv_enable_local_hw_pte_ad_updating();
> > + if (ret)
> > + pr_err("CPU%u failed to enable hardware PTE A/D updating: %d\n",
> > + cpu, ret);
> > +
> > + return ret;
> > +}
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260618064406.14508-1-cuiyunhui@bytedance.com?part=2
Thanks,
Yunhui
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 3/3] riscv: preserve A/D and soft-dirty state across PTE updates
2026-06-18 6:44 [PATCH v4 0/3] riscv: support effective hardware PTE A/D updates Yunhui Cui
2026-06-18 6:44 ` [PATCH v4 1/3] dt-bindings: riscv: describe Svadu as disabled at boot Yunhui Cui
2026-06-18 6:44 ` [PATCH v4 2/3] riscv: track effective hardware PTE A/D updating Yunhui Cui
@ 2026-06-18 6:44 ` Yunhui Cui
2 siblings, 0 replies; 7+ messages in thread
From: Yunhui Cui @ 2026-06-18 6:44 UTC (permalink / raw)
To: akpm, alex, andrew+kernel, aou, apatel, apopple, atishp,
baolin.wang, cleger, conor+dt, cuiyunhui, debug, devicetree,
guodong, hui.wang, krzk+dt, linux-kernel, linux-riscv,
liu.xuemei1, namcao, nick.hu, palmer, pincheng.plct, pjw,
qingwei.hu, ritesh.list, rmclure, robh, wangruikang, zhangchunyan,
zong.li
Use cmpxchg-based PTE updates so software permission changes do not lose
concurrent A/D updates from hardware. Preserve soft-dirty state as well,
since RISC-V marks PTEs dirty and soft-dirty together.
Signed-off-by: Yunhui Cui <cuiyunhui@bytedance.com>
Reviewed-by: Qingwei Hu <qingwei.hu@bytedance.com>
---
arch/riscv/include/asm/pgtable.h | 27 +++++++++----
arch/riscv/mm/pgtable.c | 68 ++++++++++++++++++++++++++------
2 files changed, 77 insertions(+), 18 deletions(-)
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 5d5756bda82e3..02286b48dc471 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -678,15 +678,21 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
static inline void ptep_set_wrprotect(struct mm_struct *mm,
unsigned long address, pte_t *ptep)
{
- pte_t read_pte = READ_ONCE(*ptep);
+ pte_t old_pte;
+ pte_t pte;
/*
* ptep_set_wrprotect can be called for shadow stack ranges too.
* shadow stack memory is XWR = 010 and thus clearing _PAGE_WRITE will lead to
* encoding 000b which is wrong encoding with V = 1. This should lead to page fault
* but we dont want this wrong configuration to be set in page tables.
*/
- atomic_long_set((atomic_long_t *)ptep,
- ((pte_val(read_pte) & ~(unsigned long)_PAGE_WRITE) | _PAGE_READ));
+ pte = READ_ONCE(*ptep);
+ do {
+ old_pte = pte;
+ pte = pte_wrprotect(pte);
+ pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep), pte_val(old_pte),
+ pte_val(pte));
+ } while (pte_val(pte) != pte_val(old_pte));
}
#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
@@ -742,14 +748,14 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
#define pgprot_dmacoherent pgprot_writecombine
/*
- * Both Svade and Svadu control the hardware behavior when the PTE A/D bits need to be set. By
- * default the M-mode firmware enables the hardware updating scheme when only Svadu is present in
- * DT.
+ * Both Svade and Svadu control the hardware behavior when the PTE A/D bits
+ * need to be set. The core MM code only cares whether hardware updating of
+ * the accessed/dirty state is currently active.
*/
#define arch_has_hw_pte_young arch_has_hw_pte_young
static inline bool arch_has_hw_pte_young(void)
{
- return riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
+ return riscv_has_hw_pte_ad_updating();
}
/*
@@ -1040,6 +1046,13 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
ptep_set_wrprotect(mm, address, (pte_t *)pmdp);
}
+#define __HAVE_ARCH_PUDP_SET_WRPROTECT
+static inline void pudp_set_wrprotect(struct mm_struct *mm,
+ unsigned long address, pud_t *pudp)
+{
+ ptep_set_wrprotect(mm, address, (pte_t *)pudp);
+}
+
#define pmdp_establish pmdp_establish
static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmdp, pmd_t pmd)
diff --git a/arch/riscv/mm/pgtable.c b/arch/riscv/mm/pgtable.c
index 9c4427d0b1874..98eed19ea70de 100644
--- a/arch/riscv/mm/pgtable.c
+++ b/arch/riscv/mm/pgtable.c
@@ -5,23 +5,55 @@
#include <linux/kernel.h>
#include <linux/pgtable.h>
+#define RISCV_PTE_ACCESS_FLAG_MASK (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC | \
+ _PAGE_ACCESSED | _PAGE_DIRTY | \
+ _PAGE_SOFT_DIRTY)
+
+static inline unsigned long riscv_pte_access_flags(unsigned long cur,
+ unsigned long entry)
+{
+ unsigned long pteval;
+ unsigned long preserved_flags;
+
+ preserved_flags = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_SOFT_DIRTY;
+ pteval = cur & ~RISCV_PTE_ACCESS_FLAG_MASK;
+ pteval |= entry & (RISCV_PTE_ACCESS_FLAG_MASK & ~preserved_flags);
+ pteval |= (cur | entry) & preserved_flags;
+
+ return pteval;
+}
+
int ptep_set_access_flags(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep,
pte_t entry, int dirty)
{
+ unsigned long old_pteval;
+ unsigned long new_pteval;
+ unsigned long prev_pteval;
+ bool changed;
+
+ old_pteval = pte_val(ptep_get(ptep));
+ do {
+ new_pteval = riscv_pte_access_flags(old_pteval, pte_val(entry));
+ if (new_pteval == old_pteval)
+ break;
+
+ prev_pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval,
+ new_pteval);
+ if (prev_pteval == old_pteval)
+ break;
+
+ old_pteval = prev_pteval;
+ } while (1);
+
+ changed = old_pteval != new_pteval;
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SVVPTC)) {
- if (!pte_same(ptep_get(ptep), entry)) {
- __set_pte_at(vma->vm_mm, ptep, entry);
- /* Here only not svadu is impacted */
+ if (changed)
flush_tlb_page(vma, address);
- return true;
- }
- return false;
+ return changed;
}
- if (!pte_same(ptep_get(ptep), entry))
- __set_pte_at(vma->vm_mm, ptep, entry);
/*
* update_mmu_cache will unconditionally execute, handling both
* the case that the PTE changed and the spurious fault case.
@@ -32,9 +64,23 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
bool ptep_test_and_clear_young(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep)
{
- if (!pte_young(ptep_get(ptep)))
- return false;
- return test_and_clear_bit(_PAGE_ACCESSED_OFFSET, &pte_val(*ptep));
+ unsigned long old_pteval;
+ unsigned long new_pteval;
+ unsigned long prev_pteval;
+
+ old_pteval = pte_val(ptep_get(ptep));
+ do {
+ if (!(old_pteval & _PAGE_ACCESSED))
+ return false;
+
+ new_pteval = pte_val(pte_mkold(__pte(old_pteval)));
+ prev_pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval,
+ new_pteval);
+ if (prev_pteval == old_pteval)
+ return true;
+
+ old_pteval = prev_pteval;
+ } while (1);
}
EXPORT_SYMBOL_GPL(ptep_test_and_clear_young);
--
2.39.5
^ permalink raw reply related [flat|nested] 7+ messages in thread