linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support
@ 2016-05-04 19:09 Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 01/13] KVM: x86: Misc LAPIC changes to expose helper functions Suravee Suthikulpanit
                   ` (13 more replies)
  0 siblings, 14 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, 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

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PART1 V5 01/13] KVM: x86: Misc LAPIC changes to expose helper functions
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 02/13] KVM: x86: Rename kvm_apic_get_reg to kvm_lapic_get_reg Suravee Suthikulpanit
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit,
	Suravee Suthikulpanit

Exporting LAPIC utility functions and macros for re-use in SVM code.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Reviewed-by: Radim Krčmář <rkrcmar@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 02/13] KVM: x86: Rename kvm_apic_get_reg to kvm_lapic_get_reg
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 01/13] KVM: x86: Misc LAPIC changes to expose helper functions Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 03/13] KVM: x86: Introducing kvm_x86_ops VM init/destroy hooks Suravee Suthikulpanit
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit

From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>

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 <suravee.suthikulpanit@amd.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 03/13] KVM: x86: Introducing kvm_x86_ops VM init/destroy hooks
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 01/13] KVM: x86: Misc LAPIC changes to expose helper functions Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 02/13] KVM: x86: Rename kvm_apic_get_reg to kvm_lapic_get_reg Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 04/13] KVM: x86: Introducing kvm_x86_ops VCPU blocking/unblocking hooks Suravee Suthikulpanit
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit,
	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 <suravee.suthikulpanit@amd.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 04/13] KVM: x86: Introducing kvm_x86_ops VCPU blocking/unblocking hooks
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (2 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 03/13] KVM: x86: Introducing kvm_x86_ops VM init/destroy hooks Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 05/13] KVM: split kvm_vcpu_wake_up from kvm_vcpu_kick Suravee Suthikulpanit
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit,
	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 <suravee.suthikulpanit@amd.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 05/13] KVM: split kvm_vcpu_wake_up from kvm_vcpu_kick
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (3 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 04/13] KVM: x86: Introducing kvm_x86_ops VCPU blocking/unblocking hooks Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 06/13] svm: Introduce new AVIC VMCB registers Suravee Suthikulpanit
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz

From: Radim Krčmář <rkrcmar@redhat.com>

AVIC has a use for kvm_vcpu_wake_up.

Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
Tested-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 06/13] svm: Introduce new AVIC VMCB registers
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (4 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 05/13] KVM: split kvm_vcpu_wake_up from kvm_vcpu_kick Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support Suravee Suthikulpanit
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit,
	Suravee Suthikulpanit

Introduce new AVIC VMCB registers.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (5 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 06/13] svm: Introduce new AVIC VMCB registers Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-09 10:27   ` Borislav Petkov
  2016-05-10  9:14   ` Borislav Petkov
  2016-05-04 19:09 ` [PART1 V5 08/13] svm: Add interrupt injection via AVIC Suravee Suthikulpanit
                   ` (6 subsequent siblings)
  13 siblings, 2 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit,
	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 <suravee.suthikulpanit@amd.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 08/13] svm: Add interrupt injection via AVIC
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (6 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-10  9:19   ` Borislav Petkov
  2016-05-04 19:09 ` [PART1 V5 09/13] svm: Add VMEXIT handlers for AVIC Suravee Suthikulpanit
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit,
	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 <suravee.suthikulpanit@amd.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 09/13] svm: Add VMEXIT handlers for AVIC
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (7 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 08/13] svm: Add interrupt injection via AVIC Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 10/13] KVM: x86: Introducing kvm_x86_ops.apicv_post_state_restore Suravee Suthikulpanit
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit

From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>

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 <suravee.suthikulpanit@amd.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 10/13] KVM: x86: Introducing kvm_x86_ops.apicv_post_state_restore
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (8 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 09/13] svm: Add VMEXIT handlers for AVIC Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 11/13] svm: Do not expose x2APIC when enable AVIC Suravee Suthikulpanit
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit,
	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 <suravee.suthikulpanit@amd.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 11/13] svm: Do not expose x2APIC when enable AVIC
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (9 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 10/13] KVM: x86: Introducing kvm_x86_ops.apicv_post_state_restore Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-04 19:09 ` [PART1 V5 12/13] svm: Do not intercept CR8 " Suravee Suthikulpanit
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit

