This commit adds accessors for all registers, being part of saved vGIC context in the form of ICH_VMCR_EL2. This is necessary for enabling vGICv3 live migration. Signed-off-by: Pavel Fedin <p.fedin@xxxxxxxxxxx> --- arch/arm64/kvm/sys_regs.c | 176 +++++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 18 +++- 2 files changed, 192 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 8cc4a5e..7a4f982 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -23,6 +23,7 @@ #include <linux/kvm_host.h> #include <linux/mm.h> #include <linux/uaccess.h> +#include <linux/irqchip/arm-gic-v3.h> #include <asm/cacheflush.h> #include <asm/cputype.h> @@ -136,6 +137,162 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu, return true; } +static bool access_gic_ctlr(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u64 val; + struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; + + if (vcpu->kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3) + return false; + + if (p->is_write) { + val = *vcpu_reg(vcpu, p->Rt); + + vgicv3->vgic_vmcr &= ~(ICH_VMCR_CBPR|ICH_VMCR_EOIM); + vgicv3->vgic_vmcr |= (val << (ICH_VMCR_CBPR_SHIFT - + ICC_CTLR_EL1_CBPR_SHIFT)) & + ICH_VMCR_CBPR; + vgicv3->vgic_vmcr |= (val << (ICH_VMCR_EOIM_SHIFT - + ICC_CTLR_EL1_EOImode_SHIFT)) & + ICH_VMCR_EOIM; + } else { + asm volatile("mrs_s %0," __stringify(ICC_IAR1_EL1) + : "=r" (val)); + val &= (ICC_CTLR_EL1_A3V | ICC_CTLR_EL1_SEIS | + ICC_CTLR_EL1_IDbits_MASK | ICC_CTLR_EL1_PRIbits_MASK); + val |= (vgicv3->vgic_vmcr & ICH_VMCR_CBPR) >> + (ICH_VMCR_CBPR_SHIFT - ICC_CTLR_EL1_CBPR_SHIFT); + val |= (vgicv3->vgic_vmcr & ICH_VMCR_EOIM) >> + (ICH_VMCR_EOIM_SHIFT - ICC_CTLR_EL1_EOImode_SHIFT); + + *vcpu_reg(vcpu, p->Rt) = val; + } + + return true; +} + +static bool access_gic_pmr(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u64 val; + struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; + + if (vcpu->kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3) + return false; + + if (p->is_write) { + val = *vcpu_reg(vcpu, p->Rt); + vgicv3->vgic_vmcr &= ~ICH_VMCR_PMR_MASK; + vgicv3->vgic_vmcr |= (val << ICH_VMCR_PMR_SHIFT) & + ICH_VMCR_PMR_MASK; + } else { + val = (vgicv3->vgic_vmcr & ICH_VMCR_PMR_MASK) >> + ICH_VMCR_PMR_SHIFT; + *vcpu_reg(vcpu, p->Rt) = val; + } + + return true; +} + +static bool access_gic_bpr0(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u64 val; + struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; + + if (vcpu->kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3) + return false; + + if (p->is_write) { + val = *vcpu_reg(vcpu, p->Rt); + vgicv3->vgic_vmcr &= ~ICH_VMCR_BPR0_MASK; + vgicv3->vgic_vmcr |= (val << ICH_VMCR_BPR0_SHIFT) & + ICH_VMCR_BPR0_MASK; + } else { + val = (vgicv3->vgic_vmcr & ICH_VMCR_BPR0_MASK) >> + ICH_VMCR_BPR0_SHIFT; + *vcpu_reg(vcpu, p->Rt) = val; + } + + return true; +} + +static bool access_gic_bpr1(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u64 val; + struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; + + if (vcpu->kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3) + return false; + + if (p->is_write) { + val = *vcpu_reg(vcpu, p->Rt); + vgicv3->vgic_vmcr &= ~ICH_VMCR_BPR1_MASK; + vgicv3->vgic_vmcr |= (val << ICH_VMCR_BPR1_SHIFT) & + ICH_VMCR_BPR1_MASK; + } else { + val = (vgicv3->vgic_vmcr & ICH_VMCR_BPR1_MASK) >> + ICH_VMCR_BPR1_SHIFT; + *vcpu_reg(vcpu, p->Rt) = val; + } + + return true; +} + +static bool access_gic_grpen0(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u64 val; + struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; + + if (vcpu->kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3) + return false; + + if (p->is_write) { + val = *vcpu_reg(vcpu, p->Rt); + vgicv3->vgic_vmcr &= ~ICH_VMCR_ENG0; + vgicv3->vgic_vmcr |= (val << ICH_VMCR_ENG0_SHIFT) & + ICH_VMCR_ENG0; + } else { + val = (vgicv3->vgic_vmcr & ICH_VMCR_ENG0) >> + ICH_VMCR_ENG0_SHIFT; + *vcpu_reg(vcpu, p->Rt) = val; + } + + return true; +} + +static bool access_gic_grpen1(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u64 val; + struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; + + if (vcpu->kvm->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3) + return false; + + if (p->is_write) { + val = *vcpu_reg(vcpu, p->Rt); + vgicv3->vgic_vmcr &= ~ICH_VMCR_ENG1; + vgicv3->vgic_vmcr |= (val << ICH_VMCR_ENG1_SHIFT) & + ICH_VMCR_ENG1; + } else { + val = (vgicv3->vgic_vmcr & ICH_VMCR_ENG1) >> + ICH_VMCR_ENG1_SHIFT; + *vcpu_reg(vcpu, p->Rt) = val; + } + + return true; +} + static bool trap_raz_wi(struct kvm_vcpu *vcpu, const struct sys_reg_params *p, const struct sys_reg_desc *r) @@ -579,6 +736,10 @@ static const struct sys_reg_desc sys_reg_descs[] = { { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b010), access_vm_reg, reset_val, TCR_EL1, 0 }, + /* ICC_PMR_EL1 */ + { Op0(0b11), Op1(0b000), CRn(0b0100), CRm(0b0110), Op2(0b000), + access_gic_pmr }, + /* AFSR0_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b000), access_vm_reg, reset_unknown, AFSR0_EL1 }, @@ -613,12 +774,27 @@ static const struct sys_reg_desc sys_reg_descs[] = { { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000), NULL, reset_val, VBAR_EL1, 0 }, + /* ICC_BPR0_EL1 */ + { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1000), Op2(0b011), + access_gic_bpr0 }, /* ICC_SGI1R_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1011), Op2(0b101), access_gic_sgi }, + /* ICC_BPR1_EL1 */ + { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b011), + access_gic_bpr1 }, + /* ICC_CTLR_EL1 */ + { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b100), + access_gic_ctlr }, /* ICC_SRE_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b101), trap_raz_wi }, + /* ICC_IGRPEN0_EL1 */ + { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b110), + access_gic_grpen0 }, + /* ICC_GRPEN1_EL1 */ + { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b111), + access_gic_grpen1 }, /* CONTEXTIDR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001), diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index ed0fc9f..7e9fc16 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -257,8 +257,14 @@ /* * CPU interface registers */ -#define ICC_CTLR_EL1_EOImode_drop_dir (0U << 1) -#define ICC_CTLR_EL1_EOImode_drop (1U << 1) +#define ICC_CTLR_EL1_CBPR_SHIFT 0 +#define ICC_CTLR_EL1_EOImode_SHIFT 1 +#define ICC_CTLR_EL1_EOImode_drop_dir (0U << ICC_CTLR_EL1_EOImode_SHIFT) +#define ICC_CTLR_EL1_EOImode_drop (1U << ICC_CTLR_EL1_EOImode_SHIFT) +#define ICC_CTLR_EL1_PRIbits_MASK (7U << 8) +#define ICC_CTLR_EL1_IDbits_MASK (7U << 11) +#define ICC_CTLR_EL1_SEIS (1U << 14) +#define ICC_CTLR_EL1_A3V (1U << 15) #define ICC_SRE_EL1_SRE (1U << 0) /* @@ -283,6 +289,14 @@ #define ICH_VMCR_CTLR_SHIFT 0 #define ICH_VMCR_CTLR_MASK (0x21f << ICH_VMCR_CTLR_SHIFT) +#define ICH_VMCR_ENG0_SHIFT 0 +#define ICH_VMCR_ENG0 (1 << ICH_VMCR_ENG0_SHIFT) +#define ICH_VMCR_ENG1_SHIFT 1 +#define ICH_VMCR_ENG1 (1 << ICH_VMCR_ENG1_SHIFT) +#define ICH_VMCR_CBPR_SHIFT 4 +#define ICH_VMCR_CBPR (1 << ICH_VMCR_CBPR_SHIFT) +#define ICH_VMCR_EOIM_SHIFT 9 +#define ICH_VMCR_EOIM (1 << ICH_VMCR_EOIM_SHIFT) #define ICH_VMCR_BPR1_SHIFT 18 #define ICH_VMCR_BPR1_MASK (7 << ICH_VMCR_BPR1_SHIFT) #define ICH_VMCR_BPR0_SHIFT 21 -- 2.4.4 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html