|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] Interrupt issues with hvm_emulate_one_vm_event()
On 05/26/17 18:11, Andrew Cooper wrote:
> On 26/05/17 15:29, Jan Beulich wrote:
>>>>> On 25.05.17 at 11:40, <rcojocaru@xxxxxxxxxxxxxxx> wrote:
>>> I've noticed that, with pages marked NX and vm_event emulation, we can
>>> end up emulating an ud2, for which hvm_emulate_one() returns
>>> X86EMUL_EXCEPTION in hvm_emulate_one_vm_event().
>> Could you explain what would lead to emulation of UD2?
>>
>>> This, in turn, causes a hvm_inject_event() call in the context of
>>> hvm_do_resume(), which can, if there's already a pending event there,
>>> cause a 101 BSOD (timer-related, if I understand correctly) or loss of
>>> input (mouse frozen, keyboard unresponsive).
>>>
>>> After much trial and error, I've been able to confirm this by leaving a
>>> guest on for almost a full day with this change:
>>>
>>> case X86EMUL_EXCEPTION:
>>> - hvm_inject_event(&ctx.ctxt.event);
>>> + if ( !hvm_event_pending(current) )
>>> + hvm_inject_event(&ctx.ctxt.event);
>>>
>>> and checking that there's been no BSOD or loss of input.
>>>
>>> However, just losing the event here, while fine to prove that this is
>>> indeed the problem, is not OK. But I'm not sure what an elegant / robust
>>> way of fixing this is.
>> Much depends on what the other event is: If it's an interrupt, I'd
>> assume there to be an ordering problem (interrupts shouldn't be
>> injected when there is a pending exception, their delivery instead
>> should be attempted on the first instruction of the exception
>> handler [if interrupts remain on] or whenever interrupts get
>> re-enabled).
>
> I suspect it is an ordering issue, and something has processed and
> interrupt before the emulation occurs as part of the vm_event reply happens.
>
> The interrupt ordering spec indicates that external interrupts take
> precedent over faults raised from executing an instruction, on the basis
> that once the interrupt handler returns, the instruction will generate
> the same fault again. However, its not obvious how this is intended to
> interact with interrupt windows and vmexits. I expect we can get away
> with ensuring that external interrupts are the final thing considered
> for injection on the return-to-guest path.
>
> It might be an idea to leave an assert in vmx_inject_event() that an
> event is not already pending, but in the short term, this probably also
> wants debugging by trying to identify what sequence of actions is
> leading us to inject two events in this case (if indeed this is what is
> happening).
With some patience, I've been able to catch the problem: "(XEN)
vmx_inject_event(3, 14) but 0, 225 pending".
63 /*
64 * x86 event types. This enumeration is valid for:
65 * Intel VMX: {VM_ENTRY,VM_EXIT,IDT_VECTORING}_INTR_INFO[10:8]
66 * AMD SVM: eventinj[10:8] and exitintinfo[10:8] (types 0-4 only)
67 */
68 enum x86_event_type {
69 X86_EVENTTYPE_EXT_INTR, /* External interrupt */
70 X86_EVENTTYPE_NMI = 2, /* NMI */
71 X86_EVENTTYPE_HW_EXCEPTION, /* Hardware exception */
72 X86_EVENTTYPE_SW_INTERRUPT, /* Software interrupt (CD nn) */
73 X86_EVENTTYPE_PRI_SW_EXCEPTION, /* ICEBP (F1) */
74 X86_EVENTTYPE_SW_EXCEPTION, /* INT3 (CC), INTO (CE) */
75 };
so an X86_EVENTTYPE_EXT_INTR is pending when we're trying to inject an
X86_EVENTTYPE_HW_EXCEPTION, as a result of the code quoted above.
This is the patch that has produced the above output:
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index c8ef18a..3b88eca 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1807,6 +1807,12 @@ void vmx_inject_nmi(void)
X86_EVENT_NO_EC);
}
+static bool hvm_get_pending_event(struct vcpu *v, struct x86_event *info)
+{
+ info->cr2 = v->arch.hvm_vcpu.guest_cr[2];
+ return hvm_funcs.get_pending_event(v, info);
+}
+
/*
* Generate a virtual event in the guest.
* NOTES:
@@ -1821,6 +1827,15 @@ static void vmx_inject_event(const struct
x86_event *event)
struct vcpu *curr = current;
struct x86_event _event = *event;
+ if ( hvm_event_pending(current) )
+ {
+ struct x86_event ev;
+ hvm_get_pending_event(current, &ev);
+
+ printk("vmx_inject_event(%d, %d) but %d, %d pending\n",
+ _event.type, _event.vector, ev.type, ev.vector);
+ }
+
switch ( _event.vector | -(_event.type == X86_EVENTTYPE_SW_INTERRUPT) )
{
case TRAP_debug:
Thanks,
Razvan
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |