[PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support

classic Classic list List threaded Threaded
26 messages Options
12
Reply | Threaded
Open this post in threaded view
|

[PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support

Suravee Suthikulpanit
CHANGES FROM RFCv4:
==================
(https://lkml.org/lkml/2016/4/7/87)

  * Removing the RFC since I think this is getting ready.
  * Rebase to latest tip.git.
  * Rename vm_deinit to vm_destroy.
  * Replace svm_vcpu_avic_enabled() with kvm_vcpu_apicv_active().
  * Fix the cluster logical APIC ID calculation logic.
  * Misc clean up based on previous review comments.
  * (NEW) Rename kvm_lapic_get_reg to kvm_lapic_get_reg.
  * (NEW) Introduce kvm_x86_ops.apicv_post_state_restore hook.
  * (NEW) Re-factor the VMEXIT handling code and reuse
    it in the apicv_post_state_restore to implement support for
    vmsave/restore, which has been tested migrating:
      - from AVIC mode to non-AVIC mode
      - from non-AVIC mode to AVIC mode
  * (NEW) Add support for the AVIC VMCB clean bit.

GITHUB
======
Latest git tree can be found at:
    http://github.com/ssuthiku/linux.git    avic_part1_v5

OVERVIEW
========
This patch set is the first of the two-part patch series to introduce
the new AMD Advance Virtual Interrupt Controller (AVIC) support.

Basically, SVM AVIC hardware virtualizes local APIC registers of each
vCPU via the virtual APIC (vAPIC) backing page. This allows guest access
to certain APIC registers without the need to emulate the hardware behavior
in the hypervisor. More information about AVIC can be found in the
AMD64 Architecture Programmer’s Manual Volume 2 - System Programming.

  http://support.amd.com/TechDocs/24593.pdf

For SVM AVIC, we extend the existing kvm_amd driver to:
  * Check CPUID to detect AVIC support in the processor
  * Program new fields in VMCB to enable AVIC
  * Introduce new AVIC data structures and add code to manage them
  * Handle two new AVIC #VMEXITs
  * Add new interrupt intjection code using vAPIC backing page
    instead of the existing V_IRQ, V_INTR_PRIO, V_INTR_VECTOR,
    and V_IGN_TPR fields

Currently, this patch series does not enable AVIC by default.
Users can enable SVM AVIC by specifying avic=1 during insmod kvm-amd.

Later, in part 2, we will introduce the IOMMU AVIC support, which
provides speed up for PCI device pass-through use case by allowing
the IOMMU hardware to inject interrupt directly into the guest via
the vAPIC backing page.

PERFORMANCE RESULTS
===================
Currently, AVIC is supported in the AMD family 15h models 6Xh
(Carrizo) processors. Therefore, it is used to collect the
perforamance data shown below.

Generaly, SVM AVIC alone (w/o IOMMU AVIC) should provide speedup for
IPI interrupt since hypervisor does not require VMEXIT to inject
these interrupts. Also, it should speed up the case when hypervisor
wants to inject an interrupt into a running guest by setting the
corresponded IRR bit in the vAPIC backing page and trigger
AVIC_DOORBELL MSR.

IPI PERFORMANCE
===============

* BENCHMARK 1: HACKBENCH
For IPI, I have collected some performance number on 2 and 4 CPU running
hackbech with the following detail:

  hackbench -p -l 100000
  Running in process mode with 10 groups using 40 file descriptors each (== 400 tasks)
  Each sender will pass 100000 messages of 100 bytes

                |    2 vcpus     |    4 vcpus
 ------------------------------------------------
         Vanila |  273.76        |  190.21
  AVIC disabled |  260.51 (~5%)  |  184.40 (~5%)
           AVIC |  248.53 (~10%) |  155.01 (~20%)

OVERALL PERFORMANCE
===================
Enabling AVIC should helps speeding up workloads, which generate
large amount of interrupts. However, it requires additional logics to
maintain AVIC-specific data structures during vCPU load/unload
due to vcpu scheduling.

The goal is to minimize the overhead of AVIC in most cases, so that
we can achieve equivalent or improvement in overall performance when
enabling AVIC.

* BENCHMARK 1: TAR DECOMPRESSION
This test measures the average running time (of 10 runs) of the following
tar decompression command with 1, 2, and 4 vcpus.

   tar xf linux-4.3.3.tar.xz

                |      4 vcpus
 ---------------------------------
         Vanila |  10.26  
  AVIC disabled |  10.10 (~1.5%)
           AVIC |  10.07 (~1.8%)

Note: The unit of result below is in seconds (lower is better).

* BENCHMARK 2: NETPERF w/ virtual network
This test creates a virtual network by setting up bridge and tap device
on the host and pass it into the VM as virtio-net-pci device w/ vhost.
Then it sets up netserver in the host machine, and run netperf
in the VM with following option:

  netperf -H <netserver ip> -l 60 -t TCP_RR -D 2

                |    1 vcpu      
 ------------------------------------
         Vanila |  21623.887
  AVIC disabled |  21538.09 (~-.4%)
           AVIC |  21712.68 (~0.4%)

Note: The unit of result below is trans/sec (higher is better).

Preliminary result of both benchmarks show AVIC performance are slightly
better than the other two cases.

CURRENT UNTESTED USE-CASES
===========================
    - Nested VM

Any feedback and comments are very much appreciated.

Thank you,
Suravee

Radim Krčmář (1):
  KVM: split kvm_vcpu_wake_up from kvm_vcpu_kick

Suravee Suthikulpanit (12):
  KVM: x86: Misc LAPIC changes to expose helper functions
  KVM: x86: Rename kvm_apic_get_reg to kvm_lapic_get_reg
  KVM: x86: Introducing kvm_x86_ops VM init/destroy hooks
  KVM: x86: Introducing kvm_x86_ops VCPU blocking/unblocking hooks
  svm: Introduce new AVIC VMCB registers
  KVM: x86: Detect and Initialize AVIC support
  svm: Add interrupt injection via AVIC
  svm: Add VMEXIT handlers for AVIC
  KVM: x86: Introducing kvm_x86_ops.apicv_post_state_restore
  svm: Do not expose x2APIC when enable AVIC
  svm: Do not intercept CR8 when enable AVIC
  svm: Manage vcpu load/unload when enable AVIC

 arch/x86/include/asm/kvm_host.h |  26 +-
 arch/x86/include/asm/svm.h      |  12 +-
 arch/x86/include/uapi/asm/svm.h |   9 +-
 arch/x86/kvm/ioapic.c           |   2 +-
 arch/x86/kvm/lapic.c            | 187 +++++-------
 arch/x86/kvm/lapic.h            |  38 ++-
 arch/x86/kvm/svm.c              | 660 +++++++++++++++++++++++++++++++++++++++-
 arch/x86/kvm/trace.h            |  57 ++++
 arch/x86/kvm/x86.c              |   7 +
 include/linux/kvm_host.h        |   1 +
 virt/kvm/kvm_main.c             |  19 +-
 11 files changed, 891 insertions(+), 127 deletions(-)

--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 02/13] KVM: x86: Rename kvm_apic_get_reg to kvm_lapic_get_reg

Suravee Suthikulpanit
From: Suravee Suthikulpanit <[hidden email]>

Rename kvm_apic_get_reg to kvm_lapic_get_reg to be consistent with
the existing kvm_lapic_set_reg counterpart.

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
---
 arch/x86/kvm/ioapic.c |  2 +-
 arch/x86/kvm/lapic.c  | 58 +++++++++++++++++++++++++--------------------------
 arch/x86/kvm/lapic.h  |  6 +++---
 3 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index 9db4709..5f42d03 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -443,7 +443,7 @@ static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
  spin_lock(&ioapic->lock);
 
  if (trigger_mode != IOAPIC_LEVEL_TRIG ||
-    kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
+    kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
  continue;
 
  ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index f6f42f6..34c28c0 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -159,7 +159,7 @@ static void recalculate_apic_map(struct kvm *kvm)
  continue;
 
  aid = kvm_apic_id(apic);
- ldr = kvm_apic_get_reg(apic, APIC_LDR);
+ ldr = kvm_lapic_get_reg(apic, APIC_LDR);
 
  if (aid < ARRAY_SIZE(new->phys_map))
  new->phys_map[aid] = apic;
@@ -168,7 +168,7 @@ static void recalculate_apic_map(struct kvm *kvm)
  new->mode |= KVM_APIC_MODE_X2APIC;
  } else if (ldr) {
  ldr = GET_APIC_LOGICAL_ID(ldr);
- if (kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_FLAT)
+ if (kvm_lapic_get_reg(apic, APIC_DFR) == APIC_DFR_FLAT)
  new->mode |= KVM_APIC_MODE_XAPIC_FLAT;
  else
  new->mode |= KVM_APIC_MODE_XAPIC_CLUSTER;
@@ -233,12 +233,12 @@ static inline void kvm_apic_set_x2apic_id(struct kvm_lapic *apic, u8 id)
 
 static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type)
 {
- return !(kvm_apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
+ return !(kvm_lapic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
 }
 
 static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type)
 {
- return kvm_apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
+ return kvm_lapic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
 }
 
 static inline int apic_lvtt_oneshot(struct kvm_lapic *apic)
@@ -525,8 +525,8 @@ static void apic_update_ppr(struct kvm_lapic *apic)
  u32 tpr, isrv, ppr, old_ppr;
  int isr;
 
- old_ppr = kvm_apic_get_reg(apic, APIC_PROCPRI);
- tpr = kvm_apic_get_reg(apic, APIC_TASKPRI);
+ old_ppr = kvm_lapic_get_reg(apic, APIC_PROCPRI);
+ tpr = kvm_lapic_get_reg(apic, APIC_TASKPRI);
  isr = apic_find_highest_isr(apic);
  isrv = (isr != -1) ? isr : 0;
 
@@ -577,7 +577,7 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda)
  if (kvm_apic_broadcast(apic, mda))
  return true;
 
- logical_id = kvm_apic_get_reg(apic, APIC_LDR);
+ logical_id = kvm_lapic_get_reg(apic, APIC_LDR);
 
  if (apic_x2apic_mode(apic))
  return ((logical_id >> 16) == (mda >> 16))
@@ -586,7 +586,7 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda)
  logical_id = GET_APIC_LOGICAL_ID(logical_id);
  mda = GET_APIC_DEST_FIELD(mda);
 
- switch (kvm_apic_get_reg(apic, APIC_DFR)) {
+ switch (kvm_lapic_get_reg(apic, APIC_DFR)) {
  case APIC_DFR_FLAT:
  return (logical_id & mda) != 0;
  case APIC_DFR_CLUSTER:
@@ -594,7 +594,7 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda)
        && (logical_id & mda & 0xf) != 0;
  default:
  apic_debug("Bad DFR vcpu %d: %08x\n",
-   apic->vcpu->vcpu_id, kvm_apic_get_reg(apic, APIC_DFR));
+   apic->vcpu->vcpu_id, kvm_lapic_get_reg(apic, APIC_DFR));
  return false;
  }
 }
