All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP.
@ 2015-06-02 23:51 Steve Rutherford
  2015-06-02 23:51 ` [PATCH v3 2/4] KVM: x86: Add KVM exit for IOAPIC EOIs Steve Rutherford
                   ` (3 more replies)
  0 siblings, 4 replies; 20+ messages in thread
From: Steve Rutherford @ 2015-06-02 23:51 UTC (permalink / raw)
  To: kvm

First patch in a series which enables the relocation of the
PIC/IOAPIC to userspace.

Adds capability KVM_CAP_SPLIT_IRQCHIP;

KVM_CAP_SPLIT_IRQCHIP enables the construction of LAPICs without the
rest of the irqchip.

Compile tested for x86.

Signed-off-by: Steve Rutherford <srutherford@google.com>
Suggested-by: Andrew Honig <ahonig@google.com>
---
 Documentation/virtual/kvm/api.txt | 15 ++++++++++++
 arch/powerpc/kvm/irq.h            |  5 ++++
 arch/s390/kvm/irq.h               |  4 ++++
 arch/x86/include/asm/kvm_host.h   |  2 ++
 arch/x86/kvm/assigned-dev.c       |  4 ++--
 arch/x86/kvm/irq.c                |  6 ++---
 arch/x86/kvm/irq.h                | 11 +++++++++
 arch/x86/kvm/irq_comm.c           |  7 ++++++
 arch/x86/kvm/lapic.c              | 13 +++++++----
 arch/x86/kvm/mmu.c                |  2 +-
 arch/x86/kvm/svm.c                |  4 ++--
 arch/x86/kvm/vmx.c                | 12 +++++-----
 arch/x86/kvm/x86.c                | 49 +++++++++++++++++++++++++++------------
 include/kvm/arm_vgic.h            |  1 +
 include/linux/kvm_host.h          |  1 +
 include/uapi/linux/kvm.h          |  1 +
 virt/kvm/irqchip.c                |  2 +-
 17 files changed, 104 insertions(+), 35 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 6955444..9a43d42 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2979,6 +2979,7 @@ len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
 and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
 which is the maximum number of possibly pending cpu-local interrupts.
 
+
 5. The kvm_run structure
 ------------------------
 
@@ -3575,6 +3576,20 @@ struct {
 
 KVM handlers should exit to userspace with rc = -EREMOTE.
 
+7.5 KVM_SPLIT_IRQCHIP
+
+Capability: KVM_CAP_SPLIT_IRQCHIP
+Architectures: x86
+Type:  VM ioctl
+Parameters: None
+Returns: 0 on success, -1 on error
+
+Create a local apic for each processor in the kernel.  This differs from
+KVM_CREATE_IRQCHIP in that it only creates the local apic; it creates neither
+the ioapic nor the pic in the kernel. Also, enables in kernel routing of
+interrupt requests. Fails if VCPU has already been created, or if the irqchip is
+already in the kernel.
+
 
 8. Other capabilities.
 ----------------------
diff --git a/arch/powerpc/kvm/irq.h b/arch/powerpc/kvm/irq.h
index 5a9a10b..5e6fa06 100644
--- a/arch/powerpc/kvm/irq.h
+++ b/arch/powerpc/kvm/irq.h
@@ -17,4 +17,9 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
 	return ret;
 }
 
+static inline int lapic_in_kernel(struct kvm *kvm)
+{
+	return irqchip_in_kernel(kvm);
+}
+
 #endif
diff --git a/arch/s390/kvm/irq.h b/arch/s390/kvm/irq.h
index d98e415..db876c3 100644
--- a/arch/s390/kvm/irq.h
+++ b/arch/s390/kvm/irq.h
@@ -19,4 +19,8 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
 	return 1;
 }
 
