From: wanghaibin wanghaibin.wang@huawei.com
virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8K89F CVE: NA
------------------------------------------------------------------
Add support for MBIGEN save/restore.
Signed-off-by: wanghaibin wanghaibin.wang@huawei.com Signed-off-by: Zenghui Yu yuzenghui@huawei.com Signed-off-by: Dongxu Sun sundongxu3@huawei.com --- arch/arm64/kvm/arch_timer.c | 102 ++++++++++++++++++++++++++++++++-- arch/arm64/kvm/vgic/vgic-v4.c | 10 ++++ include/kvm/arm_arch_timer.h | 12 ++++ include/kvm/arm_vgic.h | 2 + 4 files changed, 120 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 2bcb2f3308f9..58bdb920f43c 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -625,6 +625,36 @@ static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu) enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags); }
+static void kvm_vtimer_mbigen_auto_clr_set(struct kvm_vcpu *vcpu, bool set) +{ + BUG_ON(!vtimer_is_irqbypass()); + + vtimer_mbigen_set_auto_clr(vcpu->cpu, set); +} + +static void kvm_vtimer_mbigen_restore_stat(struct kvm_vcpu *vcpu) +{ + struct vtimer_mbigen_context *mbigen_ctx = vcpu_vtimer_mbigen(vcpu); + u16 vpeid = kvm_vgic_get_vcpu_vpeid(vcpu); + unsigned long flags; + + WARN_ON(!vtimer_is_irqbypass()); + + local_irq_save(flags); + + if (mbigen_ctx->loaded) + goto out; + + vtimer_mbigen_set_vector(vcpu->cpu, vpeid); + + if (mbigen_ctx->active) + vtimer_mbigen_set_active(vcpu->cpu, true); + + mbigen_ctx->loaded = true; +out: + local_irq_restore(flags); +} + void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu) { struct arch_timer_cpu *timer = vcpu_timer(vcpu); @@ -635,19 +665,30 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
get_timer_map(vcpu, &map);
- if (static_branch_likely(&has_gic_active_state)) { - kvm_timer_vcpu_load_gic(map.direct_vtimer); - if (map.direct_ptimer) - kvm_timer_vcpu_load_gic(map.direct_ptimer); + if (vtimer_is_irqbypass()) + kvm_vtimer_mbigen_auto_clr_set(vcpu, false); + + if (!vtimer_is_irqbypass()) { + if (static_branch_likely(&has_gic_active_state)) + kvm_timer_vcpu_load_gic(map.direct_vtimer); + else + kvm_timer_vcpu_load_nogic(vcpu); } else { - kvm_timer_vcpu_load_nogic(vcpu); + kvm_vtimer_mbigen_restore_stat(vcpu); }
+ if (static_branch_likely(&has_gic_active_state) && map.direct_ptimer) + kvm_timer_vcpu_load_gic(map.direct_ptimer); + set_cntvoff(timer_get_offset(map.direct_vtimer));
kvm_timer_unblocking(vcpu);
timer_restore_state(map.direct_vtimer); + + if (vtimer_is_irqbypass()) + kvm_vtimer_mbigen_auto_clr_set(vcpu, true); + if (map.direct_ptimer) timer_restore_state(map.direct_ptimer);
@@ -672,6 +713,29 @@ bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu) kvm_timer_should_fire(ptimer) != plevel; }
+static void kvm_vtimer_mbigen_save_stat(struct kvm_vcpu *vcpu) +{ + struct vtimer_mbigen_context *mbigen_ctx = vcpu_vtimer_mbigen(vcpu); + unsigned long flags; + + WARN_ON(!vtimer_is_irqbypass()); + + local_irq_save(flags); + + if (!mbigen_ctx->loaded) + goto out; + + mbigen_ctx->active = vtimer_mbigen_get_active(vcpu->cpu); + + /* Clear active state in MBIGEN now that we've saved everything. */ + if (mbigen_ctx->active) + vtimer_mbigen_set_active(vcpu->cpu, false); + + mbigen_ctx->loaded = false; +out: + local_irq_restore(flags); +} + void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu) { struct arch_timer_cpu *timer = vcpu_timer(vcpu); @@ -683,7 +747,16 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
get_timer_map(vcpu, &map);
+ if (vtimer_is_irqbypass()) + kvm_vtimer_mbigen_auto_clr_set(vcpu, false); + timer_save_state(map.direct_vtimer); + + if (vtimer_is_irqbypass()) { + kvm_vtimer_mbigen_save_stat(vcpu); + kvm_vtimer_mbigen_auto_clr_set(vcpu, true); + } + if (map.direct_ptimer) timer_save_state(map.direct_ptimer);
@@ -1189,11 +1262,28 @@ bool kvm_arch_timer_get_input_level(int vintid)
static void vtimer_set_active_stat(struct kvm_vcpu *vcpu, int vintid, bool set) { + struct vtimer_mbigen_context *mbigen_ctx = vcpu_vtimer_mbigen(vcpu); + int hwirq = vcpu_vtimer(vcpu)->irq.irq; + + WARN_ON(!vtimer_is_irqbypass() || hwirq != vintid); + + if (!mbigen_ctx->loaded) + mbigen_ctx->active = set; + else + vtimer_mbigen_set_active(vcpu->cpu, set); }
static bool vtimer_get_active_stat(struct kvm_vcpu *vcpu, int vintid) { - return false; + struct vtimer_mbigen_context *mbigen_ctx = vcpu_vtimer_mbigen(vcpu); + int hwirq = vcpu_vtimer(vcpu)->irq.irq; + + WARN_ON(!vtimer_is_irqbypass() || hwirq != vintid); + + if (!mbigen_ctx->loaded) + return mbigen_ctx->active; + else + return vtimer_mbigen_get_active(vcpu->cpu); }
int kvm_vtimer_config(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/vgic/vgic-v4.c b/arch/arm64/kvm/vgic/vgic-v4.c index f6ae1592e430..123c6456b9ff 100644 --- a/arch/arm64/kvm/vgic/vgic-v4.c +++ b/arch/arm64/kvm/vgic/vgic-v4.c @@ -249,6 +249,16 @@ void vgic_v4_configure_vtimer(struct kvm *kvm) vgic_v4_enable_vtimer(vcpu); }
+/** + * kvm_vgic_get_vcpu_vpeid - Get the VCPU's vpeid + * + * The vtimer mbigen needs the vcpu vpeid info which will resident. + */ +u16 kvm_vgic_get_vcpu_vpeid(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vpe_id; +} + /* * Must be called with GICv4.1 and the vPE unmapped, which * indicates the invalidation of any VPT caches associated diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index 44b9bbc2534a..1aabadf567b0 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h @@ -44,6 +44,13 @@ struct arch_timer_context { u32 host_timer_irq_flags; };
+struct vtimer_mbigen_context { + /* Active state in vtimer mbigen */ + bool active; + + bool loaded; +}; + struct timer_map { struct arch_timer_context *direct_vtimer; struct arch_timer_context *direct_ptimer; @@ -58,6 +65,9 @@ struct arch_timer_cpu {
/* Is the timer enabled */ bool enabled; + + /* Info for vtimer mbigen device */ + struct vtimer_mbigen_context mbigen_ctx; };
int kvm_timer_hyp_init(bool); @@ -91,6 +101,8 @@ bool kvm_arch_timer_get_input_level(int vintid); #define vcpu_vtimer(v) (&(v)->arch.timer_cpu.timers[TIMER_VTIMER]) #define vcpu_ptimer(v) (&(v)->arch.timer_cpu.timers[TIMER_PTIMER])
+#define vcpu_vtimer_mbigen(v) (&(v)->arch.timer_cpu.mbigen_ctx) + #define arch_timer_ctx_index(ctx) ((ctx) - vcpu_timer((ctx)->vcpu)->timers)
u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu, diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index e3c7f23a3f48..3390d2497af3 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -41,6 +41,8 @@ struct vtimer_info { void (*set_active_stat)(struct kvm_vcpu *vcpu, int vintid, bool active); };
+u16 kvm_vgic_get_vcpu_vpeid(struct kvm_vcpu *vcpu); + /*The number of lpi translation cache lists*/ #define LPI_TRANS_CACHES_NUM 8