]> www.infradead.org Git - users/hch/misc.git/commitdiff
KVM: arm64: selftests: Explicitly set the page attrs to Inner-Shareable
authorRaghavendra Rao Ananta <rananta@google.com>
Sat, 5 Apr 2025 00:10:42 +0000 (00:10 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Sun, 6 Apr 2025 18:13:50 +0000 (11:13 -0700)
Atomic instructions such as 'ldset' in the guest have been observed to
cause an EL1 data abort with FSC 0x35 (IMPLEMENTATION DEFINED fault
(Unsupported Exclusive or Atomic access)) on Neoverse-N3.

Per DDI0487L.a B2.2.6, atomic instructions are only architecturally
guaranteed for Inner/Outer Shareable Normal Write-Back memory. For
anything else the behavior is IMPLEMENTATION DEFINED and can lose
atomicity, or, in this case, generate an abort.

It would appear that selftests sets up the stage-1 mappings as Non
Shareable, leading to the observed abort. Explicitly set the
Shareability field to Inner Shareable for non-LPA2 page tables. Note
that for the LPA2 page table format, translations for cacheable memory
inherit the shareability attribute of the PTW, i.e. TCR_ELx.SH{0,1}.

Suggested-by: Oliver Upton <oupton@google.com>
Signed-off-by: Raghavendra Rao Ananta <rananta@google.com>
Link: https://lore.kernel.org/r/20250405001042.1470552-3-rananta@google.com
[oliver: Rephrase changelog]
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
tools/testing/selftests/kvm/include/arm64/processor.h
tools/testing/selftests/kvm/lib/arm64/processor.c

index 7d88ff22013ab437efc97700efab41c21ba6e7c3..b0fc0f945766fe82db70bbab693990c0609282f9 100644 (file)
 #define PMD_TYPE_TABLE         BIT(1)
 #define PTE_TYPE_PAGE          BIT(1)
 
+#define PTE_SHARED             (UL(3) << 8) /* SH[1:0], inner shareable */
 #define PTE_AF                 BIT(10)
 
 #define PTE_ADDR_MASK(page_shift)      GENMASK(47, (page_shift))
index da5802c8a59c1f161e87a46a1e429167356c86a1..9d69904cb6084a8bbb2fa16546fad3846fd21f86 100644 (file)
@@ -172,6 +172,9 @@ static void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
        }
 
        pg_attr = PTE_AF | PTE_ATTRINDX(attr_idx) | PTE_TYPE_PAGE | PTE_VALID;
+       if (!use_lpa2_pte_format(vm))
+               pg_attr |= PTE_SHARED;
+
        *ptep = addr_pte(vm, paddr, pg_attr);
 }