+static inline int lapic_in_kernel(struct kvm *kvm)
+{
+	return irqchip_in_kernel(kvm);
+}
 #endif
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7276107..af3225a 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -639,6 +639,8 @@ struct kvm_arch {
 	bool boot_vcpu_runs_old_kvmclock;
 
 	u64 disabled_quirks;
+
+	bool irqchip_split;
 };
 
 struct kvm_vm_stat {
diff --git a/arch/x86/kvm/assigned-dev.c b/arch/x86/kvm/assigned-dev.c
index d090ecf..1237e92 100644
--- a/arch/x86/kvm/assigned-dev.c
+++ b/arch/x86/kvm/assigned-dev.c
@@ -291,7 +291,7 @@ static int kvm_deassign_irq(struct kvm *kvm,
 {
 	unsigned long guest_irq_type, host_irq_type;
 
-	if (!irqchip_in_kernel(kvm))
+	if (!lapic_in_kernel(kvm))
 		return -EINVAL;
 	/* no irq assignment to deassign */
 	if (!assigned_dev->irq_requested_type)
@@ -568,7 +568,7 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
 	struct kvm_assigned_dev_kernel *match;
 	unsigned long host_irq_type, guest_irq_type;
 
-	if (!irqchip_in_kernel(kvm))
+	if (!lapic_in_kernel(kvm))
 		return r;
 
 	mutex_lock(&kvm->lock);
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index a1ec6a50..706e47a 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -57,7 +57,7 @@ static int kvm_cpu_has_extint(struct kvm_vcpu *v)
  */
 int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
 {
-	if (!irqchip_in_kernel(v->kvm))
+	if (!lapic_in_kernel(v->kvm))
 		return v->arch.interrupt.pending;
 
 	if (kvm_cpu_has_extint(v))
@@ -75,7 +75,7 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
  */
 int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
 {
-	if (!irqchip_in_kernel(v->kvm))
+	if (!lapic_in_kernel(v->kvm))
 		return v->arch.interrupt.pending;
 
 	if (kvm_cpu_has_extint(v))
@@ -103,7 +103,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
 {
 	int vector;
 
-	if (!irqchip_in_kernel(v->kvm))
+	if (!lapic_in_kernel(v->kvm))
 		return v->arch.interrupt.nr;
 
 	vector = kvm_cpu_get_extint(v);
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index ad68c73..e46abf3 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -92,6 +92,17 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
 	return ret;
 }
 
+static inline int irqchip_split(struct kvm *kvm)
+{
+	return kvm->arch.irqchip_split;
+}
+
+static inline int lapic_in_kernel(struct kvm *kvm)
+{
+	return irqchip_split(kvm) || irqchip_in_kernel(kvm);
+}
+
+
 void kvm_pic_reset(struct kvm_kpic_state *s);
 
 void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
index 9efff9e..f43c59a 100644
--- a/arch/x86/kvm/irq_comm.c
+++ b/arch/x86/kvm/irq_comm.c
@@ -328,3 +328,10 @@ int kvm_setup_default_irq_routing(struct kvm *kvm)
 	return kvm_set_irq_routing(kvm, default_routing,
 				   ARRAY_SIZE(default_routing), 0);
 }
+
+static const struct kvm_irq_routing_entry empty_routing[] = {};
+
+int kvm_setup_empty_irq_routing(struct kvm *kvm)
+{
+	return kvm_set_irq_routing(kvm, empty_routing, 0, 0);
+}
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index c789e00..92f4c98 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -209,7 +209,8 @@ out:
 	if (old)
 		kfree_rcu(old, rcu);
 
-	kvm_vcpu_request_scan_ioapic(kvm);
+	if (!irqchip_split(kvm))
+		kvm_vcpu_request_scan_ioapic(kvm);
 }
 
 static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
@@ -1827,7 +1828,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
 		kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
 				apic_find_highest_isr(apic));
 	kvm_make_request(KVM_REQ_EVENT, vcpu);
-	kvm_rtc_eoi_tracking_restore_one(vcpu);
+	if (!irqchip_split(vcpu->kvm))
+		kvm_rtc_eoi_tracking_restore_one(vcpu);
 }
 
 void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
@@ -1910,7 +1912,8 @@ static void apic_sync_pv_eoi_to_guest(struct kvm_vcpu *vcpu,
 	    /* Cache not set: could be safe but we don't bother. */
 	    apic->highest_isr_cache == -1 ||
 	    /* Need EOI to update ioapic. */
-	    kvm_ioapic_handles_vector(vcpu->kvm, apic->highest_isr_cache)) {
+	    kvm_ioapic_handles_vector(vcpu->kvm, apic->highest_isr_cache) ||
+	    irqchip_split(vcpu->kvm)) {
 		/*
 		 * PV EOI was disabled by apic_sync_pv_eoi_from_guest
 		 * so we need not do anything here.
@@ -1966,7 +1969,7 @@ int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 	struct kvm_lapic *apic = vcpu->arch.apic;
 	u32 reg = (msr - APIC_BASE_MSR) << 4;
 
-	if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
+	if (!lapic_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
 		return 1;
 
 	if (reg == APIC_ICR2)
@@ -1983,7 +1986,7 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
 	struct kvm_lapic *apic = vcpu->arch.apic;
 	u32 reg = (msr - APIC_BASE_MSR) << 4, low, high = 0;
 
-	if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
+	if (!lapic_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
 		return 1;
 
 	if (reg == APIC_DFR || reg == APIC_ICR2) {
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index a65ce12..1513d14 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3507,7 +3507,7 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
 
 static bool can_do_async_pf(struct kvm_vcpu *vcpu)
 {
-	if (unlikely(!irqchip_in_kernel(vcpu->kvm) ||
+	if (unlikely(!lapic_in_kernel(vcpu->kvm) ||
 		     kvm_event_needs_reinjection(vcpu)))
 		return false;
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index b9f9e10..59166de 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3054,7 +3054,7 @@ static int cr8_write_interception(struct vcpu_svm *svm)
 	u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
 	/* instruction emulation calls kvm_set_cr8() */
 	r = cr_interception(svm);
-	if (irqchip_in_kernel(svm->vcpu.kvm))
+	if (lapic_in_kernel(svm->vcpu.kvm))
 		return r;
 	if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
 		return r;
@@ -3295,7 +3295,7 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
 	 * If the user space waits to inject interrupts, exit as soon as
 	 * possible
 	 */
-	if (!irqchip_in_kernel(svm->vcpu.kvm) &&
+	if (!lapic_in_kernel(svm->vcpu.kvm) &&
 	    kvm_run->request_interrupt_window &&
 	    !kvm_cpu_has_interrupt(&svm->vcpu)) {
 		kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 9cf5030..3b58788 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -948,7 +948,7 @@ static inline bool cpu_has_vmx_tpr_shadow(void)
 
 static inline bool vm_need_tpr_shadow(struct kvm *kvm)
 {
-	return (cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm));
+	return (cpu_has_vmx_tpr_shadow()) && lapic_in_kernel(kvm);
 }
 
 static inline bool cpu_has_secondary_exec_ctrls(void)
@@ -1064,7 +1064,7 @@ static inline bool cpu_has_vmx_ple(void)
 
 static inline bool vm_need_virtualize_apic_accesses(struct kvm *kvm)
 {
-	return flexpriority_enabled && irqchip_in_kernel(kvm);
+	return flexpriority_enabled && lapic_in_kernel(kvm);
 }
 
 static inline bool cpu_has_vmx_vpid(void)
@@ -4341,7 +4341,7 @@ static void vmx_disable_intercept_msr_write_x2apic(u32 msr)
 
 static int vmx_vm_has_apicv(struct kvm *kvm)
 {
-	return enable_apicv && irqchip_in_kernel(kvm);
+	return enable_apicv && lapic_in_kernel(kvm);
 }
 
 static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
@@ -5317,7 +5317,7 @@ static int handle_cr(struct kvm_vcpu *vcpu)
 				u8 cr8 = (u8)val;
 				err = kvm_set_cr8(vcpu, cr8);
 				kvm_complete_insn_gp(vcpu, err);
-				if (irqchip_in_kernel(vcpu->kvm))
+				if (lapic_in_kernel(vcpu->kvm))
 					return 1;
 				if (cr8_prev <= cr8)
 					return 1;
@@ -5534,7 +5534,7 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu)
 	 * If the user space waits to inject interrupts, exit as soon as
 	 * possible
 	 */
-	if (!irqchip_in_kernel(vcpu->kvm) &&
+	if (!lapic_in_kernel(vcpu->kvm) &&
 	    vcpu->run->request_interrupt_window &&
 	    !kvm_cpu_has_interrupt(vcpu)) {
 		vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
@@ -9419,7 +9419,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 	/* vmcs12's VM_ENTRY_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE are
 	 * emulated by vmx_set_efer(), below.
 	 */
-	vm_entry_controls_init(vmx, 
+	vm_entry_controls_init(vmx,
 		(vmcs12->vm_entry_controls & ~VM_ENTRY_LOAD_IA32_EFER &
 			~VM_ENTRY_IA32E_MODE) |
 		(vmcs_config.vmentry_ctrl & ~VM_ENTRY_IA32E_MODE));
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 79dde16..19c8980 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -784,7 +784,7 @@ int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
 	if (cr8 & CR8_RESERVED_BITS)
 		return 1;
-	if (irqchip_in_kernel(vcpu->kvm))
+	if (lapic_in_kernel(vcpu->kvm))
 		kvm_lapic_set_tpr(vcpu, cr8);
 	else
 		vcpu->arch.cr8 = cr8;
@@ -794,7 +794,7 @@ EXPORT_SYMBOL_GPL(kvm_set_cr8);
 
 unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
 {
-	if (irqchip_in_kernel(vcpu->kvm))
+	if (lapic_in_kernel(vcpu->kvm))
 		return kvm_lapic_get_cr8(vcpu);
 	else
 		return vcpu->arch.cr8;
@@ -2866,6 +2866,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
 	case KVM_CAP_TSC_DEADLINE_TIMER:
 	case KVM_CAP_ENABLE_CAP_VM:
 	case KVM_CAP_DISABLE_QUIRKS:
+	case KVM_CAP_SPLIT_IRQCHIP:
 #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
 	case KVM_CAP_ASSIGN_DEV_IRQ:
 	case KVM_CAP_PCI_2_3:
@@ -3068,7 +3069,7 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
 {
 	if (irq->irq >= KVM_NR_INTERRUPTS)
 		return -EINVAL;
-	if (irqchip_in_kernel(vcpu->kvm))
+	if (lapic_in_kernel(vcpu->kvm))
 		return -ENXIO;
 
 	kvm_queue_interrupt(vcpu, irq->irq, false);
@@ -3546,7 +3547,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		struct kvm_vapic_addr va;
 
 		r = -EINVAL;
-		if (!irqchip_in_kernel(vcpu->kvm))
+		if (!lapic_in_kernel(vcpu->kvm))
 			goto out;
 		r = -EFAULT;
 		if (copy_from_user(&va, argp, sizeof va))
@@ -3904,7 +3905,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
 int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event,
 			bool line_status)
 {
-	if (!irqchip_in_kernel(kvm))
+	if (!lapic_in_kernel(kvm))
 		return -ENXIO;
 
 	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
@@ -3926,6 +3927,23 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 		kvm->arch.disabled_quirks = cap->args[0];
 		r = 0;
 		break;
+	case KVM_CAP_SPLIT_IRQCHIP: {
+		mutex_lock(&kvm->lock);
+		r = -EEXIST;
+		if (lapic_in_kernel(kvm))
+			goto split_irqchip_unlock;
+		r = -EINVAL;
+		if (atomic_read(&kvm->online_vcpus))
+			goto split_irqchip_unlock;
+		r = kvm_setup_empty_irq_routing(kvm);
+		if (r)
+			goto split_irqchip_unlock;
+		kvm->arch.irqchip_split = true;
+		r = 0;
+split_irqchip_unlock:
+		mutex_unlock(&kvm->lock);
+		break;
+	}
 	default:
 		r = -EINVAL;
 		break;
@@ -4194,6 +4212,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
 		r = kvm_vm_ioctl_enable_cap(kvm, &cap);
 		break;
 	}
+
 	default:
 		r = kvm_vm_ioctl_assigned_device(kvm, ioctl, arg);
 	}
@@ -5959,7 +5978,7 @@ void kvm_arch_exit(void)
 int kvm_vcpu_halt(struct kvm_vcpu *vcpu)
 {
 	++vcpu->stat.halt_exits;
-	if (irqchip_in_kernel(vcpu->kvm)) {
+	if (lapic_in_kernel(vcpu->kvm)) {
 		vcpu->arch.mp_state = KVM_MP_STATE_HALTED;
 		return 1;
 	} else {
@@ -6126,7 +6145,7 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
  */
 static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
 {
-	return (!irqchip_in_kernel(vcpu->kvm) && !kvm_cpu_has_interrupt(vcpu) &&
+	return (!lapic_in_kernel(vcpu->kvm) && !kvm_cpu_has_interrupt(vcpu) &&
 		vcpu->run->request_interrupt_window &&
 		kvm_arch_interrupt_allowed(vcpu));
 }
@@ -6138,7 +6157,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
 	kvm_run->if_flag = (kvm_get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
 	kvm_run->cr8 = kvm_get_cr8(vcpu);
 	kvm_run->apic_base = kvm_get_apic_base(vcpu);
-	if (irqchip_in_kernel(vcpu->kvm))
+	if (lapic_in_kernel(vcpu->kvm))
 		kvm_run->ready_for_interrupt_injection = 1;
 	else
 		kvm_run->ready_for_interrupt_injection =
@@ -6285,7 +6304,7 @@ void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
 {
 	struct page *page = NULL;
 
-	if (!irqchip_in_kernel(vcpu->kvm))
+	if (!lapic_in_kernel(vcpu->kvm))
 		return;
 
 	if (!kvm_x86_ops->set_apic_access_page_addr)
@@ -6323,7 +6342,7 @@ void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
 static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 {
 	int r;
-	bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
+	bool req_int_win = !lapic_in_kernel(vcpu->kvm) &&
 		vcpu->run->request_interrupt_window;
 	bool req_immediate_exit = false;
 
@@ -6712,7 +6731,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	}
 
 	/* re-sync apic's tpr */
-	if (!irqchip_in_kernel(vcpu->kvm)) {
+	if (!lapic_in_kernel(vcpu->kvm)) {
 		if (kvm_set_cr8(vcpu, kvm_run->cr8) != 0) {
 			r = -EINVAL;
 			goto out;
@@ -7421,7 +7440,7 @@ void kvm_arch_check_processor_compat(void *rtn)
 
 bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
 {
-	return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
+	return lapic_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
 }
 
 struct static_key kvm_no_apic_vcpu __read_mostly;
@@ -7437,7 +7456,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 
 	vcpu->arch.pv.pv_unhalted = false;
 	vcpu->arch.emulate_ctxt.ops = &emulate_ops;
-	if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu))
+	if (!lapic_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu))
 		vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
 	else
 		vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED;
@@ -7455,7 +7474,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 	if (r < 0)
 		goto fail_free_pio_data;
 
-	if (irqchip_in_kernel(kvm)) {
+	if (lapic_in_kernel(kvm)) {
 		r = kvm_create_lapic(vcpu);
 		if (r < 0)
 			goto fail_mmu_destroy;
@@ -7518,7 +7537,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 	kvm_mmu_destroy(vcpu);
 	srcu_read_unlock(&vcpu->kvm->srcu, idx);
 	free_page((unsigned long)vcpu->arch.pio_data);
-	if (!irqchip_in_kernel(vcpu->kvm))
+	if (!lapic_in_kernel(vcpu->kvm))
 		static_key_slow_dec(&kvm_no_apic_vcpu);
 }
 
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 133ea00..ffe1f4e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -329,6 +329,7 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu);
 
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
+#define lapic_in_kernel(k)      (irqchip_in_kernel(k))
 #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
 #define vgic_ready(k)		((k)->arch.vgic.ready)
 
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index a8bcbc9..7e2b41a 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -935,6 +935,7 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
 #endif
 
 int kvm_setup_default_irq_routing(struct kvm *kvm);
+int kvm_setup_empty_irq_routing(struct kvm *kvm);
 int kvm_set_irq_routing(struct kvm *kvm,
 			const struct kvm_irq_routing_entry *entries,
 			unsigned nr,
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 75bd9f7..1e6f6c3 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -815,6 +815,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_S390_IRQ_STATE 114
 #define KVM_CAP_PPC_HWRNG 115
 #define KVM_CAP_DISABLE_QUIRKS 116
+#define KVM_CAP_SPLIT_IRQCHIP 117
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
index 1d56a90..8aaceed 100644
--- a/virt/kvm/irqchip.c
+++ b/virt/kvm/irqchip.c
@@ -73,7 +73,7 @@ int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
 {
 	struct kvm_kernel_irq_routing_entry route;
 
-	if (!irqchip_in_kernel(kvm) || msi->flags != 0)
+	if (!lapic_in_kernel(kvm) || msi->flags != 0)
 		return -EINVAL;
 
 	route.msi.address_lo = msi->address_lo;
-- 
2.2.0.rc0.207.ga3a616c


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

* [PATCH v3 2/4] KVM: x86: Add KVM exit for IOAPIC EOIs
  2015-06-02 23:51 [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Steve Rutherford
@ 2015-06-02 23:51 ` Steve Rutherford
  2015-06-03  9:16   ` Paolo Bonzini
  2015-06-02 23:51 ` [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference Steve Rutherford
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 20+ messages in thread
From: Steve Rutherford @ 2015-06-02 23:51 UTC (permalink / raw)
  To: kvm

Adds KVM_EXIT_IOAPIC_EOI which allows the kernel to EOI
level-triggered IOAPIC interrupts.

Uses a per VCPU exit bitmap to decide whether or not the IOAPIC needs
to be informed (which is identical to the EOI_EXIT_BITMAP field used
by modern x86 processors, but can also be used to elide kvm IOAPIC EOI
exits on older processors).

[Note: A prototype using ResampleFDs found that decoupling the EOI
from the VCPU's thread made it possible for the VCPU to not see a
recent EOI after reentering the guest. This does not match real
hardware.]

Compile tested for Intel x86.

Signed-off-by: Steve Rutherford <srutherford@google.com>
---
 Documentation/virtual/kvm/api.txt | 10 ++++++++++
 arch/x86/include/asm/kvm_host.h   |  3 +++
 arch/x86/kvm/lapic.c              |  9 +++++++++
 arch/x86/kvm/x86.c                | 11 +++++++++++
 include/linux/kvm_host.h          |  1 +
 include/uapi/linux/kvm.h          |  5 +++++
 6 files changed, 39 insertions(+)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 9a43d42..6ab2a3f7 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -3271,6 +3271,16 @@ Valid values for 'type' are:
 	 */
 	__u64 kvm_valid_regs;
 	__u64 kvm_dirty_regs;
+
+	/* KVM_EXIT_IOAPIC_EOI */
+        struct {
+	       __u8 vector;
+        } eoi;
+
+Indicates that an eoi of a level triggered IOAPIC interrupt on vector has
+occurred, which should be handled by the userspace IOAPIC. Triggers when
+the Irqchip has been split between userspace and the kernel.
+
 	union {
 		struct kvm_sync_regs regs;
 		char padding[1024];
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index af3225a..2778d36 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -540,6 +540,9 @@ struct kvm_vcpu_arch {
 	struct {
 		bool pv_unhalted;
 	} pv;
+
+	u64 eoi_exit_bitmaps[4];
+	int pending_ioapic_eoi;
 };
 
 struct kvm_lpage_info {
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 92f4c98..28eb946 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -869,6 +869,15 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
 
 static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
 {
+	if (irqchip_split(apic->vcpu->kvm)) {
+		if (test_bit(vector,
+			     (void *) apic->vcpu->arch.eoi_exit_bitmaps)) {
+			apic->vcpu->arch.pending_ioapic_eoi = vector;
+			kvm_make_request(KVM_REQ_IOAPIC_EOI_EXIT, apic->vcpu);
+		}
+		return;
+	}
+
 	if (kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
 		int trigger_mode;
 		if (apic_test_vector(vector, apic->regs + APIC_TMR))
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 19c8980..5e01810 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6392,6 +6392,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 			kvm_handle_pmu_event(vcpu);
 		if (kvm_check_request(KVM_REQ_PMI, vcpu))
 			kvm_deliver_pmi(vcpu);
+		if (kvm_check_request(KVM_REQ_IOAPIC_EOI_EXIT, vcpu)) {
+			BUG_ON(vcpu->arch.pending_ioapic_eoi > 255);
+			if (test_bit(vcpu->arch.pending_ioapic_eoi,
+				     (void *) vcpu->arch.eoi_exit_bitmaps)) {
+				vcpu->run->exit_reason = KVM_EXIT_IOAPIC_EOI;
+				vcpu->run->eoi.vector =
+						vcpu->arch.pending_ioapic_eoi;
+				r = 0;
+				goto out;
+			}
+		}
 		if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
 			vcpu_scan_ioapic(vcpu);
 		if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 7e2b41a..c6df36f 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -134,6 +134,7 @@ static inline bool is_error_page(struct page *page)
 #define KVM_REQ_ENABLE_IBS        23
 #define KVM_REQ_DISABLE_IBS       24
 #define KVM_REQ_APIC_PAGE_RELOAD  25
+#define KVM_REQ_IOAPIC_EOI_EXIT   26
 
 #define KVM_USERSPACE_IRQ_SOURCE_ID		0
 #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID	1
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 1e6f6c3..826a08d 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -183,6 +183,7 @@ struct kvm_s390_skeys {
 #define KVM_EXIT_EPR              23
 #define KVM_EXIT_SYSTEM_EVENT     24
 #define KVM_EXIT_S390_STSI        25
+#define KVM_EXIT_IOAPIC_EOI       26
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -329,6 +330,10 @@ struct kvm_run {
 			__u8 sel1;
 			__u16 sel2;
 		} s390_stsi;
+		/* KVM_EXIT_IOAPIC_EOI */
+		struct {
+			__u8 vector;
+		} eoi;
 		/* Fix the size of the union. */
 		char padding[256];
 	};
-- 
2.2.0.rc0.207.ga3a616c


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

* [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference
  2015-06-02 23:51 [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Steve Rutherford
  2015-06-02 23:51 ` [PATCH v3 2/4] KVM: x86: Add KVM exit for IOAPIC EOIs Steve Rutherford
@ 2015-06-02 23:51 ` Steve Rutherford
  2015-06-03  9:16   ` Paolo Bonzini
  2015-06-08 10:33   ` Wanpeng Li
  2015-06-02 23:51 ` [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace Steve Rutherford
  2015-06-03  8:54 ` [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Paolo Bonzini
  3 siblings, 2 replies; 20+ messages in thread
From: Steve Rutherford @ 2015-06-02 23:51 UTC (permalink / raw)
  To: kvm

In order to support a userspace IOAPIC interacting with an in kernel
APIC, the EOI exit bitmaps need to be configurable.

If the IOAPIC is in userspace (i.e. the irqchip has been split), the
EOI exit bitmaps will be set whenever the GSI Routes are configured.
In particular, for the low MSI routes are reservable for userspace
IOAPICs. For these MSI routes, the EOI Exit bit corresponding to the
destination vector of the route will be set for the destination VCPU.

The intention is for the userspace IOAPICs to use the reservable MSI
routes to inject interrupts into the guest.

This is a slight abuse of the notion of an MSI Route, given that MSIs
classically bypass the IOAPIC. It might be worthwhile to add an
additional route type to improve clarity.

Compile tested for Intel x86.

Signed-off-by: Steve Rutherford <srutherford@google.com>
---
 arch/x86/include/asm/kvm_host.h |  1 +
 arch/x86/kvm/ioapic.c           | 16 ++++++++++++++++
 arch/x86/kvm/ioapic.h           |  2 ++
 arch/x86/kvm/lapic.c            |  3 +--
 arch/x86/kvm/x86.c              | 30 ++++++++++++++++++++++--------
 include/linux/kvm_host.h        |  9 +++++++++
 virt/kvm/irqchip.c              | 37 +++++++++++++++++++++++++++++++++++++
 7 files changed, 88 insertions(+), 10 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 2778d36..4f439ff 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -644,6 +644,7 @@ struct kvm_arch {
 	u64 disabled_quirks;
 
 	bool irqchip_split;
+	u8 nr_reserved_ioapic_pins;
 };
 
 struct kvm_vm_stat {
diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index 856f791..fb5281b 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -672,3 +672,19 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
 	spin_unlock(&ioapic->lock);
 	return 0;
 }
+
+void kvm_arch_irq_routing_update(struct kvm *kvm)
+{
+	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
+
+	if (ioapic)
+		return;
+	if (!lapic_in_kernel(kvm))
+		return;
+	kvm_make_scan_ioapic_request(kvm);
+}
+
+u8 kvm_arch_nr_userspace_ioapic_pins(struct kvm *kvm)
+{
+	return kvm->arch.nr_reserved_ioapic_pins;
+}
diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
index ca0b0b4..3af349c 100644
--- a/arch/x86/kvm/ioapic.h
+++ b/arch/x86/kvm/ioapic.h
@@ -9,6 +9,7 @@ struct kvm;
 struct kvm_vcpu;
 
 #define IOAPIC_NUM_PINS  KVM_IOAPIC_NUM_PINS
+#define MAX_NR_RESERVED_IOAPIC_PINS 48
 #define IOAPIC_VERSION_ID 0x11	/* IOAPIC version */
 #define IOAPIC_EDGE_TRIG  0
 #define IOAPIC_LEVEL_TRIG 1
@@ -123,4 +124,5 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
 void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap,
 			u32 *tmr);
 
+void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
 #endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 28eb946..766d297 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -209,8 +209,7 @@ out:
 	if (old)
 		kfree_rcu(old, rcu);
 
-	if (!irqchip_split(kvm))
-		kvm_vcpu_request_scan_ioapic(kvm);
+	kvm_make_scan_ioapic_request(kvm);
 }
 
 static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 5e01810..35d13d4 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3930,15 +3930,20 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
 	case KVM_CAP_SPLIT_IRQCHIP: {
 		mutex_lock(&kvm->lock);
 		r = -EEXIST;
-		if (lapic_in_kernel(kvm))
+		if (irqchip_in_kernel(kvm))
 			goto split_irqchip_unlock;
 		r = -EINVAL;
-		if (atomic_read(&kvm->online_vcpus))
-			goto split_irqchip_unlock;
-		r = kvm_setup_empty_irq_routing(kvm);
-		if (r)
+		if (cap->args[0] > MAX_NR_RESERVED_IOAPIC_PINS)
 			goto split_irqchip_unlock;
-		kvm->arch.irqchip_split = true;
+		if (!irqchip_split(kvm)) {
+			if (atomic_read(&kvm->online_vcpus))
+				goto split_irqchip_unlock;
+			r = kvm_setup_empty_irq_routing(kvm);
+			if (r)
+				goto split_irqchip_unlock;
+			kvm->arch.irqchip_split = true;
+		}
+		kvm->arch.nr_reserved_ioapic_pins = cap->args[0];
 		r = 0;
 split_irqchip_unlock:
 		mutex_unlock(&kvm->lock);
@@ -6403,8 +6408,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 				goto out;
 			}
 		}
-		if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
-			vcpu_scan_ioapic(vcpu);
+		if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu)) {
+			if (irqchip_split(vcpu->kvm)) {
+				memset(vcpu->arch.eoi_exit_bitmaps, 0, 32);
+				kvm_scan_ioapic_routes(
+				    vcpu, vcpu->arch.eoi_exit_bitmaps);
+				kvm_x86_ops->load_eoi_exitmap(
+				    vcpu, vcpu->arch.eoi_exit_bitmaps);
+
+			} else
+				vcpu_scan_ioapic(vcpu);
+		}
 		if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
 			kvm_vcpu_reload_apic_access_page(vcpu);
 	}
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index c6df36f..1bd4afa 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -438,10 +438,19 @@ void vcpu_put(struct kvm_vcpu *vcpu);
 
 #ifdef __KVM_HAVE_IOAPIC
 void kvm_vcpu_request_scan_ioapic(struct kvm *kvm);
+void kvm_arch_irq_routing_update(struct kvm *kvm);
+u8 kvm_arch_nr_userspace_ioapic_pins(struct kvm *kvm);
 #else
 static inline void kvm_vcpu_request_scan_ioapic(struct kvm *kvm)
 {
 }
+static inline void kvm_arch_irq_routing_update(struct kvm *kvm)
+{
+}
+static inline u8 kvm_arch_nr_userspace_ioapic_pins(struct kvm *kvm)
+{
+	return 0;
+}
 #endif
 
 #ifdef CONFIG_HAVE_KVM_IRQFD
diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
index 8aaceed..208fdd3 100644
--- a/virt/kvm/irqchip.c
+++ b/virt/kvm/irqchip.c
@@ -203,6 +203,8 @@ int kvm_set_irq_routing(struct kvm *kvm,
 	kvm_irq_routing_update(kvm);
 	mutex_unlock(&kvm->irq_lock);
 
+	kvm_arch_irq_routing_update(kvm);
+
 	synchronize_srcu_expedited(&kvm->irq_srcu);
 
 	new = old;
@@ -212,3 +214,38 @@ out:
 	kfree(new);
 	return r;
 }
+
+void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+{
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_kernel_irq_routing_entry *entry;
+	struct kvm_irq_routing_table *table;
+	u32 i, nr_ioapic_pins;
+	int idx;
+
+	/* kvm->irq_routing must be read after clearing
+	 * KVM_SCAN_IOAPIC. */
+	smp_mb();
+	idx = srcu_read_lock(&kvm->irq_srcu);
+	table = kvm->irq_routing;
+	nr_ioapic_pins = min_t(u32, table->nr_rt_entries,
+			      kvm_arch_nr_userspace_ioapic_pins(kvm));
+	for (i = 0; i < nr_ioapic_pins; ++i) {
+		hlist_for_each_entry(entry, &table->map[i], link) {
+			u32 dest_id, dest_mode;
+
+			if (entry->type != KVM_IRQ_ROUTING_MSI)
+				continue;
+			dest_id = (entry->msi.address_lo >> 12) & 0xff;
+			dest_mode = (entry->msi.address_lo >> 2) & 0x1;
+			if (kvm_apic_match_dest(vcpu, NULL, 0, dest_id,
+						dest_mode)) {
+				u32 vector = entry->msi.data & 0xff;
+
+				__set_bit(vector,
+					  (unsigned long *) eoi_exit_bitmap);
+			}
+		}
+	}
+	srcu_read_unlock(&kvm->irq_srcu, idx);
+}
-- 
2.2.0.rc0.207.ga3a616c


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

* [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace
  2015-06-02 23:51 [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Steve Rutherford
  2015-06-02 23:51 ` [PATCH v3 2/4] KVM: x86: Add KVM exit for IOAPIC EOIs Steve Rutherford
  2015-06-02 23:51 ` [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference Steve Rutherford
@ 2015-06-02 23:51 ` Steve Rutherford
  2015-06-03  9:38   ` Paolo Bonzini
  2015-06-03  8:54 ` [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Paolo Bonzini
  3 siblings, 1 reply; 20+ messages in thread
From: Steve Rutherford @ 2015-06-02 23:51 UTC (permalink / raw)
  To: kvm

In order to enable userspace PIC support, the userspace PIC needs to
be able to inject local interrupt requests.

This adds the ioctl KVM_REQUEST_PIC_INJECTION and kvm exit
KVM_EXIT_GET_EXTINT.

The vm ioctl KVM_REQUEST_PIC_INJECTION makes a KVM_REQ_EVENT request
on the BSP, which causes the BSP to exit to userspace to fetch the
vector of the underlying external interrupt, which the BSP then
injects into the guest. This matches the PIC spec, and is necessary to
boot Windows.

Compiles for x86.

Update: Boots Windows and passes the KVM Unit Tests.

Signed-off-by: Steve Rutherford <srutherford@google.com>
---
 Documentation/virtual/kvm/api.txt |  9 ++++++
 arch/x86/include/asm/kvm_host.h   |  2 ++
 arch/x86/kvm/irq.c                | 22 +++++++++++++--
 arch/x86/kvm/lapic.c              |  7 +++++
 arch/x86/kvm/lapic.h              |  2 ++
 arch/x86/kvm/x86.c                | 59 +++++++++++++++++++++++++++++++++++++--
 include/uapi/linux/kvm.h          |  7 +++++
 7 files changed, 103 insertions(+), 5 deletions(-)

diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 6ab2a3f7..b5d90cb 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -2979,6 +2979,15 @@ len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
 and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
 which is the maximum number of possibly pending cpu-local interrupts.
 
+4.96 KVM_REQUEST_PIC_INJECTION
+
+Capability: KVM_CAP_SPLIT_IRQCHIP
+Type: VM ioctl
+Parameters: none
+Returns: 0 on success, -1 on error.
+
+Informs the kernel that userspace has a pending external interrupt.
+
 
 5. The kvm_run structure
 ------------------------
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 4f439ff..0e8b0fc 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -543,6 +543,8 @@ struct kvm_vcpu_arch {
 
 	u64 eoi_exit_bitmaps[4];
 	int pending_ioapic_eoi;
+	bool userspace_extint_available;
+	int pending_external_vector;
 };
 
 struct kvm_lpage_info {
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index 706e47a..1270b2a 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -38,12 +38,25 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
 
 /*
+ * check if there is a pending userspace external interrupt
+ */
+static int pending_userspace_extint(struct kvm_vcpu *v)
+{
+	return v->arch.userspace_extint_available ||
+	       v->arch.pending_external_vector != -1;
+}
+
+/*
  * check if there is pending interrupt from
  * non-APIC source without intack.
  */
 static int kvm_cpu_has_extint(struct kvm_vcpu *v)
 {
-	if (kvm_apic_accept_pic_intr(v))
+	u8 accept = kvm_apic_accept_pic_intr(v);
+
+	if (accept && irqchip_split(v->kvm))
+		return pending_userspace_extint(v);
+	else if (accept)
 		return pic_irqchip(v->kvm)->output;	/* PIC */
 	else
 		return 0;
@@ -91,7 +104,12 @@ EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
  */
 static int kvm_cpu_get_extint(struct kvm_vcpu *v)
 {
-	if (kvm_cpu_has_extint(v))
+	if (irqchip_split(v->kvm) && kvm_cpu_has_extint(v)) {
+		int vector = v->arch.pending_external_vector;
+
+		v->arch.pending_external_vector = -1;
+		return vector;
+	} else if (kvm_cpu_has_extint(v))
 		return kvm_pic_read_irq(v->kvm); /* PIC */
 	return -1;
 }
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 766d297..012b56ee 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2094,3 +2094,10 @@ void kvm_lapic_init(void)
 	jump_label_rate_limit(&apic_hw_disabled, HZ);
 	jump_label_rate_limit(&apic_sw_disabled, HZ);
 }
+
+void kvm_request_pic_injection(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.userspace_extint_available = true;
+	kvm_make_request(KVM_REQ_EVENT, vcpu);
+	kvm_vcpu_kick(vcpu);
+}
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 71b150c..7831e4d 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -63,6 +63,8 @@ int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq,
 		unsigned long *dest_map);
 int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type);
 
+void kvm_request_pic_injection(struct kvm_vcpu *vcpu);
+
 bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
 		struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map);
 
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 35d13d4..40e7509 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -65,6 +65,8 @@
 #include <asm/pvclock.h>
 #include <asm/div64.h>
 
+#define GET_VECTOR_FROM_USERSPACE 1
+
 #define MAX_IO_MSRS 256
 #define KVM_MAX_MCE_BANKS 32
 #define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P)
@@ -4217,6 +4219,30 @@ long kvm_arch_vm_ioctl(struct file *filp,
 		r = kvm_vm_ioctl_enable_cap(kvm, &cap);
 		break;
 	}
+	case KVM_REQUEST_PIC_INJECTION: {
+		int i;
+		struct kvm_vcpu *vcpu;
+		struct kvm_vcpu *bsp_vcpu = NULL;
+
+		mutex_lock(&kvm->lock);
+		r = -EEXIST;
+		if (!irqchip_split(kvm))
+			goto out;
+		kvm_for_each_vcpu(i, vcpu, kvm) {
+			if (kvm_vcpu_is_reset_bsp(vcpu)) {
+				bsp_vcpu = vcpu;
+				continue;
+			}
+		}
+		r = -EINVAL;
+		if (bsp_vcpu == NULL)
+			goto interrupt_unlock;
+		kvm_request_pic_injection(bsp_vcpu);
+		r = 0;
+interrupt_unlock:
+		mutex_unlock(&kvm->lock);
+		break;
+	}
 
 	default:
 		r = kvm_vm_ioctl_assigned_device(kvm, ioctl, arg);
@@ -6194,6 +6220,17 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
 	kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
 }
 
+static int must_fetch_userspace_extint(struct kvm_vcpu *vcpu)
+{
+	if (vcpu->arch.userspace_extint_available &&
+	    kvm_apic_accept_pic_intr(vcpu)) {
+		vcpu->arch.userspace_extint_available = false;
+		return true;
+	} else
+		return false;
+
+}
+
 static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
 {
 	int r;
@@ -6258,7 +6295,12 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
 				return r;
 		}
 		if (kvm_x86_ops->interrupt_allowed(vcpu)) {
-			kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu),
+			if (irqchip_split(vcpu->kvm) &&
+			    must_fetch_userspace_extint(vcpu)) {
+				return GET_VECTOR_FROM_USERSPACE;
+			}
+			kvm_queue_interrupt(vcpu,
+					    kvm_cpu_get_interrupt(vcpu),
 					    false);
 			kvm_x86_ops->set_irq(vcpu);
 		}
@@ -6424,13 +6466,19 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 	}
 
 	if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
+		int event;
 		kvm_apic_accept_events(vcpu);
 		if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) {
 			r = 1;
 			goto out;
 		}
-
-		if (inject_pending_event(vcpu, req_int_win) != 0)
+		event = inject_pending_event(vcpu, req_int_win);
+		if (event == GET_VECTOR_FROM_USERSPACE) {
+			vcpu->run->exit_reason = KVM_EXIT_GET_EXTINT;
+			kvm_make_request(KVM_REQ_EVENT, vcpu);
+			r = 0;
+			goto out;
+		} else if (event != 0)
 			req_immediate_exit = true;
 		/* enable NMI/IRQ window open exits if needed */
 		else if (vcpu->arch.nmi_pending)
@@ -6747,6 +6795,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 	if (vcpu->sigset_active)
 		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
 
+	if (vcpu->run->exit_reason == KVM_EXIT_GET_EXTINT)
+		vcpu->arch.pending_external_vector = vcpu->run->extint.vector;
+
 	if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) {
 		kvm_vcpu_block(vcpu);
 		kvm_apic_accept_events(vcpu);
@@ -7536,6 +7587,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 	kvm_async_pf_hash_reset(vcpu);
 	kvm_pmu_init(vcpu);
 
+	vcpu->arch.pending_external_vector = -1;
+
 	return 0;
 fail_free_wbinvd_dirty_mask:
 	free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 826a08d..0cf7ed6 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -184,6 +184,7 @@ struct kvm_s390_skeys {
 #define KVM_EXIT_SYSTEM_EVENT     24
 #define KVM_EXIT_S390_STSI        25
 #define KVM_EXIT_IOAPIC_EOI       26
+#define KVM_EXIT_GET_EXTINT       27
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -334,6 +335,10 @@ struct kvm_run {
 		struct {
 			__u8 vector;
 		} eoi;
+		/* KVM_EXIT_GET_EXTINT */
+		struct {
+			__u8 vector;
+		} extint;
 		/* Fix the size of the union. */
 		char padding[256];
 	};
@@ -1206,6 +1211,8 @@ struct kvm_s390_ucas_mapping {
 /* Available with KVM_CAP_S390_IRQ_STATE */
 #define KVM_S390_SET_IRQ_STATE	  _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state)
 #define KVM_S390_GET_IRQ_STATE	  _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
+/* Available with KVM_CAP_SPLIT_IRQCHIP */
+#define KVM_REQUEST_PIC_INJECTION _IO(KVMIO, 0xb7)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
-- 
2.2.0.rc0.207.ga3a616c


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

* Re: [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP.
  2015-06-02 23:51 [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Steve Rutherford
                   ` (2 preceding siblings ...)
  2015-06-02 23:51 ` [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace Steve Rutherford
@ 2015-06-03  8:54 ` Paolo Bonzini
  2015-06-04 20:38   ` Steve Rutherford
  3 siblings, 1 reply; 20+ messages in thread
From: Paolo Bonzini @ 2015-06-03  8:54 UTC (permalink / raw)
  To: Steve Rutherford, kvm



On 03/06/2015 01:51, Steve Rutherford wrote:
> First patch in a series which enables the relocation of the
> PIC/IOAPIC to userspace.
> 
> Adds capability KVM_CAP_SPLIT_IRQCHIP;
> 
> KVM_CAP_SPLIT_IRQCHIP enables the construction of LAPICs without the
> rest of the irqchip.

The documentation is not updated.

Changing other arches is definitely a no-no, unfortunately.  But there
are so many s/irqchip_in_kernel/lapic_in_kernel/ changes here, that I
wonder if you should just keep irqchip_in_kernel true in the "split
irqchip" case.  You are already testing irqchip_split in a few cases,
and you can add ioapic_in_kernel whenever you need to test
"lapic_in_kernel && !irqchip_split" at the same time.

Paolo

> Compile tested for x86.
> 
> Signed-off-by: Steve Rutherford <srutherford@google.com>
> Suggested-by: Andrew Honig <ahonig@google.com>
> ---
>  Documentation/virtual/kvm/api.txt | 15 ++++++++++++
>  arch/powerpc/kvm/irq.h            |  5 ++++
>  arch/s390/kvm/irq.h               |  4 ++++
>  arch/x86/include/asm/kvm_host.h   |  2 ++
>  arch/x86/kvm/assigned-dev.c       |  4 ++--
>  arch/x86/kvm/irq.c                |  6 ++---
>  arch/x86/kvm/irq.h                | 11 +++++++++
>  arch/x86/kvm/irq_comm.c           |  7 ++++++
>  arch/x86/kvm/lapic.c              | 13 +++++++----
>  arch/x86/kvm/mmu.c                |  2 +-
>  arch/x86/kvm/svm.c                |  4 ++--
>  arch/x86/kvm/vmx.c                | 12 +++++-----
>  arch/x86/kvm/x86.c                | 49 +++++++++++++++++++++++++++------------
>  include/kvm/arm_vgic.h            |  1 +
>  include/linux/kvm_host.h          |  1 +
>  include/uapi/linux/kvm.h          |  1 +
>  virt/kvm/irqchip.c                |  2 +-
>  17 files changed, 104 insertions(+), 35 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 6955444..9a43d42 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2979,6 +2979,7 @@ len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
>  and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
>  which is the maximum number of possibly pending cpu-local interrupts.
>  
> +
>  5. The kvm_run structure
>  ------------------------
>  
> @@ -3575,6 +3576,20 @@ struct {
>  
>  KVM handlers should exit to userspace with rc = -EREMOTE.
>  
> +7.5 KVM_SPLIT_IRQCHIP
> +
> +Capability: KVM_CAP_SPLIT_IRQCHIP
> +Architectures: x86
> +Type:  VM ioctl
> +Parameters: None
> +Returns: 0 on success, -1 on error
> +
> +Create a local apic for each processor in the kernel.  This differs from
> +KVM_CREATE_IRQCHIP in that it only creates the local apic; it creates neither
> +the ioapic nor the pic in the kernel. Also, enables in kernel routing of
> +interrupt requests. Fails if VCPU has already been created, or if the irqchip is
> +already in the kernel.
> +
>  
>  8. Other capabilities.
>  ----------------------
> diff --git a/arch/powerpc/kvm/irq.h b/arch/powerpc/kvm/irq.h
> index 5a9a10b..5e6fa06 100644
> --- a/arch/powerpc/kvm/irq.h
> +++ b/arch/powerpc/kvm/irq.h
> @@ -17,4 +17,9 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
>  	return ret;
>  }
>  
> +static inline int lapic_in_kernel(struct kvm *kvm)
> +{
> +	return irqchip_in_kernel(kvm);
> +}
> +
>  #endif
> diff --git a/arch/s390/kvm/irq.h b/arch/s390/kvm/irq.h
> index d98e415..db876c3 100644
> --- a/arch/s390/kvm/irq.h
> +++ b/arch/s390/kvm/irq.h
> @@ -19,4 +19,8 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
>  	return 1;
>  }
>  
> +static inline int lapic_in_kernel(struct kvm *kvm)
> +{
> +	return irqchip_in_kernel(kvm);
> +}
>  #endif
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 7276107..af3225a 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -639,6 +639,8 @@ struct kvm_arch {
>  	bool boot_vcpu_runs_old_kvmclock;
>  
>  	u64 disabled_quirks;
> +
> +	bool irqchip_split;
>  };
>  
>  struct kvm_vm_stat {
> diff --git a/arch/x86/kvm/assigned-dev.c b/arch/x86/kvm/assigned-dev.c
> index d090ecf..1237e92 100644
> --- a/arch/x86/kvm/assigned-dev.c
> +++ b/arch/x86/kvm/assigned-dev.c
> @@ -291,7 +291,7 @@ static int kvm_deassign_irq(struct kvm *kvm,
>  {
>  	unsigned long guest_irq_type, host_irq_type;
>  
> -	if (!irqchip_in_kernel(kvm))
> +	if (!lapic_in_kernel(kvm))
>  		return -EINVAL;
>  	/* no irq assignment to deassign */
>  	if (!assigned_dev->irq_requested_type)
> @@ -568,7 +568,7 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
>  	struct kvm_assigned_dev_kernel *match;
>  	unsigned long host_irq_type, guest_irq_type;
>  
> -	if (!irqchip_in_kernel(kvm))
> +	if (!lapic_in_kernel(kvm))
>  		return r;
>  
>  	mutex_lock(&kvm->lock);
> diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
> index a1ec6a50..706e47a 100644
> --- a/arch/x86/kvm/irq.c
> +++ b/arch/x86/kvm/irq.c
> @@ -57,7 +57,7 @@ static int kvm_cpu_has_extint(struct kvm_vcpu *v)
>   */
>  int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
>  {
> -	if (!irqchip_in_kernel(v->kvm))
> +	if (!lapic_in_kernel(v->kvm))
>  		return v->arch.interrupt.pending;
>  
>  	if (kvm_cpu_has_extint(v))
> @@ -75,7 +75,7 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
>   */
>  int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
>  {
> -	if (!irqchip_in_kernel(v->kvm))
> +	if (!lapic_in_kernel(v->kvm))
>  		return v->arch.interrupt.pending;
>  
>  	if (kvm_cpu_has_extint(v))
> @@ -103,7 +103,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
>  {
>  	int vector;
>  
> -	if (!irqchip_in_kernel(v->kvm))
> +	if (!lapic_in_kernel(v->kvm))
>  		return v->arch.interrupt.nr;
>  
>  	vector = kvm_cpu_get_extint(v);
> diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
> index ad68c73..e46abf3 100644
> --- a/arch/x86/kvm/irq.h
> +++ b/arch/x86/kvm/irq.h
> @@ -92,6 +92,17 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
>  	return ret;
>  }
>  
> +static inline int irqchip_split(struct kvm *kvm)
> +{
> +	return kvm->arch.irqchip_split;
> +}
> +
> +static inline int lapic_in_kernel(struct kvm *kvm)
> +{
> +	return irqchip_split(kvm) || irqchip_in_kernel(kvm);
> +}
> +
> +
>  void kvm_pic_reset(struct kvm_kpic_state *s);
>  
>  void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
> diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
> index 9efff9e..f43c59a 100644
> --- a/arch/x86/kvm/irq_comm.c
> +++ b/arch/x86/kvm/irq_comm.c
> @@ -328,3 +328,10 @@ int kvm_setup_default_irq_routing(struct kvm *kvm)
>  	return kvm_set_irq_routing(kvm, default_routing,
>  				   ARRAY_SIZE(default_routing), 0);
>  }
> +
> +static const struct kvm_irq_routing_entry empty_routing[] = {};
> +
> +int kvm_setup_empty_irq_routing(struct kvm *kvm)
> +{
> +	return kvm_set_irq_routing(kvm, empty_routing, 0, 0);
> +}
> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> index c789e00..92f4c98 100644
> --- a/arch/x86/kvm/lapic.c
> +++ b/arch/x86/kvm/lapic.c
> @@ -209,7 +209,8 @@ out:
>  	if (old)
>  		kfree_rcu(old, rcu);
>  
> -	kvm_vcpu_request_scan_ioapic(kvm);
> +	if (!irqchip_split(kvm))
> +		kvm_vcpu_request_scan_ioapic(kvm);
>  }
>  
>  static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
> @@ -1827,7 +1828,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
>  		kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
>  				apic_find_highest_isr(apic));
>  	kvm_make_request(KVM_REQ_EVENT, vcpu);
> -	kvm_rtc_eoi_tracking_restore_one(vcpu);
> +	if (!irqchip_split(vcpu->kvm))
> +		kvm_rtc_eoi_tracking_restore_one(vcpu);
>  }
>  
>  void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
> @@ -1910,7 +1912,8 @@ static void apic_sync_pv_eoi_to_guest(struct kvm_vcpu *vcpu,
>  	    /* Cache not set: could be safe but we don't bother. */
>  	    apic->highest_isr_cache == -1 ||
>  	    /* Need EOI to update ioapic. */
> -	    kvm_ioapic_handles_vector(vcpu->kvm, apic->highest_isr_cache)) {
> +	    kvm_ioapic_handles_vector(vcpu->kvm, apic->highest_isr_cache) ||
> +	    irqchip_split(vcpu->kvm)) {
>  		/*
>  		 * PV EOI was disabled by apic_sync_pv_eoi_from_guest
>  		 * so we need not do anything here.
> @@ -1966,7 +1969,7 @@ int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
>  	struct kvm_lapic *apic = vcpu->arch.apic;
>  	u32 reg = (msr - APIC_BASE_MSR) << 4;
>  
> -	if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
> +	if (!lapic_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
>  		return 1;
>  
>  	if (reg == APIC_ICR2)
> @@ -1983,7 +1986,7 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
>  	struct kvm_lapic *apic = vcpu->arch.apic;
>  	u32 reg = (msr - APIC_BASE_MSR) << 4, low, high = 0;
>  
> -	if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
> +	if (!lapic_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
>  		return 1;
>  
>  	if (reg == APIC_DFR || reg == APIC_ICR2) {
> diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
> index a65ce12..1513d14 100644
> --- a/arch/x86/kvm/mmu.c
> +++ b/arch/x86/kvm/mmu.c
> @@ -3507,7 +3507,7 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
>  
>  static bool can_do_async_pf(struct kvm_vcpu *vcpu)
>  {
> -	if (unlikely(!irqchip_in_kernel(vcpu->kvm) ||
> +	if (unlikely(!lapic_in_kernel(vcpu->kvm) ||
>  		     kvm_event_needs_reinjection(vcpu)))
>  		return false;
>  
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index b9f9e10..59166de 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -3054,7 +3054,7 @@ static int cr8_write_interception(struct vcpu_svm *svm)
>  	u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
>  	/* instruction emulation calls kvm_set_cr8() */
>  	r = cr_interception(svm);
> -	if (irqchip_in_kernel(svm->vcpu.kvm))
> +	if (lapic_in_kernel(svm->vcpu.kvm))
>  		return r;
>  	if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
>  		return r;
> @@ -3295,7 +3295,7 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
>  	 * If the user space waits to inject interrupts, exit as soon as
>  	 * possible
>  	 */
> -	if (!irqchip_in_kernel(svm->vcpu.kvm) &&
> +	if (!lapic_in_kernel(svm->vcpu.kvm) &&
>  	    kvm_run->request_interrupt_window &&
>  	    !kvm_cpu_has_interrupt(&svm->vcpu)) {
>  		kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index 9cf5030..3b58788 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -948,7 +948,7 @@ static inline bool cpu_has_vmx_tpr_shadow(void)
>  
>  static inline bool vm_need_tpr_shadow(struct kvm *kvm)
>  {
> -	return (cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm));
> +	return (cpu_has_vmx_tpr_shadow()) && lapic_in_kernel(kvm);
>  }
>  
>  static inline bool cpu_has_secondary_exec_ctrls(void)
> @@ -1064,7 +1064,7 @@ static inline bool cpu_has_vmx_ple(void)
>  
>  static inline bool vm_need_virtualize_apic_accesses(struct kvm *kvm)
>  {
> -	return flexpriority_enabled && irqchip_in_kernel(kvm);
> +	return flexpriority_enabled && lapic_in_kernel(kvm);
>  }
>  
>  static inline bool cpu_has_vmx_vpid(void)
> @@ -4341,7 +4341,7 @@ static void vmx_disable_intercept_msr_write_x2apic(u32 msr)
>  
>  static int vmx_vm_has_apicv(struct kvm *kvm)
>  {
> -	return enable_apicv && irqchip_in_kernel(kvm);
> +	return enable_apicv && lapic_in_kernel(kvm);
>  }
>  
>  static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
> @@ -5317,7 +5317,7 @@ static int handle_cr(struct kvm_vcpu *vcpu)
>  				u8 cr8 = (u8)val;
>  				err = kvm_set_cr8(vcpu, cr8);
>  				kvm_complete_insn_gp(vcpu, err);
> -				if (irqchip_in_kernel(vcpu->kvm))
> +				if (lapic_in_kernel(vcpu->kvm))
>  					return 1;
>  				if (cr8_prev <= cr8)
>  					return 1;
> @@ -5534,7 +5534,7 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu)
>  	 * If the user space waits to inject interrupts, exit as soon as
>  	 * possible
>  	 */
> -	if (!irqchip_in_kernel(vcpu->kvm) &&
> +	if (!lapic_in_kernel(vcpu->kvm) &&
>  	    vcpu->run->request_interrupt_window &&
>  	    !kvm_cpu_has_interrupt(vcpu)) {
>  		vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
> @@ -9419,7 +9419,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
>  	/* vmcs12's VM_ENTRY_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE are
>  	 * emulated by vmx_set_efer(), below.
>  	 */
> -	vm_entry_controls_init(vmx, 
> +	vm_entry_controls_init(vmx,
>  		(vmcs12->vm_entry_controls & ~VM_ENTRY_LOAD_IA32_EFER &
>  			~VM_ENTRY_IA32E_MODE) |
>  		(vmcs_config.vmentry_ctrl & ~VM_ENTRY_IA32E_MODE));
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 79dde16..19c8980 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -784,7 +784,7 @@ int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
>  {
>  	if (cr8 & CR8_RESERVED_BITS)
>  		return 1;
> -	if (irqchip_in_kernel(vcpu->kvm))
> +	if (lapic_in_kernel(vcpu->kvm))
>  		kvm_lapic_set_tpr(vcpu, cr8);
>  	else
>  		vcpu->arch.cr8 = cr8;
> @@ -794,7 +794,7 @@ EXPORT_SYMBOL_GPL(kvm_set_cr8);
>  
>  unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
>  {
> -	if (irqchip_in_kernel(vcpu->kvm))
> +	if (lapic_in_kernel(vcpu->kvm))
>  		return kvm_lapic_get_cr8(vcpu);
>  	else
>  		return vcpu->arch.cr8;
> @@ -2866,6 +2866,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
>  	case KVM_CAP_TSC_DEADLINE_TIMER:
>  	case KVM_CAP_ENABLE_CAP_VM:
>  	case KVM_CAP_DISABLE_QUIRKS:
> +	case KVM_CAP_SPLIT_IRQCHIP:
>  #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
>  	case KVM_CAP_ASSIGN_DEV_IRQ:
>  	case KVM_CAP_PCI_2_3:
> @@ -3068,7 +3069,7 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
>  {
>  	if (irq->irq >= KVM_NR_INTERRUPTS)
>  		return -EINVAL;
> -	if (irqchip_in_kernel(vcpu->kvm))
> +	if (lapic_in_kernel(vcpu->kvm))
>  		return -ENXIO;
>  
>  	kvm_queue_interrupt(vcpu, irq->irq, false);
> @@ -3546,7 +3547,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>  		struct kvm_vapic_addr va;
>  
>  		r = -EINVAL;
> -		if (!irqchip_in_kernel(vcpu->kvm))
> +		if (!lapic_in_kernel(vcpu->kvm))
>  			goto out;
>  		r = -EFAULT;
>  		if (copy_from_user(&va, argp, sizeof va))
> @@ -3904,7 +3905,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
>  int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event,
>  			bool line_status)
>  {
> -	if (!irqchip_in_kernel(kvm))
> +	if (!lapic_in_kernel(kvm))
>  		return -ENXIO;
>  
>  	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
> @@ -3926,6 +3927,23 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>  		kvm->arch.disabled_quirks = cap->args[0];
>  		r = 0;
>  		break;
> +	case KVM_CAP_SPLIT_IRQCHIP: {
> +		mutex_lock(&kvm->lock);
> +		r = -EEXIST;
> +		if (lapic_in_kernel(kvm))
> +			goto split_irqchip_unlock;
> +		r = -EINVAL;
> +		if (atomic_read(&kvm->online_vcpus))
> +			goto split_irqchip_unlock;
> +		r = kvm_setup_empty_irq_routing(kvm);
> +		if (r)
> +			goto split_irqchip_unlock;
> +		kvm->arch.irqchip_split = true;
> +		r = 0;
> +split_irqchip_unlock:
> +		mutex_unlock(&kvm->lock);
> +		break;
> +	}
>  	default:
>  		r = -EINVAL;
>  		break;
> @@ -4194,6 +4212,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
>  		r = kvm_vm_ioctl_enable_cap(kvm, &cap);
>  		break;
>  	}
> +
>  	default:
>  		r = kvm_vm_ioctl_assigned_device(kvm, ioctl, arg);
>  	}
> @@ -5959,7 +5978,7 @@ void kvm_arch_exit(void)
>  int kvm_vcpu_halt(struct kvm_vcpu *vcpu)
>  {
>  	++vcpu->stat.halt_exits;
> -	if (irqchip_in_kernel(vcpu->kvm)) {
> +	if (lapic_in_kernel(vcpu->kvm)) {
>  		vcpu->arch.mp_state = KVM_MP_STATE_HALTED;
>  		return 1;
>  	} else {
> @@ -6126,7 +6145,7 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
>   */
>  static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
>  {
> -	return (!irqchip_in_kernel(vcpu->kvm) && !kvm_cpu_has_interrupt(vcpu) &&
> +	return (!lapic_in_kernel(vcpu->kvm) && !kvm_cpu_has_interrupt(vcpu) &&
>  		vcpu->run->request_interrupt_window &&
>  		kvm_arch_interrupt_allowed(vcpu));
>  }
> @@ -6138,7 +6157,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
>  	kvm_run->if_flag = (kvm_get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
>  	kvm_run->cr8 = kvm_get_cr8(vcpu);
>  	kvm_run->apic_base = kvm_get_apic_base(vcpu);
> -	if (irqchip_in_kernel(vcpu->kvm))
> +	if (lapic_in_kernel(vcpu->kvm))
>  		kvm_run->ready_for_interrupt_injection = 1;
>  	else
>  		kvm_run->ready_for_interrupt_injection =
> @@ -6285,7 +6304,7 @@ void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
>  {
>  	struct page *page = NULL;
>  
> -	if (!irqchip_in_kernel(vcpu->kvm))
> +	if (!lapic_in_kernel(vcpu->kvm))
>  		return;
>  
>  	if (!kvm_x86_ops->set_apic_access_page_addr)
> @@ -6323,7 +6342,7 @@ void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
>  static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>  {
>  	int r;
> -	bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
> +	bool req_int_win = !lapic_in_kernel(vcpu->kvm) &&
>  		vcpu->run->request_interrupt_window;
>  	bool req_immediate_exit = false;
>  
> @@ -6712,7 +6731,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
>  	}
>  
>  	/* re-sync apic's tpr */
> -	if (!irqchip_in_kernel(vcpu->kvm)) {
> +	if (!lapic_in_kernel(vcpu->kvm)) {
>  		if (kvm_set_cr8(vcpu, kvm_run->cr8) != 0) {
>  			r = -EINVAL;
>  			goto out;
> @@ -7421,7 +7440,7 @@ void kvm_arch_check_processor_compat(void *rtn)
>  
>  bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
>  {
> -	return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
> +	return lapic_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
>  }
>  
>  struct static_key kvm_no_apic_vcpu __read_mostly;
> @@ -7437,7 +7456,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
>  
>  	vcpu->arch.pv.pv_unhalted = false;
>  	vcpu->arch.emulate_ctxt.ops = &emulate_ops;
> -	if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu))
> +	if (!lapic_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu))
>  		vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
>  	else
>  		vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED;
> @@ -7455,7 +7474,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
>  	if (r < 0)
>  		goto fail_free_pio_data;
>  
> -	if (irqchip_in_kernel(kvm)) {
> +	if (lapic_in_kernel(kvm)) {
>  		r = kvm_create_lapic(vcpu);
>  		if (r < 0)
>  			goto fail_mmu_destroy;
> @@ -7518,7 +7537,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
>  	kvm_mmu_destroy(vcpu);
>  	srcu_read_unlock(&vcpu->kvm->srcu, idx);
>  	free_page((unsigned long)vcpu->arch.pio_data);
> -	if (!irqchip_in_kernel(vcpu->kvm))
> +	if (!lapic_in_kernel(vcpu->kvm))
>  		static_key_slow_dec(&kvm_no_apic_vcpu);
>  }
>  
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index 133ea00..ffe1f4e 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -329,6 +329,7 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
>  int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu);
>  
>  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> +#define lapic_in_kernel(k)      (irqchip_in_kernel(k))
>  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
>  #define vgic_ready(k)		((k)->arch.vgic.ready)
>  
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index a8bcbc9..7e2b41a 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -935,6 +935,7 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
>  #endif
>  
>  int kvm_setup_default_irq_routing(struct kvm *kvm);
> +int kvm_setup_empty_irq_routing(struct kvm *kvm);
>  int kvm_set_irq_routing(struct kvm *kvm,
>  			const struct kvm_irq_routing_entry *entries,
>  			unsigned nr,
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 75bd9f7..1e6f6c3 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -815,6 +815,7 @@ struct kvm_ppc_smmu_info {
>  #define KVM_CAP_S390_IRQ_STATE 114
>  #define KVM_CAP_PPC_HWRNG 115
>  #define KVM_CAP_DISABLE_QUIRKS 116
> +#define KVM_CAP_SPLIT_IRQCHIP 117
>  
>  #ifdef KVM_CAP_IRQ_ROUTING
>  
> diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
> index 1d56a90..8aaceed 100644
> --- a/virt/kvm/irqchip.c
> +++ b/virt/kvm/irqchip.c
> @@ -73,7 +73,7 @@ int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
>  {
>  	struct kvm_kernel_irq_routing_entry route;
>  
> -	if (!irqchip_in_kernel(kvm) || msi->flags != 0)
> +	if (!lapic_in_kernel(kvm) || msi->flags != 0)
>  		return -EINVAL;
>  
>  	route.msi.address_lo = msi->address_lo;
> 

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

* Re: [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference
  2015-06-02 23:51 ` [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference Steve Rutherford
@ 2015-06-03  9:16   ` Paolo Bonzini
  2015-06-04 20:39     ` Steve Rutherford
  2015-06-08 10:33   ` Wanpeng Li
  1 sibling, 1 reply; 20+ messages in thread
From: Paolo Bonzini @ 2015-06-03  9:16 UTC (permalink / raw)
  To: Steve Rutherford, kvm



On 03/06/2015 01:51, Steve Rutherford wrote:
> +static inline void kvm_arch_irq_routing_update(struct kvm *kvm)
> +{
> +}

Please add the static inline to all arches instead of putting it in
#ifndef __KVM_HAVE_IOAPIC.  It's not related to the existence of an ioapic.

> 
> +void kvm_arch_irq_routing_update(struct kvm *kvm)
> +{
> +	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
> +
> +	if (ioapic)
> +		return;
> +	if (!lapic_in_kernel(kvm))
> +		return;
> +	kvm_make_scan_ioapic_request(kvm);
> +}
> +

It's weird to have a function in ioapic.c that only does something if
you _do not_ have an ioapic. :)

> +
> +void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)

This must stay in arch/x86/kvm/.  I'd put both of these in irq_comm.c.

Then you do not need kvm_arch_nr_userspace_ioapic_pins anymore.

Paolo

> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	struct kvm_kernel_irq_routing_entry *entry;
> +	struct kvm_irq_routing_table *table;
> +	u32 i, nr_ioapic_pins;
> +	int idx;
> +
> +	/* kvm->irq_routing must be read after clearing
> +	 * KVM_SCAN_IOAPIC. */
> +	smp_mb();
> +	idx = srcu_read_lock(&kvm->irq_srcu);
> +	table = kvm->irq_routing;
> +	nr_ioapic_pins = min_t(u32, table->nr_rt_entries,
> +			      kvm_arch_nr_userspace_ioapic_pins(kvm));
> +	for (i = 0; i < nr_ioapic_pins; ++i) {
> +		hlist_for_each_entry(entry, &table->map[i], link) {
> +			u32 dest_id, dest_mode;
> +
> +			if (entry->type != KVM_IRQ_ROUTING_MSI)
> +				continue;
> +			dest_id = (entry->msi.address_lo >> 12) & 0xff;
> +			dest_mode = (entry->msi.address_lo >> 2) & 0x1;
> +			if (kvm_apic_match_dest(vcpu, NULL, 0, dest_id,
> +						dest_mode)) {
> +				u32 vector = entry->msi.data & 0xff;
> +
> +				__set_bit(vector,
> +					  (unsigned long *) eoi_exit_bitmap);
> +			}
> +		}
> +	}
> +	srcu_read_unlock(&kvm->irq_srcu, idx);
> +}

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

* Re: [PATCH v3 2/4] KVM: x86: Add KVM exit for IOAPIC EOIs
  2015-06-02 23:51 ` [PATCH v3 2/4] KVM: x86: Add KVM exit for IOAPIC EOIs Steve Rutherford
@ 2015-06-03  9:16   ` Paolo Bonzini
  0 siblings, 0 replies; 20+ messages in thread
From: Paolo Bonzini @ 2015-06-03  9:16 UTC (permalink / raw)
  To: Steve Rutherford, kvm



On 03/06/2015 01:51, Steve Rutherford wrote:
> Adds KVM_EXIT_IOAPIC_EOI which allows the kernel to EOI
> level-triggered IOAPIC interrupts.
> 
> Uses a per VCPU exit bitmap to decide whether or not the IOAPIC needs
> to be informed (which is identical to the EOI_EXIT_BITMAP field used
> by modern x86 processors, but can also be used to elide kvm IOAPIC EOI
> exits on older processors).
> 
> [Note: A prototype using ResampleFDs found that decoupling the EOI
> from the VCPU's thread made it possible for the VCPU to not see a
> recent EOI after reentering the guest. This does not match real
> hardware.]
> 
> Compile tested for Intel x86.
> 
> Signed-off-by: Steve Rutherford <srutherford@google.com>
> ---
>  Documentation/virtual/kvm/api.txt | 10 ++++++++++
>  arch/x86/include/asm/kvm_host.h   |  3 +++
>  arch/x86/kvm/lapic.c              |  9 +++++++++
>  arch/x86/kvm/x86.c                | 11 +++++++++++
>  include/linux/kvm_host.h          |  1 +
>  include/uapi/linux/kvm.h          |  5 +++++
>  6 files changed, 39 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 9a43d42..6ab2a3f7 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -3271,6 +3271,16 @@ Valid values for 'type' are:
>  	 */
>  	__u64 kvm_valid_regs;
>  	__u64 kvm_dirty_regs;
> +
> +	/* KVM_EXIT_IOAPIC_EOI */
> +        struct {
> +	       __u8 vector;
> +        } eoi;
> +
> +Indicates that an eoi of a level triggered IOAPIC interrupt on vector has
> +occurred, which should be handled by the userspace IOAPIC. Triggers when
> +the Irqchip has been split between userspace and the kernel.

I'm okay with making this a VCPU-level thing, but you should document
_why_ it is here.  For example,

"Indicates that the VCPU's in-kernel local APIC received an EOI for a
level-triggered IOAPIC interrupt.  This exit only triggers when the
IOAPIC is implemented in userspace; the userspace IOAPIC should process
the EOI and retrigger the interrupt if it is still asserted.  Vector is
the LAPIC interrupt vector for which the EOI was received."

Also, you have to move it inside the anonymous union just above.  It's
okay in the header, but wrong in the documentation.

Paolo

>  	union {
>  		struct kvm_sync_regs regs;
>  		char padding[1024];
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index af3225a..2778d36 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -540,6 +540,9 @@ struct kvm_vcpu_arch {
>  	struct {
>  		bool pv_unhalted;
>  	} pv;
> +
> +	u64 eoi_exit_bitmaps[4];
> +	int pending_ioapic_eoi;
>  };
>  
>  struct kvm_lpage_info {
> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> index 92f4c98..28eb946 100644
> --- a/arch/x86/kvm/lapic.c
> +++ b/arch/x86/kvm/lapic.c
> @@ -869,6 +869,15 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
>  
>  static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
>  {
> +	if (irqchip_split(apic->vcpu->kvm)) {
> +		if (test_bit(vector,
> +			     (void *) apic->vcpu->arch.eoi_exit_bitmaps)) {
> +			apic->vcpu->arch.pending_ioapic_eoi = vector;
> +			kvm_make_request(KVM_REQ_IOAPIC_EOI_EXIT, apic->vcpu);
> +		}
> +		return;
> +	}
> +
>  	if (kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
>  		int trigger_mode;
>  		if (apic_test_vector(vector, apic->regs + APIC_TMR))
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 19c8980..5e01810 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -6392,6 +6392,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>  			kvm_handle_pmu_event(vcpu);
>  		if (kvm_check_request(KVM_REQ_PMI, vcpu))
>  			kvm_deliver_pmi(vcpu);
> +		if (kvm_check_request(KVM_REQ_IOAPIC_EOI_EXIT, vcpu)) {
> +			BUG_ON(vcpu->arch.pending_ioapic_eoi > 255);
> +			if (test_bit(vcpu->arch.pending_ioapic_eoi,
> +				     (void *) vcpu->arch.eoi_exit_bitmaps)) {
> +				vcpu->run->exit_reason = KVM_EXIT_IOAPIC_EOI;
> +				vcpu->run->eoi.vector =
> +						vcpu->arch.pending_ioapic_eoi;
> +				r = 0;
> +				goto out;
> +			}
> +		}
>  		if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
>  			vcpu_scan_ioapic(vcpu);
>  		if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 7e2b41a..c6df36f 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -134,6 +134,7 @@ static inline bool is_error_page(struct page *page)
>  #define KVM_REQ_ENABLE_IBS        23
>  #define KVM_REQ_DISABLE_IBS       24
>  #define KVM_REQ_APIC_PAGE_RELOAD  25
> +#define KVM_REQ_IOAPIC_EOI_EXIT   26
>  
>  #define KVM_USERSPACE_IRQ_SOURCE_ID		0
>  #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID	1
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 1e6f6c3..826a08d 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -183,6 +183,7 @@ struct kvm_s390_skeys {
>  #define KVM_EXIT_EPR              23
>  #define KVM_EXIT_SYSTEM_EVENT     24
>  #define KVM_EXIT_S390_STSI        25
> +#define KVM_EXIT_IOAPIC_EOI       26
>  
>  /* For KVM_EXIT_INTERNAL_ERROR */
>  /* Emulate instruction failed. */
> @@ -329,6 +330,10 @@ struct kvm_run {
>  			__u8 sel1;
>  			__u16 sel2;
>  		} s390_stsi;
> +		/* KVM_EXIT_IOAPIC_EOI */
> +		struct {
> +			__u8 vector;
> +		} eoi;
>  		/* Fix the size of the union. */
>  		char padding[256];
>  	};
> 

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

* Re: [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace
  2015-06-02 23:51 ` [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace Steve Rutherford
@ 2015-06-03  9:38   ` Paolo Bonzini
  2015-06-04 20:21     ` Steve Rutherford
                       ` (2 more replies)
  0 siblings, 3 replies; 20+ messages in thread
From: Paolo Bonzini @ 2015-06-03  9:38 UTC (permalink / raw)
  To: Steve Rutherford, kvm



On 03/06/2015 01:51, Steve Rutherford wrote:
> In order to enable userspace PIC support, the userspace PIC needs to
> be able to inject local interrupt requests.
> 
> This adds the ioctl KVM_REQUEST_PIC_INJECTION and kvm exit
> KVM_EXIT_GET_EXTINT.
> 
> The vm ioctl KVM_REQUEST_PIC_INJECTION makes a KVM_REQ_EVENT request
> on the BSP, which causes the BSP to exit to userspace to fetch the
> vector of the underlying external interrupt, which the BSP then
> injects into the guest. This matches the PIC spec, and is necessary to
> boot Windows.
> 
> Compiles for x86.
> 
> Update: Boots Windows and passes the KVM Unit Tests.
> 
> Signed-off-by: Steve Rutherford <srutherford@google.com>
> ---
>  Documentation/virtual/kvm/api.txt |  9 ++++++
>  arch/x86/include/asm/kvm_host.h   |  2 ++
>  arch/x86/kvm/irq.c                | 22 +++++++++++++--
>  arch/x86/kvm/lapic.c              |  7 +++++
>  arch/x86/kvm/lapic.h              |  2 ++
>  arch/x86/kvm/x86.c                | 59 +++++++++++++++++++++++++++++++++++++--
>  include/uapi/linux/kvm.h          |  7 +++++
>  7 files changed, 103 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index 6ab2a3f7..b5d90cb 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -2979,6 +2979,15 @@ len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
>  and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
>  which is the maximum number of possibly pending cpu-local interrupts.
>  
> +4.96 KVM_REQUEST_PIC_INJECTION
> +
> +Capability: KVM_CAP_SPLIT_IRQCHIP
> +Type: VM ioctl
> +Parameters: none
> +Returns: 0 on success, -1 on error.
> +
> +Informs the kernel that userspace has a pending external interrupt.
> +

Missing documentation for the new vmexit and kvm_run member.

However, why is the roundtrip to userspace necessary?  Could you pass
the extint index directly as an argument to KVM_INTERRUPT?  It's
backwards-compatible, because KVM_INTERRUPT so far could not be used
together with an in-kernel LAPIC.  If you could do that, you could also
avoid the new userspace_extint_available field.

Userspace can figure out who's the BSP.  The rendez-vous between the
irqchip and the BSP's VCPU thread is still needed, but it can be done
entirely in userspace.

You'd also need much fewer changes to irq.c.  Basically just something like

 int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
 {
         int vector;

-        if (!irqchip_in_kernel(v->kvm))
+        if (!pic_in_kernel(v->kvm) && v->arch.interrupt.pending)
                return v->arch.interrupt.nr;

...

 int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
 {
-        if (!irqchip_in_kernel(v->kvm))
+        if (!pic_in_kernel(v->kvm))
                 return v->arch.interrupt.pending;

...

 int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
 {
-        if (!irqchip_in_kernel(v->kvm))
+        if (!pic_in_kernel(v->kvm))
                 return v->arch.interrupt.pending;

More comments below.

>  5. The kvm_run structure
>  ------------------------
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 4f439ff..0e8b0fc 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -543,6 +543,8 @@ struct kvm_vcpu_arch {
>  
>  	u64 eoi_exit_bitmaps[4];
>  	int pending_ioapic_eoi;
> +	bool userspace_extint_available;
> +	int pending_external_vector;
>  };
>  

>  struct kvm_lpage_info {
> diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
> index 706e47a..1270b2a 100644
> --- a/arch/x86/kvm/irq.c
> +++ b/arch/x86/kvm/irq.c
> @@ -38,12 +38,25 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
>  EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
>  
>  /*
> + * check if there is a pending userspace external interrupt
> + */
> +static int pending_userspace_extint(struct kvm_vcpu *v)
> +{
> +	return v->arch.userspace_extint_available ||
> +	       v->arch.pending_external_vector != -1;
> +}
> +
> +/*
>   * check if there is pending interrupt from
>   * non-APIC source without intack.
>   */
>  static int kvm_cpu_has_extint(struct kvm_vcpu *v)
>  {
> -	if (kvm_apic_accept_pic_intr(v))
> +	u8 accept = kvm_apic_accept_pic_intr(v);
> +
> +	if (accept && irqchip_split(v->kvm))
> +		return pending_userspace_extint(v);
> +	else if (accept)
>  		return pic_irqchip(v->kvm)->output;	/* PIC */

	if (accept) {
		if (irqchip_split(v->kvm))
			return pending_userspace_extint(v);
		else
			return pic_irqchip(v->kvm)->output;
	}

	return 0;

>  	else
>  		return 0;
> @@ -91,7 +104,12 @@ EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
>   */
>  static int kvm_cpu_get_extint(struct kvm_vcpu *v)
>  {
> -	if (kvm_cpu_has_extint(v))
> +	if (irqchip_split(v->kvm) && kvm_cpu_has_extint(v)) {
> +		int vector = v->arch.pending_external_vector;
> +
> +		v->arch.pending_external_vector = -1;
> +		return vector;
> +	} else if (kvm_cpu_has_extint(v))
>  		return kvm_pic_read_irq(v->kvm); /* PIC */

Same as above.

>  	return -1;
>  }
> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> index 766d297..012b56ee 100644
> --- a/arch/x86/kvm/lapic.c
> +++ b/arch/x86/kvm/lapic.c
> @@ -2094,3 +2094,10 @@ void kvm_lapic_init(void)
>  	jump_label_rate_limit(&apic_hw_disabled, HZ);
>  	jump_label_rate_limit(&apic_sw_disabled, HZ);
>  }
> +
> +void kvm_request_pic_injection(struct kvm_vcpu *vcpu)
> +{
> +	vcpu->arch.userspace_extint_available = true;
> +	kvm_make_request(KVM_REQ_EVENT, vcpu);
> +	kvm_vcpu_kick(vcpu);
> +}
> diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
> index 71b150c..7831e4d 100644
> --- a/arch/x86/kvm/lapic.h
> +++ b/arch/x86/kvm/lapic.h
> @@ -63,6 +63,8 @@ int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq,
>  		unsigned long *dest_map);
>  int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type);
>  
> +void kvm_request_pic_injection(struct kvm_vcpu *vcpu);
> +
>  bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
>  		struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map);
>  
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 35d13d4..40e7509 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -65,6 +65,8 @@
>  #include <asm/pvclock.h>
>  #include <asm/div64.h>
>  
> +#define GET_VECTOR_FROM_USERSPACE 1
> +
>  #define MAX_IO_MSRS 256
>  #define KVM_MAX_MCE_BANKS 32
>  #define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P)
> @@ -4217,6 +4219,30 @@ long kvm_arch_vm_ioctl(struct file *filp,
>  		r = kvm_vm_ioctl_enable_cap(kvm, &cap);
>  		break;
>  	}
> +	case KVM_REQUEST_PIC_INJECTION: {
> +		int i;
> +		struct kvm_vcpu *vcpu;
> +		struct kvm_vcpu *bsp_vcpu = NULL;
> +
> +		mutex_lock(&kvm->lock);
> +		r = -EEXIST;
> +		if (!irqchip_split(kvm))
> +			goto out;
> +		kvm_for_each_vcpu(i, vcpu, kvm) {
> +			if (kvm_vcpu_is_reset_bsp(vcpu)) {
> +				bsp_vcpu = vcpu;
> +				continue;
> +			}
> +		}
> +		r = -EINVAL;
> +		if (bsp_vcpu == NULL)
> +			goto interrupt_unlock;
> +		kvm_request_pic_injection(bsp_vcpu);
> +		r = 0;
> +interrupt_unlock:
> +		mutex_unlock(&kvm->lock);
> +		break;
> +	}
>  
>  	default:
>  		r = kvm_vm_ioctl_assigned_device(kvm, ioctl, arg);
> @@ -6194,6 +6220,17 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
>  	kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
>  }
>  
> +static int must_fetch_userspace_extint(struct kvm_vcpu *vcpu)

I would rename this to kvm_accept_request_pic_injection.

Paolo

> +{
> +	if (vcpu->arch.userspace_extint_available &&
> +	    kvm_apic_accept_pic_intr(vcpu)) {
> +		vcpu->arch.userspace_extint_available = false;
> +		return true;
> +	} else
> +		return false;
> +
> +}
> +
>  static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
>  {
>  	int r;
> @@ -6258,7 +6295,12 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
>  				return r;
>  		}
>  		if (kvm_x86_ops->interrupt_allowed(vcpu)) {
> -			kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu),
> +			if (irqchip_split(vcpu->kvm) &&
> +			    must_fetch_userspace_extint(vcpu)) {
> +				return GET_VECTOR_FROM_USERSPACE;
> +			}
> +			kvm_queue_interrupt(vcpu,
> +					    kvm_cpu_get_interrupt(vcpu),
>  					    false);
>  			kvm_x86_ops->set_irq(vcpu);
>  		}
> @@ -6424,13 +6466,19 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>  	}
>  
>  	if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
> +		int event;
>  		kvm_apic_accept_events(vcpu);
>  		if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) {
>  			r = 1;
>  			goto out;
>  		}
> -
> -		if (inject_pending_event(vcpu, req_int_win) != 0)
> +		event = inject_pending_event(vcpu, req_int_win);
> +		if (event == GET_VECTOR_FROM_USERSPACE) {
> +			vcpu->run->exit_reason = KVM_EXIT_GET_EXTINT;
> +			kvm_make_request(KVM_REQ_EVENT, vcpu);
> +			r = 0;
> +			goto out;
> +		} else if (event != 0)
>  			req_immediate_exit = true;
>  		/* enable NMI/IRQ window open exits if needed */
>  		else if (vcpu->arch.nmi_pending)
> @@ -6747,6 +6795,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
>  	if (vcpu->sigset_active)
>  		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
>  
> +	if (vcpu->run->exit_reason == KVM_EXIT_GET_EXTINT)
> +		vcpu->arch.pending_external_vector = vcpu->run->extint.vector;
> +
>  	if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) {
>  		kvm_vcpu_block(vcpu);
>  		kvm_apic_accept_events(vcpu);
> @@ -7536,6 +7587,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
>  	kvm_async_pf_hash_reset(vcpu);
>  	kvm_pmu_init(vcpu);
>  
> +	vcpu->arch.pending_external_vector = -1;
> +
>  	return 0;
>  fail_free_wbinvd_dirty_mask:
>  	free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 826a08d..0cf7ed6 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -184,6 +184,7 @@ struct kvm_s390_skeys {
>  #define KVM_EXIT_SYSTEM_EVENT     24
>  #define KVM_EXIT_S390_STSI        25
>  #define KVM_EXIT_IOAPIC_EOI       26
> +#define KVM_EXIT_GET_EXTINT       27
>  
>  /* For KVM_EXIT_INTERNAL_ERROR */
>  /* Emulate instruction failed. */
> @@ -334,6 +335,10 @@ struct kvm_run {
>  		struct {
>  			__u8 vector;
>  		} eoi;
> +		/* KVM_EXIT_GET_EXTINT */
> +		struct {
> +			__u8 vector;
> +		} extint;
>  		/* Fix the size of the union. */
>  		char padding[256];
>  	};
> @@ -1206,6 +1211,8 @@ struct kvm_s390_ucas_mapping {
>  /* Available with KVM_CAP_S390_IRQ_STATE */
>  #define KVM_S390_SET_IRQ_STATE	  _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state)
>  #define KVM_S390_GET_IRQ_STATE	  _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
> +/* Available with KVM_CAP_SPLIT_IRQCHIP */
> +#define KVM_REQUEST_PIC_INJECTION _IO(KVMIO, 0xb7)
>  
>  #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
>  #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
> 

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

* Re: [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace
  2015-06-03  9:38   ` Paolo Bonzini
@ 2015-06-04 20:21     ` Steve Rutherford
  2015-06-20  0:41     ` Steve Rutherford
  2015-06-26  0:26     ` Steve Rutherford
  2 siblings, 0 replies; 20+ messages in thread
From: Steve Rutherford @ 2015-06-04 20:21 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm

On Wed, Jun 03, 2015 at 11:38:21AM +0200, Paolo Bonzini wrote:
 
> However, why is the roundtrip to userspace necessary?  Could you pass
> the extint index directly as an argument to KVM_INTERRUPT?  It's
> backwards-compatible, because KVM_INTERRUPT so far could not be used
> together with an in-kernel LAPIC.  If you could do that, you could also
> avoid the new userspace_extint_available field.
This is possible, and definitely simpler, but not accurate to the spec.
In general, the PIC fires an INT, which leads to the CPU responding with
and INTA, and fetching the interrupt vector. It might not be strictly
necessary for this handshake to occur, but it is how the hardware did it
originally. 

In certain cases, having the interface modelled after the hardware is 
convenient. For example, devices can send external interrupt MSIs,
which require an Interrupt Ack to fetch the vector. They're a bit weird,
and I have absolutely no idea why someone would want these, but they are
a definitely a thing.

Looking back at KVM though, it doesn't look like KVM even supports these,
so this may not be a real issue. Eliding the roundtrip might be acceptable.
It's certainly simpler.

> Userspace can figure out who's the BSP.  The rendez-vous between the
> irqchip and the BSP's VCPU thread is still needed, but it can be done
> entirely in userspace.
Good point. I'll push this up into userspace. 

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

* Re: [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP.
  2015-06-03  8:54 ` [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Paolo Bonzini
@ 2015-06-04 20:38   ` Steve Rutherford
  2015-06-05  7:19     ` Paolo Bonzini
  0 siblings, 1 reply; 20+ messages in thread
From: Steve Rutherford @ 2015-06-04 20:38 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm

On Wed, Jun 03, 2015 at 10:54:41AM +0200, Paolo Bonzini wrote:
> 
> 
> On 03/06/2015 01:51, Steve Rutherford wrote:
> > First patch in a series which enables the relocation of the
> > PIC/IOAPIC to userspace.
> > 
> > Adds capability KVM_CAP_SPLIT_IRQCHIP;
> > 
> > KVM_CAP_SPLIT_IRQCHIP enables the construction of LAPICs without the
> > rest of the irqchip.
> 
> The documentation is not updated.
Ack.
> 
> Changing other arches is definitely a no-no, unfortunately.  But there
> are so many s/irqchip_in_kernel/lapic_in_kernel/ changes here, that I
> wonder if you should just keep irqchip_in_kernel true in the "split
> irqchip" case.  You are already testing irqchip_split in a few cases,
> and you can add ioapic_in_kernel whenever you need to test
> "lapic_in_kernel && !irqchip_split" at the same time.

>From the perspective of avoiding impacting other architectures, this is a
good idea, but the naming seems strange in the x86 case. Having
irqchip_in_kernel be "true" when the ioapic/pic are in userspace seems
strange. Admittedly, the irqchip isn't a "real" concept on x86, so
inventing a new meaning is fine.

Despite my hesitation, I'll change the naming around.

Steve

> 
> Paolo
> 
> > Compile tested for x86.
> > 
> > Signed-off-by: Steve Rutherford <srutherford@google.com>
> > Suggested-by: Andrew Honig <ahonig@google.com>
> > ---
> >  Documentation/virtual/kvm/api.txt | 15 ++++++++++++
> >  arch/powerpc/kvm/irq.h            |  5 ++++
> >  arch/s390/kvm/irq.h               |  4 ++++
> >  arch/x86/include/asm/kvm_host.h   |  2 ++
> >  arch/x86/kvm/assigned-dev.c       |  4 ++--
> >  arch/x86/kvm/irq.c                |  6 ++---
> >  arch/x86/kvm/irq.h                | 11 +++++++++
> >  arch/x86/kvm/irq_comm.c           |  7 ++++++
> >  arch/x86/kvm/lapic.c              | 13 +++++++----
> >  arch/x86/kvm/mmu.c                |  2 +-
> >  arch/x86/kvm/svm.c                |  4 ++--
> >  arch/x86/kvm/vmx.c                | 12 +++++-----
> >  arch/x86/kvm/x86.c                | 49 +++++++++++++++++++++++++++------------
> >  include/kvm/arm_vgic.h            |  1 +
> >  include/linux/kvm_host.h          |  1 +
> >  include/uapi/linux/kvm.h          |  1 +
> >  virt/kvm/irqchip.c                |  2 +-
> >  17 files changed, 104 insertions(+), 35 deletions(-)
> > 
> > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > index 6955444..9a43d42 100644
> > --- a/Documentation/virtual/kvm/api.txt
> > +++ b/Documentation/virtual/kvm/api.txt
> > @@ -2979,6 +2979,7 @@ len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
> >  and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
> >  which is the maximum number of possibly pending cpu-local interrupts.
> >  
> > +
> >  5. The kvm_run structure
> >  ------------------------
> >  
> > @@ -3575,6 +3576,20 @@ struct {
> >  
> >  KVM handlers should exit to userspace with rc = -EREMOTE.
> >  
> > +7.5 KVM_SPLIT_IRQCHIP
> > +
> > +Capability: KVM_CAP_SPLIT_IRQCHIP
> > +Architectures: x86
> > +Type:  VM ioctl
> > +Parameters: None
> > +Returns: 0 on success, -1 on error
> > +
> > +Create a local apic for each processor in the kernel.  This differs from
> > +KVM_CREATE_IRQCHIP in that it only creates the local apic; it creates neither
> > +the ioapic nor the pic in the kernel. Also, enables in kernel routing of
> > +interrupt requests. Fails if VCPU has already been created, or if the irqchip is
> > +already in the kernel.
> > +
> >  
> >  8. Other capabilities.
> >  ----------------------
> > diff --git a/arch/powerpc/kvm/irq.h b/arch/powerpc/kvm/irq.h
> > index 5a9a10b..5e6fa06 100644
> > --- a/arch/powerpc/kvm/irq.h
> > +++ b/arch/powerpc/kvm/irq.h
> > @@ -17,4 +17,9 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
> >  	return ret;
> >  }
> >  
> > +static inline int lapic_in_kernel(struct kvm *kvm)
> > +{
> > +	return irqchip_in_kernel(kvm);
> > +}
> > +
> >  #endif
> > diff --git a/arch/s390/kvm/irq.h b/arch/s390/kvm/irq.h
> > index d98e415..db876c3 100644
> > --- a/arch/s390/kvm/irq.h
> > +++ b/arch/s390/kvm/irq.h
> > @@ -19,4 +19,8 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
> >  	return 1;
> >  }
> >  
> > +static inline int lapic_in_kernel(struct kvm *kvm)
> > +{
> > +	return irqchip_in_kernel(kvm);
> > +}
> >  #endif
> > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> > index 7276107..af3225a 100644
> > --- a/arch/x86/include/asm/kvm_host.h
> > +++ b/arch/x86/include/asm/kvm_host.h
> > @@ -639,6 +639,8 @@ struct kvm_arch {
> >  	bool boot_vcpu_runs_old_kvmclock;
> >  
> >  	u64 disabled_quirks;
> > +
> > +	bool irqchip_split;
> >  };
> >  
> >  struct kvm_vm_stat {
> > diff --git a/arch/x86/kvm/assigned-dev.c b/arch/x86/kvm/assigned-dev.c
> > index d090ecf..1237e92 100644
> > --- a/arch/x86/kvm/assigned-dev.c
> > +++ b/arch/x86/kvm/assigned-dev.c
> > @@ -291,7 +291,7 @@ static int kvm_deassign_irq(struct kvm *kvm,
> >  {
> >  	unsigned long guest_irq_type, host_irq_type;
> >  
> > -	if (!irqchip_in_kernel(kvm))
> > +	if (!lapic_in_kernel(kvm))
> >  		return -EINVAL;
> >  	/* no irq assignment to deassign */
> >  	if (!assigned_dev->irq_requested_type)
> > @@ -568,7 +568,7 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
> >  	struct kvm_assigned_dev_kernel *match;
> >  	unsigned long host_irq_type, guest_irq_type;
> >  
> > -	if (!irqchip_in_kernel(kvm))
> > +	if (!lapic_in_kernel(kvm))
> >  		return r;
> >  
> >  	mutex_lock(&kvm->lock);
> > diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
> > index a1ec6a50..706e47a 100644
> > --- a/arch/x86/kvm/irq.c
> > +++ b/arch/x86/kvm/irq.c
> > @@ -57,7 +57,7 @@ static int kvm_cpu_has_extint(struct kvm_vcpu *v)
> >   */
> >  int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
> >  {
> > -	if (!irqchip_in_kernel(v->kvm))
> > +	if (!lapic_in_kernel(v->kvm))
> >  		return v->arch.interrupt.pending;
> >  
> >  	if (kvm_cpu_has_extint(v))
> > @@ -75,7 +75,7 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
> >   */
> >  int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
> >  {
> > -	if (!irqchip_in_kernel(v->kvm))
> > +	if (!lapic_in_kernel(v->kvm))
> >  		return v->arch.interrupt.pending;
> >  
> >  	if (kvm_cpu_has_extint(v))
> > @@ -103,7 +103,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
> >  {
> >  	int vector;
> >  
> > -	if (!irqchip_in_kernel(v->kvm))
> > +	if (!lapic_in_kernel(v->kvm))
> >  		return v->arch.interrupt.nr;
> >  
> >  	vector = kvm_cpu_get_extint(v);
> > diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
> > index ad68c73..e46abf3 100644
> > --- a/arch/x86/kvm/irq.h
> > +++ b/arch/x86/kvm/irq.h
> > @@ -92,6 +92,17 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
> >  	return ret;
> >  }
> >  
> > +static inline int irqchip_split(struct kvm *kvm)
> > +{
> > +	return kvm->arch.irqchip_split;
> > +}
> > +
> > +static inline int lapic_in_kernel(struct kvm *kvm)
> > +{
> > +	return irqchip_split(kvm) || irqchip_in_kernel(kvm);
> > +}
> > +
> > +
> >  void kvm_pic_reset(struct kvm_kpic_state *s);
> >  
> >  void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
> > diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
> > index 9efff9e..f43c59a 100644
> > --- a/arch/x86/kvm/irq_comm.c
> > +++ b/arch/x86/kvm/irq_comm.c
> > @@ -328,3 +328,10 @@ int kvm_setup_default_irq_routing(struct kvm *kvm)
> >  	return kvm_set_irq_routing(kvm, default_routing,
> >  				   ARRAY_SIZE(default_routing), 0);
> >  }
> > +
> > +static const struct kvm_irq_routing_entry empty_routing[] = {};
> > +
> > +int kvm_setup_empty_irq_routing(struct kvm *kvm)
> > +{
> > +	return kvm_set_irq_routing(kvm, empty_routing, 0, 0);
> > +}
> > diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> > index c789e00..92f4c98 100644
> > --- a/arch/x86/kvm/lapic.c
> > +++ b/arch/x86/kvm/lapic.c
> > @@ -209,7 +209,8 @@ out:
> >  	if (old)
> >  		kfree_rcu(old, rcu);
> >  
> > -	kvm_vcpu_request_scan_ioapic(kvm);
> > +	if (!irqchip_split(kvm))
> > +		kvm_vcpu_request_scan_ioapic(kvm);
> >  }
> >  
> >  static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
> > @@ -1827,7 +1828,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
> >  		kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
> >  				apic_find_highest_isr(apic));
> >  	kvm_make_request(KVM_REQ_EVENT, vcpu);
> > -	kvm_rtc_eoi_tracking_restore_one(vcpu);
> > +	if (!irqchip_split(vcpu->kvm))
> > +		kvm_rtc_eoi_tracking_restore_one(vcpu);
> >  }
> >  
> >  void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
> > @@ -1910,7 +1912,8 @@ static void apic_sync_pv_eoi_to_guest(struct kvm_vcpu *vcpu,
> >  	    /* Cache not set: could be safe but we don't bother. */
> >  	    apic->highest_isr_cache == -1 ||
> >  	    /* Need EOI to update ioapic. */
> > -	    kvm_ioapic_handles_vector(vcpu->kvm, apic->highest_isr_cache)) {
> > +	    kvm_ioapic_handles_vector(vcpu->kvm, apic->highest_isr_cache) ||
> > +	    irqchip_split(vcpu->kvm)) {
> >  		/*
> >  		 * PV EOI was disabled by apic_sync_pv_eoi_from_guest
> >  		 * so we need not do anything here.
> > @@ -1966,7 +1969,7 @@ int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
> >  	struct kvm_lapic *apic = vcpu->arch.apic;
> >  	u32 reg = (msr - APIC_BASE_MSR) << 4;
> >  
> > -	if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
> > +	if (!lapic_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
> >  		return 1;
> >  
> >  	if (reg == APIC_ICR2)
> > @@ -1983,7 +1986,7 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
> >  	struct kvm_lapic *apic = vcpu->arch.apic;
> >  	u32 reg = (msr - APIC_BASE_MSR) << 4, low, high = 0;
> >  
> > -	if (!irqchip_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
> > +	if (!lapic_in_kernel(vcpu->kvm) || !apic_x2apic_mode(apic))
> >  		return 1;
> >  
> >  	if (reg == APIC_DFR || reg == APIC_ICR2) {
> > diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
> > index a65ce12..1513d14 100644
> > --- a/arch/x86/kvm/mmu.c
> > +++ b/arch/x86/kvm/mmu.c
> > @@ -3507,7 +3507,7 @@ static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn)
> >  
> >  static bool can_do_async_pf(struct kvm_vcpu *vcpu)
> >  {
> > -	if (unlikely(!irqchip_in_kernel(vcpu->kvm) ||
> > +	if (unlikely(!lapic_in_kernel(vcpu->kvm) ||
> >  		     kvm_event_needs_reinjection(vcpu)))
> >  		return false;
> >  
> > diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> > index b9f9e10..59166de 100644
> > --- a/arch/x86/kvm/svm.c
> > +++ b/arch/x86/kvm/svm.c
> > @@ -3054,7 +3054,7 @@ static int cr8_write_interception(struct vcpu_svm *svm)
> >  	u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
> >  	/* instruction emulation calls kvm_set_cr8() */
> >  	r = cr_interception(svm);
> > -	if (irqchip_in_kernel(svm->vcpu.kvm))
> > +	if (lapic_in_kernel(svm->vcpu.kvm))
> >  		return r;
> >  	if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
> >  		return r;
> > @@ -3295,7 +3295,7 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
> >  	 * If the user space waits to inject interrupts, exit as soon as
> >  	 * possible
> >  	 */
> > -	if (!irqchip_in_kernel(svm->vcpu.kvm) &&
> > +	if (!lapic_in_kernel(svm->vcpu.kvm) &&
> >  	    kvm_run->request_interrupt_window &&
> >  	    !kvm_cpu_has_interrupt(&svm->vcpu)) {
> >  		kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
> > diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> > index 9cf5030..3b58788 100644
> > --- a/arch/x86/kvm/vmx.c
> > +++ b/arch/x86/kvm/vmx.c
> > @@ -948,7 +948,7 @@ static inline bool cpu_has_vmx_tpr_shadow(void)
> >  
> >  static inline bool vm_need_tpr_shadow(struct kvm *kvm)
> >  {
> > -	return (cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm));
> > +	return (cpu_has_vmx_tpr_shadow()) && lapic_in_kernel(kvm);
> >  }
> >  
> >  static inline bool cpu_has_secondary_exec_ctrls(void)
> > @@ -1064,7 +1064,7 @@ static inline bool cpu_has_vmx_ple(void)
> >  
> >  static inline bool vm_need_virtualize_apic_accesses(struct kvm *kvm)
> >  {
> > -	return flexpriority_enabled && irqchip_in_kernel(kvm);
> > +	return flexpriority_enabled && lapic_in_kernel(kvm);
> >  }
> >  
> >  static inline bool cpu_has_vmx_vpid(void)
> > @@ -4341,7 +4341,7 @@ static void vmx_disable_intercept_msr_write_x2apic(u32 msr)
> >  
> >  static int vmx_vm_has_apicv(struct kvm *kvm)
> >  {
> > -	return enable_apicv && irqchip_in_kernel(kvm);
> > +	return enable_apicv && lapic_in_kernel(kvm);
> >  }
> >  
> >  static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
> > @@ -5317,7 +5317,7 @@ static int handle_cr(struct kvm_vcpu *vcpu)
> >  				u8 cr8 = (u8)val;
> >  				err = kvm_set_cr8(vcpu, cr8);
> >  				kvm_complete_insn_gp(vcpu, err);
> > -				if (irqchip_in_kernel(vcpu->kvm))
> > +				if (lapic_in_kernel(vcpu->kvm))
> >  					return 1;
> >  				if (cr8_prev <= cr8)
> >  					return 1;
> > @@ -5534,7 +5534,7 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu)
> >  	 * If the user space waits to inject interrupts, exit as soon as
> >  	 * possible
> >  	 */
> > -	if (!irqchip_in_kernel(vcpu->kvm) &&
> > +	if (!lapic_in_kernel(vcpu->kvm) &&
> >  	    vcpu->run->request_interrupt_window &&
> >  	    !kvm_cpu_has_interrupt(vcpu)) {
> >  		vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
> > @@ -9419,7 +9419,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
> >  	/* vmcs12's VM_ENTRY_LOAD_IA32_EFER and VM_ENTRY_IA32E_MODE are
> >  	 * emulated by vmx_set_efer(), below.
> >  	 */
> > -	vm_entry_controls_init(vmx, 
> > +	vm_entry_controls_init(vmx,
> >  		(vmcs12->vm_entry_controls & ~VM_ENTRY_LOAD_IA32_EFER &
> >  			~VM_ENTRY_IA32E_MODE) |
> >  		(vmcs_config.vmentry_ctrl & ~VM_ENTRY_IA32E_MODE));
> > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> > index 79dde16..19c8980 100644
> > --- a/arch/x86/kvm/x86.c
> > +++ b/arch/x86/kvm/x86.c
> > @@ -784,7 +784,7 @@ int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
> >  {
> >  	if (cr8 & CR8_RESERVED_BITS)
> >  		return 1;
> > -	if (irqchip_in_kernel(vcpu->kvm))
> > +	if (lapic_in_kernel(vcpu->kvm))
> >  		kvm_lapic_set_tpr(vcpu, cr8);
> >  	else
> >  		vcpu->arch.cr8 = cr8;
> > @@ -794,7 +794,7 @@ EXPORT_SYMBOL_GPL(kvm_set_cr8);
> >  
> >  unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
> >  {
> > -	if (irqchip_in_kernel(vcpu->kvm))
> > +	if (lapic_in_kernel(vcpu->kvm))
> >  		return kvm_lapic_get_cr8(vcpu);
> >  	else
> >  		return vcpu->arch.cr8;
> > @@ -2866,6 +2866,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
> >  	case KVM_CAP_TSC_DEADLINE_TIMER:
> >  	case KVM_CAP_ENABLE_CAP_VM:
> >  	case KVM_CAP_DISABLE_QUIRKS:
> > +	case KVM_CAP_SPLIT_IRQCHIP:
> >  #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
> >  	case KVM_CAP_ASSIGN_DEV_IRQ:
> >  	case KVM_CAP_PCI_2_3:
> > @@ -3068,7 +3069,7 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
> >  {
> >  	if (irq->irq >= KVM_NR_INTERRUPTS)
> >  		return -EINVAL;
> > -	if (irqchip_in_kernel(vcpu->kvm))
> > +	if (lapic_in_kernel(vcpu->kvm))
> >  		return -ENXIO;
> >  
> >  	kvm_queue_interrupt(vcpu, irq->irq, false);
> > @@ -3546,7 +3547,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> >  		struct kvm_vapic_addr va;
> >  
> >  		r = -EINVAL;
> > -		if (!irqchip_in_kernel(vcpu->kvm))
> > +		if (!lapic_in_kernel(vcpu->kvm))
> >  			goto out;
> >  		r = -EFAULT;
> >  		if (copy_from_user(&va, argp, sizeof va))
> > @@ -3904,7 +3905,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
> >  int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event,
> >  			bool line_status)
> >  {
> > -	if (!irqchip_in_kernel(kvm))
> > +	if (!lapic_in_kernel(kvm))
> >  		return -ENXIO;
> >  
> >  	irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
> > @@ -3926,6 +3927,23 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
> >  		kvm->arch.disabled_quirks = cap->args[0];
> >  		r = 0;
> >  		break;
> > +	case KVM_CAP_SPLIT_IRQCHIP: {
> > +		mutex_lock(&kvm->lock);
> > +		r = -EEXIST;
> > +		if (lapic_in_kernel(kvm))
> > +			goto split_irqchip_unlock;
> > +		r = -EINVAL;
> > +		if (atomic_read(&kvm->online_vcpus))
> > +			goto split_irqchip_unlock;
> > +		r = kvm_setup_empty_irq_routing(kvm);
> > +		if (r)
> > +			goto split_irqchip_unlock;
> > +		kvm->arch.irqchip_split = true;
> > +		r = 0;
> > +split_irqchip_unlock:
> > +		mutex_unlock(&kvm->lock);
> > +		break;
> > +	}
> >  	default:
> >  		r = -EINVAL;
> >  		break;
> > @@ -4194,6 +4212,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
> >  		r = kvm_vm_ioctl_enable_cap(kvm, &cap);
> >  		break;
> >  	}
> > +
> >  	default:
> >  		r = kvm_vm_ioctl_assigned_device(kvm, ioctl, arg);
> >  	}
> > @@ -5959,7 +5978,7 @@ void kvm_arch_exit(void)
> >  int kvm_vcpu_halt(struct kvm_vcpu *vcpu)
> >  {
> >  	++vcpu->stat.halt_exits;
> > -	if (irqchip_in_kernel(vcpu->kvm)) {
> > +	if (lapic_in_kernel(vcpu->kvm)) {
> >  		vcpu->arch.mp_state = KVM_MP_STATE_HALTED;
> >  		return 1;
> >  	} else {
> > @@ -6126,7 +6145,7 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
> >   */
> >  static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
> >  {
> > -	return (!irqchip_in_kernel(vcpu->kvm) && !kvm_cpu_has_interrupt(vcpu) &&
> > +	return (!lapic_in_kernel(vcpu->kvm) && !kvm_cpu_has_interrupt(vcpu) &&
> >  		vcpu->run->request_interrupt_window &&
> >  		kvm_arch_interrupt_allowed(vcpu));
> >  }
> > @@ -6138,7 +6157,7 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
> >  	kvm_run->if_flag = (kvm_get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
> >  	kvm_run->cr8 = kvm_get_cr8(vcpu);
> >  	kvm_run->apic_base = kvm_get_apic_base(vcpu);
> > -	if (irqchip_in_kernel(vcpu->kvm))
> > +	if (lapic_in_kernel(vcpu->kvm))
> >  		kvm_run->ready_for_interrupt_injection = 1;
> >  	else
> >  		kvm_run->ready_for_interrupt_injection =
> > @@ -6285,7 +6304,7 @@ void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)
> >  {
> >  	struct page *page = NULL;
> >  
> > -	if (!irqchip_in_kernel(vcpu->kvm))
> > +	if (!lapic_in_kernel(vcpu->kvm))
> >  		return;
> >  
> >  	if (!kvm_x86_ops->set_apic_access_page_addr)
> > @@ -6323,7 +6342,7 @@ void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
> >  static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
> >  {
> >  	int r;
> > -	bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
> > +	bool req_int_win = !lapic_in_kernel(vcpu->kvm) &&
> >  		vcpu->run->request_interrupt_window;
> >  	bool req_immediate_exit = false;
> >  
> > @@ -6712,7 +6731,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
> >  	}
> >  
> >  	/* re-sync apic's tpr */
> > -	if (!irqchip_in_kernel(vcpu->kvm)) {
> > +	if (!lapic_in_kernel(vcpu->kvm)) {
> >  		if (kvm_set_cr8(vcpu, kvm_run->cr8) != 0) {
> >  			r = -EINVAL;
> >  			goto out;
> > @@ -7421,7 +7440,7 @@ void kvm_arch_check_processor_compat(void *rtn)
> >  
> >  bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
> >  {
> > -	return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
> > +	return lapic_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
> >  }
> >  
> >  struct static_key kvm_no_apic_vcpu __read_mostly;
> > @@ -7437,7 +7456,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
> >  
> >  	vcpu->arch.pv.pv_unhalted = false;
> >  	vcpu->arch.emulate_ctxt.ops = &emulate_ops;
> > -	if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu))
> > +	if (!lapic_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu))
> >  		vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
> >  	else
> >  		vcpu->arch.mp_state = KVM_MP_STATE_UNINITIALIZED;
> > @@ -7455,7 +7474,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
> >  	if (r < 0)
> >  		goto fail_free_pio_data;
> >  
> > -	if (irqchip_in_kernel(kvm)) {
> > +	if (lapic_in_kernel(kvm)) {
> >  		r = kvm_create_lapic(vcpu);
> >  		if (r < 0)
> >  			goto fail_mmu_destroy;
> > @@ -7518,7 +7537,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
> >  	kvm_mmu_destroy(vcpu);
> >  	srcu_read_unlock(&vcpu->kvm->srcu, idx);
> >  	free_page((unsigned long)vcpu->arch.pio_data);
> > -	if (!irqchip_in_kernel(vcpu->kvm))
> > +	if (!lapic_in_kernel(vcpu->kvm))
> >  		static_key_slow_dec(&kvm_no_apic_vcpu);
> >  }
> >  
> > diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> > index 133ea00..ffe1f4e 100644
> > --- a/include/kvm/arm_vgic.h
> > +++ b/include/kvm/arm_vgic.h
> > @@ -329,6 +329,7 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
> >  int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu);
> >  
> >  #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
> > +#define lapic_in_kernel(k)      (irqchip_in_kernel(k))
> >  #define vgic_initialized(k)	(!!((k)->arch.vgic.nr_cpus))
> >  #define vgic_ready(k)		((k)->arch.vgic.ready)
> >  
> > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> > index a8bcbc9..7e2b41a 100644
> > --- a/include/linux/kvm_host.h
> > +++ b/include/linux/kvm_host.h
> > @@ -935,6 +935,7 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
> >  #endif
> >  
> >  int kvm_setup_default_irq_routing(struct kvm *kvm);
> > +int kvm_setup_empty_irq_routing(struct kvm *kvm);
> >  int kvm_set_irq_routing(struct kvm *kvm,
> >  			const struct kvm_irq_routing_entry *entries,
> >  			unsigned nr,
> > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> > index 75bd9f7..1e6f6c3 100644
> > --- a/include/uapi/linux/kvm.h
> > +++ b/include/uapi/linux/kvm.h
> > @@ -815,6 +815,7 @@ struct kvm_ppc_smmu_info {
> >  #define KVM_CAP_S390_IRQ_STATE 114
> >  #define KVM_CAP_PPC_HWRNG 115
> >  #define KVM_CAP_DISABLE_QUIRKS 116
> > +#define KVM_CAP_SPLIT_IRQCHIP 117
> >  
> >  #ifdef KVM_CAP_IRQ_ROUTING
> >  
> > diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
> > index 1d56a90..8aaceed 100644
> > --- a/virt/kvm/irqchip.c
> > +++ b/virt/kvm/irqchip.c
> > @@ -73,7 +73,7 @@ int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
> >  {
> >  	struct kvm_kernel_irq_routing_entry route;
> >  
> > -	if (!irqchip_in_kernel(kvm) || msi->flags != 0)
> > +	if (!lapic_in_kernel(kvm) || msi->flags != 0)
> >  		return -EINVAL;
> >  
> >  	route.msi.address_lo = msi->address_lo;
> > 

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

* Re: [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference
  2015-06-03  9:16   ` Paolo Bonzini
@ 2015-06-04 20:39     ` Steve Rutherford
  0 siblings, 0 replies; 20+ messages in thread
From: Steve Rutherford @ 2015-06-04 20:39 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm

On Wed, Jun 03, 2015 at 11:16:16AM +0200, Paolo Bonzini wrote:
> 
> 
> On 03/06/2015 01:51, Steve Rutherford wrote:
> > +static inline void kvm_arch_irq_routing_update(struct kvm *kvm)
> > +{
> > +}
> 
> Please add the static inline to all arches instead of putting it in
> #ifndef __KVM_HAVE_IOAPIC.  It's not related to the existence of an ioapic.
> 
> > 
> > +void kvm_arch_irq_routing_update(struct kvm *kvm)
> > +{
> > +	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
> > +
> > +	if (ioapic)
> > +		return;
> > +	if (!lapic_in_kernel(kvm))
> > +		return;
> > +	kvm_make_scan_ioapic_request(kvm);
> > +}
> > +
> 
> It's weird to have a function in ioapic.c that only does something if
> you _do not_ have an ioapic. :)
> 
> > +
> > +void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
> 
> This must stay in arch/x86/kvm/.  I'd put both of these in irq_comm.c.
> 
> Then you do not need kvm_arch_nr_userspace_ioapic_pins anymore.
Yes! This is way cleaner. I'll make these changes.

Steve
> 
> Paolo
> 
> > +{
> > +	struct kvm *kvm = vcpu->kvm;
> > +	struct kvm_kernel_irq_routing_entry *entry;
> > +	struct kvm_irq_routing_table *table;
> > +	u32 i, nr_ioapic_pins;
> > +	int idx;
> > +
> > +	/* kvm->irq_routing must be read after clearing
> > +	 * KVM_SCAN_IOAPIC. */
> > +	smp_mb();
> > +	idx = srcu_read_lock(&kvm->irq_srcu);
> > +	table = kvm->irq_routing;
> > +	nr_ioapic_pins = min_t(u32, table->nr_rt_entries,
> > +			      kvm_arch_nr_userspace_ioapic_pins(kvm));
> > +	for (i = 0; i < nr_ioapic_pins; ++i) {
> > +		hlist_for_each_entry(entry, &table->map[i], link) {
> > +			u32 dest_id, dest_mode;
> > +
> > +			if (entry->type != KVM_IRQ_ROUTING_MSI)
> > +				continue;
> > +			dest_id = (entry->msi.address_lo >> 12) & 0xff;
> > +			dest_mode = (entry->msi.address_lo >> 2) & 0x1;
> > +			if (kvm_apic_match_dest(vcpu, NULL, 0, dest_id,
> > +						dest_mode)) {
> > +				u32 vector = entry->msi.data & 0xff;
> > +
> > +				__set_bit(vector,
> > +					  (unsigned long *) eoi_exit_bitmap);
> > +			}
> > +		}
> > +	}
> > +	srcu_read_unlock(&kvm->irq_srcu, idx);
> > +}

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

* Re: [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP.
  2015-06-04 20:38   ` Steve Rutherford
@ 2015-06-05  7:19     ` Paolo Bonzini
  0 siblings, 0 replies; 20+ messages in thread
From: Paolo Bonzini @ 2015-06-05  7:19 UTC (permalink / raw)
  To: Steve Rutherford; +Cc: kvm


> From the perspective of avoiding impacting other architectures, this is a
> good idea, but the naming seems strange in the x86 case. Having
> irqchip_in_kernel be "true" when the ioapic/pic are in userspace seems
> strange. Admittedly, the irqchip isn't a "real" concept on x86, so
> inventing a new meaning is fine.

>From the KVM point of view, the "irqchip" is whatever delivers
interrupts to the vCPU---which is the LAPIC for x86.

Paolo

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

* Re: [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference
  2015-06-02 23:51 ` [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference Steve Rutherford
  2015-06-03  9:16   ` Paolo Bonzini
@ 2015-06-08 10:33   ` Wanpeng Li
  2015-06-08 14:15     ` Paolo Bonzini
  1 sibling, 1 reply; 20+ messages in thread
From: Wanpeng Li @ 2015-06-08 10:33 UTC (permalink / raw)
  To: Steve Rutherford, kvm


On 6/3/15 7:51 AM, Steve Rutherford wrote:
> In order to support a userspace IOAPIC interacting with an in kernel
> APIC, the EOI exit bitmaps need to be configurable.
>
> If the IOAPIC is in userspace (i.e. the irqchip has been split), the
> EOI exit bitmaps will be set whenever the GSI Routes are configured.
> In particular, for the low MSI routes are reservable for userspace
> IOAPICs. For these MSI routes, the EOI Exit bit corresponding to the
> destination vector of the route will be set for the destination VCPU.
>
> The intention is for the userspace IOAPICs to use the reservable MSI
> routes to inject interrupts into the guest.
>
> This is a slight abuse of the notion of an MSI Route, given that MSIs
> classically bypass the IOAPIC. It might be worthwhile to add an
> additional route type to improve clarity.
>
> Compile tested for Intel x86.
>
> Signed-off-by: Steve Rutherford <srutherford@google.com>
> ---
>   arch/x86/include/asm/kvm_host.h |  1 +
>   arch/x86/kvm/ioapic.c           | 16 ++++++++++++++++
>   arch/x86/kvm/ioapic.h           |  2 ++
>   arch/x86/kvm/lapic.c            |  3 +--
>   arch/x86/kvm/x86.c              | 30 ++++++++++++++++++++++--------
>   include/linux/kvm_host.h        |  9 +++++++++
>   virt/kvm/irqchip.c              | 37 +++++++++++++++++++++++++++++++++++++
>   7 files changed, 88 insertions(+), 10 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 2778d36..4f439ff 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -644,6 +644,7 @@ struct kvm_arch {
>   	u64 disabled_quirks;
>   
>   	bool irqchip_split;
> +	u8 nr_reserved_ioapic_pins;
>   };
>   
>   struct kvm_vm_stat {
> diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
> index 856f791..fb5281b 100644
> --- a/arch/x86/kvm/ioapic.c
> +++ b/arch/x86/kvm/ioapic.c
> @@ -672,3 +672,19 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
>   	spin_unlock(&ioapic->lock);
>   	return 0;
>   }
> +
> +void kvm_arch_irq_routing_update(struct kvm *kvm)
> +{
> +	struct kvm_ioapic *ioapic = kvm->arch.vioapic;
> +
> +	if (ioapic)
> +		return;
> +	if (!lapic_in_kernel(kvm))
> +		return;
> +	kvm_make_scan_ioapic_request(kvm);
> +}
> +
> +u8 kvm_arch_nr_userspace_ioapic_pins(struct kvm *kvm)
> +{
> +	return kvm->arch.nr_reserved_ioapic_pins;
> +}
> diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
> index ca0b0b4..3af349c 100644
> --- a/arch/x86/kvm/ioapic.h
> +++ b/arch/x86/kvm/ioapic.h
> @@ -9,6 +9,7 @@ struct kvm;
>   struct kvm_vcpu;
>   
>   #define IOAPIC_NUM_PINS  KVM_IOAPIC_NUM_PINS
> +#define MAX_NR_RESERVED_IOAPIC_PINS 48
>   #define IOAPIC_VERSION_ID 0x11	/* IOAPIC version */
>   #define IOAPIC_EDGE_TRIG  0
>   #define IOAPIC_LEVEL_TRIG 1
> @@ -123,4 +124,5 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
>   void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap,
>   			u32 *tmr);
>   
> +void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
>   #endif
> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> index 28eb946..766d297 100644
> --- a/arch/x86/kvm/lapic.c
> +++ b/arch/x86/kvm/lapic.c
> @@ -209,8 +209,7 @@ out:
>   	if (old)
>   		kfree_rcu(old, rcu);
>   
> -	if (!irqchip_split(kvm))
> -		kvm_vcpu_request_scan_ioapic(kvm);
> +	kvm_make_scan_ioapic_request(kvm);
>   }
>   
>   static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 5e01810..35d13d4 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -3930,15 +3930,20 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
>   	case KVM_CAP_SPLIT_IRQCHIP: {
>   		mutex_lock(&kvm->lock);
>   		r = -EEXIST;
> -		if (lapic_in_kernel(kvm))
> +		if (irqchip_in_kernel(kvm))
>   			goto split_irqchip_unlock;
>   		r = -EINVAL;
> -		if (atomic_read(&kvm->online_vcpus))
> -			goto split_irqchip_unlock;
> -		r = kvm_setup_empty_irq_routing(kvm);
> -		if (r)
> +		if (cap->args[0] > MAX_NR_RESERVED_IOAPIC_PINS)
>   			goto split_irqchip_unlock;
> -		kvm->arch.irqchip_split = true;
> +		if (!irqchip_split(kvm)) {
> +			if (atomic_read(&kvm->online_vcpus))
> +				goto split_irqchip_unlock;
> +			r = kvm_setup_empty_irq_routing(kvm);
> +			if (r)
> +				goto split_irqchip_unlock;
> +			kvm->arch.irqchip_split = true;
> +		}
> +		kvm->arch.nr_reserved_ioapic_pins = cap->args[0];
>   		r = 0;
>   split_irqchip_unlock:
>   		mutex_unlock(&kvm->lock);
> @@ -6403,8 +6408,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
>   				goto out;
>   			}
>   		}
> -		if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu))
> -			vcpu_scan_ioapic(vcpu);
> +		if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu)) {
> +			if (irqchip_split(vcpu->kvm)) {
> +				memset(vcpu->arch.eoi_exit_bitmaps, 0, 32);
> +				kvm_scan_ioapic_routes(
> +				    vcpu, vcpu->arch.eoi_exit_bitmaps);
> +				kvm_x86_ops->load_eoi_exitmap(
> +				    vcpu, vcpu->arch.eoi_exit_bitmaps);

How about introduce a handler to fold above just like vcpu_scan_ioapic() ?

Regards,
Wanpeng Li

> +
> +			} else
> +				vcpu_scan_ioapic(vcpu);
> +		}
>   		if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
>   			kvm_vcpu_reload_apic_access_page(vcpu);
>   	}
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index c6df36f..1bd4afa 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -438,10 +438,19 @@ void vcpu_put(struct kvm_vcpu *vcpu);
>   
>   #ifdef __KVM_HAVE_IOAPIC
>   void kvm_vcpu_request_scan_ioapic(struct kvm *kvm);
> +void kvm_arch_irq_routing_update(struct kvm *kvm);
> +u8 kvm_arch_nr_userspace_ioapic_pins(struct kvm *kvm);
>   #else
>   static inline void kvm_vcpu_request_scan_ioapic(struct kvm *kvm)
>   {
>   }
> +static inline void kvm_arch_irq_routing_update(struct kvm *kvm)
> +{
> +}
> +static inline u8 kvm_arch_nr_userspace_ioapic_pins(struct kvm *kvm)
> +{
> +	return 0;
> +}
>   #endif
>   
>   #ifdef CONFIG_HAVE_KVM_IRQFD
> diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
> index 8aaceed..208fdd3 100644
> --- a/virt/kvm/irqchip.c
> +++ b/virt/kvm/irqchip.c
> @@ -203,6 +203,8 @@ int kvm_set_irq_routing(struct kvm *kvm,
>   	kvm_irq_routing_update(kvm);
>   	mutex_unlock(&kvm->irq_lock);
>   
> +	kvm_arch_irq_routing_update(kvm);
> +
>   	synchronize_srcu_expedited(&kvm->irq_srcu);
>   
>   	new = old;
> @@ -212,3 +214,38 @@ out:
>   	kfree(new);
>   	return r;
>   }
> +
> +void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	struct kvm_kernel_irq_routing_entry *entry;
> +	struct kvm_irq_routing_table *table;
> +	u32 i, nr_ioapic_pins;
> +	int idx;
> +
> +	/* kvm->irq_routing must be read after clearing
> +	 * KVM_SCAN_IOAPIC. */
> +	smp_mb();
> +	idx = srcu_read_lock(&kvm->irq_srcu);
> +	table = kvm->irq_routing;
> +	nr_ioapic_pins = min_t(u32, table->nr_rt_entries,
> +			      kvm_arch_nr_userspace_ioapic_pins(kvm));
> +	for (i = 0; i < nr_ioapic_pins; ++i) {
> +		hlist_for_each_entry(entry, &table->map[i], link) {
> +			u32 dest_id, dest_mode;
> +
> +			if (entry->type != KVM_IRQ_ROUTING_MSI)
> +				continue;
> +			dest_id = (entry->msi.address_lo >> 12) & 0xff;
> +			dest_mode = (entry->msi.address_lo >> 2) & 0x1;
> +			if (kvm_apic_match_dest(vcpu, NULL, 0, dest_id,
> +						dest_mode)) {
> +				u32 vector = entry->msi.data & 0xff;
> +
> +				__set_bit(vector,
> +					  (unsigned long *) eoi_exit_bitmap);
> +			}
> +		}
> +	}
> +	srcu_read_unlock(&kvm->irq_srcu, idx);
> +}


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

* Re: [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference
  2015-06-08 10:33   ` Wanpeng Li
@ 2015-06-08 14:15     ` Paolo Bonzini
  2015-06-09  2:16       ` Wanpeng Li
  0 siblings, 1 reply; 20+ messages in thread
From: Paolo Bonzini @ 2015-06-08 14:15 UTC (permalink / raw)
  To: Wanpeng Li, Steve Rutherford, kvm



On 08/06/2015 12:33, Wanpeng Li wrote:
>> +        if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu)) {
>> +            if (irqchip_split(vcpu->kvm)) {
>> +                memset(vcpu->arch.eoi_exit_bitmaps, 0, 32);
>> +                kvm_scan_ioapic_routes(
>> +                    vcpu, vcpu->arch.eoi_exit_bitmaps);
>> +                kvm_x86_ops->load_eoi_exitmap(
>> +                    vcpu, vcpu->arch.eoi_exit_bitmaps);
> 
> How about introduce a handler to fold above just like vcpu_scan_ioapic() ?

Or just move the "if" inside the existing vcpu_scan_ioapic().  This is a
good suggestion because it raises more question:

1) should the

        if (!kvm_apic_hw_enabled(vcpu->arch.apic))
                return;

of vcpu_scan_ioapic apply to the "split irqchip" case too?

2) the "non-split irqchip" can also use vcpu->arch.eoi_exit_bitmaps
instead of the local eoi_exit_bitmap variable of vcpu_scan_ioapic.

So in the end the patched vcpu_scan_ioapic becomes

	if (kvm_apic_hw_enabled(vcpu->arch.apic))
                return;

	memset(vcpu->arch.eoi_exit_bitmaps, 0, 32);
	if (irqchip_split)
		scan_ioapic_routes(...)
	else {
		memset(tmr, 0, 32)
		kvm_ioapic_scan_entry(...)
		kvm_apic_update_tmr(vcpu, tmr);
	}
	kvm_x86_ops->load_eoi_exitmap(vcpu,
				      vcpu->arch.eoi_exit_bitmaps);

A FIXME/TODO comment about TMR in the split-irqchip case is probably in
order too.

Paolo

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

* Re: [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference
  2015-06-08 14:15     ` Paolo Bonzini
@ 2015-06-09  2:16       ` Wanpeng Li
  2015-06-17  8:14         ` Paolo Bonzini
  0 siblings, 1 reply; 20+ messages in thread
From: Wanpeng Li @ 2015-06-09  2:16 UTC (permalink / raw)
  To: Paolo Bonzini, Steve Rutherford, kvm


On 6/8/15 10:15 PM, Paolo Bonzini wrote:
>
> On 08/06/2015 12:33, Wanpeng Li wrote:
>>> +        if (kvm_check_request(KVM_REQ_SCAN_IOAPIC, vcpu)) {
>>> +            if (irqchip_split(vcpu->kvm)) {
>>> +                memset(vcpu->arch.eoi_exit_bitmaps, 0, 32);
>>> +                kvm_scan_ioapic_routes(
>>> +                    vcpu, vcpu->arch.eoi_exit_bitmaps);
>>> +                kvm_x86_ops->load_eoi_exitmap(
>>> +                    vcpu, vcpu->arch.eoi_exit_bitmaps);
>> How about introduce a handler to fold above just like vcpu_scan_ioapic() ?
> Or just move the "if" inside the existing vcpu_scan_ioapic().  This is a
> good suggestion because it raises more question:
>
> 1) should the
>
>          if (!kvm_apic_hw_enabled(vcpu->arch.apic))
>                  return;
>
> of vcpu_scan_ioapic apply to the "split irqchip" case too?
>
> 2) the "non-split irqchip" can also use vcpu->arch.eoi_exit_bitmaps
> instead of the local eoi_exit_bitmap variable of vcpu_scan_ioapic.
>
> So in the end the patched vcpu_scan_ioapic becomes
>
> 	if (kvm_apic_hw_enabled(vcpu->arch.apic))

s/kvm_apic_hw_enabled(vcpu->arch.apic)/!kvm_apic_hw_enabled(vcpu->arch.apic)

Regards,
Wanpeng Li

>                  return;
>
> 	memset(vcpu->arch.eoi_exit_bitmaps, 0, 32);
> 	if (irqchip_split)
> 		scan_ioapic_routes(...)
> 	else {
> 		memset(tmr, 0, 32)
> 		kvm_ioapic_scan_entry(...)
> 		kvm_apic_update_tmr(vcpu, tmr);
> 	}
> 	kvm_x86_ops->load_eoi_exitmap(vcpu,
> 				      vcpu->arch.eoi_exit_bitmaps);
>
> A FIXME/TODO comment about TMR in the split-irqchip case is probably in
> order too.
>
> Paolo
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference
  2015-06-09  2:16       ` Wanpeng Li
@ 2015-06-17  8:14         ` Paolo Bonzini
  0 siblings, 0 replies; 20+ messages in thread
From: Paolo Bonzini @ 2015-06-17  8:14 UTC (permalink / raw)
  To: Wanpeng Li, Steve Rutherford, kvm



On 09/06/2015 04:16, Wanpeng Li wrote:
>>
>> So in the end the patched vcpu_scan_ioapic becomes
>>
>>     if (kvm_apic_hw_enabled(vcpu->arch.apic))
> 
> s/kvm_apic_hw_enabled(vcpu->arch.apic)/!kvm_apic_hw_enabled(vcpu->arch.apic)

Right, thanks for the correction.

Paolo

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

* Re: [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace
  2015-06-03  9:38   ` Paolo Bonzini
  2015-06-04 20:21     ` Steve Rutherford
@ 2015-06-20  0:41     ` Steve Rutherford
  2015-06-21 20:10       ` Paolo Bonzini
  2015-06-26  0:26     ` Steve Rutherford
  2 siblings, 1 reply; 20+ messages in thread
From: Steve Rutherford @ 2015-06-20  0:41 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm

On Wed, Jun 03, 2015 at 11:38:21AM +0200, Paolo Bonzini wrote:
> 
> 
> On 03/06/2015 01:51, Steve Rutherford wrote:
> > In order to enable userspace PIC support, the userspace PIC needs to
> > be able to inject local interrupt requests.
> > 
> > This adds the ioctl KVM_REQUEST_PIC_INJECTION and kvm exit
> > KVM_EXIT_GET_EXTINT.
> > 
> > The vm ioctl KVM_REQUEST_PIC_INJECTION makes a KVM_REQ_EVENT request
> > on the BSP, which causes the BSP to exit to userspace to fetch the
> > vector of the underlying external interrupt, which the BSP then
> > injects into the guest. This matches the PIC spec, and is necessary to
> > boot Windows.
> > 
> > Compiles for x86.
> > 
> > Update: Boots Windows and passes the KVM Unit Tests.
> > 
> > Signed-off-by: Steve Rutherford <srutherford@google.com>
> > ---
> >  Documentation/virtual/kvm/api.txt |  9 ++++++
> >  arch/x86/include/asm/kvm_host.h   |  2 ++
> >  arch/x86/kvm/irq.c                | 22 +++++++++++++--
> >  arch/x86/kvm/lapic.c              |  7 +++++
> >  arch/x86/kvm/lapic.h              |  2 ++
> >  arch/x86/kvm/x86.c                | 59 +++++++++++++++++++++++++++++++++++++--
> >  include/uapi/linux/kvm.h          |  7 +++++
> >  7 files changed, 103 insertions(+), 5 deletions(-)
> > 
> > diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> > index 6ab2a3f7..b5d90cb 100644
> > --- a/Documentation/virtual/kvm/api.txt
> > +++ b/Documentation/virtual/kvm/api.txt
> > @@ -2979,6 +2979,15 @@ len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
> >  and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
> >  which is the maximum number of possibly pending cpu-local interrupts.
> >  
> > +4.96 KVM_REQUEST_PIC_INJECTION
> > +
> > +Capability: KVM_CAP_SPLIT_IRQCHIP
> > +Type: VM ioctl
> > +Parameters: none
> > +Returns: 0 on success, -1 on error.
> > +
> > +Informs the kernel that userspace has a pending external interrupt.
> > +
> 
> Missing documentation for the new vmexit and kvm_run member.
> 
> However, why is the roundtrip to userspace necessary?  Could you pass
> the extint index directly as an argument to KVM_INTERRUPT?  It's
> backwards-compatible, because KVM_INTERRUPT so far could not be used
> together with an in-kernel LAPIC.  If you could do that, you could also
> avoid the new userspace_extint_available field.
> 
> Userspace can figure out who's the BSP.  The rendez-vous between the
> irqchip and the BSP's VCPU thread is still needed, but it can be done
> entirely in userspace.
> 
> You'd also need much fewer changes to irq.c.  Basically just something like
> 
>  int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
>  {
>          int vector;
> 
> -        if (!irqchip_in_kernel(v->kvm))
> +        if (!pic_in_kernel(v->kvm) && v->arch.interrupt.pending)
>                 return v->arch.interrupt.nr;
> 
> ...
> 
>  int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
>  {
> -        if (!irqchip_in_kernel(v->kvm))
> +        if (!pic_in_kernel(v->kvm))
>                  return v->arch.interrupt.pending;
> 
> ...
> 
>  int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
>  {
> -        if (!irqchip_in_kernel(v->kvm))
> +        if (!pic_in_kernel(v->kvm))
>                  return v->arch.interrupt.pending;
> 
> More comments below.
> 
> >  5. The kvm_run structure
> >  ------------------------
> > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> > index 4f439ff..0e8b0fc 100644
> > --- a/arch/x86/include/asm/kvm_host.h
> > +++ b/arch/x86/include/asm/kvm_host.h
> > @@ -543,6 +543,8 @@ struct kvm_vcpu_arch {
> >  
> >  	u64 eoi_exit_bitmaps[4];
> >  	int pending_ioapic_eoi;
> > +	bool userspace_extint_available;
> > +	int pending_external_vector;
> >  };
> >  
> 
> >  struct kvm_lpage_info {
> > diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
> > index 706e47a..1270b2a 100644
> > --- a/arch/x86/kvm/irq.c
> > +++ b/arch/x86/kvm/irq.c
> > @@ -38,12 +38,25 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
> >  EXPORT_SYMBOL(kvm_cpu_has_pending_timer);
> >  
> >  /*
> > + * check if there is a pending userspace external interrupt
> > + */
> > +static int pending_userspace_extint(struct kvm_vcpu *v)
> > +{
> > +	return v->arch.userspace_extint_available ||
> > +	       v->arch.pending_external_vector != -1;
> > +}
> > +
> > +/*
> >   * check if there is pending interrupt from
> >   * non-APIC source without intack.
> >   */
> >  static int kvm_cpu_has_extint(struct kvm_vcpu *v)
> >  {
> > -	if (kvm_apic_accept_pic_intr(v))
> > +	u8 accept = kvm_apic_accept_pic_intr(v);
> > +
> > +	if (accept && irqchip_split(v->kvm))
> > +		return pending_userspace_extint(v);
> > +	else if (accept)
> >  		return pic_irqchip(v->kvm)->output;	/* PIC */
> 
> 	if (accept) {
> 		if (irqchip_split(v->kvm))
> 			return pending_userspace_extint(v);
> 		else
> 			return pic_irqchip(v->kvm)->output;
> 	}
> 
> 	return 0;
> 
> >  	else
> >  		return 0;
> > @@ -91,7 +104,12 @@ EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
> >   */
> >  static int kvm_cpu_get_extint(struct kvm_vcpu *v)
> >  {
> > -	if (kvm_cpu_has_extint(v))
> > +	if (irqchip_split(v->kvm) && kvm_cpu_has_extint(v)) {
> > +		int vector = v->arch.pending_external_vector;
> > +
> > +		v->arch.pending_external_vector = -1;
> > +		return vector;
> > +	} else if (kvm_cpu_has_extint(v))
> >  		return kvm_pic_read_irq(v->kvm); /* PIC */
> 
> Same as above.
> 
> >  	return -1;
> >  }
> > diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> > index 766d297..012b56ee 100644
> > --- a/arch/x86/kvm/lapic.c
> > +++ b/arch/x86/kvm/lapic.c
> > @@ -2094,3 +2094,10 @@ void kvm_lapic_init(void)
> >  	jump_label_rate_limit(&apic_hw_disabled, HZ);
> >  	jump_label_rate_limit(&apic_sw_disabled, HZ);
> >  }
> > +
> > +void kvm_request_pic_injection(struct kvm_vcpu *vcpu)
> > +{
> > +	vcpu->arch.userspace_extint_available = true;
> > +	kvm_make_request(KVM_REQ_EVENT, vcpu);
> > +	kvm_vcpu_kick(vcpu);
> > +}
> > diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
> > index 71b150c..7831e4d 100644
> > --- a/arch/x86/kvm/lapic.h
> > +++ b/arch/x86/kvm/lapic.h
> > @@ -63,6 +63,8 @@ int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq,
> >  		unsigned long *dest_map);
> >  int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type);
> >  
> > +void kvm_request_pic_injection(struct kvm_vcpu *vcpu);
> > +
> >  bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
> >  		struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map);
> >  
> > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> > index 35d13d4..40e7509 100644
> > --- a/arch/x86/kvm/x86.c
> > +++ b/arch/x86/kvm/x86.c
> > @@ -65,6 +65,8 @@
> >  #include <asm/pvclock.h>
> >  #include <asm/div64.h>
> >  
> > +#define GET_VECTOR_FROM_USERSPACE 1
> > +
> >  #define MAX_IO_MSRS 256
> >  #define KVM_MAX_MCE_BANKS 32
> >  #define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P)
> > @@ -4217,6 +4219,30 @@ long kvm_arch_vm_ioctl(struct file *filp,
> >  		r = kvm_vm_ioctl_enable_cap(kvm, &cap);
> >  		break;
> >  	}
> > +	case KVM_REQUEST_PIC_INJECTION: {
> > +		int i;
> > +		struct kvm_vcpu *vcpu;
> > +		struct kvm_vcpu *bsp_vcpu = NULL;
> > +
> > +		mutex_lock(&kvm->lock);
> > +		r = -EEXIST;
> > +		if (!irqchip_split(kvm))
> > +			goto out;
> > +		kvm_for_each_vcpu(i, vcpu, kvm) {
> > +			if (kvm_vcpu_is_reset_bsp(vcpu)) {
> > +				bsp_vcpu = vcpu;
> > +				continue;
> > +			}
> > +		}
> > +		r = -EINVAL;
> > +		if (bsp_vcpu == NULL)
> > +			goto interrupt_unlock;
> > +		kvm_request_pic_injection(bsp_vcpu);
> > +		r = 0;
> > +interrupt_unlock:
> > +		mutex_unlock(&kvm->lock);
> > +		break;
> > +	}
> >  
> >  	default:
> >  		r = kvm_vm_ioctl_assigned_device(kvm, ioctl, arg);
> > @@ -6194,6 +6220,17 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
> >  	kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
> >  }
> >  
> > +static int must_fetch_userspace_extint(struct kvm_vcpu *vcpu)
> 
> I would rename this to kvm_accept_request_pic_injection.
> 
> Paolo
> 
> > +{
> > +	if (vcpu->arch.userspace_extint_available &&
> > +	    kvm_apic_accept_pic_intr(vcpu)) {
> > +		vcpu->arch.userspace_extint_available = false;
> > +		return true;
> > +	} else
> > +		return false;
> > +
> > +}
> > +
> >  static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
> >  {
> >  	int r;
> > @@ -6258,7 +6295,12 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
> >  				return r;
> >  		}
> >  		if (kvm_x86_ops->interrupt_allowed(vcpu)) {
> > -			kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu),
> > +			if (irqchip_split(vcpu->kvm) &&
> > +			    must_fetch_userspace_extint(vcpu)) {
> > +				return GET_VECTOR_FROM_USERSPACE;
> > +			}
> > +			kvm_queue_interrupt(vcpu,
> > +					    kvm_cpu_get_interrupt(vcpu),
> >  					    false);
> >  			kvm_x86_ops->set_irq(vcpu);
> >  		}
> > @@ -6424,13 +6466,19 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
> >  	}
> >  
> >  	if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
> > +		int event;
> >  		kvm_apic_accept_events(vcpu);
> >  		if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) {
> >  			r = 1;
> >  			goto out;
> >  		}
> > -
> > -		if (inject_pending_event(vcpu, req_int_win) != 0)
> > +		event = inject_pending_event(vcpu, req_int_win);
> > +		if (event == GET_VECTOR_FROM_USERSPACE) {
> > +			vcpu->run->exit_reason = KVM_EXIT_GET_EXTINT;
> > +			kvm_make_request(KVM_REQ_EVENT, vcpu);
> > +			r = 0;
> > +			goto out;
> > +		} else if (event != 0)
> >  			req_immediate_exit = true;
> >  		/* enable NMI/IRQ window open exits if needed */
> >  		else if (vcpu->arch.nmi_pending)
> > @@ -6747,6 +6795,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
> >  	if (vcpu->sigset_active)
> >  		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
> >  
> > +	if (vcpu->run->exit_reason == KVM_EXIT_GET_EXTINT)
> > +		vcpu->arch.pending_external_vector = vcpu->run->extint.vector;
> > +
> >  	if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) {
> >  		kvm_vcpu_block(vcpu);
> >  		kvm_apic_accept_events(vcpu);
> > @@ -7536,6 +7587,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
> >  	kvm_async_pf_hash_reset(vcpu);
> >  	kvm_pmu_init(vcpu);
> >  
> > +	vcpu->arch.pending_external_vector = -1;
> > +
> >  	return 0;
> >  fail_free_wbinvd_dirty_mask:
> >  	free_cpumask_var(vcpu->arch.wbinvd_dirty_mask);
> > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> > index 826a08d..0cf7ed6 100644
> > --- a/include/uapi/linux/kvm.h
> > +++ b/include/uapi/linux/kvm.h
> > @@ -184,6 +184,7 @@ struct kvm_s390_skeys {
> >  #define KVM_EXIT_SYSTEM_EVENT     24
> >  #define KVM_EXIT_S390_STSI        25
> >  #define KVM_EXIT_IOAPIC_EOI       26
> > +#define KVM_EXIT_GET_EXTINT       27
> >  
> >  /* For KVM_EXIT_INTERNAL_ERROR */
> >  /* Emulate instruction failed. */
> > @@ -334,6 +335,10 @@ struct kvm_run {
> >  		struct {
> >  			__u8 vector;
> >  		} eoi;
> > +		/* KVM_EXIT_GET_EXTINT */
> > +		struct {
> > +			__u8 vector;
> > +		} extint;
> >  		/* Fix the size of the union. */
> >  		char padding[256];
> >  	};
> > @@ -1206,6 +1211,8 @@ struct kvm_s390_ucas_mapping {
> >  /* Available with KVM_CAP_S390_IRQ_STATE */
> >  #define KVM_S390_SET_IRQ_STATE	  _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state)
> >  #define KVM_S390_GET_IRQ_STATE	  _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
> > +/* Available with KVM_CAP_SPLIT_IRQCHIP */
> > +#define KVM_REQUEST_PIC_INJECTION _IO(KVMIO, 0xb7)
> >  
> >  #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
> >  #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
> > 

Pinging this thread.

Should I go with skipping the round trip, and combining
KVM_REQUEST_PIC_INJECTION with the KVM_INTERRUPT (a VCPU IOCTL)?
[It's currently a VM IOCTL, which seems reasonable, given that the
PIC is a per VM device. When skipping the round trip, a VCPU Ioctl
seems sensible, given that an interrupt is associated with a specific
CPU.]

Steve
--
To unsubscribe from this list: send the line "unsubscribe kvm" in

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

* Re: [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace
  2015-06-20  0:41     ` Steve Rutherford
@ 2015-06-21 20:10       ` Paolo Bonzini
  0 siblings, 0 replies; 20+ messages in thread
From: Paolo Bonzini @ 2015-06-21 20:10 UTC (permalink / raw)
  To: Steve Rutherford; +Cc: kvm



On 20/06/2015 02:41, Steve Rutherford wrote:
> Pinging this thread.
> 
> Should I go with skipping the round trip, and combining
> KVM_REQUEST_PIC_INJECTION with the KVM_INTERRUPT (a VCPU IOCTL)?
> [It's currently a VM IOCTL, which seems reasonable, given that the
> PIC is a per VM device. When skipping the round trip, a VCPU Ioctl
> seems sensible, given that an interrupt is associated with a specific
> CPU.]

Yes, please.  Sorry for not answering, I didn't understand a question
was implied.  The roundtrip can be done in userspace.

Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in

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

* Re: [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace
  2015-06-03  9:38   ` Paolo Bonzini
  2015-06-04 20:21     ` Steve Rutherford
  2015-06-20  0:41     ` Steve Rutherford
@ 2015-06-26  0:26     ` Steve Rutherford
  2015-06-26  8:49       ` Paolo Bonzini
  2 siblings, 1 reply; 20+ messages in thread
From: Steve Rutherford @ 2015-06-26  0:26 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm

> However, why is the roundtrip to userspace necessary?  Could you pass
> the extint index directly as an argument to KVM_INTERRUPT?  It's
> backwards-compatible, because KVM_INTERRUPT so far could not be used
> together with an in-kernel LAPIC.  If you could do that, you could also
> avoid the new userspace_extint_available field.

Implemented a basic version of this, and ran into some potential
issues with this strategy. Supporting PIC masking/unmasking by the
CPU/APIC means that either:
A) PIC interrupts need to be bufferable in the kernel (with some way
   of comparing priorities).
B) the APIC state needs to be read in order to fetch the bit as to
   whether or not the PIC is being masked (which I believe can be done
   from userspace via the APIC state ioctl).
C) something hacky that doesn't conform to the PIC spec but still
   happens to boot common OSes (like buffering the interrupts and
   injecting them in the order of arrival (which is wrong)).

Steve

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

* Re: [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace
  2015-06-26  0:26     ` Steve Rutherford
@ 2015-06-26  8:49       ` Paolo Bonzini
  0 siblings, 0 replies; 20+ messages in thread
From: Paolo Bonzini @ 2015-06-26  8:49 UTC (permalink / raw)
  To: Steve Rutherford; +Cc: kvm



On 26/06/2015 02:26, Steve Rutherford wrote:
> Implemented a basic version of this, and ran into some potential
> issues with this strategy. Supporting PIC masking/unmasking by the
> CPU/APIC means that either:
> A) PIC interrupts need to be bufferable in the kernel (with some way
>    of comparing priorities).
> B) the APIC state needs to be read in order to fetch the bit as to
>    whether or not the PIC is being masked (which I believe can be done
>    from userspace via the APIC state ioctl).
> C) something hacky that doesn't conform to the PIC spec but still
>    happens to boot common OSes (like buffering the interrupts and
>    injecting them in the order of arrival (which is wrong)).

I think B is okay to do.  Later if needed we can make it possible for
userspace to mmap the LAPIC page instead of using the APIC state ioctl.

Paolo

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

end of thread, other threads:[~2015-06-26  8:49 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-02 23:51 [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Steve Rutherford
2015-06-02 23:51 ` [PATCH v3 2/4] KVM: x86: Add KVM exit for IOAPIC EOIs Steve Rutherford
2015-06-03  9:16   ` Paolo Bonzini
2015-06-02 23:51 ` [PATCH v3 3/4] KVM: x86: Add EOI exit bitmap inference Steve Rutherford
2015-06-03  9:16   ` Paolo Bonzini
2015-06-04 20:39     ` Steve Rutherford
2015-06-08 10:33   ` Wanpeng Li
2015-06-08 14:15     ` Paolo Bonzini
2015-06-09  2:16       ` Wanpeng Li
2015-06-17  8:14         ` Paolo Bonzini
2015-06-02 23:51 ` [PATCH v3 4/4] KVM: x86: Add support for local interrupt requests from userspace Steve Rutherford
2015-06-03  9:38   ` Paolo Bonzini
2015-06-04 20:21     ` Steve Rutherford
2015-06-20  0:41     ` Steve Rutherford
2015-06-21 20:10       ` Paolo Bonzini
2015-06-26  0:26     ` Steve Rutherford
2015-06-26  8:49       ` Paolo Bonzini
2015-06-03  8:54 ` [PATCH v3 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Paolo Bonzini
2015-06-04 20:38   ` Steve Rutherford
2015-06-05  7:19     ` Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.