* [PATCH v5 2/4] KVM: x86: Add KVM exit for IOAPIC EOIs
2015-07-27 23:17 [PATCH v5 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Steve Rutherford
@ 2015-07-27 23:17 ` Steve Rutherford
2015-07-27 23:17 ` [PATCH v5 3/4] KVM: x86: Add EOI exit bitmap inference Steve Rutherford
` (2 subsequent siblings)
3 siblings, 0 replies; 16+ messages in thread
From: Steve Rutherford @ 2015-07-27 23:17 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 | 13 +++++++++++++
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 | 2 +-
include/uapi/linux/kvm.h | 5 +++++
6 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index b655024..6a13dff 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -3302,6 +3302,18 @@ Valid values for 'type' are:
to ignore the request, or to gather VM memory core dump and/or
reset/shutdown of the VM.
+ /* KVM_EXIT_IOAPIC_EOI */
+ struct {
+ __u8 vector;
+ } eoi;
+
+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 (i.e. KVM_CAP_SPLIT_IRQCHIP is enabled);
+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.
+
/* Fix the size of the union. */
char padding[256];
};
@@ -3315,6 +3327,7 @@ Valid values for 'type' are:
*/
__u64 kvm_valid_regs;
__u64 kvm_dirty_regs;
+
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 18a110b..f1e0103 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -560,6 +560,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 536b79e..37e220d 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -871,6 +871,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 6d4b4dc..03ba33a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6278,6 +6278,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
kvm_pmu_handle_event(vcpu);
if (kvm_check_request(KVM_REQ_PMI, vcpu))
kvm_pmu_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 f7eab09..8e12d67 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -140,6 +140,7 @@ static inline bool is_error_page(struct page *page)
#define KVM_REQ_APIC_PAGE_RELOAD 25
#define KVM_REQ_SMI 26
#define KVM_REQ_HV_CRASH 27
+#define KVM_REQ_IOAPIC_EOI_EXIT 28
#define KVM_USERSPACE_IRQ_SOURCE_ID 0
#define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1
@@ -1157,4 +1158,3 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
}
#endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
#endif
-
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index e4304d0..c15f5d9 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. */
@@ -330,6 +331,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.5.0.rc2.392.g76e840b
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v5 3/4] KVM: x86: Add EOI exit bitmap inference
2015-07-27 23:17 [PATCH v5 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Steve Rutherford
2015-07-27 23:17 ` [PATCH v5 2/4] KVM: x86: Add KVM exit for IOAPIC EOIs Steve Rutherford
@ 2015-07-27 23:17 ` Steve Rutherford
2015-07-29 12:38 ` Paolo Bonzini
2015-07-27 23:17 ` [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace Steve Rutherford
2015-07-29 12:56 ` [PATCH v5 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Paolo Bonzini
3 siblings, 1 reply; 16+ messages in thread
From: Steve Rutherford @ 2015-07-27 23:17 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>
---
Documentation/virtual/kvm/api.txt | 8 ++++----
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/kvm/ioapic.h | 2 ++
arch/x86/kvm/irq_comm.c | 42 +++++++++++++++++++++++++++++++++++++++
arch/x86/kvm/lapic.c | 3 +--
arch/x86/kvm/x86.c | 29 +++++++++++++++++----------
include/linux/kvm_host.h | 20 +++++++++++++++++++
virt/kvm/irqchip.c | 12 ++---------
8 files changed, 91 insertions(+), 26 deletions(-)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 6a13dff..39e4c02 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -3302,10 +3302,10 @@ Valid values for 'type' are:
to ignore the request, or to gather VM memory core dump and/or
reset/shutdown of the VM.
- /* KVM_EXIT_IOAPIC_EOI */
- struct {
- __u8 vector;
- } eoi;
+ /* KVM_EXIT_IOAPIC_EOI */
+ struct {
+ __u8 vector;
+ } eoi;
Indicates that the VCPU's in-kernel local APIC received an EOI for a
level-triggered IOAPIC interrupt. This exit only triggers when the
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f1e0103..ebe7f07 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -674,6 +674,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.h b/arch/x86/kvm/ioapic.h
index d8cc54b..f6ce112 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
@@ -132,4 +133,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/irq_comm.c b/arch/x86/kvm/irq_comm.c
index 67f6b62..da4827f 100644
--- a/arch/x86/kvm/irq_comm.c
+++ b/arch/x86/kvm/irq_comm.c
@@ -335,3 +335,45 @@ int kvm_setup_empty_irq_routing(struct kvm *kvm)
{
return kvm_set_irq_routing(kvm, empty_routing, 0, 0);
}
+
+void kvm_arch_irq_routing_update(struct kvm *kvm)
+{
+ if (ioapic_in_kernel(kvm) || !irqchip_in_kernel(kvm))
+ return;
+ kvm_make_scan_ioapic_request(kvm);
+}
+
+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_reserved_ioapic_pins);
+ 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);
+}
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 37e220d..4dbf6c1 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 03ba33a..eef562f 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3575,12 +3575,17 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *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);
@@ -6164,18 +6169,22 @@ static void process_smi(struct kvm_vcpu *vcpu)
static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
{
- u64 eoi_exit_bitmap[4];
+ struct kvm *kvm = vcpu->kvm;
u32 tmr[8];
if (!kvm_apic_hw_enabled(vcpu->arch.apic))
return;
- memset(eoi_exit_bitmap, 0, 32);
+ memset(vcpu->arch.eoi_exit_bitmaps, 0, 32);
memset(tmr, 0, 32);
+ if (irqchip_split(kvm))
+ kvm_scan_ioapic_routes(vcpu, vcpu->arch.eoi_exit_bitmaps);
+ else
+ kvm_ioapic_scan_entry(vcpu, vcpu->arch.eoi_exit_bitmaps, tmr);
+ kvm_x86_ops->load_eoi_exitmap(vcpu, vcpu->arch.eoi_exit_bitmaps);
- kvm_ioapic_scan_entry(vcpu, eoi_exit_bitmap, tmr);
- kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap);
- kvm_apic_update_tmr(vcpu, tmr);
+ if (!irqchip_split(kvm))
+ kvm_apic_update_tmr(vcpu, tmr);
}
static void kvm_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 8e12d67..064067e 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -329,6 +329,17 @@ struct kvm_kernel_irq_routing_entry {
struct hlist_node link;
};
+struct kvm_irq_routing_table {
+ int chip[KVM_NR_IRQCHIPS][KVM_IRQCHIP_NUM_PINS];
+ struct kvm_kernel_irq_routing_entry *rt_entries;
+ u32 nr_rt_entries;
+ /*
+ * Array indexed by gsi. Each entry contains list of irq chips
+ * the gsi is connected to.
+ */
+ struct hlist_head map[0];
+};
+
#ifndef KVM_PRIVATE_MEM_SLOTS
#define KVM_PRIVATE_MEM_SLOTS 0
#endif
@@ -454,10 +465,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 21c1424..4f85c6e 100644
--- a/virt/kvm/irqchip.c
+++ b/virt/kvm/irqchip.c
@@ -31,16 +31,6 @@
#include <trace/events/kvm.h>
#include "irq.h"
-struct kvm_irq_routing_table {
- int chip[KVM_NR_IRQCHIPS][KVM_IRQCHIP_NUM_PINS];
- u32 nr_rt_entries;
- /*
- * Array indexed by gsi. Each entry contains list of irq chips
- * the gsi is connected to.
- */
- struct hlist_head map[0];
-};
-
int kvm_irq_map_gsi(struct kvm *kvm,
struct kvm_kernel_irq_routing_entry *entries, int gsi)
{
@@ -227,6 +217,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;
--
2.5.0.rc2.392.g76e840b
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v5 3/4] KVM: x86: Add EOI exit bitmap inference
2015-07-27 23:17 ` [PATCH v5 3/4] KVM: x86: Add EOI exit bitmap inference Steve Rutherford
@ 2015-07-29 12:38 ` Paolo Bonzini
2015-07-29 20:27 ` Steve Rutherford
0 siblings, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2015-07-29 12:38 UTC (permalink / raw)
To: Steve Rutherford, kvm
On 28/07/2015 01:17, Steve Rutherford wrote:
> diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
> index d8cc54b..f6ce112 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
Why is this needed?
Paolo
> #define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */
> #define IOAPIC_EDGE_TRIG 0
> #define IOAPIC_LEVEL_TRIG 1
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 3/4] KVM: x86: Add EOI exit bitmap inference
2015-07-29 12:38 ` Paolo Bonzini
@ 2015-07-29 20:27 ` Steve Rutherford
2015-07-30 6:23 ` Jan Kiszka
0 siblings, 1 reply; 16+ messages in thread
From: Steve Rutherford @ 2015-07-29 20:27 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: kvm
On Wed, Jul 29, 2015 at 02:38:09PM +0200, Paolo Bonzini wrote:
>
>
> On 28/07/2015 01:17, Steve Rutherford wrote:
> > diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
> > index d8cc54b..f6ce112 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
>
> Why is this needed?
This constant is used to bound the number of IOAPIC pins that are
reservable when enabling KVM_CAP_SPLIT_IRQCHIP. IIRC, x86 doesn't
support more than 2 IOAPICs.
>
> Paolo
>
> > #define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */
> > #define IOAPIC_EDGE_TRIG 0
> > #define IOAPIC_LEVEL_TRIG 1
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 3/4] KVM: x86: Add EOI exit bitmap inference
2015-07-29 20:27 ` Steve Rutherford
@ 2015-07-30 6:23 ` Jan Kiszka
2015-07-30 6:27 ` Steve Rutherford
0 siblings, 1 reply; 16+ messages in thread
From: Jan Kiszka @ 2015-07-30 6:23 UTC (permalink / raw)
To: Steve Rutherford, Paolo Bonzini; +Cc: kvm
On 2015-07-29 22:27, Steve Rutherford wrote:
> On Wed, Jul 29, 2015 at 02:38:09PM +0200, Paolo Bonzini wrote:
>>
>>
>> On 28/07/2015 01:17, Steve Rutherford wrote:
>>> diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
>>> index d8cc54b..f6ce112 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
>>
>> Why is this needed?
> This constant is used to bound the number of IOAPIC pins that are
> reservable when enabling KVM_CAP_SPLIT_IRQCHIP. IIRC, x86 doesn't
> support more than 2 IOAPICs.
Huh? Surely not. I've already seen boxes with at least three, and I
think you can even hot-plug them today via extension cards. Not saying
that QEMU supports that already, even without KVM, but we must not limit
ourselves in the kernel API.
So please remove such a static limit on how many IOAPICs userspace can
emulate or raise it to something sufficiently large that will last long
enough.
Jan
--
Siemens AG, Corporate Technology, CT RTC ITP SES-DE
Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 3/4] KVM: x86: Add EOI exit bitmap inference
2015-07-30 6:23 ` Jan Kiszka
@ 2015-07-30 6:27 ` Steve Rutherford
0 siblings, 0 replies; 16+ messages in thread
From: Steve Rutherford @ 2015-07-30 6:27 UTC (permalink / raw)
To: Jan Kiszka; +Cc: Paolo Bonzini, kvm
On Thu, Jul 30, 2015 at 08:23:43AM +0200, Jan Kiszka wrote:
> On 2015-07-29 22:27, Steve Rutherford wrote:
> > On Wed, Jul 29, 2015 at 02:38:09PM +0200, Paolo Bonzini wrote:
> >>
> >>
> >> On 28/07/2015 01:17, Steve Rutherford wrote:
> >>> diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
> >>> index d8cc54b..f6ce112 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
> >>
> >> Why is this needed?
> > This constant is used to bound the number of IOAPIC pins that are
> > reservable when enabling KVM_CAP_SPLIT_IRQCHIP. IIRC, x86 doesn't
> > support more than 2 IOAPICs.
>
> Huh? Surely not. I've already seen boxes with at least three, and I
> think you can even hot-plug them today via extension cards. Not saying
> that QEMU supports that already, even without KVM, but we must not limit
> ourselves in the kernel API.
>
> So please remove such a static limit on how many IOAPICs userspace can
> emulate or raise it to something sufficiently large that will last long
> enough.
I'll go with the latter. I'll set it to the same size as the max size of the
GSI routing table, which needs to upper bound it.
>
> Jan
>
> --
> Siemens AG, Corporate Technology, CT RTC ITP SES-DE
> Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace
2015-07-27 23:17 [PATCH v5 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Steve Rutherford
2015-07-27 23:17 ` [PATCH v5 2/4] KVM: x86: Add KVM exit for IOAPIC EOIs Steve Rutherford
2015-07-27 23:17 ` [PATCH v5 3/4] KVM: x86: Add EOI exit bitmap inference Steve Rutherford
@ 2015-07-27 23:17 ` Steve Rutherford
2015-07-28 15:58 ` Paolo Bonzini
2015-07-29 10:15 ` Paolo Bonzini
2015-07-29 12:56 ` [PATCH v5 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Paolo Bonzini
3 siblings, 2 replies; 16+ messages in thread
From: Steve Rutherford @ 2015-07-27 23:17 UTC (permalink / raw)
To: kvm
In order to enable userspace PIC support, the userspace PIC needs to
be able to inject local interrupts even when the APICs are in the
kernel.
KVM_INTERRUPT now supports sending local interrupts to an APIC when
APICs are in the kernel.
The ready_for_interrupt_request flag is now only set when the CPU/APIC
will immediately accept and inject an interrupt (i.e. APIC has not
masked the PIC).
When the PIC wishes to initiate an INTA cycle with, say, CPU0, it
kicks CPU0 out of the guest, and renedezvous with CPU0 once it arrives
in userspace.
When the CPU/APIC unmasks the PIC, a KVM_EXIT_IRQ_WINDOW_OPEN is
triggered, so that userspace has a chance to inject a PIC interrupt
if it had been pending.
Overall, this design can lead to a small number of spurious userspace
renedezvous. In particular, whenever the PIC transistions from low to
high while it is masked and whenever the PIC becomes unmasked while
it is low.
Note: this does not buffer more than one local interrupt in the
kernel, so the VMM needs to enter the guest in order to complete
interrupt injection before injecting an additional interrupt.
Compiles for x86.
Can pass the KVM Unit Tests.
Signed-off-by: Steve Rutherford <srutherford@google.com>
---
Documentation/virtual/kvm/api.txt | 14 ++++++++++----
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/kvm/irq.c | 38 +++++++++++++++++++++++++++++---------
arch/x86/kvm/irq.h | 9 +++++++++
arch/x86/kvm/lapic.h | 2 ++
arch/x86/kvm/x86.c | 34 +++++++++++++++++++++++++++++++---
include/linux/kvm_host.h | 1 +
7 files changed, 83 insertions(+), 16 deletions(-)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 39e4c02..8f754d1 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -401,10 +401,9 @@ Capability: basic
Architectures: x86, ppc, mips
Type: vcpu ioctl
Parameters: struct kvm_interrupt (in)
-Returns: 0 on success, -1 on error
+Returns: 0 on success, negative on failure.
-Queues a hardware interrupt vector to be injected. This is only
-useful if in-kernel local APIC or equivalent is not used.
+Queues a hardware interrupt vector to be injected.
/* for KVM_INTERRUPT */
struct kvm_interrupt {
@@ -414,7 +413,14 @@ struct kvm_interrupt {
X86:
-Note 'irq' is an interrupt vector, not an interrupt pin or line.
+Returns: 0 on success,
+ -EEXIST if an interrupt is already enqueued
+ -EINVAL the the irq number is invalid
+ -ENXIO if the PIC is in the kernel
+ -EFAULT if the pointer is invalid
+
+Note 'irq' is an interrupt vector, not an interrupt pin or line. This
+ioctl is useful if the in-kernel PIC is not used.
PPC:
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index ebe7f07..b6508a3 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -563,6 +563,7 @@ struct kvm_vcpu_arch {
u64 eoi_exit_bitmaps[4];
int pending_ioapic_eoi;
+ int pending_external_vector;
};
struct kvm_lpage_info {
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index a1ec6a50..5fa0e6f 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -38,14 +38,27 @@ 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.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))
- return pic_irqchip(v->kvm)->output; /* PIC */
- else
+ u8 accept = kvm_apic_accept_pic_intr(v);
+
+ if (accept) {
+ if (irqchip_split(v->kvm))
+ return pending_userspace_extint(v);
+ else
+ return pic_irqchip(v->kvm)->output;
+ } else
return 0;
}
@@ -57,7 +70,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 (!pic_in_kernel(v->kvm))
return v->arch.interrupt.pending;
if (kvm_cpu_has_extint(v))
@@ -75,7 +88,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 (!pic_in_kernel(v->kvm))
return v->arch.interrupt.pending;
if (kvm_cpu_has_extint(v))
@@ -91,9 +104,16 @@ EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
*/
static int kvm_cpu_get_extint(struct kvm_vcpu *v)
{
- if (kvm_cpu_has_extint(v))
- return kvm_pic_read_irq(v->kvm); /* PIC */
- return -1;
+ if (kvm_cpu_has_extint(v)) {
+ if (irqchip_split(v->kvm)) {
+ int vector = v->arch.pending_external_vector;
+
+ v->arch.pending_external_vector = -1;
+ return vector;
+ } else
+ return kvm_pic_read_irq(v->kvm); /* PIC */
+ } else
+ return -1;
}
/*
@@ -103,7 +123,7 @@ 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;
vector = kvm_cpu_get_extint(v);
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index 2f13dd5..96a86a5 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -83,6 +83,15 @@ static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
return kvm->arch.vpic;
}
+static inline int pic_in_kernel(struct kvm *kvm)
+{
+ int ret;
+
+ ret = (pic_irqchip(kvm) != NULL);
+ smp_rmb();
+ return ret;
+}
+
static inline int irqchip_split(struct kvm *kvm)
{
return kvm->arch.irqchip_split;
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 7640379..6926430 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -64,6 +64,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 eef562f..80cb387 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)
@@ -2675,7 +2677,14 @@ 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 (irqchip_in_kernel(vcpu->kvm) && !pic_in_kernel(vcpu->kvm) &&
+ vcpu->arch.pending_external_vector == -1) {
+ vcpu->arch.pending_external_vector = irq->irq;
+ return 0;
+ } else if (irqchip_in_kernel(vcpu->kvm) && !pic_in_kernel(vcpu->kvm))
+ return -EEXIST;
+ else if (irqchip_in_kernel(vcpu->kvm))
return -ENXIO;
kvm_queue_interrupt(vcpu, irq->irq, false);
@@ -5819,13 +5828,24 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
kvm_run->flags = is_smm(vcpu) ? KVM_RUN_X86_SMM : 0;
kvm_run->cr8 = kvm_get_cr8(vcpu);
kvm_run->apic_base = kvm_get_apic_base(vcpu);
- if (irqchip_in_kernel(vcpu->kvm))
+ if (irqchip_in_kernel(vcpu->kvm) && pic_in_kernel(vcpu->kvm))
kvm_run->ready_for_interrupt_injection = 1;
- else
+ else if (irqchip_in_kernel(vcpu->kvm)) {
+ int ready_for_interrupt_injection =
+ kvm_apic_accept_pic_intr(vcpu);
+
+ if (!kvm_run->ready_for_interrupt_injection &&
+ ready_for_interrupt_injection)
+ kvm_make_request(KVM_REQ_PIC_UNMASK_EXIT, vcpu);
+
+ kvm_run->ready_for_interrupt_injection =
+ ready_for_interrupt_injection;
+ } else {
kvm_run->ready_for_interrupt_injection =
kvm_arch_interrupt_allowed(vcpu) &&
!kvm_cpu_has_interrupt(vcpu) &&
!kvm_event_needs_reinjection(vcpu);
+ }
}
static void update_cr8_intercept(struct kvm_vcpu *vcpu)
@@ -6308,6 +6328,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
r = 0;
goto out;
}
+ if (kvm_check_request(KVM_REQ_PIC_UNMASK_EXIT, vcpu)) {
+ vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
+ r = 0;
+ goto out;
+ }
+
}
if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
@@ -7401,6 +7427,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_mce_banks:
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 064067e..919a1be 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -141,6 +141,7 @@ static inline bool is_error_page(struct page *page)
#define KVM_REQ_SMI 26
#define KVM_REQ_HV_CRASH 27
#define KVM_REQ_IOAPIC_EOI_EXIT 28
+#define KVM_REQ_PIC_UNMASK_EXIT 29
#define KVM_USERSPACE_IRQ_SOURCE_ID 0
#define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1
--
2.5.0.rc2.392.g76e840b
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace
2015-07-27 23:17 ` [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace Steve Rutherford
@ 2015-07-28 15:58 ` Paolo Bonzini
2015-07-28 19:06 ` Steve Rutherford
2015-07-29 10:15 ` Paolo Bonzini
1 sibling, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2015-07-28 15:58 UTC (permalink / raw)
To: Steve Rutherford, kvm
On 28/07/2015 01:17, Steve Rutherford wrote:
> return kvm->arch.vpic;
> }
>
> +static inline int pic_in_kernel(struct kvm *kvm)
> +{
> + int ret;
> +
> + ret = (pic_irqchip(kvm) != NULL);
> + smp_rmb();
What does this memory barrier pair with? I don't think it's necessary.
> + return ret;
> +}
> +
> static inline int irqchip_split(struct kvm *kvm)
> {
> return kvm->arch.irqchip_split;
> @@ -5819,13 +5828,24 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
> kvm_run->flags = is_smm(vcpu) ? KVM_RUN_X86_SMM : 0;
> kvm_run->cr8 = kvm_get_cr8(vcpu);
> kvm_run->apic_base = kvm_get_apic_base(vcpu);
> - if (irqchip_in_kernel(vcpu->kvm))
> + if (irqchip_in_kernel(vcpu->kvm) && pic_in_kernel(vcpu->kvm))
> kvm_run->ready_for_interrupt_injection = 1;
> - else
> + else if (irqchip_in_kernel(vcpu->kvm)) {
> + int ready_for_interrupt_injection =
> + kvm_apic_accept_pic_intr(vcpu);
> +
> + if (!kvm_run->ready_for_interrupt_injection &&
> + ready_for_interrupt_injection)
> + kvm_make_request(KVM_REQ_PIC_UNMASK_EXIT, vcpu);
> +
> + kvm_run->ready_for_interrupt_injection =
> + ready_for_interrupt_injection;
> + } else {
> kvm_run->ready_for_interrupt_injection =
> kvm_arch_interrupt_allowed(vcpu) &&
> !kvm_cpu_has_interrupt(vcpu) &&
> !kvm_event_needs_reinjection(vcpu);
> + }
> }
>
> static void update_cr8_intercept(struct kvm_vcpu *vcpu)
Why is this necessary? Could it just set
kvm_run->ready_for_interrupt_injection as in the pic_in_kernel case?
Paolo
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace
2015-07-28 15:58 ` Paolo Bonzini
@ 2015-07-28 19:06 ` Steve Rutherford
2015-07-28 22:05 ` Paolo Bonzini
2015-07-29 10:21 ` Paolo Bonzini
0 siblings, 2 replies; 16+ messages in thread
From: Steve Rutherford @ 2015-07-28 19:06 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: kvm
On Tue, Jul 28, 2015 at 05:58:38PM +0200, Paolo Bonzini wrote:
>
>
> On 28/07/2015 01:17, Steve Rutherford wrote:
> > return kvm->arch.vpic;
> > }
> >
> > +static inline int pic_in_kernel(struct kvm *kvm)
> > +{
> > + int ret;
> > +
> > + ret = (pic_irqchip(kvm) != NULL);
> > + smp_rmb();
>
> What does this memory barrier pair with? I don't think it's necessary.
To be honest, it's probably not necessary. I couldn't find why
irqchip_in_kernel (which this function is more or less a copy of)
needed it's memory barrier, so I cargo culted this one in.
>
> > + return ret;
> > +}
> > +
> > static inline int irqchip_split(struct kvm *kvm)
> > {
> > return kvm->arch.irqchip_split;
>
>
> > @@ -5819,13 +5828,24 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
> > kvm_run->flags = is_smm(vcpu) ? KVM_RUN_X86_SMM : 0;
> > kvm_run->cr8 = kvm_get_cr8(vcpu);
> > kvm_run->apic_base = kvm_get_apic_base(vcpu);
> > - if (irqchip_in_kernel(vcpu->kvm))
> > + if (irqchip_in_kernel(vcpu->kvm) && pic_in_kernel(vcpu->kvm))
> > kvm_run->ready_for_interrupt_injection = 1;
> > - else
> > + else if (irqchip_in_kernel(vcpu->kvm)) {
> > + int ready_for_interrupt_injection =
> > + kvm_apic_accept_pic_intr(vcpu);
> > +
> > + if (!kvm_run->ready_for_interrupt_injection &&
> > + ready_for_interrupt_injection)
> > + kvm_make_request(KVM_REQ_PIC_UNMASK_EXIT, vcpu);
> > +
> > + kvm_run->ready_for_interrupt_injection =
> > + ready_for_interrupt_injection;
> > + } else {
> > kvm_run->ready_for_interrupt_injection =
> > kvm_arch_interrupt_allowed(vcpu) &&
> > !kvm_cpu_has_interrupt(vcpu) &&
> > !kvm_event_needs_reinjection(vcpu);
> > + }
> > }
> >
> > static void update_cr8_intercept(struct kvm_vcpu *vcpu)
>
> Why is this necessary? Could it just set
> kvm_run->ready_for_interrupt_injection as in the pic_in_kernel case?
The goal is to couple the interrupt ack cycle as closely as possible
with the injection of the local interrupt (which occur more or less
atomically on real hardware). The idea is to only ever attempt to
inject local interrupts when the CPU/APIC is ready to immediately
accept.
If the CPU is ignoring the PIC, the interrupt acknowledge cycle should
not be performed, even if the PIC is high. This patch uses the
ready_for_interrupt_injection flag to let userspace whether or not the
cpu is paying attention to the PIC at the moment.
When the PIC is high and the CPU transitions from ignoring the PIC to
paying attention to the PIC, it should (per real hardware)
immediately trigger an interrupt acknowledge cycle (which requires
bouncing up to userspace).
Steve
>
> Paolo
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace
2015-07-28 19:06 ` Steve Rutherford
@ 2015-07-28 22:05 ` Paolo Bonzini
2015-07-29 0:50 ` Steve Rutherford
2015-07-29 10:21 ` Paolo Bonzini
1 sibling, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2015-07-28 22:05 UTC (permalink / raw)
To: Steve Rutherford, KVM list
On 28/07/2015 21:06, Steve Rutherford wrote:
>>> > > + if (!kvm_run->ready_for_interrupt_injection &&
>>> > > + ready_for_interrupt_injection)
>>> > > + kvm_make_request(KVM_REQ_PIC_UNMASK_EXIT, vcpu);
>>> > > +
>>> > > + kvm_run->ready_for_interrupt_injection =
>>> > > + ready_for_interrupt_injection;
>>> > > + } else {
>>> > > kvm_run->ready_for_interrupt_injection =
>>> > > kvm_arch_interrupt_allowed(vcpu) &&
>>> > > !kvm_cpu_has_interrupt(vcpu) &&
>>> > > !kvm_event_needs_reinjection(vcpu);
>>> > > + }
>>> > > }
>>> > >
>>> > > static void update_cr8_intercept(struct kvm_vcpu *vcpu)
>> >
>> > Why is this necessary? Could it just set
>> > kvm_run->ready_for_interrupt_injection as in the pic_in_kernel case?
> The goal is to couple the interrupt ack cycle as closely as possible
> with the injection of the local interrupt (which occur more or less
> atomically on real hardware). The idea is to only ever attempt to
> inject local interrupts when the CPU/APIC is ready to immediately
> accept.
Ok, I understand it now. However, you're still not causing an exit
when LVT0 changes, are you? post_kvm_run_save is not run until the
next exit to userspace, which could be a long time later.
So, I think that you do not need KVM_REQ_PIC_UNMASK_EXIT. Instead,
you can modify dm_request_for_irq_injection to handle the split-irqchip
case, like this:
if (!vcpu->run->request_interrupt_window || pic_in_kernel(vcpu->kvm))
return false;
if (kvm_cpu_has_interrupt(vcpu))
return false;
return (irqchip_split(vcpu->kvm)
? kvm_apic_accept_pic_intr(vcpu)
: kvm_arch_interrupt_allowed(vcpu));
This will cause KVM_RUN to return -EINTR, which QEMU happens to handle
the same way as KVM_EXIT_IRQ_WINDOW_OPEN. If you prefer the explicit
reason, this small change will provide it:
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 5ef2560075bf..3269169233fb 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6720,8 +6720,8 @@ static int vcpu_run(struct kvm_vcpu *vcpu)
kvm_inject_pending_timer_irqs(vcpu);
if (dm_request_for_irq_injection(vcpu)) {
- r = -EINTR;
- vcpu->run->exit_reason = KVM_EXIT_INTR;
+ r = 0;
+ vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
++vcpu->stat.request_irq_exits;
break;
}
Feel free to post v6 of this patch only. Everything else is mostly
okay; there are some leftovers here and there (lapic_in_kernel,
GET_VECTOR_FROM_USERSPACE) but I can fix that.
How is the integration with QEMU going? With this latest iteration
it should be relatively easy.
Paolo
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace
2015-07-28 22:05 ` Paolo Bonzini
@ 2015-07-29 0:50 ` Steve Rutherford
0 siblings, 0 replies; 16+ messages in thread
From: Steve Rutherford @ 2015-07-29 0:50 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: KVM list
On Wed, Jul 29, 2015 at 12:05:37AM +0200, Paolo Bonzini wrote:
> Ok, I understand it now. However, you're still not causing an exit
> when LVT0 changes, are you? post_kvm_run_save is not run until the
> next exit to userspace, which could be a long time later.
Yes! This is definitely right. This may wait as long as an entire entry/exit
before actually exiting to userspace. Moving into dm_request_for_irq_injection
is definitely the way to go.
>
> So, I think that you do not need KVM_REQ_PIC_UNMASK_EXIT. Instead,
> you can modify dm_request_for_irq_injection to handle the split-irqchip
> case, like this:
>
> if (!vcpu->run->request_interrupt_window || pic_in_kernel(vcpu->kvm))
> return false;
>
> if (kvm_cpu_has_interrupt(vcpu))
> return false;
>
> return (irqchip_split(vcpu->kvm)
> ? kvm_apic_accept_pic_intr(vcpu)
> : kvm_arch_interrupt_allowed(vcpu));
>
> This will cause KVM_RUN to return -EINTR, which QEMU happens to handle
> the same way as KVM_EXIT_IRQ_WINDOW_OPEN.
I definitely prefer the explit exit reason.
It's also a bit easier to make work with our VMM ;)
> Feel free to post v6 of this patch only. Everything else is mostly
> okay; there are some leftovers here and there (lapic_in_kernel,
> GET_VECTOR_FROM_USERSPACE) but I can fix that.
I'll give it another once over to remove the dead code. Sorry about
leaving that junk in.
> How is the integration with QEMU going? With this latest iteration
> it should be relatively easy.
A new team member is sinking his teeth into it, as an starter project.
He'll likely have a prototype of it working soon.
Steve
>
> Paolo
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace
2015-07-28 19:06 ` Steve Rutherford
2015-07-28 22:05 ` Paolo Bonzini
@ 2015-07-29 10:21 ` Paolo Bonzini
1 sibling, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2015-07-29 10:21 UTC (permalink / raw)
To: Steve Rutherford; +Cc: kvm
On 28/07/2015 21:06, Steve Rutherford wrote:
>>> > > +static inline int pic_in_kernel(struct kvm *kvm)
>>> > > +{
>>> > > + int ret;
>>> > > +
>>> > > + ret = (pic_irqchip(kvm) != NULL);
>>> > > + smp_rmb();
>> >
>> > What does this memory barrier pair with? I don't think it's necessary.
> To be honest, it's probably not necessary. I couldn't find why
> irqchip_in_kernel (which this function is more or less a copy of)
> needed it's memory barrier, so I cargo culted this one in.
It's for stuff like injecting an interrupt before any CPU is created,
while another thread is doing KVM_CREATE_IRQCHIP. In your case a VCPU
has been created so you don't need it (the synchronization point is the
mutex_lock(&kvm->lock) in kvm_vm_ioctl_create_vcpu).
Paolo
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace
2015-07-27 23:17 ` [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace Steve Rutherford
2015-07-28 15:58 ` Paolo Bonzini
@ 2015-07-29 10:15 ` Paolo Bonzini
1 sibling, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2015-07-29 10:15 UTC (permalink / raw)
To: Steve Rutherford, kvm
On 28/07/2015 01:17, Steve Rutherford wrote:
> +
> + if (irqchip_in_kernel(vcpu->kvm) && !pic_in_kernel(vcpu->kvm) &&
> + vcpu->arch.pending_external_vector == -1) {
> + vcpu->arch.pending_external_vector = irq->irq;
> + return 0;
> + } else if (irqchip_in_kernel(vcpu->kvm) && !pic_in_kernel(vcpu->kvm))
> + return -EEXIST;
> + else if (irqchip_in_kernel(vcpu->kvm))
> return -ENXIO;
This is better written as:
if (!irqchip_in_kernel(vcpu->kvm)) {
kvm_queue_interrupt(vcpu, irq->irq, false);
kvm_make_request(KVM_REQ_EVENT, vcpu);
return 0;
}
/*
* With in-kernel LAPIC, we only use this to inject EXTINT, so
* fail for in-kernel 8259.
*/
if (pic_in_kernel(vcpu->kvm)) {
return -ENXIO;
if (vcpu->arch.pending_external_vector != -1)
return -EEXIST;
vcpu->arch.pending_external_vector = irq->irq;
return 0;
Paolo
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v5 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP.
2015-07-27 23:17 [PATCH v5 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Steve Rutherford
` (2 preceding siblings ...)
2015-07-27 23:17 ` [PATCH v5 4/4] KVM: x86: Add support for local interrupt requests from userspace Steve Rutherford
@ 2015-07-29 12:56 ` Paolo Bonzini
2015-07-30 3:04 ` Steve Rutherford
3 siblings, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2015-07-29 12:56 UTC (permalink / raw)
To: Steve Rutherford, kvm
On 28/07/2015 01:17, 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.
>
> 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 | 1 -
> arch/s390/kvm/irq.h | 1 -
> arch/x86/include/asm/kvm_host.h | 2 ++
> arch/x86/kvm/i8254.c | 5 ++++-
> arch/x86/kvm/ioapic.h | 9 +++++++++
> arch/x86/kvm/irq.h | 6 ++++++
> arch/x86/kvm/irq_comm.c | 9 ++++++++-
> arch/x86/kvm/lapic.c | 9 ++++++---
> arch/x86/kvm/vmx.c | 4 ++--
> arch/x86/kvm/x86.c | 23 +++++++++++++++++++++--
> include/kvm/arm_vgic.h | 1 +
> include/linux/kvm_host.h | 1 +
> include/uapi/linux/kvm.h | 1 +
> 14 files changed, 76 insertions(+), 11 deletions(-)
>
> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
> index a4ebcb7..b655024 100644
> --- a/Documentation/virtual/kvm/api.txt
> +++ b/Documentation/virtual/kvm/api.txt
> @@ -3620,6 +3620,21 @@ struct {
>
> KVM handlers should exit to userspace with rc = -EREMOTE.
>
> +7.5 KVM_SPLIT_IRQCHIP
> +
> +Architectures: x86
> +Parameters: None
> +Returns: 0 on success, -1 on error
> +
> +Create a local apic for each processor in the kernel. With this capability
> +enabled, the userspace VMM is expected to emulate the IOAPIC and PIC.
> +
> +This supersedes KVM_CREATE_IRQCHIP, creating only local APICs, but no in kernel
> +IOAPIC or PIC. This also enables in kernel routing of interrupt requests.
> +
> +Fails if VCPU has already been created, or if the irqchip is already in the
> +kernel (i.e. KVM_CREATE_IRQCHIP has already been called).
> +
>
> 8. Other capabilities.
> ----------------------
> diff --git a/arch/powerpc/kvm/irq.h b/arch/powerpc/kvm/irq.h
> index 5a9a10b..772fa8c 100644
> --- a/arch/powerpc/kvm/irq.h
> +++ b/arch/powerpc/kvm/irq.h
> @@ -16,5 +16,4 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
> smp_rmb();
> return ret;
> }
> -
> #endif
> diff --git a/arch/s390/kvm/irq.h b/arch/s390/kvm/irq.h
> index d98e415..9a21a86 100644
> --- a/arch/s390/kvm/irq.h
> +++ b/arch/s390/kvm/irq.h
> @@ -18,5 +18,4 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
> {
> return 1;
> }
> -
> #endif
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index fa32b53..18a110b 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -669,6 +669,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/i8254.c b/arch/x86/kvm/i8254.c
> index f90952f..5708850 100644
> --- a/arch/x86/kvm/i8254.c
> +++ b/arch/x86/kvm/i8254.c
> @@ -35,6 +35,7 @@
> #include <linux/kvm_host.h>
> #include <linux/slab.h>
>
> +#include "ioapic.h"
> #include "irq.h"
> #include "i8254.h"
> #include "x86.h"
> @@ -333,7 +334,9 @@ static void create_pit_timer(struct kvm *kvm, u32 val, int is_period)
> struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
> s64 interval;
>
> - if (!irqchip_in_kernel(kvm) || ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)
> + if (!irqchip_in_kernel(kvm) ||
> + !ioapic_in_kernel(kvm) ||
Here the irqchip_in_kernel check is unnecessary.
> + ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)
> return;
>
> interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ);
> diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
> index ca0b0b4..d8cc54b 100644
> --- a/arch/x86/kvm/ioapic.h
> +++ b/arch/x86/kvm/ioapic.h
> @@ -98,6 +98,15 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
> return kvm->arch.vioapic;
> }
>
> +static inline int ioapic_in_kernel(struct kvm *kvm)
> +{
> + int ret;
> +
> + ret = (ioapic_irqchip(kvm) != NULL);
> + smp_rmb();
> + return ret;
> +}
> +
> static inline bool kvm_ioapic_handles_vector(struct kvm *kvm, int vector)
> {
> struct kvm_ioapic *ioapic = kvm->arch.vioapic;
> diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
> index ad68c73..2f13dd5 100644
> --- a/arch/x86/kvm/irq.h
> +++ b/arch/x86/kvm/irq.h
> @@ -83,11 +83,17 @@ static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
> return kvm->arch.vpic;
> }
>
> +static inline int irqchip_split(struct kvm *kvm)
> +{
> + return kvm->arch.irqchip_split;
> +}
> +
> static inline int irqchip_in_kernel(struct kvm *kvm)
> {
> int ret;
>
> ret = (pic_irqchip(kvm) != NULL);
> + ret |= irqchip_split(kvm);
> smp_rmb();
> return ret;
> }
> diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
> index 9efff9e..67f6b62 100644
> --- a/arch/x86/kvm/irq_comm.c
> +++ b/arch/x86/kvm/irq_comm.c
> @@ -208,7 +208,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
> goto unlock;
> }
> clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap);
> - if (!irqchip_in_kernel(kvm))
> + if (!ioapic_in_kernel(kvm))
> goto unlock;
>
> kvm_ioapic_clear_all(kvm->arch.vioapic, irq_source_id);
> @@ -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 2a5ca97..536b79e 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))
Here please check ioapic_in_kernel.
> + kvm_vcpu_request_scan_ioapic(kvm);
> }
>
> static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
> @@ -1838,7 +1839,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))
Here please check ioapic_in_kernel.
> + kvm_rtc_eoi_tracking_restore_one(vcpu);
> }
>
> void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
> @@ -1921,7 +1923,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)) {
This is ugly (and if anything irqchip_split should be done before
kvm_ioapic_handles_vector). Could this just test the EOI exit bitmap
instead?
Also, who sets TMR in the split irqchip case? I'll post a patch roday
or tomorrow to compute TMR in __apic_accept_irq and to do the
aforementioned EOI exit bitmap test.
> /*
> * PV EOI was disabled by apic_sync_pv_eoi_from_guest
> * so we need not do anything here.
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index 4014a82..08203a1 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()) && irqchip_in_kernel(kvm);
> }
>
> static inline bool cpu_has_secondary_exec_ctrls(void)
> @@ -9485,7 +9485,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 28076c2..6d4b4dc 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -2461,6 +2461,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:
> @@ -3568,6 +3569,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 (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)
> + goto split_irqchip_unlock;
Need a smp_wmb() here, pairing with irqchip_in_kernel.
Paolo
> + kvm->arch.irqchip_split = true;
> + r = 0;
> +split_irqchip_unlock:
> + mutex_unlock(&kvm->lock);
> + break;
> + }
> default:
> r = -EINVAL;
> break;
> @@ -3686,7 +3704,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
> }
>
> r = -ENXIO;
> - if (!irqchip_in_kernel(kvm))
> + if (!irqchip_in_kernel(kvm) || !ioapic_in_kernel(kvm))
> goto get_irqchip_out;
> r = kvm_vm_ioctl_get_irqchip(kvm, chip);
> if (r)
> @@ -3710,7 +3728,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
> }
>
> r = -ENXIO;
> - if (!irqchip_in_kernel(kvm))
> + if (!irqchip_in_kernel(kvm) || !ioapic_in_kernel(kvm))
> goto set_irqchip_out;
> r = kvm_vm_ioctl_set_irqchip(kvm, chip);
> if (r)
> @@ -3836,6 +3854,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);
> }
> 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 51103f0..f7eab09 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -1000,6 +1000,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 9ef19eb..e4304d0 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -818,6 +818,7 @@ struct kvm_ppc_smmu_info {
> #define KVM_CAP_DISABLE_QUIRKS 116
> #define KVM_CAP_X86_SMM 117
> #define KVM_CAP_MULTI_ADDRESS_SPACE 118
> +#define KVM_CAP_SPLIT_IRQCHIP 119
>
> #ifdef KVM_CAP_IRQ_ROUTING
>
>
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v5 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP.
2015-07-29 12:56 ` [PATCH v5 1/4] KVM: x86: Split the APIC from the rest of IRQCHIP Paolo Bonzini
@ 2015-07-30 3:04 ` Steve Rutherford
0 siblings, 0 replies; 16+ messages in thread
From: Steve Rutherford @ 2015-07-30 3:04 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: kvm
On Wed, Jul 29, 2015 at 02:56:42PM +0200, Paolo Bonzini wrote:
>
> > + kvm_rtc_eoi_tracking_restore_one(vcpu);
> > }
> >
> > void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
> > @@ -1921,7 +1923,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)) {
>
> This is ugly (and if anything irqchip_split should be done before
> kvm_ioapic_handles_vector). Could this just test the EOI exit bitmap
> instead?
>
That could be done. The EOI exit bitmap write paths for split and !split
would need to be consolidated. (We can't pull them from the VMCS, so we'd
need to fetch them from the one stored in kvm_vcpu).
> Also, who sets TMR in the split irqchip case? I'll post a patch roday
> or tomorrow to compute TMR in __apic_accept_irq and to do the
> aforementioned EOI exit bitmap test.
Another option would be to compute the TMR in vcpu_scan_ioapic, by
extracting it from the EOI exit bitmaps (which would be most similar
to how it had been done previously), but I prefer computing it in
__apic_accept_irq.
^ permalink raw reply [flat|nested] 16+ messages in thread