@@ -1050,8 +1050,8 @@ EXPORT_SYMBOL_GPL(kvm_apic_set_eoi_accelerated);
 
 static void apic_send_ipi(struct kvm_lapic *apic)
 {
- u32 icr_low = kvm_apic_get_reg(apic, APIC_ICR);
- u32 icr_high = kvm_apic_get_reg(apic, APIC_ICR2);
+ u32 icr_low = kvm_lapic_get_reg(apic, APIC_ICR);
+ u32 icr_high = kvm_lapic_get_reg(apic, APIC_ICR2);
  struct kvm_lapic_irq irq;
 
  irq.vector = icr_low & APIC_VECTOR_MASK;
@@ -1088,7 +1088,7 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
  ASSERT(apic != NULL);
 
  /* if initial count is 0, current count should also be 0 */
- if (kvm_apic_get_reg(apic, APIC_TMICT) == 0 ||
+ if (kvm_lapic_get_reg(apic, APIC_TMICT) == 0 ||
  apic->lapic_timer.period == 0)
  return 0;
 
@@ -1145,13 +1145,13 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
  break;
  case APIC_PROCPRI:
  apic_update_ppr(apic);
- val = kvm_apic_get_reg(apic, offset);
+ val = kvm_lapic_get_reg(apic, offset);
  break;
  case APIC_TASKPRI:
  report_tpr_access(apic, false);
  /* fall thru */
  default:
- val = kvm_apic_get_reg(apic, offset);
+ val = kvm_lapic_get_reg(apic, offset);
  break;
  }
 
@@ -1227,7 +1227,7 @@ static void update_divide_count(struct kvm_lapic *apic)
 {
  u32 tmp1, tmp2, tdcr;
 
- tdcr = kvm_apic_get_reg(apic, APIC_TDCR);
+ tdcr = kvm_lapic_get_reg(apic, APIC_TDCR);
  tmp1 = tdcr & 0xf;
  tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
  apic->divide_count = 0x1 << (tmp2 & 0x7);
@@ -1238,7 +1238,7 @@ static void update_divide_count(struct kvm_lapic *apic)
 
 static void apic_update_lvtt(struct kvm_lapic *apic)
 {
- u32 timer_mode = kvm_apic_get_reg(apic, APIC_LVTT) &
+ u32 timer_mode = kvm_lapic_get_reg(apic, APIC_LVTT) &
  apic->lapic_timer.timer_mode_mask;
 
  if (apic->lapic_timer.timer_mode != timer_mode) {
@@ -1274,7 +1274,7 @@ static void apic_timer_expired(struct kvm_lapic *apic)
 static bool lapic_timer_int_injected(struct kvm_vcpu *vcpu)
 {
  struct kvm_lapic *apic = vcpu->arch.apic;
- u32 reg = kvm_apic_get_reg(apic, APIC_LVTT);
+ u32 reg = kvm_lapic_get_reg(apic, APIC_LVTT);
 
  if (kvm_apic_hw_enabled(apic)) {
  int vec = reg & APIC_VECTOR_MASK;
@@ -1322,7 +1322,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
  if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) {
  /* lapic timer in oneshot or periodic mode */
  now = apic->lapic_timer.timer.base->get_time();
- apic->lapic_timer.period = (u64)kvm_apic_get_reg(apic, APIC_TMICT)
+ apic->lapic_timer.period = (u64)kvm_lapic_get_reg(apic, APIC_TMICT)
     * APIC_BUS_CYCLE_NS * apic->divide_count;
 
  if (!apic->lapic_timer.period)
@@ -1354,7 +1354,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
    "timer initial count 0x%x, period %lldns, "
    "expire @ 0x%016" PRIx64 ".\n", __func__,
    APIC_BUS_CYCLE_NS, ktime_to_ns(now),
-   kvm_apic_get_reg(apic, APIC_TMICT),
+   kvm_lapic_get_reg(apic, APIC_TMICT),
    apic->lapic_timer.period,
    ktime_to_ns(ktime_add_ns(now,
  apic->lapic_timer.period)));
@@ -1443,7 +1443,7 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
  case APIC_SPIV: {
  u32 mask = 0x3ff;
- if (kvm_apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI)
+ if (kvm_lapic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI)
  mask |= APIC_SPIV_DIRECTED_EOI;
  apic_set_spiv(apic, val & mask);
  if (!(val & APIC_SPIV_APIC_ENABLED)) {
@@ -1451,7 +1451,7 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
  u32 lvt_val;
 
  for (i = 0; i < KVM_APIC_LVT_NUM; i++) {
- lvt_val = kvm_apic_get_reg(apic,
+ lvt_val = kvm_lapic_get_reg(apic,
        APIC_LVTT + 0x10 * i);
  kvm_lapic_set_reg(apic, APIC_LVTT + 0x10 * i,
      lvt_val | APIC_LVT_MASKED);
@@ -1646,14 +1646,14 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
  struct kvm_lapic *apic = vcpu->arch.apic;
 
  apic_set_tpr(apic, ((cr8 & 0x0f) << 4)
-     | (kvm_apic_get_reg(apic, APIC_TASKPRI) & 4));
+     | (kvm_lapic_get_reg(apic, APIC_TASKPRI) & 4));
 }
 
 u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
 {
  u64 tpr;
 
- tpr = (u64) kvm_apic_get_reg(vcpu->arch.apic, APIC_TASKPRI);
+ tpr = (u64) kvm_lapic_get_reg(vcpu->arch.apic, APIC_TASKPRI);
 
  return (tpr & 0xf0) >> 4;
 }
@@ -1725,7 +1725,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
  if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_LINT0_REENABLED))
  kvm_lapic_set_reg(apic, APIC_LVT0,
      SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
- apic_manage_nmi_watchdog(apic, kvm_apic_get_reg(apic, APIC_LVT0));
+ apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0));
 
  kvm_lapic_set_reg(apic, APIC_DFR, 0xffffffffU);
  apic_set_spiv(apic, 0xff);
@@ -1785,7 +1785,7 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu)
 
 int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type)
 {
- u32 reg = kvm_apic_get_reg(apic, lvt_type);
+ u32 reg = kvm_lapic_get_reg(apic, lvt_type);
  int vector, mode, trig_mode;
 
  if (kvm_apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) {
@@ -1880,14 +1880,14 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
  apic_update_ppr(apic);
  highest_irr = apic_find_highest_irr(apic);
  if ((highest_irr == -1) ||
-    ((highest_irr & 0xF0) <= kvm_apic_get_reg(apic, APIC_PROCPRI)))
+    ((highest_irr & 0xF0) <= kvm_lapic_get_reg(apic, APIC_PROCPRI)))
  return -1;
  return highest_irr;
 }
 
 int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
 {
- u32 lvt0 = kvm_apic_get_reg(vcpu->arch.apic, APIC_LVT0);
+ u32 lvt0 = kvm_lapic_get_reg(vcpu->arch.apic, APIC_LVT0);
  int r = 0;
 
  if (!kvm_apic_hw_enabled(vcpu->arch.apic))
@@ -1953,7 +1953,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
  apic_update_ppr(apic);
  hrtimer_cancel(&apic->lapic_timer.timer);
  apic_update_lvtt(apic);
- apic_manage_nmi_watchdog(apic, kvm_apic_get_reg(apic, APIC_LVT0));
+ apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0));
  update_divide_count(apic);
  start_apic_timer(apic);
  apic->irr_pending = true;
@@ -2076,7 +2076,7 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
  if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention))
  return;
 
- tpr = kvm_apic_get_reg(apic, APIC_TASKPRI) & 0xff;
+ tpr = kvm_lapic_get_reg(apic, APIC_TASKPRI) & 0xff;
  max_irr = apic_find_highest_irr(apic);
  if (max_irr < 0)
  max_irr = 0;
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index a70cb62..bbe5d12 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -123,9 +123,9 @@ static inline void kvm_lapic_set_irr(int vec, struct kvm_lapic *apic)
  apic->irr_pending = true;
 }
 
-static inline u32 kvm_apic_get_reg(struct kvm_lapic *apic, int reg_off)
+static inline u32 kvm_lapic_get_reg(struct kvm_lapic *apic, int reg_off)
 {
-        return *((u32 *) (apic->regs + reg_off));
+ return *((u32 *) (apic->regs + reg_off));
 }
 
 static inline void kvm_lapic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val)
@@ -198,7 +198,7 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
 
 static inline int kvm_apic_id(struct kvm_lapic *apic)
 {
- return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
+ return (kvm_lapic_get_reg(apic, APIC_ID) >> 24) & 0xff;
 }
 
 bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 03/13] KVM: x86: Introducing kvm_x86_ops VM init/destroy hooks

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
Adding function pointers in struct kvm_x86_ops for processor-specific
layer to provide hooks for when KVM initialize and destroy VM.

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
---
 arch/x86/include/asm/kvm_host.h | 3 +++
 arch/x86/kvm/x86.c              | 5 +++++
 2 files changed, 8 insertions(+)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index b7e3944..353d61b 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -848,6 +848,9 @@ struct kvm_x86_ops {
  bool (*cpu_has_high_real_mode_segbase)(void);
  void (*cpuid_update)(struct kvm_vcpu *vcpu);
 
+ int (*vm_init)(struct kvm *kvm);
+ void (*vm_destroy)(struct kvm *kvm);
+
  /* Create, but do not attach this VCPU */
  struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id);
  void (*vcpu_free)(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 12f33e6..bbdcaa8 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7752,6 +7752,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
  kvm_page_track_init(kvm);
  kvm_mmu_init_vm(kvm);
 
+ if (kvm_x86_ops->vm_init)
+ return kvm_x86_ops->vm_init(kvm);
+
  return 0;
 }
 
@@ -7873,6 +7876,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
  x86_set_memory_region(kvm, IDENTITY_PAGETABLE_PRIVATE_MEMSLOT, 0, 0);
  x86_set_memory_region(kvm, TSS_PRIVATE_MEMSLOT, 0, 0);
  }
+ if (kvm_x86_ops->vm_destroy)
+ kvm_x86_ops->vm_destroy(kvm);
  kvm_iommu_unmap_guest(kvm);
  kfree(kvm->arch.vpic);
  kfree(kvm->arch.vioapic);
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 04/13] KVM: x86: Introducing kvm_x86_ops VCPU blocking/unblocking hooks

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
Adding new function pointer in struct kvm_x86_ops, and calling them
from the kvm_arch_vcpu[blocking/unblocking].

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
Reviewed-by: Paolo Bonzini <[hidden email]>
---
 arch/x86/include/asm/kvm_host.h | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 353d61b..1454859 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -993,6 +993,10 @@ struct kvm_x86_ops {
  */
  int (*pre_block)(struct kvm_vcpu *vcpu);
  void (*post_block)(struct kvm_vcpu *vcpu);
+
+ void (*vcpu_blocking)(struct kvm_vcpu *vcpu);
+ void (*vcpu_unblocking)(struct kvm_vcpu *vcpu);
+
  int (*update_pi_irte)(struct kvm *kvm, unsigned int host_irq,
       uint32_t guest_irq, bool set);
 };
@@ -1344,7 +1348,16 @@ bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq,
 void kvm_set_msi_irq(struct kvm_kernel_irq_routing_entry *e,
      struct kvm_lapic_irq *irq);
 
-static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {}
-static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {}
+static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
+{
+ if (kvm_x86_ops->vcpu_blocking)
+ kvm_x86_ops->vcpu_blocking(vcpu);
+}
+
+static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+ if (kvm_x86_ops->vcpu_unblocking)
+ kvm_x86_ops->vcpu_unblocking(vcpu);
+}
 
 #endif /* _ASM_X86_KVM_HOST_H */
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 05/13] KVM: split kvm_vcpu_wake_up from kvm_vcpu_kick

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
From: Radim Krčmář <[hidden email]>

AVIC has a use for kvm_vcpu_wake_up.

Signed-off-by: Radim Krčmář <[hidden email]>
Tested-by: Suravee Suthikulpanit <[hidden email]>
Reviewed-by: Paolo Bonzini <[hidden email]>
---
 include/linux/kvm_host.h |  1 +
 virt/kvm/kvm_main.c      | 19 +++++++++++++------
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 5276fe0..673749d 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -651,6 +651,7 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn);
 void kvm_vcpu_block(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu);
+void kvm_vcpu_wake_up(struct kvm_vcpu *vcpu);
 void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
 int kvm_vcpu_yield_to(struct kvm_vcpu *target);
 void kvm_vcpu_on_spin(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 4fd482f..5bf20f8 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2071,13 +2071,8 @@ out:
 EXPORT_SYMBOL_GPL(kvm_vcpu_block);
 
 #ifndef CONFIG_S390
-/*
- * Kick a sleeping VCPU, or a guest VCPU in guest mode, into host kernel mode.
- */
-void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
+void kvm_vcpu_wake_up(struct kvm_vcpu *vcpu)
 {
- int me;
- int cpu = vcpu->cpu;
  struct swait_queue_head *wqp;
 
  wqp = kvm_arch_vcpu_wq(vcpu);
@@ -2086,6 +2081,18 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
  ++vcpu->stat.halt_wakeup;
  }
 
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_wake_up);
+
+/*
+ * Kick a sleeping VCPU, or a guest VCPU in guest mode, into host kernel mode.
+ */
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
+{
+ int me;
+ int cpu = vcpu->cpu;
+
+ kvm_vcpu_wake_up(vcpu);
  me = get_cpu();
  if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu))
  if (kvm_arch_vcpu_should_kick(vcpu))
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 08/13] svm: Add interrupt injection via AVIC

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
This patch introduces a new mechanism to inject interrupt using AVIC.
Since VINTR is not supported when enable AVIC, we need to inject
interrupt via APIC backing page instead.

This patch also adds support for AVIC doorbell, which is used by
KVM to signal a running vcpu to check IRR for injected interrupts.

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
---
 arch/x86/kvm/svm.c | 39 +++++++++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 4b00dc6..3a97874 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -71,6 +71,8 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
 #define SVM_FEATURE_DECODE_ASSIST  (1 <<  7)
 #define SVM_FEATURE_PAUSE_FILTER   (1 << 10)
 
+#define SVM_AVIC_DOORBELL 0xc001011b
+
 #define NESTED_EXIT_HOST 0 /* Exit handled on host level */
 #define NESTED_EXIT_DONE 1 /* Exit caused nested vmexit  */
 #define NESTED_EXIT_CONTINUE 2 /* Further checks needed      */
@@ -293,6 +295,17 @@ static inline void avic_update_vapic_bar(struct vcpu_svm *svm, u64 data)
  mark_dirty(svm->vmcb, VMCB_AVIC);
 }
 
+static inline bool avic_vcpu_is_running(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u64 *entry = svm->avic_physical_id_cache;
+
+ if (!entry)
+ return false;
+
+ return (READ_ONCE(*entry) & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK);
+}
+
 static void recalc_intercepts(struct vcpu_svm *svm)
 {
  struct vmcb_control_area *c, *h;
@@ -2865,10 +2878,11 @@ static int clgi_interception(struct vcpu_svm *svm)
  disable_gif(svm);
 
  /* After a CLGI no interrupts should come */
- svm_clear_vintr(svm);
- svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
-
- mark_dirty(svm->vmcb, VMCB_INTR);
+ if (!kvm_vcpu_apicv_active(&svm->vcpu)) {
+ svm_clear_vintr(svm);
+ svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
+ mark_dirty(svm->vmcb, VMCB_INTR);
+ }
 
  return 1;
 }
@@ -3762,6 +3776,7 @@ static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
 {
  struct vmcb_control_area *control;
 
+ /* The following fields are ignored when AVIC is enabled */
  control = &svm->vmcb->control;
  control->int_vector = irq;
  control->int_ctl &= ~V_INTR_PRIO_MASK;
@@ -3840,6 +3855,18 @@ static void svm_sync_pir_to_irr(struct kvm_vcpu *vcpu)
  return;
 }
 
+static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
+{
+ kvm_lapic_set_irr(vec, vcpu->arch.apic);
+ smp_mb__after_atomic();
+
+ if (avic_vcpu_is_running(vcpu))
+ wrmsrl(SVM_AVIC_DOORBELL,
+       __default_cpu_present_to_apicid(vcpu->cpu));
+ else
+ kvm_vcpu_wake_up(vcpu);
+}
+
 static int svm_nmi_allowed(struct kvm_vcpu *vcpu)
 {
  struct vcpu_svm *svm = to_svm(vcpu);
@@ -3894,6 +3921,9 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
 {
  struct vcpu_svm *svm = to_svm(vcpu);
 
+ if (kvm_vcpu_apicv_active(vcpu))
+ return;
+
  /*
  * In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
  * 1, because that's a separate STGI/VMRUN intercept.  The next time we
@@ -4637,6 +4667,7 @@ static struct kvm_x86_ops svm_x86_ops = {
  .sched_in = svm_sched_in,
 
  .pmu_ops = &amd_pmu_ops,
+ .deliver_posted_interrupt = svm_deliver_avic_intr,
 };
 
 static int __init svm_init(void)
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 10/13] KVM: x86: Introducing kvm_x86_ops.apicv_post_state_restore

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
Adding kvm_x86_ops hooks to allow APICv to do post state restore.
This is required to support VM save and restore feature.

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
---
 arch/x86/include/asm/kvm_host.h |  1 +
 arch/x86/kvm/lapic.c            |  2 ++
 arch/x86/kvm/svm.c              | 10 ++++++++++
 3 files changed, 13 insertions(+)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index a87e825..753359e 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1004,6 +1004,7 @@ struct kvm_x86_ops {
 
  int (*update_pi_irte)(struct kvm *kvm, unsigned int host_irq,
       uint32_t guest_irq, bool set);
+ void (*apicv_post_state_restore)(struct kvm_vcpu *vcpu);
 };
 
 struct kvm_arch_async_pf {
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 34c28c0..539675c 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1961,6 +1961,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
  1 : count_vectors(apic->regs + APIC_ISR);
  apic->highest_isr_cache = -1;
  if (vcpu->arch.apicv_active) {
+ if (kvm_x86_ops->apicv_post_state_restore)
+ kvm_x86_ops->apicv_post_state_restore(vcpu);
  kvm_x86_ops->hwapic_irr_update(vcpu,
  apic_find_highest_irr(apic));
  kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 90b34fa..6c1d558 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -4833,6 +4833,15 @@ static void svm_sched_in(struct kvm_vcpu *vcpu, int cpu)
 {
 }
 
+static inline void avic_post_state_restore(struct kvm_vcpu *vcpu)
+{
+ if (avic_handle_apic_id_update(vcpu) != 0)
+ return;
+ if (avic_handle_dfr_update(vcpu) != 0)
+ return;
+ avic_handle_ldr_update(vcpu);
+}
+
 static struct kvm_x86_ops svm_x86_ops = {
  .cpu_has_kvm_support = has_svm,
  .disabled_by_bios = is_disabled,
@@ -4913,6 +4922,7 @@ static struct kvm_x86_ops svm_x86_ops = {
  .sync_pir_to_irr = svm_sync_pir_to_irr,
  .hwapic_irr_update = svm_hwapic_irr_update,
  .hwapic_isr_update = svm_hwapic_isr_update,
+ .apicv_post_state_restore = avic_post_state_restore,
 
  .set_tss_addr = svm_set_tss_addr,
  .get_tdp_level = get_npt_level,
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 13/13] svm: Manage vcpu load/unload when enable AVIC

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
From: Suravee Suthikulpanit <[hidden email]>

When a vcpu is loaded/unloaded to a physical core, we need to update
host physical APIC ID information in the Physical APIC-ID table
accordingly.

Also, when vCPU is blocking/un-blocking (due to halt instruction),
we need to make sure that the is-running bit in set accordingly in the
physical APIC-ID table.

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
Reviewed-by: Radim Krčmář <[hidden email]>
---
 arch/x86/kvm/svm.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 721e514..f903d33 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -35,6 +35,7 @@
 #include <linux/trace_events.h>
 #include <linux/slab.h>
 
+#include <asm/apic.h>
 #include <asm/perf_event.h>
 #include <asm/tlbflush.h>
 #include <asm/desc.h>
@@ -183,6 +184,7 @@ struct vcpu_svm {
  u32 ldr_reg;
  struct page *avic_backing_page;
  u64 *avic_physical_id_cache;
+ bool avic_is_blocking;
 };
 
 #define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFF)
@@ -1315,6 +1317,61 @@ free_avic:
  return err;
 }
 
+/**
+ * This function is called during VCPU halt/unhalt.
+ */
+static int avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
+{
+ u64 entry;
+ int h_physical_id = __default_cpu_present_to_apicid(vcpu->cpu);
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ if (!kvm_vcpu_apicv_active(vcpu))
+ return 0;
+
+ /* ID = 0xff (broadcast), ID > 0xff (reserved) */
+ if (h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)
+ return -EINVAL;
+
+ entry = READ_ONCE(*(svm->avic_physical_id_cache));
+ WARN_ON(is_run == !!(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK));
+
+ entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
+ if (is_run)
+ entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
+ WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
+
+ return 0;
+}
+
+static int avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu, bool is_load)
+{
+ u64 entry;
+ int h_physical_id = __default_cpu_present_to_apicid(cpu);
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ if (!kvm_vcpu_apicv_active(vcpu))
+ return 0;
+
+ /* ID = 0xff (broadcast), ID > 0xff (reserved) */
+ if (h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)
+ return -EINVAL;
+
+ entry = READ_ONCE(*(svm->avic_physical_id_cache));
+ WARN_ON(is_load && (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK));
+
+ entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
+ if (is_load) {
+ entry &= ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
+ entry |= (h_physical_id & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK);
+ if (!svm->avic_is_blocking)
+ entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
+ }
+ WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
+
+ return 0;
+}
+
 static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 {
  struct vcpu_svm *svm = to_svm(vcpu);
@@ -1378,6 +1435,11 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
  goto free_page4;
  }
 
+ /* We initialize this flag to one to make sure that the is_running
+ * bit would be set the first time the vcpu is loaded.
+ */
+ svm->avic_is_blocking = false;
+
  svm->nested.hsave = page_address(hsave_page);
 
  svm->msrpm = page_address(msrpm_pages);
@@ -1454,6 +1516,8 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
  /* This assumes that the kernel never uses MSR_TSC_AUX */
  if (static_cpu_has(X86_FEATURE_RDTSCP))
  wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
+
+ avic_vcpu_load(vcpu, cpu, true);
 }
 
 static void svm_vcpu_put(struct kvm_vcpu *vcpu)
@@ -1461,6 +1525,8 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
  struct vcpu_svm *svm = to_svm(vcpu);
  int i;
 
+ avic_vcpu_load(vcpu, 0, false);
+
  ++vcpu->stat.host_state_reload;
  kvm_load_ldt(svm->host.ldt);
 #ifdef CONFIG_X86_64
@@ -1476,6 +1542,18 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
  wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
 }
 
+static void svm_vcpu_blocking(struct kvm_vcpu *vcpu)
+{
+ to_svm(vcpu)->avic_is_blocking = true;
+ avic_set_running(vcpu, false);
+}
+
+static void svm_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+ to_svm(vcpu)->avic_is_blocking = false;
+ avic_set_running(vcpu, true);
+}
+
 static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
 {
  return to_svm(vcpu)->vmcb->save.rflags;
@@ -4883,6 +4961,8 @@ static struct kvm_x86_ops svm_x86_ops = {
  .prepare_guest_switch = svm_prepare_guest_switch,
  .vcpu_load = svm_vcpu_load,
  .vcpu_put = svm_vcpu_put,
+ .vcpu_blocking = svm_vcpu_blocking,
+ .vcpu_unblocking = svm_vcpu_unblocking,
 
  .update_bp_intercept = update_bp_intercept,
  .get_msr = svm_get_msr,
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 12/13] svm: Do not intercept CR8 when enable AVIC

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
When enable AVIC:
    * Do not intercept CR8 since this should be handled by AVIC HW.
    * Also, we don't need to sync cr8/V_TPR and APIC backing page.

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
---
 arch/x86/kvm/svm.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index d35fd61e..721e514 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1092,7 +1092,8 @@ static void init_vmcb(struct vcpu_svm *svm)
  set_cr_intercept(svm, INTERCEPT_CR0_WRITE);
  set_cr_intercept(svm, INTERCEPT_CR3_WRITE);
  set_cr_intercept(svm, INTERCEPT_CR4_WRITE);
- set_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+ if (!kvm_vcpu_apicv_active(&svm->vcpu))
+ set_cr_intercept(svm, INTERCEPT_CR8_WRITE);
 
  set_dr_intercepts(svm);
 
@@ -4077,11 +4078,17 @@ static void svm_set_irq(struct kvm_vcpu *vcpu)
  SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR;
 }
 
+static inline bool svm_in_nested_interrupt_shadow(struct kvm_vcpu *vcpu)
+{
+ return is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK);
+}
+
 static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
 {
  struct vcpu_svm *svm = to_svm(vcpu);
 
- if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK))
+ if (svm_in_nested_interrupt_shadow(vcpu) ||
+    kvm_vcpu_apicv_active(vcpu))
  return;
 
  clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