From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>

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

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 12/13] svm: Do not intercept CR8 when enable AVIC
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (10 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 11/13] svm: Do not expose x2APIC when enable AVIC Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-10 15:12   ` Paolo Bonzini
  2016-05-04 19:09 ` [PART1 V5 13/13] svm: Manage vcpu load/unload " Suravee Suthikulpanit
  2016-05-10 14:57 ` [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Paolo Bonzini
  13 siblings, 1 reply; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit,
	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 <suravee.suthikulpanit@amd.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PART1 V5 13/13] svm: Manage vcpu load/unload when enable AVIC
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (11 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 12/13] svm: Do not intercept CR8 " Suravee Suthikulpanit
@ 2016-05-04 19:09 ` Suravee Suthikulpanit
  2016-05-10 15:43   ` Paolo Bonzini
  2016-05-10 14:57 ` [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Paolo Bonzini
  13 siblings, 1 reply; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-05-04 19:09 UTC (permalink / raw)
  To: pbonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz, Suravee Suthikulpanit

From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>

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 <suravee.suthikulpanit@amd.com>
Reviewed-by: Radim Krčmář <rkrcmar@redhat.com>
---
 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

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support
  2016-05-04 19:09 ` [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support Suravee Suthikulpanit
@ 2016-05-09 10:27   ` Borislav Petkov
  2016-05-10  9:14   ` Borislav Petkov
  1 sibling, 0 replies; 29+ messages in thread
From: Borislav Petkov @ 2016-05-09 10:27 UTC (permalink / raw)
  To: Suravee Suthikulpanit
  Cc: pbonzini, rkrcmar, joro, gleb, alex.williamson, kvm,
	linux-kernel, wei, sherry.hurwitz

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 <suravee.suthikulpanit@amd.com>
> ---
>  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.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support
  2016-05-04 19:09 ` [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support Suravee Suthikulpanit
  2016-05-09 10:27   ` Borislav Petkov
@ 2016-05-10  9:14   ` Borislav Petkov
  2016-05-10 14:43     ` Paolo Bonzini
  1 sibling, 1 reply; 29+ messages in thread
From: Borislav Petkov @ 2016-05-10  9:14 UTC (permalink / raw)
  To: Suravee Suthikulpanit
  Cc: pbonzini, rkrcmar, joro, gleb, alex.williamson, kvm,
	linux-kernel, wei, sherry.hurwitz

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 <suravee.suthikulpanit@amd.com>
> ---
>  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.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 08/13] svm: Add interrupt injection via AVIC
  2016-05-04 19:09 ` [PART1 V5 08/13] svm: Add interrupt injection via AVIC Suravee Suthikulpanit
@ 2016-05-10  9:19   ` Borislav Petkov
  2016-05-10 14:50     ` Paolo Bonzini
  0 siblings, 1 reply; 29+ messages in thread
From: Borislav Petkov @ 2016-05-10  9:19 UTC (permalink / raw)
  To: Suravee Suthikulpanit
  Cc: pbonzini, rkrcmar, joro, gleb, alex.williamson, kvm,
	linux-kernel, wei, sherry.hurwitz

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 <suravee.suthikulpanit@amd.com>
> ---
>  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.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support
  2016-05-10  9:14   ` Borislav Petkov
@ 2016-05-10 14:43     ` Paolo Bonzini
  2016-05-10 16:24       ` Borislav Petkov
  0 siblings, 1 reply; 29+ messages in thread
From: Paolo Bonzini @ 2016-05-10 14:43 UTC (permalink / raw)
  To: Borislav Petkov, Suravee Suthikulpanit
  Cc: rkrcmar, joro, gleb, alex.williamson, kvm, linux-kernel, wei,
	sherry.hurwitz



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

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 08/13] svm: Add interrupt injection via AVIC
  2016-05-10  9:19   ` Borislav Petkov
@ 2016-05-10 14:50     ` Paolo Bonzini
  2016-06-01  4:02       ` Suravee Suthikulpanit
  0 siblings, 1 reply; 29+ messages in thread
From: Paolo Bonzini @ 2016-05-10 14:50 UTC (permalink / raw)
  To: Borislav Petkov, Suravee Suthikulpanit
  Cc: rkrcmar, joro, gleb, alex.williamson, kvm, linux-kernel, wei,
	sherry.hurwitz



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

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support
  2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
                   ` (12 preceding siblings ...)
  2016-05-04 19:09 ` [PART1 V5 13/13] svm: Manage vcpu load/unload " Suravee Suthikulpanit
@ 2016-05-10 14:57 ` Paolo Bonzini
  13 siblings, 0 replies; 29+ messages in thread
From: Paolo Bonzini @ 2016-05-10 14:57 UTC (permalink / raw)
  To: Suravee Suthikulpanit, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz

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.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 12/13] svm: Do not intercept CR8 when enable AVIC
  2016-05-04 19:09 ` [PART1 V5 12/13] svm: Do not intercept CR8 " Suravee Suthikulpanit
@ 2016-05-10 15:12   ` Paolo Bonzini
  0 siblings, 0 replies; 29+ messages in thread
From: Paolo Bonzini @ 2016-05-10 15:12 UTC (permalink / raw)
  To: Suravee Suthikulpanit, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz



On 04/05/2016 21:09, Suravee Suthikulpanit wrote:
> +static inline bool svm_in_nested_interrupt_shadow(struct kvm_vcpu *vcpu)
> +{
> +	return is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK);
> +}
> +

A better name (yes, I know I suggested this one) is
svm_nested_virtualize_tpr.  I can change this when committing.

Paolo

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 13/13] svm: Manage vcpu load/unload when enable AVIC
  2016-05-04 19:09 ` [PART1 V5 13/13] svm: Manage vcpu load/unload " Suravee Suthikulpanit
@ 2016-05-10 15:43   ` Paolo Bonzini
  2016-05-17 12:09     ` Paolo Bonzini
  0 siblings, 1 reply; 29+ messages in thread
From: Paolo Bonzini @ 2016-05-10 15:43 UTC (permalink / raw)
  To: Suravee Suthikulpanit, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz



On 04/05/2016 21:09, Suravee Suthikulpanit wrote:
> From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
> 
> 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 <suravee.suthikulpanit@amd.com>
> Reviewed-by: Radim Krčmář <rkrcmar@redhat.com>
> ---

I think this is the only patch that needs a little more work, because 
there are a bunch of unused return values that really should be 
WARN_ON.  In addition the load and put cases are different enough that 
they should be separate functions.

Can you please test this?

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index f3dbf1d33a61..3168d6c8d24f 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -184,7 +184,7 @@ struct vcpu_svm {
 	u32 ldr_reg;
 	struct page *avic_backing_page;
 	u64 *avic_physical_id_cache;
-	bool avic_is_blocking;
+	bool avic_is_running;
 };
 
 #define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK	(0xFF)
@@ -1321,18 +1321,20 @@ free_avic:
 /**
  * This function is called during VCPU halt/unhalt.
  */
-static int avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
+static void 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;
+		return;
+
+	svm->avic_is_running = is_run;
 
 	/* ID = 0xff (broadcast), ID > 0xff (reserved) */
-	if (h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)
-		return -EINVAL;
+	if (WARN_ON(h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT))
+		return;
 
 	entry = READ_ONCE(*(svm->avic_physical_id_cache));
 	WARN_ON(is_run == !!(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK));
@@ -1341,36 +1343,45 @@ static int avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
 	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)
+static void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	u64 entry;
+	/* ID = 0xff (broadcast), ID > 0xff (reserved) */
 	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;
+		return;
 
-	/* ID = 0xff (broadcast), ID > 0xff (reserved) */
-	if (h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)
-		return -EINVAL;
+	if (WARN_ON(h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT))
+		return;
 
 	entry = READ_ONCE(*(svm->avic_physical_id_cache));
-	WARN_ON(is_load && (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK));
+	WARN_ON(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK);
+
+	entry &= ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
+	entry |= (h_physical_id & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_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;
-	}
+	if (svm->avic_is_running)
+		entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
+
 	WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
+}
 
