Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: arm64: Use CAST instruction for swapping guest descriptor

Use the CAST instruction to swap the guest descriptor when FEAT_LSUI
is enabled, avoiding the need to clear the PAN bit.

FEAT_LSUI is introduced in Armv9.6, where FEAT_PAN is mandatory. However,
this assumption may not always hold:

- Some CPUs may advertise FEAT_LSUI but lack FEAT_PAN.
- Virtualization or ID register overrides may expose invalid feature
combinations.

Therefore, instead of disabling FEAT_LSUI when FEAT_PAN is absent, wrap
LSUI instructions with uaccess_ttbr0_enable()/disable() when
ARM64_SW_TTBR0_PAN is enabled.

Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Yeoreum Yun and committed by
Catalin Marinas
16dbe77a 44adf2bf

+33 -1
+33 -1
arch/arm64/kvm/at.c
··· 9 9 #include <asm/esr.h> 10 10 #include <asm/kvm_hyp.h> 11 11 #include <asm/kvm_mmu.h> 12 + #include <asm/lsui.h> 12 13 13 14 static void fail_s1_walk(struct s1_walk_result *wr, u8 fst, bool s1ptw) 14 15 { ··· 1682 1681 } 1683 1682 } 1684 1683 1684 + static int __lsui_swap_desc(u64 __user *ptep, u64 old, u64 new) 1685 + { 1686 + u64 tmp = old; 1687 + int ret = 0; 1688 + 1689 + /* 1690 + * Wrap LSUI instructions with uaccess_ttbr0_enable()/disable(), 1691 + * as PAN toggling is not required. 1692 + */ 1693 + uaccess_ttbr0_enable(); 1694 + 1695 + asm volatile(__LSUI_PREAMBLE 1696 + "1: cast %[old], %[new], %[addr]\n" 1697 + "2:\n" 1698 + _ASM_EXTABLE_UACCESS_ERR(1b, 2b, %w[ret]) 1699 + : [old] "+r" (old), [addr] "+Q" (*ptep), [ret] "+r" (ret) 1700 + : [new] "r" (new) 1701 + : "memory"); 1702 + 1703 + uaccess_ttbr0_disable(); 1704 + 1705 + if (ret) 1706 + return ret; 1707 + if (tmp != old) 1708 + return -EAGAIN; 1709 + 1710 + return ret; 1711 + } 1712 + 1685 1713 static int __lse_swap_desc(u64 __user *ptep, u64 old, u64 new) 1686 1714 { 1687 1715 u64 tmp = old; ··· 1786 1756 return -EPERM; 1787 1757 1788 1758 ptep = (u64 __user *)hva + offset; 1789 - if (cpus_have_final_cap(ARM64_HAS_LSE_ATOMICS)) 1759 + if (cpus_have_final_cap(ARM64_HAS_LSUI)) 1760 + r = __lsui_swap_desc(ptep, old, new); 1761 + else if (cpus_have_final_cap(ARM64_HAS_LSE_ATOMICS)) 1790 1762 r = __lse_swap_desc(ptep, old, new); 1791 1763 else 1792 1764 r = __llsc_swap_desc(ptep, old, new);