@@ -4254,7 +4261,7 @@ static inline void sync_cr8_to_lapic(struct kvm_vcpu *vcpu)
 {
  struct vcpu_svm *svm = to_svm(vcpu);
 
- if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK))
+ if (svm_in_nested_interrupt_shadow(vcpu))
  return;
 
  if (!is_cr_intercept(svm, INTERCEPT_CR8_WRITE)) {
@@ -4268,7 +4275,8 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu)
  struct vcpu_svm *svm = to_svm(vcpu);
  u64 cr8;
 
- if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK))
+ if (svm_in_nested_interrupt_shadow(vcpu) ||
+    kvm_vcpu_apicv_active(vcpu))
  return;
 
  cr8 = kvm_get_cr8(vcpu);
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 11/13] svm: Do not expose x2APIC when enable AVIC

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
From: Suravee Suthikulpanit <[hidden email]>

Since AVIC only virtualizes xAPIC hardware for the guest, this patch
disable x2APIC support in guest CPUID.

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
---
 arch/x86/kvm/svm.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 6c1d558..d35fd61e 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -4571,14 +4571,26 @@ static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio)
 static void svm_cpuid_update(struct kvm_vcpu *vcpu)
 {
  struct vcpu_svm *svm = to_svm(vcpu);
+ struct kvm_cpuid_entry2 *entry;
 
  /* Update nrips enabled cache */
  svm->nrips_enabled = !!guest_cpuid_has_nrips(&svm->vcpu);
+
+ if (!kvm_vcpu_apicv_active(vcpu))
+ return;
+
+ entry = kvm_find_cpuid_entry(vcpu, 1, 0);
+ if (entry)
+ entry->ecx &= ~bit(X86_FEATURE_X2APIC);
 }
 
 static void svm_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
 {
  switch (func) {
+ case 0x1:
+ if (avic)
+ entry->ecx &= ~bit(X86_FEATURE_X2APIC);
+ break;
  case 0x80000001:
  if (nested)
  entry->ecx |= (1 << 2); /* Set SVM bit */
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 09/13] svm: Add VMEXIT handlers for AVIC

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
From: Suravee Suthikulpanit <[hidden email]>

This patch introduces VMEXIT handlers, avic_incomplete_ipi_interception()
and avic_unaccelerated_access_interception() along with two trace points
(trace_kvm_avic_incomplete_ipi and trace_kvm_avic_unaccelerated_access).

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
---
 arch/x86/include/asm/kvm_host.h |   1 +
 arch/x86/include/uapi/asm/svm.h |   9 +-
 arch/x86/kvm/lapic.h            |   3 +
 arch/x86/kvm/svm.c              | 279 ++++++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/trace.h            |  57 ++++++++
 arch/x86/kvm/x86.c              |   2 +
 6 files changed, 350 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 1ff2d46..a87e825 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -776,6 +776,7 @@ struct kvm_arch {
  bool disabled_lapic_found;
 
  /* Struct members for AVIC */
+ u32 ldr_mode;
  struct page *avic_logical_id_table_page;
  struct page *avic_physical_id_table_page;
 };
diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
index 8a4add8..b9e9bb2 100644
--- a/arch/x86/include/uapi/asm/svm.h
+++ b/arch/x86/include/uapi/asm/svm.h
@@ -73,6 +73,8 @@
 #define SVM_EXIT_MWAIT_COND    0x08c
 #define SVM_EXIT_XSETBV        0x08d
 #define SVM_EXIT_NPF           0x400
+#define SVM_EXIT_AVIC_INCOMPLETE_IPI 0x401
+#define SVM_EXIT_AVIC_UNACCELERATED_ACCESS 0x402
 
 #define SVM_EXIT_ERR           -1
 
@@ -107,8 +109,10 @@
  { SVM_EXIT_SMI,         "smi" }, \
  { SVM_EXIT_INIT,        "init" }, \
  { SVM_EXIT_VINTR,       "vintr" }, \
+ { SVM_EXIT_CR0_SEL_WRITE, "cr0_sel_write" }, \
  { SVM_EXIT_CPUID,       "cpuid" }, \
  { SVM_EXIT_INVD,        "invd" }, \
+ { SVM_EXIT_PAUSE,       "pause" }, \
  { SVM_EXIT_HLT,         "hlt" }, \
  { SVM_EXIT_INVLPG,      "invlpg" }, \
  { SVM_EXIT_INVLPGA,     "invlpga" }, \
@@ -127,7 +131,10 @@
  { SVM_EXIT_MONITOR,     "monitor" }, \
  { SVM_EXIT_MWAIT,       "mwait" }, \
  { SVM_EXIT_XSETBV,      "xsetbv" }, \
- { SVM_EXIT_NPF,         "npf" }
+ { SVM_EXIT_NPF,         "npf" }, \
+ { SVM_EXIT_RSM,         "rsm" }, \
+ { SVM_EXIT_AVIC_INCOMPLETE_IPI, "avic_incomplete_ipi" }, \
+ { SVM_EXIT_AVIC_UNACCELERATED_ACCESS,   "avic_unaccelerated_access" }
 
 
 #endif /* _UAPI__SVM_H */
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index bbe5d12..891c6da 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -9,6 +9,9 @@
 #define KVM_APIC_SIPI 1
 #define KVM_APIC_LVT_NUM 6
 
+#define KVM_APIC_SHORT_MASK 0xc0000
+#define KVM_APIC_DEST_MASK 0x800
+
 struct kvm_timer {
  struct hrtimer timer;
  s64 period; /* unit: ns */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 3a97874..90b34fa 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -91,6 +91,10 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
  */
 #define AVIC_MAX_PHYSICAL_ID_COUNT 255
 
+#define AVIC_UNACCEL_ACCESS_WRITE_MASK 1
+#define AVIC_UNACCEL_ACCESS_OFFSET_MASK 0xFF0
+#define AVIC_UNACCEL_ACCESS_VECTOR_MASK 0xFFFFFFFF
+
 static bool erratum_383_found __read_mostly;
 
 static const u32 host_save_user_msrs[] = {
@@ -176,6 +180,7 @@ struct vcpu_svm {
  /* cached guest cpuid flags for faster access */
  bool nrips_enabled : 1;
 
+ u32 ldr_reg;
  struct page *avic_backing_page;
  u64 *avic_physical_id_cache;
 };
@@ -3491,6 +3496,278 @@ static int mwait_interception(struct vcpu_svm *svm)
  return nop_interception(svm);
 }
 
+enum avic_ipi_failure_cause {
+ AVIC_IPI_FAILURE_INVALID_INT_TYPE,
+ AVIC_IPI_FAILURE_TARGET_NOT_RUNNING,
+ AVIC_IPI_FAILURE_INVALID_TARGET,
+ AVIC_IPI_FAILURE_INVALID_BACKING_PAGE,
+};
+
+static int avic_incomplete_ipi_interception(struct vcpu_svm *svm)
+{
+ u32 icrh = svm->vmcb->control.exit_info_1 >> 32;
+ u32 icrl = svm->vmcb->control.exit_info_1;
+ u32 id = svm->vmcb->control.exit_info_2 >> 32;
+ u32 index = svm->vmcb->control.exit_info_2 && 0xFF;
+ struct kvm_lapic *apic = svm->vcpu.arch.apic;
+
+ trace_kvm_avic_incomplete_ipi(svm->vcpu.vcpu_id, icrh, icrl, id, index);
+
+ switch (id) {
+ case AVIC_IPI_FAILURE_INVALID_INT_TYPE:
+ /*
+ * AVIC hardware handles the generation of
+ * IPIs when the specified Message Type is Fixed
+ * (also known as fixed delivery mode) and
+ * the Trigger Mode is edge-triggered. The hardware
+ * also supports self and broadcast delivery modes
+ * specified via the Destination Shorthand(DSH)
+ * field of the ICRL. Logical and physical APIC ID
+ * formats are supported. All other IPI types cause
+ * a #VMEXIT, which needs to emulated.
+ */
+ kvm_lapic_reg_write(apic, APIC_ICR2, icrh);
+ kvm_lapic_reg_write(apic, APIC_ICR, icrl);
+ break;
+ case AVIC_IPI_FAILURE_TARGET_NOT_RUNNING: {
+ int i;
+ struct kvm_vcpu *vcpu;
+ struct kvm *kvm = svm->vcpu.kvm;
+ struct kvm_lapic *apic = svm->vcpu.arch.apic;
+
+ /*
+ * At this point, we expect that the AVIC HW has already
+ * set the appropriate IRR bits on the valid target
+ * vcpus. So, we just need to kick the appropriate vcpu.
+ */
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ bool m = kvm_apic_match_dest(vcpu, apic,
+     icrl & KVM_APIC_SHORT_MASK,
+     GET_APIC_DEST_FIELD(icrh),
+     icrl & KVM_APIC_DEST_MASK);
+
+ if (m && !avic_vcpu_is_running(vcpu))
+ kvm_vcpu_wake_up(vcpu);
+ }
+ break;
+ }
+ case AVIC_IPI_FAILURE_INVALID_TARGET:
+ break;
+ case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE:
+ WARN_ONCE(1, "Invalid backing page\n");
+ break;
+ default:
+ pr_err("Unknown IPI interception\n");
+ }
+
+ return 1;
+}
+
+static u32 *avic_get_logical_id_entry(struct kvm_vcpu *vcpu, u32 ldr, bool flat)
+{
+ struct kvm_arch *vm_data = &vcpu->kvm->arch;
+ int index;
+ u32 *logical_apic_id_table;
+ int dlid = GET_APIC_LOGICAL_ID(ldr);
+
+ if (!dlid)
+ return NULL;
+
+ if (flat) { /* flat */
+ index = ffs(dlid) - 1;
+ if (index > 7)
+ return NULL;
+ } else { /* cluster */
+ int cluster = (dlid & 0xf0) >> 4;
+ int apic = ffs(dlid & 0x0f) - 1;
+
+ if ((apic < 0) || (apic > 7) ||
+    (cluster >= 0xf))
+ return NULL;
+ index = (cluster << 2) + apic;
+ }
+
+ logical_apic_id_table = (u32 *) page_address(vm_data->avic_logical_id_table_page);
+
+ return &logical_apic_id_table[index];
+}
+
+static int avic_ldr_write(struct kvm_vcpu *vcpu, u8 g_physical_id, u32 ldr,
+  bool valid)
+{
+ bool flat;
+ u32 *entry, new_entry;
+
+ flat = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR) == APIC_DFR_FLAT;
+ entry = avic_get_logical_id_entry(vcpu, ldr, flat);
+ if (!entry)
+ return -EINVAL;
+
+ new_entry = READ_ONCE(*entry);
+ new_entry &= ~AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK;
+ new_entry |= (g_physical_id & AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK);
+ if (valid)
+ new_entry |= AVIC_LOGICAL_ID_ENTRY_VALID_MASK;
+ else
+ new_entry &= ~AVIC_LOGICAL_ID_ENTRY_VALID_MASK;
+ WRITE_ONCE(*entry, new_entry);
+
+ return 0;
+}
+
+static int avic_handle_ldr_update(struct kvm_vcpu *vcpu)
+{
+ int ret;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u32 ldr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_LDR);
+
+ if (!ldr)
+ return 1;
+
+ ret = avic_ldr_write(vcpu, vcpu->vcpu_id, ldr, true);
+ if (ret && svm->ldr_reg) {
+ avic_ldr_write(vcpu, 0, svm->ldr_reg, false);
+ svm->ldr_reg = 0;
+ } else {
+ svm->ldr_reg = ldr;
+ }
+ return ret;
+}
+
+static int avic_handle_apic_id_update(struct kvm_vcpu *vcpu)
+{
+ u64 *old, *new;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u32 apic_id_reg = kvm_lapic_get_reg(vcpu->arch.apic, APIC_ID);
+ u32 id = (apic_id_reg >> 24) & 0xff;
+
+ if (vcpu->vcpu_id == id)
+ return 0;
+
+ old = avic_get_physical_id_entry(vcpu, vcpu->vcpu_id);
+ new = avic_get_physical_id_entry(vcpu, id);
+ if (!new || !old)
+ return 1;
+
+ /* We need to move physical_id_entry to new offset */
+ *new = *old;
+ *old = 0ULL;
+ to_svm(vcpu)->avic_physical_id_cache = new;
+
+ /*
+ * Also update the guest physical APIC ID in the logical
+ * APIC ID table entry if already setup the LDR.
+ */
+ if (svm->ldr_reg)
+ avic_handle_ldr_update(vcpu);
+
+ return 0;
+}
+
+static int avic_handle_dfr_update(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct kvm_arch *vm_data = &vcpu->kvm->arch;
+ u32 dfr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_DFR);
+ u32 mod = (dfr >> 28) & 0xf;
+
+ /*
+ * We assume that all local APICs are using the same type.
+ * If this changes, we need to flush the AVIC logical
+ * APID id table.
+ */
+ if (vm_data->ldr_mode == mod)
+ return 0;
+
+ clear_page(page_address(vm_data->avic_logical_id_table_page));
+ vm_data->ldr_mode = mod;
+
+ if (svm->ldr_reg)
+ avic_handle_ldr_update(vcpu);
+ return 0;
+}
+
+static int avic_unaccel_trap_write(struct vcpu_svm *svm)
+{
+ struct kvm_lapic *apic = svm->vcpu.arch.apic;
+ u32 offset = svm->vmcb->control.exit_info_1 &
+ AVIC_UNACCEL_ACCESS_OFFSET_MASK;
+
+ switch (offset) {
+ case APIC_ID:
+ if (avic_handle_apic_id_update(&svm->vcpu))
+ return 0;
+ break;
+ case APIC_LDR:
+ if (avic_handle_ldr_update(&svm->vcpu))
+ return 0;
+ break;
+ case APIC_DFR:
+ avic_handle_dfr_update(&svm->vcpu);
+ break;
+ default:
+ break;
+ }
+
+ kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset));
+
+ return 1;
+}
+
+static bool is_avic_unaccelerated_access_trap(u32 offset)
+{
+ bool ret = false;
+
+ switch (offset) {
+ case APIC_ID:
+ case APIC_EOI:
+ case APIC_RRR:
+ case APIC_LDR:
+ case APIC_DFR:
+ case APIC_SPIV:
+ case APIC_ESR:
+ case APIC_ICR:
+ case APIC_LVTT:
+ case APIC_LVTTHMR:
+ case APIC_LVTPC:
+ case APIC_LVT0:
+ case APIC_LVT1:
+ case APIC_LVTERR:
+ case APIC_TMICT:
+ case APIC_TDCR:
+ ret = true;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static int avic_unaccelerated_access_interception(struct vcpu_svm *svm)
+{
+ int ret = 0;
+ u32 offset = svm->vmcb->control.exit_info_1 &
+     AVIC_UNACCEL_ACCESS_OFFSET_MASK;
+ u32 vector = svm->vmcb->control.exit_info_2 &
+     AVIC_UNACCEL_ACCESS_VECTOR_MASK;
+ bool write = (svm->vmcb->control.exit_info_1 >> 32) &
+     AVIC_UNACCEL_ACCESS_WRITE_MASK;
+ bool trap = is_avic_unaccelerated_access_trap(offset);
+
+ trace_kvm_avic_unaccelerated_access(svm->vcpu.vcpu_id, offset,
+    trap, write, vector);
+ if (trap) {
+ /* Handling Trap */
+ WARN_ONCE(!write, "svm: Handling trap read.\n");
+ ret = avic_unaccel_trap_write(svm);
+ } else {
+ /* Handling Fault */
+ ret = (emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE);
+ }
+
+ return ret;
+}
+
 static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
  [SVM_EXIT_READ_CR0] = cr_interception,
  [SVM_EXIT_READ_CR3] = cr_interception,
@@ -3554,6 +3831,8 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
  [SVM_EXIT_XSETBV] = xsetbv_interception,
  [SVM_EXIT_NPF] = pf_interception,
  [SVM_EXIT_RSM]                          = emulate_on_interception,
+ [SVM_EXIT_AVIC_INCOMPLETE_IPI] = avic_incomplete_ipi_interception,
+ [SVM_EXIT_AVIC_UNACCELERATED_ACCESS] = avic_unaccelerated_access_interception,
 };
 
 static void dump_vmcb(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index b72743c..8de9250 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -1291,6 +1291,63 @@ TRACE_EVENT(kvm_hv_stimer_cleanup,
   __entry->vcpu_id, __entry->timer_index)
 );
 
+/*
+ * Tracepoint for AMD AVIC
+ */
+TRACE_EVENT(kvm_avic_incomplete_ipi,
+    TP_PROTO(u32 vcpu, u32 icrh, u32 icrl, u32 id, u32 index),
+    TP_ARGS(vcpu, icrh, icrl, id, index),
+
+ TP_STRUCT__entry(
+ __field(u32, vcpu)
+ __field(u32, icrh)
+ __field(u32, icrl)
+ __field(u32, id)
+ __field(u32, index)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu = vcpu;
+ __entry->icrh = icrh;
+ __entry->icrl = icrl;
+ __entry->id = id;
+ __entry->index = index;
+ ),
+
+ TP_printk("vcpu=%u, icrh:icrl=%#010x:%08x, id=%u, index=%u\n",
+  __entry->vcpu, __entry->icrh, __entry->icrl,
+  __entry->id, __entry->index)
+);
+
+TRACE_EVENT(kvm_avic_unaccelerated_access,
+    TP_PROTO(u32 vcpu, u32 offset, bool ft, bool rw, u32 vec),
+    TP_ARGS(vcpu, offset, ft, rw, vec),
+
+ TP_STRUCT__entry(
+ __field(u32, vcpu)
+ __field(u32, offset)
+ __field(bool, ft)
+ __field(bool, rw)
+ __field(u32, vec)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu = vcpu;
+ __entry->offset = offset;
+ __entry->ft = ft;
+ __entry->rw = rw;
+ __entry->vec = vec;
+ ),
+
+ TP_printk("vcpu=%u, offset=%#x(%s), %s, %s, vec=%#x\n",
+  __entry->vcpu,
+  __entry->offset,
+  __print_symbolic(__entry->offset, kvm_trace_symbol_apic),
+  __entry->ft ? "trap" : "fault",
+  __entry->rw ? "write" : "read",
+  __entry->vec)
+);
+
 #endif /* _TRACE_KVM_H */
 
 #undef TRACE_INCLUDE_PATH
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index bbdcaa8..336a2b9 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8434,3 +8434,5 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_write_tsc_offset);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ple_window);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pml_full);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pi_irte_update);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_unaccelerated_access);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_incomplete_ipi);
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 01/13] KVM: x86: Misc LAPIC changes to expose helper functions

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
Exporting LAPIC utility functions and macros for re-use in SVM code.

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
Reviewed-by: Radim Krčmář <[hidden email]>
---
 arch/x86/kvm/lapic.c | 127 +++++++++++++++++++++------------------------------
 arch/x86/kvm/lapic.h |  29 ++++++++++++
 2 files changed, 82 insertions(+), 74 deletions(-)

diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 1a2da0e..f6f42f6 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -59,9 +59,8 @@
 /* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
 #define apic_debug(fmt, arg...)
 
-#define APIC_LVT_NUM 6
 /* 14 is the version for Xeon and Pentium 8.4.8*/
-#define APIC_VERSION (0x14UL | ((APIC_LVT_NUM - 1) << 16))
+#define APIC_VERSION (0x14UL | ((KVM_APIC_LVT_NUM - 1) << 16))
 #define LAPIC_MMIO_LENGTH (1 << 12)
 /* followed define is not in apicdef.h */
 #define APIC_SHORT_MASK 0xc0000
@@ -73,14 +72,6 @@
 #define APIC_BROADCAST 0xFF
 #define X2APIC_BROADCAST 0xFFFFFFFFul
 
-#define VEC_POS(v) ((v) & (32 - 1))
-#define REG_POS(v) (((v) >> 5) << 4)
-
-static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val)
-{
- *((u32 *) (apic->regs + reg_off)) = val;
-}
-
 static inline int apic_test_vector(int vec, void *bitmap)
 {
  return test_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
@@ -94,11 +85,6 @@ bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector)
  apic_test_vector(vector, apic->regs + APIC_IRR);
 }
 
-static inline void apic_set_vector(int vec, void *bitmap)
-{
- set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
-}
-
 static inline void apic_clear_vector(int vec, void *bitmap)
 {
  clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
@@ -212,7 +198,7 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
 {
  bool enabled = val & APIC_SPIV_APIC_ENABLED;
 
- apic_set_reg(apic, APIC_SPIV, val);
+ kvm_lapic_set_reg(apic, APIC_SPIV, val);
 
  if (enabled != apic->sw_enabled) {
  apic->sw_enabled = enabled;
@@ -226,13 +212,13 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
 
 static inline void kvm_apic_set_id(struct kvm_lapic *apic, u8 id)
 {
- apic_set_reg(apic, APIC_ID, id << 24);
+ kvm_lapic_set_reg(apic, APIC_ID, id << 24);
  recalculate_apic_map(apic->vcpu->kvm);
 }
 
 static inline void kvm_apic_set_ldr(struct kvm_lapic *apic, u32 id)
 {
- apic_set_reg(apic, APIC_LDR, id);
+ kvm_lapic_set_reg(apic, APIC_LDR, id);
  recalculate_apic_map(apic->vcpu->kvm);
 }
 
@@ -240,8 +226,8 @@ static inline void kvm_apic_set_x2apic_id(struct kvm_lapic *apic, u8 id)
 {
  u32 ldr = ((id >> 4) << 16) | (1 << (id & 0xf));
 
- apic_set_reg(apic, APIC_ID, id << 24);
- apic_set_reg(apic, APIC_LDR, ldr);
+ kvm_lapic_set_reg(apic, APIC_ID, id << 24);
+ kvm_lapic_set_reg(apic, APIC_LDR, ldr);
  recalculate_apic_map(apic->vcpu->kvm);
 }
 
@@ -287,10 +273,10 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu)
  feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0);
  if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31))))
  v |= APIC_LVR_DIRECTED_EOI;
- apic_set_reg(apic, APIC_LVR, v);
+ kvm_lapic_set_reg(apic, APIC_LVR, v);
 }
 
-static const unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
+static const unsigned int apic_lvt_mask[KVM_APIC_LVT_NUM] = {
  LVT_MASK ,      /* part LVTT mask, timer mode mask added at runtime */
  LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */
  LVT_MASK | APIC_MODE_MASK, /* LVTPC */
@@ -349,16 +335,6 @@ void kvm_apic_update_irr(struct kvm_vcpu *vcpu, u32 *pir)
 }
 EXPORT_SYMBOL_GPL(kvm_apic_update_irr);
 
-static inline void apic_set_irr(int vec, struct kvm_lapic *apic)
-{
- apic_set_vector(vec, apic->regs + APIC_IRR);
- /*
- * irr_pending must be true if any interrupt is pending; set it after
- * APIC_IRR to avoid race with apic_clear_irr
- */
- apic->irr_pending = true;
-}
-
 static inline int apic_search_irr(struct kvm_lapic *apic)
 {
  return find_highest_vector(apic->regs + APIC_IRR);
@@ -563,7 +539,7 @@ static void apic_update_ppr(struct kvm_lapic *apic)
    apic, ppr, isr, isrv);
 
  if (old_ppr != ppr) {
- apic_set_reg(apic, APIC_PROCPRI, ppr);
+ kvm_lapic_set_reg(apic, APIC_PROCPRI, ppr);
  if (ppr < old_ppr)
  kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
  }
@@ -571,7 +547,7 @@ static void apic_update_ppr(struct kvm_lapic *apic)
 
 static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
 {
- apic_set_reg(apic, APIC_TASKPRI, tpr);
+ kvm_lapic_set_reg(apic, APIC_TASKPRI, tpr);
  apic_update_ppr(apic);
 }
 
@@ -668,6 +644,7 @@ bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
  return false;
  }
 }