-	return 0;
+static void avic_vcpu_put(struct kvm_vcpu *vcpu)
+{
+	u64 entry;
+	struct vcpu_svm *svm = to_svm(vcpu);
+
+	if (!kvm_vcpu_apicv_active(vcpu))
+		return;
+
+	entry = READ_ONCE(*(svm->avic_physical_id_cache));
+	entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
+	WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
 }
 
 static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
@@ -1436,10 +1447,10 @@ 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
+	/* We initialize this flag to true to make sure that the is_running
 	 * bit would be set the first time the vcpu is loaded.
 	 */
-	svm->avic_is_blocking = false;
+	svm->avic_is_running = true;
 
 	svm->nested.hsave = page_address(hsave_page);
 
@@ -1518,7 +1529,7 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 	if (static_cpu_has(X86_FEATURE_RDTSCP))
 		wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
 
-	avic_vcpu_load(vcpu, cpu, true);
+	avic_vcpu_load(vcpu, cpu);
 }
 
 static void svm_vcpu_put(struct kvm_vcpu *vcpu)
@@ -1526,7 +1537,7 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
 	struct vcpu_svm *svm = to_svm(vcpu);
 	int i;
 
-	avic_vcpu_load(vcpu, 0, false);
+	avic_vcpu_put(vcpu);
 
 	++vcpu->stat.host_state_reload;
 	kvm_load_ldt(svm->host.ldt);
