diff options
-rw-r--r-- | arch/arm/kvm/coproc.c | 23 | ||||
-rw-r--r-- | arch/arm64/kvm/sys_regs.c | 32 | ||||
-rw-r--r-- | include/kvm/arm_vgic.h | 1 | ||||
-rw-r--r-- | virt/kvm/arm/arm.c | 11 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-mmio.c | 16 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-v2.c | 9 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-v3.c | 7 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic.c | 11 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic.h | 2 |
9 files changed, 88 insertions, 24 deletions
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index d2806bcff8bb..07745ee022a1 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c | |||
@@ -651,13 +651,22 @@ int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
651 | } | 651 | } |
652 | 652 | ||
653 | static void reset_coproc_regs(struct kvm_vcpu *vcpu, | 653 | static void reset_coproc_regs(struct kvm_vcpu *vcpu, |
654 | const struct coproc_reg *table, size_t num) | 654 | const struct coproc_reg *table, size_t num, |
655 | unsigned long *bmap) | ||
655 | { | 656 | { |
656 | unsigned long i; | 657 | unsigned long i; |
657 | 658 | ||
658 | for (i = 0; i < num; i++) | 659 | for (i = 0; i < num; i++) |
659 | if (table[i].reset) | 660 | if (table[i].reset) { |
661 | int reg = table[i].reg; | ||
662 | |||
660 | table[i].reset(vcpu, &table[i]); | 663 | table[i].reset(vcpu, &table[i]); |
664 | if (reg > 0 && reg < NR_CP15_REGS) { | ||
665 | set_bit(reg, bmap); | ||
666 | if (table[i].is_64bit) | ||
667 | set_bit(reg + 1, bmap); | ||
668 | } | ||
669 | } | ||
661 | } | 670 | } |
662 | 671 | ||
663 | static struct coproc_params decode_32bit_hsr(struct kvm_vcpu *vcpu) | 672 | static struct coproc_params decode_32bit_hsr(struct kvm_vcpu *vcpu) |
@@ -1432,17 +1441,15 @@ void kvm_reset_coprocs(struct kvm_vcpu *vcpu) | |||
1432 | { | 1441 | { |
1433 | size_t num; | 1442 | size_t num; |
1434 | const struct coproc_reg *table; | 1443 | const struct coproc_reg *table; |
1435 | 1444 | DECLARE_BITMAP(bmap, NR_CP15_REGS) = { 0, }; | |
1436 | /* Catch someone adding a register without putting in reset entry. */ | ||
1437 | memset(vcpu->arch.ctxt.cp15, 0x42, sizeof(vcpu->arch.ctxt.cp15)); | ||
1438 | 1445 | ||
1439 | /* Generic chip reset first (so target could override). */ | 1446 | /* Generic chip reset first (so target could override). */ |
1440 | reset_coproc_regs(vcpu, cp15_regs, ARRAY_SIZE(cp15_regs)); | 1447 | reset_coproc_regs(vcpu, cp15_regs, ARRAY_SIZE(cp15_regs), bmap); |
1441 | 1448 | ||
1442 | table = get_target_table(vcpu->arch.target, &num); | 1449 | table = get_target_table(vcpu->arch.target, &num); |
1443 | reset_coproc_regs(vcpu, table, num); | 1450 | reset_coproc_regs(vcpu, table, num, bmap); |
1444 | 1451 | ||
1445 | for (num = 1; num < NR_CP15_REGS; num++) | 1452 | for (num = 1; num < NR_CP15_REGS; num++) |
1446 | WARN(vcpu_cp15(vcpu, num) == 0x42424242, | 1453 | WARN(!test_bit(num, bmap), |
1447 | "Didn't reset vcpu_cp15(vcpu, %zi)", num); | 1454 | "Didn't reset vcpu_cp15(vcpu, %zi)", num); |
1448 | } | 1455 | } |
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index f26e181d881c..2071260a275b 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c | |||
@@ -632,7 +632,7 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) | |||
632 | */ | 632 | */ |
633 | val = ((pmcr & ~ARMV8_PMU_PMCR_MASK) | 633 | val = ((pmcr & ~ARMV8_PMU_PMCR_MASK) |
634 | | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E); | 634 | | (ARMV8_PMU_PMCR_MASK & 0xdecafbad)) & (~ARMV8_PMU_PMCR_E); |
635 | __vcpu_sys_reg(vcpu, PMCR_EL0) = val; | 635 | __vcpu_sys_reg(vcpu, r->reg) = val; |
636 | } | 636 | } |
637 | 637 | ||
638 | static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags) | 638 | static bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags) |
@@ -981,13 +981,13 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, | |||
981 | /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */ | 981 | /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */ |
982 | #define DBG_BCR_BVR_WCR_WVR_EL1(n) \ | 982 | #define DBG_BCR_BVR_WCR_WVR_EL1(n) \ |
983 | { SYS_DESC(SYS_DBGBVRn_EL1(n)), \ | 983 | { SYS_DESC(SYS_DBGBVRn_EL1(n)), \ |
984 | trap_bvr, reset_bvr, n, 0, get_bvr, set_bvr }, \ | 984 | trap_bvr, reset_bvr, 0, 0, get_bvr, set_bvr }, \ |
985 | { SYS_DESC(SYS_DBGBCRn_EL1(n)), \ | 985 | { SYS_DESC(SYS_DBGBCRn_EL1(n)), \ |
986 | trap_bcr, reset_bcr, n, 0, get_bcr, set_bcr }, \ | 986 | trap_bcr, reset_bcr, 0, 0, get_bcr, set_bcr }, \ |
987 | { SYS_DESC(SYS_DBGWVRn_EL1(n)), \ | 987 | { SYS_DESC(SYS_DBGWVRn_EL1(n)), \ |
988 | trap_wvr, reset_wvr, n, 0, get_wvr, set_wvr }, \ | 988 | trap_wvr, reset_wvr, 0, 0, get_wvr, set_wvr }, \ |
989 | { SYS_DESC(SYS_DBGWCRn_EL1(n)), \ | 989 | { SYS_DESC(SYS_DBGWCRn_EL1(n)), \ |
990 | trap_wcr, reset_wcr, n, 0, get_wcr, set_wcr } | 990 | trap_wcr, reset_wcr, 0, 0, get_wcr, set_wcr } |
991 | 991 | ||
992 | /* Macro to expand the PMEVCNTRn_EL0 register */ | 992 | /* Macro to expand the PMEVCNTRn_EL0 register */ |
993 | #define PMU_PMEVCNTR_EL0(n) \ | 993 | #define PMU_PMEVCNTR_EL0(n) \ |
@@ -1540,7 +1540,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { | |||
1540 | { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 }, | 1540 | { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 }, |
1541 | { SYS_DESC(SYS_CTR_EL0), access_ctr }, | 1541 | { SYS_DESC(SYS_CTR_EL0), access_ctr }, |
1542 | 1542 | ||
1543 | { SYS_DESC(SYS_PMCR_EL0), access_pmcr, reset_pmcr, }, | 1543 | { SYS_DESC(SYS_PMCR_EL0), access_pmcr, reset_pmcr, PMCR_EL0 }, |
1544 | { SYS_DESC(SYS_PMCNTENSET_EL0), access_pmcnten, reset_unknown, PMCNTENSET_EL0 }, | 1544 | { SYS_DESC(SYS_PMCNTENSET_EL0), access_pmcnten, reset_unknown, PMCNTENSET_EL0 }, |
1545 | { SYS_DESC(SYS_PMCNTENCLR_EL0), access_pmcnten, NULL, PMCNTENSET_EL0 }, | 1545 | { SYS_DESC(SYS_PMCNTENCLR_EL0), access_pmcnten, NULL, PMCNTENSET_EL0 }, |
1546 | { SYS_DESC(SYS_PMOVSCLR_EL0), access_pmovs, NULL, PMOVSSET_EL0 }, | 1546 | { SYS_DESC(SYS_PMOVSCLR_EL0), access_pmovs, NULL, PMOVSSET_EL0 }, |
@@ -2254,13 +2254,19 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu, | |||
2254 | } | 2254 | } |
2255 | 2255 | ||
2256 | static void reset_sys_reg_descs(struct kvm_vcpu *vcpu, | 2256 | static void reset_sys_reg_descs(struct kvm_vcpu *vcpu, |
2257 | const struct sys_reg_desc *table, size_t num) | 2257 | const struct sys_reg_desc *table, size_t num, |
2258 | unsigned long *bmap) | ||
2258 | { | 2259 | { |
2259 | unsigned long i; | 2260 | unsigned long i; |
2260 | 2261 | ||
2261 | for (i = 0; i < num; i++) | 2262 | for (i = 0; i < num; i++) |
2262 | if (table[i].reset) | 2263 | if (table[i].reset) { |
2264 | int reg = table[i].reg; | ||
2265 | |||
2263 | table[i].reset(vcpu, &table[i]); | 2266 | table[i].reset(vcpu, &table[i]); |
2267 | if (reg > 0 && reg < NR_SYS_REGS) | ||
2268 | set_bit(reg, bmap); | ||
2269 | } | ||
2264 | } | 2270 | } |
2265 | 2271 | ||
2266 | /** | 2272 | /** |
@@ -2774,18 +2780,16 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu) | |||
2774 | { | 2780 | { |
2775 | size_t num; | 2781 | size_t num; |
2776 | const struct sys_reg_desc *table; | 2782 | const struct sys_reg_desc *table; |
2777 | 2783 | DECLARE_BITMAP(bmap, NR_SYS_REGS) = { 0, }; | |
2778 | /* Catch someone adding a register without putting in reset entry. */ | ||
2779 | memset(&vcpu->arch.ctxt.sys_regs, 0x42, sizeof(vcpu->arch.ctxt.sys_regs)); | ||
2780 | 2784 | ||
2781 | /* Generic chip reset first (so target could override). */ | 2785 | /* Generic chip reset first (so target could override). */ |
2782 | reset_sys_reg_descs(vcpu, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); | 2786 | reset_sys_reg_descs(vcpu, sys_reg_descs, ARRAY_SIZE(sys_reg_descs), bmap); |
2783 | 2787 | ||
2784 | table = get_target_table(vcpu->arch.target, true, &num); | 2788 | table = get_target_table(vcpu->arch.target, true, &num); |
2785 | reset_sys_reg_descs(vcpu, table, num); | 2789 | reset_sys_reg_descs(vcpu, table, num, bmap); |
2786 | 2790 | ||
2787 | for (num = 1; num < NR_SYS_REGS; num++) { | 2791 | for (num = 1; num < NR_SYS_REGS; num++) { |
2788 | if (WARN(__vcpu_sys_reg(vcpu, num) == 0x4242424242424242, | 2792 | if (WARN(!test_bit(num, bmap), |
2789 | "Didn't reset __vcpu_sys_reg(%zi)\n", num)) | 2793 | "Didn't reset __vcpu_sys_reg(%zi)\n", num)) |
2790 | break; | 2794 | break; |
2791 | } | 2795 | } |
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 46bbc949c20a..7a30524a80ee 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h | |||
@@ -350,6 +350,7 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu); | |||
350 | 350 | ||
351 | void kvm_vgic_load(struct kvm_vcpu *vcpu); | 351 | void kvm_vgic_load(struct kvm_vcpu *vcpu); |
352 | void kvm_vgic_put(struct kvm_vcpu *vcpu); | 352 | void kvm_vgic_put(struct kvm_vcpu *vcpu); |
353 | void kvm_vgic_vmcr_sync(struct kvm_vcpu *vcpu); | ||
353 | 354 | ||
354 | #define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel)) | 355 | #define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel)) |
355 | #define vgic_initialized(k) ((k)->arch.vgic.initialized) | 356 | #define vgic_initialized(k) ((k)->arch.vgic.initialized) |
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 3f7bea930acf..35a069815baf 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c | |||
@@ -318,6 +318,17 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) | |||
318 | 318 | ||
319 | void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) | 319 | void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) |
320 | { | 320 | { |
321 | /* | ||
322 | * If we're about to block (most likely because we've just hit a | ||
323 | * WFI), we need to sync back the state of the GIC CPU interface | ||
324 | * so that we have the lastest PMR and group enables. This ensures | ||
325 | * that kvm_arch_vcpu_runnable has up-to-date data to decide | ||
326 | * whether we have pending interrupts. | ||
327 | */ | ||
328 | preempt_disable(); | ||
329 | kvm_vgic_vmcr_sync(vcpu); | ||
330 | preempt_enable(); | ||
331 | |||
321 | kvm_vgic_v4_enable_doorbell(vcpu); | 332 | kvm_vgic_v4_enable_doorbell(vcpu); |
322 | } | 333 | } |
323 | 334 | ||
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c index 3ba7278fb533..44efc2ff863f 100644 --- a/virt/kvm/arm/vgic/vgic-mmio.c +++ b/virt/kvm/arm/vgic/vgic-mmio.c | |||
@@ -113,6 +113,22 @@ void vgic_mmio_write_senable(struct kvm_vcpu *vcpu, | |||
113 | struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); | 113 | struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); |
114 | 114 | ||
115 | raw_spin_lock_irqsave(&irq->irq_lock, flags); | 115 | raw_spin_lock_irqsave(&irq->irq_lock, flags); |
116 | if (vgic_irq_is_mapped_level(irq)) { | ||
117 | bool was_high = irq->line_level; | ||
118 | |||
119 | /* | ||
120 | * We need to update the state of the interrupt because | ||
121 | * the guest might have changed the state of the device | ||
122 | * while the interrupt was disabled at the VGIC level. | ||
123 | */ | ||
124 | irq->line_level = vgic_get_phys_line_level(irq); | ||
125 | /* | ||
126 | * Deactivate the physical interrupt so the GIC will let | ||
127 | * us know when it is asserted again. | ||
128 | */ | ||
129 | if (!irq->active && was_high && !irq->line_level) | ||
130 | vgic_irq_set_phys_active(irq, false); | ||
131 | } | ||
116 | irq->enabled = true; | 132 | irq->enabled = true; |
117 | vgic_queue_irq_unlock(vcpu->kvm, irq, flags); | 133 | vgic_queue_irq_unlock(vcpu->kvm, irq, flags); |
118 | 134 | ||
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c index 6dd5ad706c92..96aab77d0471 100644 --- a/virt/kvm/arm/vgic/vgic-v2.c +++ b/virt/kvm/arm/vgic/vgic-v2.c | |||
@@ -484,10 +484,17 @@ void vgic_v2_load(struct kvm_vcpu *vcpu) | |||
484 | kvm_vgic_global_state.vctrl_base + GICH_APR); | 484 | kvm_vgic_global_state.vctrl_base + GICH_APR); |
485 | } | 485 | } |
486 | 486 | ||
487 | void vgic_v2_put(struct kvm_vcpu *vcpu) | 487 | void vgic_v2_vmcr_sync(struct kvm_vcpu *vcpu) |
488 | { | 488 | { |
489 | struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; | 489 | struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; |
490 | 490 | ||
491 | cpu_if->vgic_vmcr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VMCR); | 491 | cpu_if->vgic_vmcr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VMCR); |
492 | } | ||
493 | |||
494 | void vgic_v2_put(struct kvm_vcpu *vcpu) | ||
495 | { | ||
496 | struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; | ||
497 | |||
498 | vgic_v2_vmcr_sync(vcpu); | ||
492 | cpu_if->vgic_apr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_APR); | 499 | cpu_if->vgic_apr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_APR); |
493 | } | 500 | } |
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c index c2c9ce009f63..0c653a1e5215 100644 --- a/virt/kvm/arm/vgic/vgic-v3.c +++ b/virt/kvm/arm/vgic/vgic-v3.c | |||
@@ -662,12 +662,17 @@ void vgic_v3_load(struct kvm_vcpu *vcpu) | |||
662 | __vgic_v3_activate_traps(vcpu); | 662 | __vgic_v3_activate_traps(vcpu); |
663 | } | 663 | } |
664 | 664 | ||
665 | void vgic_v3_put(struct kvm_vcpu *vcpu) | 665 | void vgic_v3_vmcr_sync(struct kvm_vcpu *vcpu) |
666 | { | 666 | { |
667 | struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; | 667 | struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3; |
668 | 668 | ||
669 | if (likely(cpu_if->vgic_sre)) | 669 | if (likely(cpu_if->vgic_sre)) |
670 | cpu_if->vgic_vmcr = kvm_call_hyp_ret(__vgic_v3_read_vmcr); | 670 | cpu_if->vgic_vmcr = kvm_call_hyp_ret(__vgic_v3_read_vmcr); |
671 | } | ||
672 | |||
673 | void vgic_v3_put(struct kvm_vcpu *vcpu) | ||
674 | { | ||
675 | vgic_v3_vmcr_sync(vcpu); | ||
671 | 676 | ||
672 | kvm_call_hyp(__vgic_v3_save_aprs, vcpu); | 677 | kvm_call_hyp(__vgic_v3_save_aprs, vcpu); |
673 | 678 | ||
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c index 04786c8ec77e..13d4b38a94ec 100644 --- a/virt/kvm/arm/vgic/vgic.c +++ b/virt/kvm/arm/vgic/vgic.c | |||
@@ -919,6 +919,17 @@ void kvm_vgic_put(struct kvm_vcpu *vcpu) | |||
919 | vgic_v3_put(vcpu); | 919 | vgic_v3_put(vcpu); |
920 | } | 920 | } |
921 | 921 | ||
922 | void kvm_vgic_vmcr_sync(struct kvm_vcpu *vcpu) | ||
923 | { | ||
924 | if (unlikely(!irqchip_in_kernel(vcpu->kvm))) | ||
925 | return; | ||
926 | |||
927 | if (kvm_vgic_global_state.type == VGIC_V2) | ||
928 | vgic_v2_vmcr_sync(vcpu); | ||
929 | else | ||
930 | vgic_v3_vmcr_sync(vcpu); | ||
931 | } | ||
932 | |||
922 | int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu) | 933 | int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu) |
923 | { | 934 | { |
924 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; | 935 | struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; |
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h index 3b7525deec80..797e05004d80 100644 --- a/virt/kvm/arm/vgic/vgic.h +++ b/virt/kvm/arm/vgic/vgic.h | |||
@@ -193,6 +193,7 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address, | |||
193 | void vgic_v2_init_lrs(void); | 193 | void vgic_v2_init_lrs(void); |
194 | void vgic_v2_load(struct kvm_vcpu *vcpu); | 194 | void vgic_v2_load(struct kvm_vcpu *vcpu); |
195 | void vgic_v2_put(struct kvm_vcpu *vcpu); | 195 | void vgic_v2_put(struct kvm_vcpu *vcpu); |
196 | void vgic_v2_vmcr_sync(struct kvm_vcpu *vcpu); | ||
196 | 197 | ||
197 | void vgic_v2_save_state(struct kvm_vcpu *vcpu); | 198 | void vgic_v2_save_state(struct kvm_vcpu *vcpu); |
198 | void vgic_v2_restore_state(struct kvm_vcpu *vcpu); | 199 | void vgic_v2_restore_state(struct kvm_vcpu *vcpu); |
@@ -223,6 +224,7 @@ bool vgic_v3_check_base(struct kvm *kvm); | |||
223 | 224 | ||
224 | void vgic_v3_load(struct kvm_vcpu *vcpu); | 225 | void vgic_v3_load(struct kvm_vcpu *vcpu); |
225 | void vgic_v3_put(struct kvm_vcpu *vcpu); | 226 | void vgic_v3_put(struct kvm_vcpu *vcpu); |
227 | void vgic_v3_vmcr_sync(struct kvm_vcpu *vcpu); | ||
226 | 228 | ||
227 | bool vgic_has_its(struct kvm *kvm); | 229 | bool vgic_has_its(struct kvm *kvm); |
228 | int kvm_vgic_register_its_device(void); | 230 | int kvm_vgic_register_its_device(void); |