Skip to content

Commit

Permalink
KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
Browse files Browse the repository at this point in the history
SPSR_EL1 is not used by a VHE host kernel and can be deferred, but we
need to rework the accesses to this register to access the latest value
depending on whether or not guest system registers are loaded on the CPU
or only reside in memory.

The handling of accessing the various banked SPSRs for 32-bit VMs is a
bit clunky, but this will be improved in following patches which will
first prepare and subsequently implement deferred save/restore of the
32-bit registers, including the 32-bit SPSRs.

Reviewed-by: Marc Zyngier <[email protected]>
Reviewed-by: Andrew Jones <[email protected]>
Signed-off-by: Christoffer Dall <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
  • Loading branch information
chazy authored and Marc Zyngier committed Mar 19, 2018
1 parent d47533d commit 00536ec
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 10 deletions.
12 changes: 11 additions & 1 deletion arch/arm/include/asm/kvm_emulate.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,17 @@ static inline unsigned long *vcpu_reg32(struct kvm_vcpu *vcpu, u8 reg_num)
return vcpu_reg(vcpu, reg_num);
}

unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu);

static inline unsigned long vpcu_read_spsr(struct kvm_vcpu *vcpu)
{
return *__vcpu_spsr(vcpu);
}

static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
{
*__vcpu_spsr(vcpu) = v;
}

static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
u8 reg_num)
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/kvm/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num)
/*
* Return the SPSR for the current mode of the virtual CPU.
*/
unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu)
unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu)
{
unsigned long mode = *vcpu_cpsr(vcpu) & MODE_MASK;
switch (mode) {
Expand Down
41 changes: 36 additions & 5 deletions arch/arm64/include/asm/kvm_emulate.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <asm/esr.h>
#include <asm/kvm_arm.h>
#include <asm/kvm_hyp.h>
#include <asm/kvm_mmio.h>
#include <asm/ptrace.h>
#include <asm/cputype.h>
Expand Down Expand Up @@ -143,13 +144,43 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
}

/* Get vcpu SPSR for current mode */
static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
{
if (vcpu_mode_is_32bit(vcpu))
return vcpu_spsr32(vcpu);
unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];

if (vcpu_mode_is_32bit(vcpu)) {
unsigned long *p_32bit = vcpu_spsr32(vcpu);

/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
if (p_32bit != p)
return *p_32bit;
}

if (vcpu->arch.sysregs_loaded_on_cpu)
return read_sysreg_el1(spsr);
else
return *p;
}

return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
{
unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];

/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
if (vcpu_mode_is_32bit(vcpu)) {
unsigned long *p_32bit = vcpu_spsr32(vcpu);

/* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
if (p_32bit != p) {
*p_32bit = v;
return;
}
}

if (vcpu->arch.sysregs_loaded_on_cpu)
write_sysreg_el1(v, spsr);
else
*p = v;
}

static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
Expand Down
4 changes: 2 additions & 2 deletions arch/arm64/kvm/inject_fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);

*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
*vcpu_spsr(vcpu) = cpsr;
vcpu_write_spsr(vcpu, cpsr);

vcpu_write_sys_reg(vcpu, addr, FAR_EL1);

Expand Down Expand Up @@ -106,7 +106,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
*vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);

*vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
*vcpu_spsr(vcpu) = cpsr;
vcpu_write_spsr(vcpu, cpsr);

/*
* Build an unknown exception, depending on the instruction
Expand Down
2 changes: 1 addition & 1 deletion virt/kvm/arm/aarch32.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
*vcpu_cpsr(vcpu) = cpsr;

/* Note: These now point to the banked copies */
*vcpu_spsr(vcpu) = new_spsr_value;
vcpu_write_spsr(vcpu, new_spsr_value);
*vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;

/* Branch to exception vector */
Expand Down

0 comments on commit 00536ec

Please sign in to comment.