[PATCH v4 29/40] KVM: arm64: Prepare to handle deferred save/restore of 32-bit registers
Julien Grall
julien.grall at arm.com
Fri Feb 23 03:35:38 PST 2018
Hi Christoffer,
On 15/02/18 21:03, Christoffer Dall wrote:
> 32-bit registers are not used by a 64-bit 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.
I realize that you explain in the new patch why FPEXC32_EL2 is not
directly accessed below. But I think it might be worth to explain it
here as well because the commit message implies all 32-bit registers
could be deferred.
>
> Signed-off-by: Christoffer Dall <christoffer.dall at linaro.org>
> ---
>
> Notes:
> Changes since v3:
> - Don't also try to write hardware spsr when sysregs are not loaded
> - Adapted patch to use switch-based sysreg save/restore approach
> - (Kept additional BUG_ON() in vcpu_read_spsr32() to keep the compiler happy)
>
> Changes since v2:
> - New patch (deferred register handling has been reworked)
>
> arch/arm64/include/asm/kvm_emulate.h | 32 +++++------------
> arch/arm64/kvm/regmap.c | 67 +++++++++++++++++++++++++++---------
> arch/arm64/kvm/sys_regs.c | 6 ++++
> 3 files changed, 65 insertions(+), 40 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
> index 9cb13b23c7a1..23b33e8ea03a 100644
> --- a/arch/arm64/include/asm/kvm_emulate.h
> +++ b/arch/arm64/include/asm/kvm_emulate.h
> @@ -33,7 +33,8 @@
> #include <asm/virt.h>
>
> unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
> -unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu);
> +unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu);
> +void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v);
>
> bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
> void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
> @@ -162,41 +163,26 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
>
> static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *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 != (unsigned long *)p)
> - return *p_32bit;
> - }
> + if (vcpu_mode_is_32bit(vcpu))
> + return vcpu_read_spsr32(vcpu);
>
> if (vcpu->arch.sysregs_loaded_on_cpu)
> return read_sysreg_el1(spsr);
> else
> - return *p;
> + return vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
> }
>
> -static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
> +static inline void vcpu_write_spsr(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 != (unsigned long *)p) {
> - *p_32bit = v;
> - return;
> - }
> + vcpu_write_spsr32(vcpu, v);
> + return;
> }
>
> if (vcpu->arch.sysregs_loaded_on_cpu)
> write_sysreg_el1(v, spsr);
> else
> - *p = v;
> + vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1] = v;
> }
>
> static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
> diff --git a/arch/arm64/kvm/regmap.c b/arch/arm64/kvm/regmap.c
> index bbc6ae32e4af..eefe403a2e63 100644
> --- a/arch/arm64/kvm/regmap.c
> +++ b/arch/arm64/kvm/regmap.c
> @@ -141,28 +141,61 @@ unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num)
> /*
> * Return the SPSR for the current mode of the virtual CPU.
> */
> -unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu)
> +static int vcpu_spsr32_mode(const struct kvm_vcpu *vcpu)
> {
> unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
> switch (mode) {
> - case COMPAT_PSR_MODE_SVC:
> - mode = KVM_SPSR_SVC;
> - break;
> - case COMPAT_PSR_MODE_ABT:
> - mode = KVM_SPSR_ABT;
> - break;
> - case COMPAT_PSR_MODE_UND:
> - mode = KVM_SPSR_UND;
> - break;
> - case COMPAT_PSR_MODE_IRQ:
> - mode = KVM_SPSR_IRQ;
> - break;
> - case COMPAT_PSR_MODE_FIQ:
> - mode = KVM_SPSR_FIQ;
> - break;
> + case COMPAT_PSR_MODE_SVC: return KVM_SPSR_SVC;
> + case COMPAT_PSR_MODE_ABT: return KVM_SPSR_ABT;
> + case COMPAT_PSR_MODE_UND: return KVM_SPSR_UND;
> + case COMPAT_PSR_MODE_IRQ: return KVM_SPSR_IRQ;
> + case COMPAT_PSR_MODE_FIQ: return KVM_SPSR_FIQ;
> + default: BUG();
> + }
> +}
> +
> +unsigned long vcpu_read_spsr32(const struct kvm_vcpu *vcpu)
> +{
> + int spsr_idx = vcpu_spsr32_mode(vcpu);
> +
> + if (!vcpu->arch.sysregs_loaded_on_cpu)
> + return vcpu_gp_regs(vcpu)->spsr[spsr_idx];
> +
> + switch (spsr_idx) {
> + case KVM_SPSR_SVC:
> + return read_sysreg_el1(spsr);
> + case KVM_SPSR_ABT:
> + return read_sysreg(spsr_abt);
> + case KVM_SPSR_UND:
> + return read_sysreg(spsr_und);
> + case KVM_SPSR_IRQ:
> + return read_sysreg(spsr_irq);
> + case KVM_SPSR_FIQ:
> + return read_sysreg(spsr_fiq);
> default:
> BUG();
> }
> +}
> +
> +void vcpu_write_spsr32(struct kvm_vcpu *vcpu, unsigned long v)
> +{
> + int spsr_idx = vcpu_spsr32_mode(vcpu);
> +
> + if (!vcpu->arch.sysregs_loaded_on_cpu) {
> + vcpu_gp_regs(vcpu)->spsr[spsr_idx] = v;
> + return;
> + }
>
> - return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[mode];
> + switch (spsr_idx) {
> + case KVM_SPSR_SVC:
> + write_sysreg_el1(v, spsr);
> + case KVM_SPSR_ABT:
> + write_sysreg(v, spsr_abt);
> + case KVM_SPSR_UND:
> + write_sysreg(v, spsr_und);
> + case KVM_SPSR_IRQ:
> + write_sysreg(v, spsr_irq);
> + case KVM_SPSR_FIQ:
> + write_sysreg(v, spsr_fiq);
> + }
> }
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f060309337aa..d2324560c9f5 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -107,6 +107,9 @@ u64 vcpu_read_sys_reg(struct kvm_vcpu *vcpu, int reg)
> case AMAIR_EL1: return read_sysreg_s(amair_EL12);
> case CNTKCTL_EL1: return read_sysreg_s(cntkctl_EL12);
> case PAR_EL1: return read_sysreg_s(SYS_PAR_EL1);
> + case DACR32_EL2: return read_sysreg_s(SYS_DACR32_EL2);
> + case IFSR32_EL2: return read_sysreg_s(SYS_IFSR32_EL2);
> + case DBGVCR32_EL2: return read_sysreg_s(SYS_DBGVCR32_EL2);
> }
>
> immediate_read:
> @@ -143,6 +146,9 @@ void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
> case AMAIR_EL1: write_sysreg_s(val, amair_EL12); return;
> case CNTKCTL_EL1: write_sysreg_s(val, cntkctl_EL12); return;
> case PAR_EL1: write_sysreg_s(val, SYS_PAR_EL1); return;
> + case DACR32_EL2: write_sysreg_s(val, SYS_DACR32_EL2); return;
> + case IFSR32_EL2: write_sysreg_s(val, SYS_IFSR32_EL2); return;
> + case DBGVCR32_EL2: write_sysreg_s(val, SYS_DBGVCR32_EL2); return;
> }
>
> immediate_write:
>
Cheers,
--
Julien Grall
More information about the linux-arm-kernel
mailing list