mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Merge branch 'kvm-arm64/nv-xnx-haf' into kvmarm/next
* kvm-arm64/nv-xnx-haf: (22 commits)
: Support for FEAT_XNX and FEAT_HAF in nested
:
: Add support for a couple of MMU-related features that weren't
: implemented by KVM's software page table walk:
:
: - FEAT_XNX: Allows the hypervisor to describe execute permissions
: separately for EL0 and EL1
:
: - FEAT_HAF: Hardware update of the Access Flag, which in the context of
: nested means software walkers must also set the Access Flag.
:
: The series also adds some basic support for testing KVM's emulation of
: the AT instruction, including the implementation detail that AT sets the
: Access Flag in KVM.
KVM: arm64: at: Update AF on software walk only if VM has FEAT_HAFDBS
KVM: arm64: at: Use correct HA bit in TCR_EL2 when regime is EL2
KVM: arm64: Document KVM_PGTABLE_PROT_{UX,PX}
KVM: arm64: Fix spelling mistake "Unexpeced" -> "Unexpected"
KVM: arm64: Add break to default case in kvm_pgtable_stage2_pte_prot()
KVM: arm64: Add endian casting to kvm_swap_s[12]_desc()
KVM: arm64: Fix compilation when CONFIG_ARM64_USE_LSE_ATOMICS=n
KVM: arm64: selftests: Add test for AT emulation
KVM: arm64: nv: Expose hardware access flag management to NV guests
KVM: arm64: nv: Implement HW access flag management in stage-2 SW PTW
KVM: arm64: Implement HW access flag management in stage-1 SW PTW
KVM: arm64: Propagate PTW errors up to AT emulation
KVM: arm64: Add helper for swapping guest descriptor
KVM: arm64: nv: Use pgtable definitions in stage-2 walk
KVM: arm64: Handle endianness in read helper for emulated PTW
KVM: arm64: nv: Stop passing vCPU through void ptr in S2 PTW
KVM: arm64: Call helper for reading descriptors directly
KVM: arm64: nv: Advertise support for FEAT_XNX
KVM: arm64: Teach ptdump about FEAT_XNX permissions
KVM: arm64: nv: Forward FEAT_XNX permissions to the shadow stage-2
...
Signed-off-by: Oliver Upton <oupton@kernel.org>
This commit is contained in:
@@ -661,11 +661,37 @@ void kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu,
|
||||
|
||||
#define KVM_S2_MEMATTR(pgt, attr) PAGE_S2_MEMATTR(attr, stage2_has_fwb(pgt))
|
||||
|
||||
static int stage2_set_xn_attr(enum kvm_pgtable_prot prot, kvm_pte_t *attr)
|
||||
{
|
||||
bool px, ux;
|
||||
u8 xn;
|
||||
|
||||
px = prot & KVM_PGTABLE_PROT_PX;
|
||||
ux = prot & KVM_PGTABLE_PROT_UX;
|
||||
|
||||
if (!cpus_have_final_cap(ARM64_HAS_XNX) && px != ux)
|
||||
return -EINVAL;
|
||||
|
||||
if (px && ux)
|
||||
xn = 0b00;
|
||||
else if (!px && ux)
|
||||
xn = 0b01;
|
||||
else if (!px && !ux)
|
||||
xn = 0b10;
|
||||
else
|
||||
xn = 0b11;
|
||||
|
||||
*attr &= ~KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
*attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_HI_S2_XN, xn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot prot,
|
||||
kvm_pte_t *ptep)
|
||||
{
|
||||
kvm_pte_t attr;
|
||||
u32 sh = KVM_PTE_LEAF_ATTR_LO_S2_SH_IS;
|
||||
int r;
|
||||
|
||||
switch (prot & (KVM_PGTABLE_PROT_DEVICE |
|
||||
KVM_PGTABLE_PROT_NORMAL_NC)) {
|
||||
@@ -685,8 +711,9 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
|
||||
attr = KVM_S2_MEMATTR(pgt, NORMAL);
|
||||
}
|
||||
|
||||
if (!(prot & KVM_PGTABLE_PROT_X))
|
||||
attr |= KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
r = stage2_set_xn_attr(prot, &attr);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (prot & KVM_PGTABLE_PROT_R)
|
||||
attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R;
|
||||
@@ -715,8 +742,20 @@ enum kvm_pgtable_prot kvm_pgtable_stage2_pte_prot(kvm_pte_t pte)
|
||||
prot |= KVM_PGTABLE_PROT_R;
|
||||
if (pte & KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W)
|
||||
prot |= KVM_PGTABLE_PROT_W;
|
||||
if (!(pte & KVM_PTE_LEAF_ATTR_HI_S2_XN))
|
||||
prot |= KVM_PGTABLE_PROT_X;
|
||||
|
||||
switch (FIELD_GET(KVM_PTE_LEAF_ATTR_HI_S2_XN, pte)) {
|
||||
case 0b00:
|
||||
prot |= KVM_PGTABLE_PROT_PX | KVM_PGTABLE_PROT_UX;
|
||||
break;
|
||||
case 0b01:
|
||||
prot |= KVM_PGTABLE_PROT_UX;
|
||||
break;
|
||||
case 0b11:
|
||||
prot |= KVM_PGTABLE_PROT_PX;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return prot;
|
||||
}
|
||||
@@ -1290,9 +1329,9 @@ bool kvm_pgtable_stage2_test_clear_young(struct kvm_pgtable *pgt, u64 addr,
|
||||
int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
|
||||
enum kvm_pgtable_prot prot, enum kvm_pgtable_walk_flags flags)
|
||||
{
|
||||
int ret;
|
||||
kvm_pte_t xn = 0, set = 0, clr = 0;
|
||||
s8 level;
|
||||
kvm_pte_t set = 0, clr = 0;
|
||||
int ret;
|
||||
|
||||
if (prot & KVM_PTE_LEAF_ATTR_HI_SW)
|
||||
return -EINVAL;
|
||||
@@ -1303,8 +1342,12 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
|
||||
if (prot & KVM_PGTABLE_PROT_W)
|
||||
set |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
|
||||
|
||||
if (prot & KVM_PGTABLE_PROT_X)
|
||||
clr |= KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
ret = stage2_set_xn_attr(prot, &xn);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
set |= xn & KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
clr |= ~xn & KVM_PTE_LEAF_ATTR_HI_S2_XN;
|
||||
|
||||
ret = stage2_update_leaf_attrs(pgt, addr, 1, set, clr, NULL, &level, flags);
|
||||
if (!ret || ret == -EAGAIN)
|
||||
|
||||
Reference in New Issue
Block a user