All of lore.kernel.org
 help / color / mirror / Atom feed
From: Oleksii Kurochko <oleksii.kurochko@gmail.com>
To: Baptiste Le Duc <baptiste.le-duc@vates.tech>,
	xen-devel@lists.xenproject.org
Cc: zhangzheng@iscas.ac.cn,
	"Alistair Francis" <alistair.francis@wdc.com>,
	"Connor Davis" <connojdavis@gmail.com>,
	"Andrew Cooper" <andrew.cooper3@citrix.com>,
	"Anthony PERARD" <anthony.perard@vates.tech>,
	"Michal Orzel" <michal.orzel@amd.com>,
	"Jan Beulich" <jbeulich@suse.com>,
	"Julien Grall" <julien@xen.org>,
	"Roger Pau Monné" <roger@xenproject.org>,
	"Stefano Stabellini" <sstabellini@kernel.org>
Subject: Re: [PATCH 2/5] xen/riscv: preset A/D bits in Xen's own page-table mappings
Date: Fri, 28 Aug 2026 15:34:46 +0200	[thread overview]
Message-ID: <ec69b941-2648-4c3f-bbee-95d4d56fb543@gmail.com> (raw)
In-Reply-To: <1787844809.8631fc262581453bbf619ec5b2062170.1a043dad225000c4f3@vates.tech>



On 8/27/26 5:33 PM, Baptiste Le Duc wrote:
> The previous patch made p2m_set_permission() always set the PTE A/D bits to
> map pages in G-stage, to avoid a page fault on platforms that implement
> neither Svade nor Svadu, or that declare both in the device tree. Xen's own
> page tables, built by setup_initial_mapping(), never go through
> p2m_set_permission() and need the same fix.
> 
> Add PTE_ACCESSED to PTE_LEAF_DEFAULT and make it the minimal common leaf
> permission set by dropping PTE_WRITABLE. Rebuild PAGE_HYPERVISOR_RO,
> PAGE_HYPERVISOR_RW and PAGE_HYPERVISOR_RX from that common base, with
> PAGE_HYPERVISOR_RW also adding PTE_DIRTY. Switch setup_initial_mapping() to
> use these macros for its default, text, and rodata permissions instead of
> the equivalent raw bit lists.
> 
> A PTE is a table entry iff PTE_VALID is set and R/W/X are all clear, so
> update pte_is_table() accordingly.
> 
> Assisted-by: Claude:claude-opus-5
> Signed-off-by: Baptiste Le Duc <baptiste.le-duc@vates.tech>
> ---
>   xen/arch/riscv/include/asm/page.h | 14 ++++++++------
>   xen/arch/riscv/mm.c               |  7 +++----
>   2 files changed, 11 insertions(+), 10 deletions(-)
> 
> diff --git a/xen/arch/riscv/include/asm/page.h b/xen/arch/riscv/include/asm/page.h
> index b465a90325..5c02f64a17 100644
> --- a/xen/arch/riscv/include/asm/page.h
> +++ b/xen/arch/riscv/include/asm/page.h
> @@ -46,12 +46,12 @@
>   #define PTE_PBMT_NOCACHE            BIT(61, UL)
>   #define PTE_PBMT_IO                 BIT(62, UL)
>   
> -#define PTE_LEAF_DEFAULT            (PTE_VALID | PTE_READABLE | PTE_WRITABLE)
> +#define PTE_LEAF_DEFAULT            (PTE_VALID | PTE_READABLE | PTE_ACCESSED)

Dropping PTE_WRITABLE here silently changes the permissions of an 
existing user of this macro that the patch doesn't touch.

check_pgtbl_mode_support() in mm.c still builds its temporary root entry as:
  index = pt_index(page_table_level, aligned_load_start);
  stage1_pgtbl_root[index] = paddr_to_pte(aligned_load_start,
                                      PTE_LEAF_DEFAULT | PTE_EXECUTABLE);

Before this patch that evaluated to V|R|W|X (RWX); afterwards it is 
V|R|A|X (RX). So the mapping loses write permission.

I believe that is harmless in practice: the entry is only alive between 
the csr_write(CSR_SATP, ...) that turns the MMU on and the 
csr_write(CSR_SATP, 0) a few lines below, it only has to make the 
current instruction stream fetchable so that the SATP mode probe can 
complete, and nothing writes through it. Arguably RX is the better 
permission set for it anyway. But it is still a behavioural change 
rather than a cosmetic one, and the commit message doesn't mention it(it 
only talks about setup_initial_mapping()).
Please call it out explicitly there.

While at it, this site should be converted too:

     stage1_pgtbl_root[index] = paddr_to_pte(aligned_load_start,
                                             PAGE_HYPERVISOR_RX);

Otherwise the patch converts three sites in setup_initial_mapping() to 
the new PAGE_HYPERVISOR_* macros while leaving a fourth one open-coding 
the redefined PTE_LEAF_DEFAULT, which is exactly the kind of asymmetry 
that makes the redefinition easy to miss on the next change.

After that conversion PTE_LEAF_DEFAULT has no users left
outside page.h itself, so it could either be dropped entirely in favour 
of PAGE_HYPERVISOR_{RO,RW,RX}, or renamed to something that reflects its 
new meaning (PTE_LEAF_COMMON or similar). "DEFAULT" now names a set that 
is not a usable permission on its own, which is misleading.