+EXPORT_SYMBOL_GPL(kvm_apic_match_dest);
 
 int kvm_vector_to_index(u32 vector, u32 dest_vcpus,
        const unsigned long *bitmap, u32 bitmap_size)
@@ -921,7 +898,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
 
  if (apic_test_vector(vector, apic->regs + APIC_TMR) != !!trig_mode) {
  if (trig_mode)
- apic_set_vector(vector, apic->regs + APIC_TMR);
+ kvm_lapic_set_vector(vector, apic->regs + APIC_TMR);
  else
  apic_clear_vector(vector, apic->regs + APIC_TMR);
  }
@@ -929,7 +906,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
  if (vcpu->arch.apicv_active)
  kvm_x86_ops->deliver_posted_interrupt(vcpu, vector);
  else {
- apic_set_irr(vector, apic);
+ kvm_lapic_set_irr(vector, apic);
 
  kvm_make_request(KVM_REQ_EVENT, vcpu);
  kvm_vcpu_kick(vcpu);
@@ -1186,7 +1163,7 @@ static inline struct kvm_lapic *to_lapic(struct kvm_io_device *dev)
  return container_of(dev, struct kvm_lapic, dev);
 }
 
-static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
+int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
  void *data)
 {
  unsigned char alignment = offset & 0xf;
@@ -1223,6 +1200,7 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
  }
  return 0;
 }
+EXPORT_SYMBOL_GPL(kvm_lapic_reg_read);
 
 static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr)
 {
@@ -1240,7 +1218,7 @@ static int apic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
  if (!apic_mmio_in_range(apic, address))
  return -EOPNOTSUPP;
 
- apic_reg_read(apic, offset, len, data);
+ kvm_lapic_reg_read(apic, offset, len, data);
 
  return 0;
 }
@@ -1425,7 +1403,7 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
  }
 }
 
-static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
+int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 {
  int ret = 0;
 
@@ -1457,7 +1435,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
  case APIC_DFR:
  if (!apic_x2apic_mode(apic)) {
- apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
+ kvm_lapic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
  recalculate_apic_map(apic->vcpu->kvm);
  } else
  ret = 1;
@@ -1472,10 +1450,10 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
  int i;
  u32 lvt_val;
 
- for (i = 0; i < APIC_LVT_NUM; i++) {
+ for (i = 0; i < KVM_APIC_LVT_NUM; i++) {
  lvt_val = kvm_apic_get_reg(apic,
        APIC_LVTT + 0x10 * i);
- apic_set_reg(apic, APIC_LVTT + 0x10 * i,
+ kvm_lapic_set_reg(apic, APIC_LVTT + 0x10 * i,
      lvt_val | APIC_LVT_MASKED);
  }
  apic_update_lvtt(apic);
@@ -1486,14 +1464,14 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
  }
  case APIC_ICR:
  /* No delay here, so we always clear the pending bit */
- apic_set_reg(apic, APIC_ICR, val & ~(1 << 12));
+ kvm_lapic_set_reg(apic, APIC_ICR, val & ~(1 << 12));
  apic_send_ipi(apic);
  break;
 
  case APIC_ICR2:
  if (!apic_x2apic_mode(apic))
  val &= 0xff000000;
- apic_set_reg(apic, APIC_ICR2, val);
+ kvm_lapic_set_reg(apic, APIC_ICR2, val);
  break;
 
  case APIC_LVT0:
@@ -1507,7 +1485,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
  val |= APIC_LVT_MASKED;
 
  val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4];
- apic_set_reg(apic, reg, val);
+ kvm_lapic_set_reg(apic, reg, val);
 
  break;
 
@@ -1515,7 +1493,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
  if (!kvm_apic_sw_enabled(apic))
  val |= APIC_LVT_MASKED;
  val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask);
- apic_set_reg(apic, APIC_LVTT, val);
+ kvm_lapic_set_reg(apic, APIC_LVTT, val);
  apic_update_lvtt(apic);
  break;
 
@@ -1524,14 +1502,14 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
  break;
 
  hrtimer_cancel(&apic->lapic_timer.timer);
- apic_set_reg(apic, APIC_TMICT, val);
+ kvm_lapic_set_reg(apic, APIC_TMICT, val);
  start_apic_timer(apic);
  break;
 
  case APIC_TDCR:
  if (val & 4)
  apic_debug("KVM_WRITE:TDCR %x\n", val);
- apic_set_reg(apic, APIC_TDCR, val);
+ kvm_lapic_set_reg(apic, APIC_TDCR, val);
  update_divide_count(apic);
  break;
 
@@ -1544,7 +1522,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
  case APIC_SELF_IPI:
  if (apic_x2apic_mode(apic)) {
- apic_reg_write(apic, APIC_ICR, 0x40000 | (val & 0xff));
+ kvm_lapic_reg_write(apic, APIC_ICR, 0x40000 | (val & 0xff));
  } else
  ret = 1;
  break;
@@ -1556,6 +1534,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
  apic_debug("Local APIC Write to read-only register %x\n", reg);
  return ret;
 }
+EXPORT_SYMBOL_GPL(kvm_lapic_reg_write);
 
 static int apic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
     gpa_t address, int len, const void *data)
@@ -1585,14 +1564,14 @@ static int apic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
  apic_debug("%s: offset 0x%x with length 0x%x, and value is "
    "0x%x\n", __func__, offset, len, val);
 
- apic_reg_write(apic, offset & 0xff0, val);
+ kvm_lapic_reg_write(apic, offset & 0xff0, val);
 
  return 0;
 }
 
 void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu)
 {
- apic_reg_write(vcpu->arch.apic, APIC_EOI, 0);
+ kvm_lapic_reg_write(vcpu->arch.apic, APIC_EOI, 0);
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi);
 
@@ -1604,10 +1583,10 @@ void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset)
  /* hw has done the conditional check and inst decode */
  offset &= 0xff0;
 
- apic_reg_read(vcpu->arch.apic, offset, 4, &val);
+ kvm_lapic_reg_read(vcpu->arch.apic, offset, 4, &val);
 
  /* TODO: optimize to just emulate side effect w/o one more write */
- apic_reg_write(vcpu->arch.apic, offset, val);
+ kvm_lapic_reg_write(vcpu->arch.apic, offset, val);
 }
 EXPORT_SYMBOL_GPL(kvm_apic_write_nodecode);
 
@@ -1740,28 +1719,28 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
  kvm_apic_set_id(apic, vcpu->vcpu_id);
  kvm_apic_set_version(apic->vcpu);
 
- for (i = 0; i < APIC_LVT_NUM; i++)
- apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
+ for (i = 0; i < KVM_APIC_LVT_NUM; i++)
+ kvm_lapic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
  apic_update_lvtt(apic);
  if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_LINT0_REENABLED))
- apic_set_reg(apic, APIC_LVT0,
+ kvm_lapic_set_reg(apic, APIC_LVT0,
      SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
  apic_manage_nmi_watchdog(apic, kvm_apic_get_reg(apic, APIC_LVT0));
 
- apic_set_reg(apic, APIC_DFR, 0xffffffffU);
+ kvm_lapic_set_reg(apic, APIC_DFR, 0xffffffffU);
  apic_set_spiv(apic, 0xff);
- apic_set_reg(apic, APIC_TASKPRI, 0);
+ kvm_lapic_set_reg(apic, APIC_TASKPRI, 0);
  if (!apic_x2apic_mode(apic))
  kvm_apic_set_ldr(apic, 0);
- apic_set_reg(apic, APIC_ESR, 0);
- apic_set_reg(apic, APIC_ICR, 0);
- apic_set_reg(apic, APIC_ICR2, 0);
- apic_set_reg(apic, APIC_TDCR, 0);
- apic_set_reg(apic, APIC_TMICT, 0);
+ kvm_lapic_set_reg(apic, APIC_ESR, 0);
+ kvm_lapic_set_reg(apic, APIC_ICR, 0);
+ kvm_lapic_set_reg(apic, APIC_ICR2, 0);
+ kvm_lapic_set_reg(apic, APIC_TDCR, 0);
+ kvm_lapic_set_reg(apic, APIC_TMICT, 0);
  for (i = 0; i < 8; i++) {
- apic_set_reg(apic, APIC_IRR + 0x10 * i, 0);
- apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
- apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
+ kvm_lapic_set_reg(apic, APIC_IRR + 0x10 * i, 0);
+ kvm_lapic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
+ kvm_lapic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
  }
  apic->irr_pending = vcpu->arch.apicv_active;
  apic->isr_count = vcpu->arch.apicv_active ? 1 : 0;
@@ -2139,8 +2118,8 @@ int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 
  /* if this is ICR write vector before command */
  if (reg == APIC_ICR)
- apic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
- return apic_reg_write(apic, reg, (u32)data);
+ kvm_lapic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
+ return kvm_lapic_reg_write(apic, reg, (u32)data);
 }
 
 int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
@@ -2157,10 +2136,10 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
  return 1;
  }
 
- if (apic_reg_read(apic, reg, 4, &low))
+ if (kvm_lapic_reg_read(apic, reg, 4, &low))
  return 1;
  if (reg == APIC_ICR)
- apic_reg_read(apic, APIC_ICR2, 4, &high);
+ kvm_lapic_reg_read(apic, APIC_ICR2, 4, &high);
 
  *data = (((u64)high) << 32) | low;
 
@@ -2176,8 +2155,8 @@ int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 reg, u64 data)
 
  /* if this is ICR write vector before command */
  if (reg == APIC_ICR)
- apic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
- return apic_reg_write(apic, reg, (u32)data);
+ kvm_lapic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
+ return kvm_lapic_reg_write(apic, reg, (u32)data);
 }
 
 int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data)
@@ -2188,10 +2167,10 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data)
  if (!lapic_in_kernel(vcpu))
  return 1;
 
- if (apic_reg_read(apic, reg, 4, &low))
+ if (kvm_lapic_reg_read(apic, reg, 4, &low))
  return 1;
  if (reg == APIC_ICR)
- apic_reg_read(apic, APIC_ICR2, 4, &high);
+ kvm_lapic_reg_read(apic, APIC_ICR2, 4, &high);
 
  *data = (((u64)high) << 32) | low;
 
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index f71183e..a70cb62 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -7,6 +7,7 @@
 
 #define KVM_APIC_INIT 0
 #define KVM_APIC_SIPI 1
+#define KVM_APIC_LVT_NUM 6
 
 struct kvm_timer {
  struct hrtimer timer;
@@ -59,6 +60,11 @@ void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu);
 void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
 u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
 void kvm_apic_set_version(struct kvm_vcpu *vcpu);
+int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val);
+int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
+       void *data);
+bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+   int short_hand, unsigned int dest, int dest_mode);
 
 void __kvm_apic_update_irr(u32 *pir, void *regs);
 void kvm_apic_update_irr(struct kvm_vcpu *vcpu, u32 *pir);
@@ -99,11 +105,34 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu)
 int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data);
 void kvm_lapic_init(void);
 
+#define VEC_POS(v) ((v) & (32 - 1))
+#define REG_POS(v) (((v) >> 5) << 4)
+
+static inline void kvm_lapic_set_vector(int vec, void *bitmap)
+{
+ set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline void kvm_lapic_set_irr(int vec, struct kvm_lapic *apic)
+{
+ kvm_lapic_set_vector(vec, apic->regs + APIC_IRR);
+ /*
+ * irr_pending must be true if any interrupt is pending; set it after
+ * APIC_IRR to avoid race with apic_clear_irr
+ */
+ apic->irr_pending = true;
+}
+
 static inline u32 kvm_apic_get_reg(struct kvm_lapic *apic, int reg_off)
 {
         return *((u32 *) (apic->regs + reg_off));
 }
 
+static inline void kvm_lapic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val)
+{
+ *((u32 *) (apic->regs + reg_off)) = val;
+}
+
 extern struct static_key kvm_no_apic_vcpu;
 
 static inline bool lapic_in_kernel(struct kvm_vcpu *vcpu)
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 06/13] svm: Introduce new AVIC VMCB registers

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
Introduce new AVIC VMCB registers.

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
Reviewed-by: Paolo Bonzini <[hidden email]>
---
 arch/x86/include/asm/svm.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index 6136d99..4711fa4 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -78,7 +78,8 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
  u32 exit_int_info;
  u32 exit_int_info_err;
  u64 nested_ctl;