@@ -1545,13 +1556,11 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
 
 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);
 }
 

The two functions now have the same signature as their callers,
svm_vcpu_load and svm_vcpu_put.

Thanks,

Paolo

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support
  2016-05-10 14:43     ` Paolo Bonzini
@ 2016-05-10 16:24       ` Borislav Petkov
  2016-05-10 17:00         ` Paolo Bonzini
  0 siblings, 1 reply; 29+ messages in thread
From: Borislav Petkov @ 2016-05-10 16:24 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Suravee Suthikulpanit, rkrcmar, joro, gleb, alex.williamson, kvm,
	linux-kernel, wei, sherry.hurwitz

On Tue, May 10, 2016 at 04:43:05PM +0200, Paolo Bonzini wrote:
> 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).

Sure but how can one even read that?

AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK

AVIC's physical ID entry's host's physical ID's mask?

That sucks in any language :-)

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support
  2016-05-10 16:24       ` Borislav Petkov
@ 2016-05-10 17:00         ` Paolo Bonzini
  2016-05-10 17:06           ` Borislav Petkov
  0 siblings, 1 reply; 29+ messages in thread
From: Paolo Bonzini @ 2016-05-10 17:00 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Suravee Suthikulpanit, rkrcmar, joro, gleb, alex.williamson, kvm,
	linux-kernel, wei, sherry.hurwitz



On 10/05/2016 18:24, Borislav Petkov wrote:
> Sure but how can one even read that?
> 
> AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK
> 
> AVIC's physical ID entry's host's physical ID's mask?
> 
> That sucks in any language :-)

If you read it backwards, that's the

        Mask
      for the host physical id
    in entries of
  the physical ID table
(an AVIC thing).

Quite a mouthful, can't deny that.  But I'm sure Germans would
appreciate it.

Paolo "Rindfleischetikettierungsueberwachungsaufgabenuebertragungsgesetz"

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support
  2016-05-10 17:00         ` Paolo Bonzini
@ 2016-05-10 17:06           ` Borislav Petkov
  0 siblings, 0 replies; 29+ messages in thread
From: Borislav Petkov @ 2016-05-10 17:06 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Suravee Suthikulpanit, rkrcmar, joro, gleb, alex.williamson, kvm,
	linux-kernel, wei, sherry.hurwitz

On Tue, May 10, 2016 at 07:00:43PM +0200, Paolo Bonzini wrote:
> If you read it backwards, that's the
> 
>         Mask
>       for the host physical id
>     in entries of
>   the physical ID table
> (an AVIC thing).

Note to self: defines in arch/x86/kvm/ should be read backwards.

> Quite a mouthful, can't deny that.  But I'm sure Germans would
> appreciate it.

<Insert joke here!>

Oh boy, I have a gazillion of those... will tell ya live! :-)

> Paolo "Rindfleischetikettierungsueberwachungsaufgabenuebertragungsgesetz"

I think that one is not in effect anymore :-)

-- 
Regards/Gruss,
    Boris.

