Merge branch kvm-arm64/misc-6.10 into kvmarm-master/next
* kvm-arm64/misc-6.10: : . : Misc fixes and updates targeting 6.10 : : - Improve boot-time diagnostics when the sysreg tables : are not correctly sorted : : - Allow FFA_MSG_SEND_DIRECT_REQ in the FFA proxy : : - Fix duplicate XNX field in the ID_AA64MMFR1_EL1 : writeable mask : : - Allocate PPIs and SGIs outside of the vcpu structure, allowing : for smaller EL2 mapping and some flexibility in implementing : more or less than 32 private IRQs. : : - Use bitmap_gather() instead of its open-coded equivalent : : - Make protected mode use hVHE if available : : - Purge stale mpidr_data if a vcpu is created after the MPIDR : map has been created : . KVM: arm64: Destroy mpidr_data for 'late' vCPU creation KVM: arm64: Use hVHE in pKVM by default on CPUs with VHE support KVM: arm64: Fix hvhe/nvhe early alias parsing KVM: arm64: Convert kvm_mpidr_index() to bitmap_gather() KVM: arm64: vgic: Allocate private interrupts on demand KVM: arm64: Remove duplicated AA64MMFR1_EL1 XNX KVM: arm64: Remove FFA_MSG_SEND_DIRECT_REQ from the denylist KVM: arm64: Improve out-of-order sysreg table diagnostics Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
commit
e28157060c
|
@ -221,20 +221,10 @@ struct kvm_mpidr_data {
|
|||
|
||||
static inline u16 kvm_mpidr_index(struct kvm_mpidr_data *data, u64 mpidr)
|
||||
{
|
||||
unsigned long mask = data->mpidr_mask;
|
||||
u64 aff = mpidr & MPIDR_HWID_BITMASK;
|
||||
int nbits, bit, bit_idx = 0;
|
||||
u16 index = 0;
|
||||
unsigned long index = 0, mask = data->mpidr_mask;
|
||||
unsigned long aff = mpidr & MPIDR_HWID_BITMASK;
|
||||
|
||||
/*
|
||||
* If this looks like RISC-V's BEXT or x86's PEXT
|
||||
* instructions, it isn't by accident.
|
||||
*/
|
||||
nbits = fls(mask);
|
||||
for_each_set_bit(bit, &mask, nbits) {
|
||||
index |= (aff & BIT(bit)) >> (bit - bit_idx);
|
||||
bit_idx++;
|
||||
}
|
||||
bitmap_gather(&index, &aff, &mask, fls(mask));
|
||||
|
||||
return index;
|
||||
}
|
||||
|
|
|
@ -209,8 +209,8 @@ static const struct {
|
|||
char alias[FTR_ALIAS_NAME_LEN];
|
||||
char feature[FTR_ALIAS_OPTION_LEN];
|
||||
} aliases[] __initconst = {
|
||||
{ "kvm_arm.mode=nvhe", "id_aa64mmfr1.vh=0" },
|
||||
{ "kvm_arm.mode=protected", "id_aa64mmfr1.vh=0" },
|
||||
{ "kvm_arm.mode=nvhe", "arm64_sw.hvhe=0 id_aa64mmfr1.vh=0" },
|
||||
{ "kvm_arm.mode=protected", "arm64_sw.hvhe=1" },
|
||||
{ "arm64.nosve", "id_aa64pfr0.sve=0" },
|
||||
{ "arm64.nosme", "id_aa64pfr1.sme=0" },
|
||||
{ "arm64.nobti", "id_aa64pfr1.bt=0" },
|
||||
|
|
|
@ -218,6 +218,23 @@ void kvm_arch_create_vm_debugfs(struct kvm *kvm)
|
|||
kvm_sys_regs_create_debugfs(kvm);
|
||||
}
|
||||
|
||||
static void kvm_destroy_mpidr_data(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_mpidr_data *data;
|
||||
|
||||
mutex_lock(&kvm->arch.config_lock);
|
||||
|
||||
data = rcu_dereference_protected(kvm->arch.mpidr_data,
|
||||
lockdep_is_held(&kvm->arch.config_lock));
|
||||
if (data) {
|
||||
rcu_assign_pointer(kvm->arch.mpidr_data, NULL);
|
||||
synchronize_rcu();
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
mutex_unlock(&kvm->arch.config_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_arch_destroy_vm - destroy the VM data structure
|
||||
* @kvm: pointer to the KVM struct
|
||||
|
@ -232,7 +249,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
|
|||
if (is_protected_kvm_enabled())
|
||||
pkvm_destroy_hyp_vm(kvm);
|
||||
|
||||
kfree(kvm->arch.mpidr_data);
|
||||
kvm_destroy_mpidr_data(kvm);
|
||||
|
||||
kfree(kvm->arch.sysreg_masks);
|
||||
kvm_destroy_vcpus(kvm);
|
||||
|
||||
|
@ -450,6 +468,13 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
|
|||
|
||||
vcpu->arch.hw_mmu = &vcpu->kvm->arch.mmu;
|
||||
|
||||
/*
|
||||
* This vCPU may have been created after mpidr_data was initialized.
|
||||
* Throw out the pre-computed mappings if that is the case which forces
|
||||
* KVM to fall back to iteratively searching the vCPUs.
|
||||
*/
|
||||
kvm_destroy_mpidr_data(vcpu->kvm);
|
||||
|
||||
err = kvm_vgic_vcpu_init(vcpu);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -687,7 +712,8 @@ static void kvm_init_mpidr_data(struct kvm *kvm)
|
|||
|
||||
mutex_lock(&kvm->arch.config_lock);
|
||||
|
||||
if (kvm->arch.mpidr_data || atomic_read(&kvm->online_vcpus) == 1)
|
||||
if (rcu_access_pointer(kvm->arch.mpidr_data) ||
|
||||
atomic_read(&kvm->online_vcpus) == 1)
|
||||
goto out;
|
||||
|
||||
kvm_for_each_vcpu(c, vcpu, kvm) {
|
||||
|
@ -724,7 +750,7 @@ static void kvm_init_mpidr_data(struct kvm *kvm)
|
|||
data->cmpidr_to_idx[index] = c;
|
||||
}
|
||||
|
||||
kvm->arch.mpidr_data = data;
|
||||
rcu_assign_pointer(kvm->arch.mpidr_data, data);
|
||||
out:
|
||||
mutex_unlock(&kvm->arch.config_lock);
|
||||
}
|
||||
|
@ -2562,22 +2588,28 @@ out_err:
|
|||
|
||||
struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct kvm_vcpu *vcpu = NULL;
|
||||
struct kvm_mpidr_data *data;
|
||||
unsigned long i;
|
||||
|
||||
mpidr &= MPIDR_HWID_BITMASK;
|
||||
|
||||
if (kvm->arch.mpidr_data) {
|
||||
u16 idx = kvm_mpidr_index(kvm->arch.mpidr_data, mpidr);
|
||||
rcu_read_lock();
|
||||
data = rcu_dereference(kvm->arch.mpidr_data);
|
||||
|
||||
vcpu = kvm_get_vcpu(kvm,
|
||||
kvm->arch.mpidr_data->cmpidr_to_idx[idx]);
|
||||
if (data) {
|
||||
u16 idx = kvm_mpidr_index(data, mpidr);
|
||||
|
||||
vcpu = kvm_get_vcpu(kvm, data->cmpidr_to_idx[idx]);
|
||||
if (mpidr != kvm_vcpu_get_mpidr_aff(vcpu))
|
||||
vcpu = NULL;
|
||||
|
||||
return vcpu;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (vcpu)
|
||||
return vcpu;
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
if (mpidr == kvm_vcpu_get_mpidr_aff(vcpu))
|
||||
return vcpu;
|
||||
|
|
|
@ -600,7 +600,6 @@ static bool ffa_call_supported(u64 func_id)
|
|||
case FFA_MSG_POLL:
|
||||
case FFA_MSG_WAIT:
|
||||
/* 32-bit variants of 64-bit calls */
|
||||
case FFA_MSG_SEND_DIRECT_REQ:
|
||||
case FFA_MSG_SEND_DIRECT_RESP:
|
||||
case FFA_RXTX_MAP:
|
||||
case FFA_MEM_DONATE:
|
||||
|
|
|
@ -2338,7 +2338,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
|||
ID_AA64MMFR0_EL1_TGRAN16_2)),
|
||||
ID_WRITABLE(ID_AA64MMFR1_EL1, ~(ID_AA64MMFR1_EL1_RES0 |
|
||||
ID_AA64MMFR1_EL1_HCX |
|
||||
ID_AA64MMFR1_EL1_XNX |
|
||||
ID_AA64MMFR1_EL1_TWED |
|
||||
ID_AA64MMFR1_EL1_XNX |
|
||||
ID_AA64MMFR1_EL1_VH |
|
||||
|
@ -3069,12 +3068,14 @@ static bool check_sysreg_table(const struct sys_reg_desc *table, unsigned int n,
|
|||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (!is_32 && table[i].reg && !table[i].reset) {
|
||||
kvm_err("sys_reg table %pS entry %d lacks reset\n", &table[i], i);
|
||||
kvm_err("sys_reg table %pS entry %d (%s) lacks reset\n",
|
||||
&table[i], i, table[i].name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i && cmp_sys_reg(&table[i-1], &table[i]) >= 0) {
|
||||
kvm_err("sys_reg table %pS entry %d out of order\n", &table[i - 1], i - 1);
|
||||
kvm_err("sys_reg table %pS entry %d (%s -> %s) out of order\n",
|
||||
&table[i], i, table[i - 1].name, table[i].name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,27 +180,22 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_vgic_vcpu_init() - Initialize static VGIC VCPU data
|
||||
* structures and register VCPU-specific KVM iodevs
|
||||
*
|
||||
* @vcpu: pointer to the VCPU being created and initialized
|
||||
*
|
||||
* Only do initialization, but do not actually enable the
|
||||
* VGIC CPU interface
|
||||
*/
|
||||
int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
|
||||
static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
|
||||
lockdep_assert_held(&vcpu->kvm->arch.config_lock);
|
||||
|
||||
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
|
||||
raw_spin_lock_init(&vgic_cpu->ap_list_lock);
|
||||
atomic_set(&vgic_cpu->vgic_v3.its_vpe.vlpi_count, 0);
|
||||
if (vgic_cpu->private_irqs)
|
||||
return 0;
|
||||
|
||||
vgic_cpu->private_irqs = kcalloc(VGIC_NR_PRIVATE_IRQS,
|
||||
sizeof(struct vgic_irq),
|
||||
GFP_KERNEL_ACCOUNT);
|
||||
|
||||
if (!vgic_cpu->private_irqs)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Enable and configure all SGIs to be edge-triggered and
|
||||
|
@ -225,9 +220,48 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vgic_allocate_private_irqs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&vcpu->kvm->arch.config_lock);
|
||||
ret = vgic_allocate_private_irqs_locked(vcpu);
|
||||
mutex_unlock(&vcpu->kvm->arch.config_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_vgic_vcpu_init() - Initialize static VGIC VCPU data
|
||||
* structures and register VCPU-specific KVM iodevs
|
||||
*
|
||||
* @vcpu: pointer to the VCPU being created and initialized
|
||||
*
|
||||
* Only do initialization, but do not actually enable the
|
||||
* VGIC CPU interface
|
||||
*/
|
||||
int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
|
||||
int ret = 0;
|
||||
|
||||
vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
|
||||
|
||||
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
|
||||
raw_spin_lock_init(&vgic_cpu->ap_list_lock);
|
||||
atomic_set(&vgic_cpu->vgic_v3.its_vpe.vlpi_count, 0);
|
||||
|
||||
if (!irqchip_in_kernel(vcpu->kvm))
|
||||
return 0;
|
||||
|
||||
ret = vgic_allocate_private_irqs(vcpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If we are creating a VCPU with a GICv3 we must also register the
|
||||
* KVM io device for the redistributor that belongs to this VCPU.
|
||||
|
@ -283,10 +317,13 @@ int vgic_init(struct kvm *kvm)
|
|||
|
||||
/* Initialize groups on CPUs created before the VGIC type was known */
|
||||
kvm_for_each_vcpu(idx, vcpu, kvm) {
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
ret = vgic_allocate_private_irqs_locked(vcpu);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
|
||||
struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
|
||||
struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, i);
|
||||
|
||||
switch (dist->vgic_model) {
|
||||
case KVM_DEV_TYPE_ARM_VGIC_V3:
|
||||
irq->group = 1;
|
||||
|
@ -298,8 +335,12 @@ int vgic_init(struct kvm *kvm)
|
|||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vgic_put_irq(kvm, irq);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,6 +414,9 @@ static void __kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
|
|||
vgic_flush_pending_lpis(vcpu);
|
||||
|
||||
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
|
||||
kfree(vgic_cpu->private_irqs);
|
||||
vgic_cpu->private_irqs = NULL;
|
||||
|
||||
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
|
||||
vgic_unregister_redist_iodev(vcpu);
|
||||
vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
|
||||
|
|
|
@ -331,7 +331,7 @@ struct vgic_cpu {
|
|||
struct vgic_v3_cpu_if vgic_v3;
|
||||
};
|
||||
|
||||
struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
|
||||
struct vgic_irq *private_irqs;
|
||||
|
||||
raw_spinlock_t ap_list_lock; /* Protects the ap_list */
|
||||
|
||||
|
|
Loading…
Reference in New Issue