FROMLIST: KVM: arm64: Refactor kvm_arm_setup_stage2()
In order to re-use some of the stage 2 setup code at EL2, factor parts of kvm_arm_setup_stage2() out into separate functions. No functional change intended. Acked-by: Will Deacon <will@kernel.org> Signed-off-by: Quentin Perret <qperret@google.com> Link: https://lore.kernel.org/r/20210315143536.214621-23-qperret@google.com Bug: 178098380 Change-Id: I928220a66638c57f7aacb8b62b59163e297f6614
This commit is contained in:
@@ -13,6 +13,16 @@
|
|||||||
|
|
||||||
#define KVM_PGTABLE_MAX_LEVELS 4U
|
#define KVM_PGTABLE_MAX_LEVELS 4U
|
||||||
|
|
||||||
|
static inline u64 kvm_get_parange(u64 mmfr0)
|
||||||
|
{
|
||||||
|
u64 parange = cpuid_feature_extract_unsigned_field(mmfr0,
|
||||||
|
ID_AA64MMFR0_PARANGE_SHIFT);
|
||||||
|
if (parange > ID_AA64MMFR0_PARANGE_MAX)
|
||||||
|
parange = ID_AA64MMFR0_PARANGE_MAX;
|
||||||
|
|
||||||
|
return parange;
|
||||||
|
}
|
||||||
|
|
||||||
typedef u64 kvm_pte_t;
|
typedef u64 kvm_pte_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -159,6 +169,22 @@ void kvm_pgtable_hyp_destroy(struct kvm_pgtable *pgt);
|
|||||||
int kvm_pgtable_hyp_map(struct kvm_pgtable *pgt, u64 addr, u64 size, u64 phys,
|
int kvm_pgtable_hyp_map(struct kvm_pgtable *pgt, u64 addr, u64 size, u64 phys,
|
||||||
enum kvm_pgtable_prot prot);
|
enum kvm_pgtable_prot prot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* kvm_get_vtcr() - Helper to construct VTCR_EL2
|
||||||
|
* @mmfr0: Sanitized value of SYS_ID_AA64MMFR0_EL1 register.
|
||||||
|
* @mmfr1: Sanitized value of SYS_ID_AA64MMFR1_EL1 register.
|
||||||
|
* @phys_shfit: Value to set in VTCR_EL2.T0SZ.
|
||||||
|
*
|
||||||
|
* The VTCR value is common across all the physical CPUs on the system.
|
||||||
|
* We use system wide sanitised values to fill in different fields,
|
||||||
|
* except for Hardware Management of Access Flags. HA Flag is set
|
||||||
|
* unconditionally on all CPUs, as it is safe to run with or without
|
||||||
|
* the feature and the bit is RES0 on CPUs that don't support it.
|
||||||
|
*
|
||||||
|
* Return: VTCR_EL2 value
|
||||||
|
*/
|
||||||
|
u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kvm_pgtable_stage2_init() - Initialise a guest stage-2 page-table.
|
* kvm_pgtable_stage2_init() - Initialise a guest stage-2 page-table.
|
||||||
* @pgt: Uninitialised page-table structure to initialise.
|
* @pgt: Uninitialised page-table structure to initialise.
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <linux/bitfield.h>
|
#include <linux/bitfield.h>
|
||||||
#include <asm/kvm_pgtable.h>
|
#include <asm/kvm_pgtable.h>
|
||||||
|
#include <asm/stage2_pgtable.h>
|
||||||
|
|
||||||
#define KVM_PTE_VALID BIT(0)
|
#define KVM_PTE_VALID BIT(0)
|
||||||
|
|
||||||
@@ -450,6 +451,37 @@ struct stage2_map_data {
|
|||||||
struct kvm_pgtable_mm_ops *mm_ops;
|
struct kvm_pgtable_mm_ops *mm_ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
|
||||||
|
{
|
||||||
|
u64 vtcr = VTCR_EL2_FLAGS;
|
||||||
|
u8 lvls;
|
||||||
|
|
||||||
|
vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT;
|
||||||
|
vtcr |= VTCR_EL2_T0SZ(phys_shift);
|
||||||
|
/*
|
||||||
|
* Use a minimum 2 level page table to prevent splitting
|
||||||
|
* host PMD huge pages at stage2.
|
||||||
|
*/
|
||||||
|
lvls = stage2_pgtable_levels(phys_shift);
|
||||||
|
if (lvls < 2)
|
||||||
|
lvls = 2;
|
||||||
|
vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable the Hardware Access Flag management, unconditionally
|
||||||
|
* on all CPUs. The features is RES0 on CPUs without the support
|
||||||
|
* and must be ignored by the CPUs.
|
||||||
|
*/
|
||||||
|
vtcr |= VTCR_EL2_HA;
|
||||||
|
|
||||||
|
/* Set the vmid bits */
|
||||||
|
vtcr |= (get_vmid_bits(mmfr1) == 16) ?
|
||||||
|
VTCR_EL2_VS_16BIT :
|
||||||
|
VTCR_EL2_VS_8BIT;
|
||||||
|
|
||||||
|
return vtcr;
|
||||||
|
}
|
||||||
|
|
||||||
static int stage2_map_set_prot_attr(enum kvm_pgtable_prot prot,
|
static int stage2_map_set_prot_attr(enum kvm_pgtable_prot prot,
|
||||||
struct stage2_map_data *data)
|
struct stage2_map_data *data)
|
||||||
{
|
{
|
||||||
|
@@ -331,19 +331,10 @@ int kvm_set_ipa_limit(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Configure the VTCR_EL2 for this VM. The VTCR value is common
|
|
||||||
* across all the physical CPUs on the system. We use system wide
|
|
||||||
* sanitised values to fill in different fields, except for Hardware
|
|
||||||
* Management of Access Flags. HA Flag is set unconditionally on
|
|
||||||
* all CPUs, as it is safe to run with or without the feature and
|
|
||||||
* the bit is RES0 on CPUs that don't support it.
|
|
||||||
*/
|
|
||||||
int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
|
int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
|
||||||
{
|
{
|
||||||
u64 vtcr = VTCR_EL2_FLAGS, mmfr0;
|
u64 mmfr0, mmfr1;
|
||||||
u32 parange, phys_shift;
|
u32 phys_shift;
|
||||||
u8 lvls;
|
|
||||||
|
|
||||||
if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
|
if (type & ~KVM_VM_TYPE_ARM_IPA_SIZE_MASK)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -363,33 +354,8 @@ int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
|
mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
|
||||||
parange = cpuid_feature_extract_unsigned_field(mmfr0,
|
mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
|
||||||
ID_AA64MMFR0_PARANGE_SHIFT);
|
kvm->arch.vtcr = kvm_get_vtcr(mmfr0, mmfr1, phys_shift);
|
||||||
if (parange > ID_AA64MMFR0_PARANGE_MAX)
|
|
||||||
parange = ID_AA64MMFR0_PARANGE_MAX;
|
|
||||||
vtcr |= parange << VTCR_EL2_PS_SHIFT;
|
|
||||||
|
|
||||||
vtcr |= VTCR_EL2_T0SZ(phys_shift);
|
|
||||||
/*
|
|
||||||
* Use a minimum 2 level page table to prevent splitting
|
|
||||||
* host PMD huge pages at stage2.
|
|
||||||
*/
|
|
||||||
lvls = stage2_pgtable_levels(phys_shift);
|
|
||||||
if (lvls < 2)
|
|
||||||
lvls = 2;
|
|
||||||
vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Enable the Hardware Access Flag management, unconditionally
|
|
||||||
* on all CPUs. The features is RES0 on CPUs without the support
|
|
||||||
* and must be ignored by the CPUs.
|
|
||||||
*/
|
|
||||||
vtcr |= VTCR_EL2_HA;
|
|
||||||
|
|
||||||
/* Set the vmid bits */
|
|
||||||
vtcr |= (kvm_get_vmid_bits() == 16) ?
|
|
||||||
VTCR_EL2_VS_16BIT :
|
|
||||||
VTCR_EL2_VS_8BIT;
|
|
||||||
kvm->arch.vtcr = vtcr;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user