ECO tip #101: Trim your mails when you reply.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 13/13] svm: Manage vcpu load/unload when enable AVIC
  2016-05-10 15:43   ` Paolo Bonzini
@ 2016-05-17 12:09     ` Paolo Bonzini
  2016-06-01 18:18       ` Suravee Suthikulpanit
  0 siblings, 1 reply; 29+ messages in thread
From: Paolo Bonzini @ 2016-05-17 12:09 UTC (permalink / raw)
  To: Suravee Suthikulpanit, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz



On 10/05/2016 17:43, Paolo Bonzini wrote:
> 
> 
> On 04/05/2016 21:09, Suravee Suthikulpanit wrote:
>> From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
>>
>> 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 <suravee.suthikulpanit@amd.com>
>> Reviewed-by: Radim Krčmář <rkrcmar@redhat.com>
>> ---
> 
> I think this is the only patch that needs a little more work, because 
> there are a bunch of unused return values that really should be 
> WARN_ON.  In addition the load and put cases are different enough that 
> they should be separate functions.
> 
> Can you please test this?
> 
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index f3dbf1d33a61..3168d6c8d24f 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -184,7 +184,7 @@ struct vcpu_svm {
>  	u32 ldr_reg;
>  	struct page *avic_backing_page;
>  	u64 *avic_physical_id_cache;
> -	bool avic_is_blocking;
> +	bool avic_is_running;
>  };
>  
>  #define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK	(0xFF)
> @@ -1321,18 +1321,20 @@ free_avic:
>  /**
>   * This function is called during VCPU halt/unhalt.
>   */
> -static int avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
> +static void 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;
> +		return;
> +
> +	svm->avic_is_running = is_run;
>  
>  	/* ID = 0xff (broadcast), ID > 0xff (reserved) */
> -	if (h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)
> -		return -EINVAL;
> +	if (WARN_ON(h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT))
> +		return;
>  
>  	entry = READ_ONCE(*(svm->avic_physical_id_cache));
>  	WARN_ON(is_run == !!(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK));
> @@ -1341,36 +1343,45 @@ static int avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
>  	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)
> +static void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>  {
>  	u64 entry;
> +	/* ID = 0xff (broadcast), ID > 0xff (reserved) */
>  	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;
> +		return;
>  
> -	/* ID = 0xff (broadcast), ID > 0xff (reserved) */
> -	if (h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)
> -		return -EINVAL;
> +	if (WARN_ON(h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT))
> +		return;
>  
>  	entry = READ_ONCE(*(svm->avic_physical_id_cache));
> -	WARN_ON(is_load && (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK));
> +	WARN_ON(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK);
> +
> +	entry &= ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
> +	entry |= (h_physical_id & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_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;
> -	}
> +	if (svm->avic_is_running)
> +		entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
> +
>  	WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
> +}
>  
> -	return 0;
> +static void avic_vcpu_put(struct kvm_vcpu *vcpu)
> +{
> +	u64 entry;
> +	struct vcpu_svm *svm = to_svm(vcpu);
> +
> +	if (!kvm_vcpu_apicv_active(vcpu))
> +		return;
> +
> +	entry = READ_ONCE(*(svm->avic_physical_id_cache));
> +	entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
> +	WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
>  }
>  
>  static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
> @@ -1436,10 +1447,10 @@ 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
> +	/* We initialize this flag to true to make sure that the is_running
>  	 * bit would be set the first time the vcpu is loaded.
>  	 */
> -	svm->avic_is_blocking = false;
> +	svm->avic_is_running = true;
>  
>  	svm->nested.hsave = page_address(hsave_page);
>  
> @@ -1518,7 +1529,7 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>  	if (static_cpu_has(X86_FEATURE_RDTSCP))
>  		wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
>  
> -	avic_vcpu_load(vcpu, cpu, true);
> +	avic_vcpu_load(vcpu, cpu);
>  }
>  
>  static void svm_vcpu_put(struct kvm_vcpu *vcpu)
> @@ -1526,7 +1537,7 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
>  	struct vcpu_svm *svm = to_svm(vcpu);
>  	int i;
>  
> -	avic_vcpu_load(vcpu, 0, false);
> +	avic_vcpu_put(vcpu);
>  
>  	++vcpu->stat.host_state_reload;
>  	kvm_load_ldt(svm->host.ldt);
> @@ -1545,13 +1556,11 @@ static void svm_vcpu_put(struct kvm_vcpu *vcpu)
>  
>  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);
>  }
>  
> 
> The two functions now have the same signature as their callers,
> svm_vcpu_load and svm_vcpu_put.

Radim, does this look sane?  I plan to include it in my pull request
(I'm running AMD autotest now and it passed the first few tests).

Thanks,

Paolo

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 08/13] svm: Add interrupt injection via AVIC
  2016-05-10 14:50     ` Paolo Bonzini