- u8 reserved_4[16];
+ u64 avic_vapic_bar;
+ u8 reserved_4[8];
  u32 event_inj;
  u32 event_inj_err;
  u64 nested_cr3;
@@ -88,7 +89,11 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
  u64 next_rip;
  u8 insn_len;
  u8 insn_bytes[15];
- u8 reserved_6[800];
+ u64 avic_backing_page; /* Offset 0xe0 */
+ u8 reserved_6[8]; /* Offset 0xe8 */
+ u64 avic_logical_id; /* Offset 0xf0 */
+ u64 avic_physical_id; /* Offset 0xf8 */
+ u8 reserved_7[768];
 };
 
 
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

[PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support

Suravee Suthikulpanit
In reply to this post by Suravee Suthikulpanit
This patch introduces AVIC-related data structure, and AVIC
initialization code.

There are three main data structures for AVIC:
    * Virtual APIC (vAPIC) backing page (per-VCPU)
    * Physical APIC ID table (per-VM)
    * Logical APIC ID table (per-VM)

Currently, AVIC is disabled by default. Users can manually
enable AVIC via kernel boot option kvm-amd.avic=1 or during
kvm-amd module loading with parameter avic=1.

Signed-off-by: Suravee Suthikulpanit <[hidden email]>
---
 arch/x86/include/asm/kvm_host.h |   4 +
 arch/x86/include/asm/svm.h      |   3 +
 arch/x86/kvm/svm.c              | 224 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 230 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 1454859..1ff2d46 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -774,6 +774,10 @@ struct kvm_arch {
  u8 nr_reserved_ioapic_pins;
 
  bool disabled_lapic_found;
+
+ /* Struct members for AVIC */
+ struct page *avic_logical_id_table_page;
+ struct page *avic_physical_id_table_page;
 };
 
 struct kvm_vm_stat {
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index 4711fa4..d0fe23e 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -116,6 +116,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
 #define V_INTR_MASKING_SHIFT 24
 #define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
 
+#define AVIC_ENABLE_SHIFT 31
+#define AVIC_ENABLE_MASK (1 << AVIC_ENABLE_SHIFT)
+
 #define SVM_INTERRUPT_SHADOW_MASK 1
 
 #define SVM_IOIO_STR_SHIFT 2
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 31346a3..4b00dc6 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -14,6 +14,9 @@
  * the COPYING file in the top-level directory.
  *
  */
+
+#define pr_fmt(fmt) "SVM: " fmt
+
 #include <linux/kvm_host.h>
 
 #include "irq.h"
@@ -78,6 +81,14 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
 #define TSC_RATIO_MIN 0x0000000000000001ULL
 #define TSC_RATIO_MAX 0x000000ffffffffffULL
 
+#define AVIC_HPA_MASK ~((0xFFFULL << 52) || 0xFFF)
+
+/*
+ * 0xff is broadcast, so the max index allowed for physical APIC ID
+ * table is 0xfe.  APIC IDs above 0xff are reserved.
+ */
+#define AVIC_MAX_PHYSICAL_ID_COUNT 255
+
 static bool erratum_383_found __read_mostly;
 
 static const u32 host_save_user_msrs[] = {
@@ -162,8 +173,19 @@ struct vcpu_svm {
 
  /* cached guest cpuid flags for faster access */
  bool nrips_enabled : 1;
+
+ struct page *avic_backing_page;
+ u64 *avic_physical_id_cache;
 };
 
+#define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFF)
+#define AVIC_LOGICAL_ID_ENTRY_VALID_MASK (1 << 31)
+
+#define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK (0xFFULL)
+#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK (0xFFFFFFFFFFULL << 12)
+#define AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK (1ULL << 62)
+#define AVIC_PHYSICAL_ID_ENTRY_VALID_MASK (1ULL << 63)
+
 static DEFINE_PER_CPU(u64, current_tsc_ratio);
 #define TSC_RATIO_DEFAULT 0x0100000000ULL
 
@@ -205,6 +227,10 @@ module_param(npt, int, S_IRUGO);
 static int nested = true;
 module_param(nested, int, S_IRUGO);
 
+/* enable / disable AVIC */
+static int avic;
+module_param(avic, int, S_IRUGO);
+
 static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
 static void svm_flush_tlb(struct kvm_vcpu *vcpu);
 static void svm_complete_interrupts(struct vcpu_svm *svm);
@@ -228,12 +254,18 @@ enum {
  VMCB_SEG,        /* CS, DS, SS, ES, CPL */
  VMCB_CR2,        /* CR2 only */
  VMCB_LBR,        /* DBGCTL, BR_FROM, BR_TO, LAST_EX_FROM, LAST_EX_TO */
+ VMCB_AVIC,       /* AVIC APIC_BAR, AVIC APIC_BACKING_PAGE,
+  * AVIC PHYSICAL_TABLE pointer,
+  * AVIC LOGICAL_TABLE pointer
+  */
  VMCB_DIRTY_MAX,
 };
 
 /* TPR and CR2 are always written before VMRUN */
 #define VMCB_ALWAYS_DIRTY_MASK ((1U << VMCB_INTR) | (1U << VMCB_CR2))
 
+#define VMCB_AVIC_APIC_BAR_MASK 0xFFFFFFFFFF000ULL
+
 static inline void mark_all_dirty(struct vmcb *vmcb)
 {
  vmcb->control.clean = 0;
@@ -255,6 +287,12 @@ static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
  return container_of(vcpu, struct vcpu_svm, vcpu);
 }
 
+static inline void avic_update_vapic_bar(struct vcpu_svm *svm, u64 data)
+{
+ svm->vmcb->control.avic_vapic_bar = data & VMCB_AVIC_APIC_BAR_MASK;
+ mark_dirty(svm->vmcb, VMCB_AVIC);
+}
+
 static void recalc_intercepts(struct vcpu_svm *svm)
 {
  struct vmcb_control_area *c, *h;
@@ -923,6 +961,12 @@ static __init int svm_hardware_setup(void)
  } else
  kvm_disable_tdp();
 
+ if (avic && (!npt_enabled || !boot_cpu_has(X86_FEATURE_AVIC)))
+ avic = false;
+
+ if (avic)
+ pr_info("AVIC enabled\n");
+
  return 0;
 
 err:
@@ -1000,6 +1044,22 @@ static void svm_adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, s64 adjustment)
  mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
 }
 
+static void avic_init_vmcb(struct vcpu_svm *svm)
+{
+ struct vmcb *vmcb = svm->vmcb;
+ struct kvm_arch *vm_data = &svm->vcpu.kvm->arch;
+ phys_addr_t bpa = page_to_phys(svm->avic_backing_page);
+ phys_addr_t lpa = page_to_phys(vm_data->avic_logical_id_table_page);
+ phys_addr_t ppa = page_to_phys(vm_data->avic_physical_id_table_page);
+
+ vmcb->control.avic_backing_page = bpa & AVIC_HPA_MASK;
+ vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK;
+ vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK;
+ vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID_COUNT;
+ vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
+ svm->vcpu.arch.apicv_active = true;
+}
+
 static void init_vmcb(struct vcpu_svm *svm)
 {
  struct vmcb_control_area *control = &svm->vmcb->control;
@@ -1110,9 +1170,130 @@ static void init_vmcb(struct vcpu_svm *svm)
  set_intercept(svm, INTERCEPT_PAUSE);
  }
 
+ if (avic)
+ avic_init_vmcb(svm);
+
  mark_all_dirty(svm->vmcb);
 
  enable_gif(svm);
+
+}
+
+static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu, int index)
+{
+ u64 *avic_physical_id_table;
+ struct kvm_arch *vm_data = &vcpu->kvm->arch;
+
+ if (index >= AVIC_MAX_PHYSICAL_ID_COUNT)
+ return NULL;
+
+ avic_physical_id_table = page_address(vm_data->avic_physical_id_table_page);
+
+ return &avic_physical_id_table[index];
+}
+
+/**
+ * Note:
+ * AVIC hardware walks the nested page table to check permissions,
+ * but does not use the SPA address specified in the leaf page
+ * table entry since it uses  address in the AVIC_BACKING_PAGE pointer
+ * field of the VMCB. Therefore, we set up the
+ * APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (4KB) here.
+ */
+static int avic_init_access_page(struct kvm_vcpu *vcpu)
+{
+ int ret = 0;
+ struct kvm *kvm = vcpu->kvm;
+
+ if (!kvm->arch.apic_access_page_done) {
+ ret = x86_set_memory_region(kvm,
+    APIC_ACCESS_PAGE_PRIVATE_MEMSLOT,
+    APIC_DEFAULT_PHYS_BASE,
+    PAGE_SIZE);
+ if (ret)
+ return ret;
+ kvm->arch.apic_access_page_done = true;
+ }
+
+ return ret;
+}
+
+static int avic_init_backing_page(struct kvm_vcpu *vcpu)
+{
+ int ret;
+ u64 *entry, new_entry;
+ int id = vcpu->vcpu_id;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ ret = avic_init_access_page(vcpu);
+ if (ret)
+ return ret;
+
+ if (id >= AVIC_MAX_PHYSICAL_ID_COUNT)
+ return -EINVAL;
+
+ if (!svm->vcpu.arch.apic->regs)
+ return -EINVAL;
+
+ svm->avic_backing_page = virt_to_page(svm->vcpu.arch.apic->regs);
+
+ /* Setting AVIC backing page address in the phy APIC ID table */
+ entry = avic_get_physical_id_entry(vcpu, id);
+ if (!entry)
+ return -EINVAL;
+
+ new_entry = READ_ONCE(*entry);
+ new_entry = (page_to_phys(svm->avic_backing_page) &
+     AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK) |
+     AVIC_PHYSICAL_ID_ENTRY_VALID_MASK;
+ WRITE_ONCE(*entry, new_entry);
+
+ svm->avic_physical_id_cache = entry;
+
+ return 0;
+}
+
+static void avic_vm_destroy(struct kvm *kvm)
+{
+ struct kvm_arch *vm_data = &kvm->arch;
+
+ if (vm_data->avic_logical_id_table_page)
+ __free_page(vm_data->avic_logical_id_table_page);
+ if (vm_data->avic_physical_id_table_page)
+ __free_page(vm_data->avic_physical_id_table_page);
+}
+
+static int avic_vm_init(struct kvm *kvm)
+{
+ int err = -ENOMEM;
+ struct kvm_arch *vm_data = &kvm->arch;
+ struct page *p_page;
+ struct page *l_page;
+
+ if (!avic)
+ return 0;
+
+ /* Allocating physical APIC ID table (4KB) */
+ p_page = alloc_page(GFP_KERNEL);
+ if (!p_page)
+ goto free_avic;
+
+ vm_data->avic_physical_id_table_page = p_page;
+ clear_page(page_address(p_page));
+
+ /* Allocating logical APIC ID table (4KB) */
+ l_page = alloc_page(GFP_KERNEL);
+ if (!l_page)
+ goto free_avic;
+
+ vm_data->avic_logical_id_table_page = l_page;
+ clear_page(page_address(l_page));
+
+ return 0;
+
+free_avic:
+ avic_vm_destroy(kvm);
+ return err;
 }
 
 static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
@@ -1131,6 +1312,9 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 
  kvm_cpuid(vcpu, &eax, &dummy, &dummy, &dummy);
  kvm_register_write(vcpu, VCPU_REGS_RDX, eax);
+
+ if (kvm_vcpu_apicv_active(vcpu) && !init_event)
+ avic_update_vapic_bar(svm, APIC_DEFAULT_PHYS_BASE);
 }
 
 static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
@@ -1169,6 +1353,12 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
  if (!hsave_page)
  goto free_page3;
 
+ if (avic) {
+ err = avic_init_backing_page(&svm->vcpu);
+ if (err)
+ goto free_page4;
+ }
+
  svm->nested.hsave = page_address(hsave_page);
 
  svm->msrpm = page_address(msrpm_pages);
