Skip to content

Commit e016333

Browse files
ouptonMarc Zyngier
authored andcommitted
KVM: arm64: Only reset vCPU-scoped feature ID regs once
The general expecation with feature ID registers is that they're 'reset' exactly once by KVM for the lifetime of a vCPU/VM, such that any userspace changes to the CPU features / identity are honored after a vCPU gets reset (e.g. PSCI_ON). KVM handles what it calls VM-scoped feature ID registers correctly, but feature ID registers local to a vCPU (CLIDR_EL1, MPIDR_EL1) get wiped after every reset. What's especially concerning is that a potentially-changing MPIDR_EL1 breaks MPIDR compression for indexing mpidr_data, as the mask of useful bits to build the index could change. This is absolutely no good. Avoid resetting vCPU feature ID registers more than once. Signed-off-by: Oliver Upton <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Marc Zyngier <[email protected]>
1 parent 44cbe80 commit e016333

File tree

3 files changed

+26
-13
lines changed

3 files changed

+26
-13
lines changed

arch/arm64/include/asm/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,8 @@ static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)
12751275

12761276
#define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f))
12771277

1278+
#define kvm_vcpu_initialized(v) vcpu_get_flag(vcpu, VCPU_INITIALIZED)
1279+
12781280
int kvm_trng_call(struct kvm_vcpu *vcpu);
12791281
#ifdef CONFIG_KVM
12801282
extern phys_addr_t hyp_mem_base;

arch/arm64/kvm/arm.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -580,11 +580,6 @@ unsigned long kvm_arch_vcpu_get_ip(struct kvm_vcpu *vcpu)
580580
}
581581
#endif
582582

583-
static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu)
584-
{
585-
return vcpu_get_flag(vcpu, VCPU_INITIALIZED);
586-
}
587-
588583
static void kvm_init_mpidr_data(struct kvm *kvm)
589584
{
590585
struct kvm_mpidr_data *data = NULL;

arch/arm64/kvm/sys_regs.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,14 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *r
15681568
return IDREG(vcpu->kvm, reg_to_encoding(r));
15691569
}
15701570

1571+
static bool is_feature_id_reg(u32 encoding)
1572+
{
1573+
return (sys_reg_Op0(encoding) == 3 &&
1574+
(sys_reg_Op1(encoding) < 2 || sys_reg_Op1(encoding) == 3) &&
1575+
sys_reg_CRn(encoding) == 0 &&
1576+
sys_reg_CRm(encoding) <= 7);
1577+
}
1578+
15711579
/*
15721580
* Return true if the register's (Op0, Op1, CRn, CRm, Op2) is
15731581
* (3, 0, 0, crm, op2), where 1<=crm<8, 0<=op2<8, which is the range of ID
@@ -1580,6 +1588,11 @@ static inline bool is_vm_ftr_id_reg(u32 id)
15801588
sys_reg_CRm(id) < 8);
15811589
}
15821590

1591+
static inline bool is_vcpu_ftr_id_reg(u32 id)
1592+
{
1593+
return is_feature_id_reg(id) && !is_vm_ftr_id_reg(id);
1594+
}
1595+
15831596
static inline bool is_aa32_id_reg(u32 id)
15841597
{
15851598
return (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 &&
@@ -3522,6 +3535,15 @@ static void reset_vm_ftr_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc
35223535
IDREG(kvm, id) = reg->reset(vcpu, reg);
35233536
}
35243537

3538+
static void reset_vcpu_ftr_id_reg(struct kvm_vcpu *vcpu,
3539+
const struct sys_reg_desc *reg)
3540+
{
3541+
if (kvm_vcpu_initialized(vcpu))
3542+
return;
3543+
3544+
reg->reset(vcpu, reg);
3545+
}
3546+
35253547
/**
35263548
* kvm_reset_sys_regs - sets system registers to reset value
35273549
* @vcpu: The VCPU pointer
@@ -3542,6 +3564,8 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
35423564

35433565
if (is_vm_ftr_id_reg(reg_to_encoding(r)))
35443566
reset_vm_ftr_id_reg(vcpu, r);
3567+
else if (is_vcpu_ftr_id_reg(reg_to_encoding(r)))
3568+
reset_vcpu_ftr_id_reg(vcpu, r);
35453569
else
35463570
r->reset(vcpu, r);
35473571
}
@@ -3972,14 +3996,6 @@ int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
39723996
sys_reg_CRm(r), \
39733997
sys_reg_Op2(r))
39743998

3975-
static bool is_feature_id_reg(u32 encoding)
3976-
{
3977-
return (sys_reg_Op0(encoding) == 3 &&
3978-
(sys_reg_Op1(encoding) < 2 || sys_reg_Op1(encoding) == 3) &&
3979-
sys_reg_CRn(encoding) == 0 &&
3980-
sys_reg_CRm(encoding) <= 7);
3981-
}
3982-
39833999
int kvm_vm_ioctl_get_reg_writable_masks(struct kvm *kvm, struct reg_mask_range *range)
39844000
{
39854001
const void *zero_page = page_to_virt(ZERO_PAGE(0));

0 commit comments

Comments
 (0)