@ 2016-06-01  4:02       ` Suravee Suthikulpanit
  0 siblings, 0 replies; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-06-01  4:02 UTC (permalink / raw)
  To: Paolo Bonzini, Borislav Petkov
  Cc: rkrcmar, joro, gleb, alex.williamson, kvm, linux-kernel, wei,
	sherry.hurwitz

Hi,

Sorry for late response on this.

On 5/10/16 09:50, Paolo Bonzini wrote:
>
>
> 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
>

Basically, from the APM vol2 here:

   http://developer.amd.com/wordpress/media/2012/10/24593_APM_v21.pdf

On page 115, section AVIC Enable—Virtual Interrupt Control, Bit 31:

   "... Enabling AVIC implicitly disables the V_IRQ, V_INTR_PRIO,
    V_IGN_TPR, and V_INTR_VECTOR fields in the VMCB Control Word."

Thanks,
Suravee

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 13/13] svm: Manage vcpu load/unload when enable AVIC
  2016-05-17 12:09     ` Paolo Bonzini
@ 2016-06-01 18:18       ` Suravee Suthikulpanit
  2016-06-01 18:37         ` Paolo Bonzini
  0 siblings, 1 reply; 29+ messages in thread
From: Suravee Suthikulpanit @ 2016-06-01 18:18 UTC (permalink / raw)
  To: Paolo Bonzini, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz

Hi Paolo/Radim,

I was a bit behind on catching up with the AVIC stuff the past couple 
weeks. Thank you for the help cleaning up on this patch and pulling this 
in to your tree. I can see now that it has been pulled into the 4.7-rc1. 
I really appreciate your help.

Please see a minor comment below.

On 5/17/16 07:09, Paolo Bonzini wrote:
>
>
> On 10/05/2016 17:43, Paolo Bonzini wrote:
>>
>>
>> On 04/05/2016 21:09, Suravee Suthikulpanit wrote:
>>> From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
>>>
>>> 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 <suravee.suthikulpanit@amd.com>
>>> Reviewed-by: Radim Krčmář <rkrcmar@redhat.com>
>>> ---
>>
>> I think this is the only patch that needs a little more work, because
>> there are a bunch of unused return values that really should be
>> WARN_ON.  In addition the load and put cases are different enough that
>> they should be separate functions.
>>
>> Can you please test this?
>>
>> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
>> index f3dbf1d33a61..3168d6c8d24f 100644
>> --- a/arch/x86/kvm/svm.c
>> +++ b/arch/x86/kvm/svm.c
>> @@ -184,7 +184,7 @@ struct vcpu_svm {
>>   	u32 ldr_reg;
>>   	struct page *avic_backing_page;
>>   	u64 *avic_physical_id_cache;
>> -	bool avic_is_blocking;
>> +	bool avic_is_running;
>>   };
>>
>>   #define AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK	(0xFF)
>> @@ -1321,18 +1321,20 @@ free_avic:
>>   /**
>>    * This function is called during VCPU halt/unhalt.
>>    */
>> -static int avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
>> +static void 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;
>> +		return;
>> +
>> +	svm->avic_is_running = is_run;

Shouldn't we do this below --->
>>
>>   	/* ID = 0xff (broadcast), ID > 0xff (reserved) */
>> -	if (h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)
>> -		return -EINVAL;
>> +	if (WARN_ON(h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT))
>> +		return;