@@ -1187,6 +1377,8 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
 
  return &svm->vcpu;
 
+free_page4:
+ __free_page(hsave_page);
 free_page3:
  __free_pages(nested_msrpm_pages, MSRPM_ALLOC_ORDER);
 free_page2:
@@ -3212,6 +3404,10 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
  case MSR_VM_IGNNE:
  vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
  break;
+ case MSR_IA32_APICBASE:
+ if (kvm_vcpu_apicv_active(vcpu))
+ avic_update_vapic_bar(to_svm(vcpu), data);
+ /* Follow through */
  default:
  return kvm_set_msr_common(vcpu, msr);
  }
@@ -3375,10 +3571,14 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
  pr_err("%-20s%08x\n", "exit_int_info_err:", control->exit_int_info_err);
  pr_err("%-20s%lld\n", "nested_ctl:", control->nested_ctl);
  pr_err("%-20s%016llx\n", "nested_cr3:", control->nested_cr3);
+ pr_err("%-20s%016llx\n", "avic_vapic_bar:", control->avic_vapic_bar);
  pr_err("%-20s%08x\n", "event_inj:", control->event_inj);
  pr_err("%-20s%08x\n", "event_inj_err:", control->event_inj_err);
  pr_err("%-20s%lld\n", "lbr_ctl:", control->lbr_ctl);
  pr_err("%-20s%016llx\n", "next_rip:", control->next_rip);
+ pr_err("%-20s%016llx\n", "avic_backing_page:", control->avic_backing_page);
+ pr_err("%-20s%016llx\n", "avic_logical_id:", control->avic_logical_id);
+ pr_err("%-20s%016llx\n", "avic_physical_id:", control->avic_physical_id);
  pr_err("VMCB State Save Area:\n");
  pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
        "es:",
@@ -3606,11 +3806,28 @@ static void svm_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
 
 static bool svm_get_enable_apicv(void)
 {
- return false;
+ return avic;
 }
 
+static void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
+{
+}
+
+static void svm_hwapic_isr_update(struct kvm *kvm, int isr)
+{
+}
+
+/* Note: Currently only used by Hyper-V. */
 static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
 {
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct vmcb *vmcb = svm->vmcb;
+
+ if (!avic)
+ return;
+
+ vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
+ mark_dirty(vmcb, VMCB_INTR);
 }
 
 static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
@@ -4322,6 +4539,9 @@ static struct kvm_x86_ops svm_x86_ops = {
  .vcpu_free = svm_free_vcpu,
  .vcpu_reset = svm_vcpu_reset,
 
+ .vm_init = avic_vm_init,
+ .vm_destroy = avic_vm_destroy,
+
  .prepare_guest_switch = svm_prepare_guest_switch,
  .vcpu_load = svm_vcpu_load,
  .vcpu_put = svm_vcpu_put,
@@ -4382,6 +4602,8 @@ static struct kvm_x86_ops svm_x86_ops = {
  .refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl,
  .load_eoi_exitmap = svm_load_eoi_exitmap,
  .sync_pir_to_irr = svm_sync_pir_to_irr,
+ .hwapic_irr_update = svm_hwapic_irr_update,
+ .hwapic_isr_update = svm_hwapic_isr_update,
 
  .set_tss_addr = svm_set_tss_addr,
  .get_tdp_level = get_npt_level,
--
1.9.1

Reply | Threaded
Open this post in threaded view
|

Re: [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support

Borislav Petkov-3
On Wed, May 04, 2016 at 02:09:46PM -0500, Suravee Suthikulpanit wrote:

> This patch introduces AVIC-related data structure, and AVIC
> initialization code.
>
> There are three main data structures for AVIC:
>     * Virtual APIC (vAPIC) backing page (per-VCPU)
>     * Physical APIC ID table (per-VM)
>     * Logical APIC ID table (per-VM)
>
> Currently, AVIC is disabled by default. Users can manually
> enable AVIC via kernel boot option kvm-amd.avic=1 or during
> kvm-amd module loading with parameter avic=1.
>
> Signed-off-by: Suravee Suthikulpanit <[hidden email]>
> ---
>  arch/x86/include/asm/kvm_host.h |   4 +
>  arch/x86/include/asm/svm.h      |   3 +
>  arch/x86/kvm/svm.c              | 224 +++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 230 insertions(+), 1 deletion(-)

...

> + * Note:
> + * AVIC hardware walks the nested page table to check permissions,
> + * but does not use the SPA address specified in the leaf page
> + * table entry since it uses  address in the AVIC_BACKING_PAGE pointer
> + * field of the VMCB. Therefore, we set up the
> + * APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (4KB) here.
> + */
> +static int avic_init_access_page(struct kvm_vcpu *vcpu)
> +{
> + int ret = 0;
> + struct kvm *kvm = vcpu->kvm;
> +
> + if (!kvm->arch.apic_access_page_done) {
> + ret = x86_set_memory_region(kvm,
> +    APIC_ACCESS_PAGE_PRIVATE_MEMSLOT,
> +    APIC_DEFAULT_PHYS_BASE,
> +    PAGE_SIZE);
> + if (ret)
> + return ret;
> + kvm->arch.apic_access_page_done = true;
> + }
> +
> + return ret;
> +}

You can save yourself and indentation level:

        if (kvm->arch.apic_access_page_done)
                return ret;

        ret = x86_set_memory_region(kvm, APIC_ACCESS_PAGE_PRIVATE_MEMSLOT,
                                    APIC_DEFAULT_PHYS_BASE, PAGE_SIZE);
        if (ret)
                return ret;

        kvm->arch.apic_access_page_done = true;


--
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
Reply | Threaded
Open this post in threaded view
|

Re: [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support

Borislav Petkov-3
In reply to this post by Suravee Suthikulpanit
On Wed, May 04, 2016 at 02:09:46PM -0500, Suravee Suthikulpanit wrote:

> This patch introduces AVIC-related data structure, and AVIC
> initialization code.
>
> There are three main data structures for AVIC:
>     * Virtual APIC (vAPIC) backing page (per-VCPU)
>     * Physical APIC ID table (per-VM)
>     * Logical APIC ID table (per-VM)
>
> Currently, AVIC is disabled by default. Users can manually
> enable AVIC via kernel boot option kvm-amd.avic=1 or during
> kvm-amd module loading with parameter avic=1.
>
> Signed-off-by: Suravee Suthikulpanit <[hidden email]>
> ---
>  arch/x86/include/asm/kvm_host.h |   4 +
>  arch/x86/include/asm/svm.h      |   3 +
>  arch/x86/kvm/svm.c              | 224 +++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 230 insertions(+), 1 deletion(-)

...

> @@ -162,8 +173,19 @@ struct vcpu_svm {
>  
>   /* cached guest cpuid flags for faster access */
>   bool nrips_enabled : 1;
> +
> + struct page *avic_backing_page;
> + u64 *avic_physical_id_cache;
>  };
>  
> +#define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFF)
> +#define AVIC_LOGICAL_ID_ENTRY_VALID_MASK (1 << 31)
> +
> +#define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK (0xFFULL)
> +#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK (0xFFFFFFFFFFULL << 12)
> +#define AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK (1ULL << 62)
> +#define AVIC_PHYSICAL_ID_ENTRY_VALID_MASK (1ULL << 63)

Those defines could be shortened a little. Maybe

#define AVIC_PHYSID_HOST_PHYS_MASK
#define AVIC_PHYSID_BACKING_PG_MASK

and so on...

--
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
Reply | Threaded
Open this post in threaded view
|

Re: [PART1 V5 08/13] svm: Add interrupt injection via AVIC

Borislav Petkov-3
In reply to this post by Suravee Suthikulpanit
On Wed, May 04, 2016 at 02:09:47PM -0500, Suravee Suthikulpanit wrote:
> This patch introduces a new mechanism to inject interrupt using AVIC.
> Since VINTR is not supported when enable AVIC, we need to inject

        "... is not supported when AVIC is enabled ..."

VINTR?

Please write those things out in the commit message for maximum
information transfer to the reader. :)

> interrupt via APIC backing page instead.
>
> This patch also adds support for AVIC doorbell, which is used by
> KVM to signal a running vcpu to check IRR for injected interrupts.
>
> Signed-off-by: Suravee Suthikulpanit <[hidden email]>
> ---
>  arch/x86/kvm/svm.c | 39 +++++++++++++++++++++++++++++++++++----
>  1 file changed, 35 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index 4b00dc6..3a97874 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -71,6 +71,8 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
>  #define SVM_FEATURE_DECODE_ASSIST  (1 <<  7)
>  #define SVM_FEATURE_PAUSE_FILTER   (1 << 10)
>  
> +#define SVM_AVIC_DOORBELL 0xc001011b

MSR_SVM_AVIC_DOORBELL

> +
>  #define NESTED_EXIT_HOST 0 /* Exit handled on host level */
>  #define NESTED_EXIT_DONE 1 /* Exit caused nested vmexit  */
>  #define NESTED_EXIT_CONTINUE 2 /* Further checks needed      */

--
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.
Reply | Threaded
Open this post in threaded view
|

Re: [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support

Paolo Bonzini
In reply to this post by Borislav Petkov-3


On 10/05/2016 11:14, Borislav Petkov wrote:

>> > +#define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK (0xFF)
>> > +#define AVIC_LOGICAL_ID_ENTRY_VALID_MASK (1 << 31)
>> > +
>> > +#define AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK (0xFFULL)
>> > +#define AVIC_PHYSICAL_ID_ENTRY_BACKING_PAGE_MASK (0xFFFFFFFFFFULL << 12)
>> > +#define AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK (1ULL << 62)
>> > +#define AVIC_PHYSICAL_ID_ENTRY_VALID_MASK (1ULL << 63)
> Those defines could be shortened a little. Maybe
>
> #define AVIC_PHYSID_HOST_PHYS_MASK
> #define AVIC_PHYSID_BACKING_PG_MASK

That was actually our suggestion.  Despite the long names, the lines do
not come out too long because the masks are only used for writing
fields, not very much for reading them (e.g. in complex "if" conditions).

Paolo
Reply | Threaded
Open this post in threaded view
|

Re: [PART1 V5 08/13] svm: Add interrupt injection via AVIC

Paolo Bonzini
In reply to this post by Borislav Petkov-3


On 10/05/2016 11:19, Borislav Petkov wrote:
>> > This patch introduces a new mechanism to inject interrupt using AVIC.
>> > Since VINTR is not supported when enable AVIC, we need to inject
> "... is not supported when AVIC is enabled ..."
>
> VINTR?

The ability to request a vmexit as soon as an interrupt can be injected
(IF=GIF=1, no interrupt window, etc.).  It's called the "VINTR intercept".

> Please write those things out in the commit message for maximum
> information transfer to the reader. :)

More important, where does the APM document that VINTR is not supported
when AVIC is enabled?  It is certainly pointless and inefficient, but
I'm not sure where it says that it doesn't work.

Paolo
Reply | Threaded
Open this post in threaded view
|

Re: [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support

Paolo Bonzini
In reply to this post by Suravee Suthikulpanit
On 04/05/2016 21:09, Suravee Suthikulpanit wrote:
>   * Removing the RFC since I think this is getting ready.

It's pretty good indeed.  Since it's still disabled by default, I'm
going ahead and merging it.

Can you please test that it doesn't break nested virtualization?

Paolo

>   * Rebase to latest tip.git.
>   * Rename vm_deinit to vm_destroy.
>   * Replace svm_vcpu_avic_enabled() with kvm_vcpu_apicv_active().
>   * Fix the cluster logical APIC ID calculation logic.
>   * Misc clean up based on previous review comments.
>   * (NEW) Rename kvm_lapic_get_reg to kvm_lapic_get_reg.
>   * (NEW) Introduce kvm_x86_ops.apicv_post_state_restore hook.
>   * (NEW) Re-factor the VMEXIT handling code and reuse
>     it in the apicv_post_state_restore to implement support for
>     vmsave/restore, which has been tested migrating:
>       - from AVIC mode to non-AVIC mode
>       - from non-AVIC mode to AVIC mode
>   * (NEW) Add support for the AVIC VMCB clean bit.
12