>   #define PTE_TABLE                   (PTE_VALID)
>   
> -#define PAGE_HYPERVISOR_RO          (PTE_VALID | PTE_READABLE)
> -#define PAGE_HYPERVISOR_RW          (PTE_VALID | PTE_READABLE | PTE_WRITABLE)
> -#define PAGE_HYPERVISOR_RX          (PTE_VALID | PTE_READABLE | PTE_EXECUTABLE)
> +#define PAGE_HYPERVISOR_RO          (PTE_LEAF_DEFAULT)
> +#define PAGE_HYPERVISOR_RW          (PTE_LEAF_DEFAULT | PTE_WRITABLE | PTE_DIRTY)
> +#define PAGE_HYPERVISOR_RX          (PTE_LEAF_DEFAULT | PTE_EXECUTABLE)

Adding A/D to PAGE_HYPERVISOR_RW fixes a second site beyond the ones the
commit message mentions, and I think it deserves to be spelled out.

arch_pmap_map() in asm/pmap.h writes the fixmap leaf entry directly:
     pte = pte_from_mfn(mfn, PAGE_HYPERVISOR_RW);
     write_pte(entry, pte);
i.e. it bypasses pt_update_entry(), which is the place that ORs in
PTE_ACCESSED | PTE_DIRTY for everything going through map_pages_to_xen().
So before this patch every pmap mapping was installed with A=D=0 and 
would fault on first access under Svade, in exactly the same way the 
boot page tables did.

The commit message currently frames the problem as "Xen's own page 
tables, built by setup_initial_mapping()", which undersells the fix. 
Please extend it to say that arch_pmap_map() is affected as well, and 
that it is fixed by the PAGE_HYPERVISOR_RW change rather than by the 
mm.c conversion.

FWIW I checked the remaining leaf-PTE construction sites (paddr_to_pte() 
/pte_from_mfn() callers) and with these two the series covers all of 
them: everything else either builds table entries (PTE_TABLE) or goes 
through pt_update_entry() / p2m_set_permission(), both of which set A/D 
themselves.

>   
>   #define PAGE_HYPERVISOR             PAGE_HYPERVISOR_RW
>   /*
> @@ -177,7 +177,8 @@ static inline bool pte_is_table(pte_t p)
>        *
>        * PAGE_HYPERVISOR_RW contains PTE_VALID too.
>        */
> -    ASSERT(((p.pte & PAGE_HYPERVISOR_RW) != (PTE_VALID | PTE_WRITABLE)));
> +    ASSERT((p.pte & (PTE_VALID | PTE_READABLE | PTE_WRITABLE)) !=
> +           (PTE_VALID | PTE_WRITABLE));

Please drop the last line of the comment above it:

      * PAGE_HYPERVISOR_RW contains PTE_VALID too.

That sentence existed only to explain why the old mask was written as
PAGE_HYPERVISOR_RW, i.e. that the macro is not just R|W but carries
PTE_VALID as well, which is what made the comparison against V|W work.
With the mask now written out literally, the macro is no longer 
referenced anywhere in the function, so the line dangles. It is also 
inaccurate now, since PAGE_HYPERVISOR_RW carries A and D in addition to V.

~ Oleksii


  reply	other threads:[~2026-08-28 13:35 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-27 15:27 [PATCH 0/5] xen/riscv: fix boot on missing extensions and MMU setup bugs Baptiste Le Duc
2026-08-27 15:33 ` [PATCH 1/5] xen/riscv: always set A/D bits at boot time Baptiste Le Duc
2026-08-28 10:59   ` Oleksii Kurochko
2026-08-28 13:58     ` Baptiste Le Duc
2026-08-28 16:12       ` Oleksii Kurochko
2026-08-27 15:33 ` [PATCH 2/5] xen/riscv: preset A/D bits in Xen's own page-table mappings Baptiste Le Duc
2026-08-28 13:34   ` Oleksii Kurochko [this message]
2026-08-27 15:33 ` [PATCH 3/5] xen/riscv: make Svpbmt no longer a required extension Baptiste Le Duc
2026-08-28 15:58   ` Oleksii Kurochko
2026-08-27 15:33 ` [PATCH 4/5] xen/riscv: make Zihintpause " Baptiste Le Duc
2026-08-28  8:59   ` Oleksii Kurochko
2026-08-28  9:16     ` Baptiste Le Duc
2026-08-27 15:33 ` [PATCH 5/5] xen/riscv: add SFENCE.VMA after enabling paging Baptiste Le Duc
2026-08-27 16:53   ` Oleksii Kurochko
2026-08-27 16:58     ` Oleksii Kurochko
2026-08-28  7:13     ` Jan Beulich
2026-08-28  8:03       ` Oleksii Kurochko
2026-08-28  8:11     ` Oleksii Kurochko
2026-08-28  8:29       ` Baptiste Le Duc

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ec69b941-2648-4c3f-bbee-95d4d56fb543@gmail.com \
    --to=oleksii.kurochko@gmail.com \
    --cc=alistair.francis@wdc.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=anthony.perard@vates.tech \
    --cc=baptiste.le-duc@vates.tech \
    --cc=connojdavis@gmail.com \
    --cc=jbeulich@suse.com \
    --cc=julien@xen.org \
    --cc=michal.orzel@amd.com \
    --cc=roger@xenproject.org \
    --cc=sstabellini@kernel.org \
    --cc=xen-devel@lists.xenproject.org \
    --cc=zhangzheng@iscas.ac.cn \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.