<--- HERE
>>
>>   	entry = READ_ONCE(*(svm->avic_physical_id_cache));
>>   	WARN_ON(is_run == !!(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK));
>> @@ -1341,36 +1343,45 @@ static int avic_set_running(struct kvm_vcpu *vcpu, bool is_run)
>>   	if (is_run)
>>   		entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK;
>>   	WRITE_ONCE(*(svm->avic_physical_id_cache), entry);
>> -
>> -	return 0;
>>   }
>>
>> [....]
>>
>> The two functions now have the same signature as their callers,
>> svm_vcpu_load and svm_vcpu_put.
>
> Radim, does this look sane?  I plan to include it in my pull request
> (I'm running AMD autotest now and it passed the first few tests).
>
> Thanks,
>
> Paolo
>


I have also tested the changes in the 4.7-rc1 on the CZ hardware w/ AVIC 
and everything looks good.

As for the nested virtualization. Currently, this is not working with 
AVIC enabled on the host, but it works fine w/ AVIC disabled. I'll look 
into enabling nested virtualization w/ AVIC enable next.

Thank you for all your help,
Suravee

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PART1 V5 13/13] svm: Manage vcpu load/unload when enable AVIC
  2016-06-01 18:18       ` Suravee Suthikulpanit
@ 2016-06-01 18:37         ` Paolo Bonzini
  0 siblings, 0 replies; 29+ messages in thread
From: Paolo Bonzini @ 2016-06-01 18:37 UTC (permalink / raw)
  To: Suravee Suthikulpanit, rkrcmar, joro, bp, gleb, alex.williamson
  Cc: kvm, linux-kernel, wei, sherry.hurwitz



On 01/06/2016 20:18, Suravee Suthikulpanit wrote:
>>>
>>> +    svm->avic_is_running = is_run;
> 
> Shouldn't we do this below --->
>>>
>>>       /* ID = 0xff (broadcast), ID > 0xff (reserved) */
>>> -    if (h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT)
>>> -        return -EINVAL;
>>> +    if (WARN_ON(h_physical_id >= AVIC_MAX_PHYSICAL_ID_COUNT))
>>> +        return;
> 
> <--- HERE

It doesn't really matter because these physical APIC IDs are not
reachable anyway so they don't have the IS_RUNNING field.

The avic_is_running field is only used in avic_vcpu_load, and again only
when h_physical_id is in range.  I left the assignment before the
warning so that avic_vcpu_load does the right thing after a
(hypothetical) migration from an out-of-range physical CPU to an
in-range physical CPU.

Paolo

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2016-06-01 18:38 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-05-04 19:09 [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 01/13] KVM: x86: Misc LAPIC changes to expose helper functions Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 02/13] KVM: x86: Rename kvm_apic_get_reg to kvm_lapic_get_reg Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 03/13] KVM: x86: Introducing kvm_x86_ops VM init/destroy hooks Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 04/13] KVM: x86: Introducing kvm_x86_ops VCPU blocking/unblocking hooks Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 05/13] KVM: split kvm_vcpu_wake_up from kvm_vcpu_kick Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 06/13] svm: Introduce new AVIC VMCB registers Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 07/13] KVM: x86: Detect and Initialize AVIC support Suravee Suthikulpanit
2016-05-09 10:27   ` Borislav Petkov
2016-05-10  9:14   ` Borislav Petkov
2016-05-10 14:43     ` Paolo Bonzini
2016-05-10 16:24       ` Borislav Petkov
2016-05-10 17:00         ` Paolo Bonzini
2016-05-10 17:06           ` Borislav Petkov
2016-05-04 19:09 ` [PART1 V5 08/13] svm: Add interrupt injection via AVIC Suravee Suthikulpanit
2016-05-10  9:19   ` Borislav Petkov
2016-05-10 14:50     ` Paolo Bonzini
2016-06-01  4:02       ` Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 09/13] svm: Add VMEXIT handlers for AVIC Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 10/13] KVM: x86: Introducing kvm_x86_ops.apicv_post_state_restore Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 11/13] svm: Do not expose x2APIC when enable AVIC Suravee Suthikulpanit
2016-05-04 19:09 ` [PART1 V5 12/13] svm: Do not intercept CR8 " Suravee Suthikulpanit
2016-05-10 15:12   ` Paolo Bonzini
2016-05-04 19:09 ` [PART1 V5 13/13] svm: Manage vcpu load/unload " Suravee Suthikulpanit
2016-05-10 15:43   ` Paolo Bonzini
2016-05-17 12:09     ` Paolo Bonzini
2016-06-01 18:18       ` Suravee Suthikulpanit
2016-06-01 18:37         ` Paolo Bonzini
2016-05-10 14:57 ` [PART1 V5 00/13] KVM: x86: Introduce SVM AVIC support Paolo Bonzini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).