Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/hvm/vmx/intr.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * intr.c: handling I/O, interrupts related VMX entry/exit
3
 * Copyright (c) 2004, Intel Corporation.
4
 * Copyright (c) 2004-2007, XenSource Inc.
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms and conditions of the GNU General Public License,
8
 * version 2, as published by the Free Software Foundation.
9
 *
10
 * This program is distributed in the hope it will be useful, but WITHOUT
11
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13
 * more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along with
16
 * this program; If not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
#include <xen/init.h>
20
#include <xen/mm.h>
21
#include <xen/lib.h>
22
#include <xen/errno.h>
23
#include <xen/trace.h>
24
#include <xen/event.h>
25
#include <asm/apicdef.h>
26
#include <asm/current.h>
27
#include <asm/cpufeature.h>
28
#include <asm/processor.h>
29
#include <asm/msr.h>
30
#include <asm/hvm/hvm.h>
31
#include <asm/hvm/io.h>
32
#include <asm/hvm/support.h>
33
#include <asm/hvm/vmx/vmx.h>
34
#include <asm/hvm/vmx/vmcs.h>
35
#include <asm/hvm/vpic.h>
36
#include <asm/hvm/vlapic.h>
37
#include <asm/hvm/nestedhvm.h>
38
#include <public/hvm/ioreq.h>
39
#include <asm/hvm/trace.h>
40
41
/*
42
 * A few notes on virtual NMI and INTR delivery, and interactions with
43
 * interruptibility states:
44
 * 
45
 * We can only inject an ExtInt if EFLAGS.IF = 1 and no blocking by
46
 * STI nor MOV SS. Otherwise the VM entry fails. The 'virtual interrupt
47
 * pending' control causes a VM exit when all these checks succeed. It will
48
 * exit immediately after VM entry if the checks succeed at that point.
49
 * 
50
 * We can only inject an NMI if no blocking by MOV SS (also, depending on
51
 * implementation, if no blocking by STI). If pin-based 'virtual NMIs'
52
 * control is specified then the NMI-blocking interruptibility flag is
53
 * also checked. The 'virtual NMI pending' control (available only in
54
 * conjunction with 'virtual NMIs') causes a VM exit when all these checks
55
 * succeed. It will exit immediately after VM entry if the checks succeed
56
 * at that point.
57
 * 
58
 * Because a processor may or may not check blocking-by-STI when injecting
59
 * a virtual NMI, it will be necessary to convert that to block-by-MOV-SS
60
 * before specifying the 'virtual NMI pending' control. Otherwise we could
61
 * enter an infinite loop where we check blocking-by-STI in software and
62
 * thus delay delivery of a virtual NMI, but the processor causes immediate
63
 * VM exit because it does not check blocking-by-STI.
64
 * 
65
 * Injecting a virtual NMI sets the NMI-blocking interruptibility flag only
66
 * if the 'virtual NMIs' control is set. Injecting *any* kind of event clears
67
 * the STI- and MOV-SS-blocking interruptibility-state flags.
68
 */
69
70
static void vmx_enable_intr_window(struct vcpu *v, struct hvm_intack intack)
71
2.02M
{
72
2.02M
    u32 ctl = CPU_BASED_VIRTUAL_INTR_PENDING;
73
2.02M
74
2.02M
    ASSERT(intack.source != hvm_intsrc_none);
75
2.02M
76
2.02M
    if ( unlikely(tb_init_done) )
77
0
    {
78
0
        unsigned long intr;
79
0
80
0
        __vmread(VM_ENTRY_INTR_INFO, &intr);
81
0
        HVMTRACE_3D(INTR_WINDOW, intack.vector, intack.source,
82
0
                    (intr & INTR_INFO_VALID_MASK) ? intr & 0xff : -1);
83
0
    }
84
2.02M
85
2.02M
    if ( (intack.source == hvm_intsrc_nmi) && cpu_has_vmx_vnmi )
86
0
    {
87
0
        /*
88
0
         * We set MOV-SS blocking in lieu of STI blocking when delivering an
89
0
         * NMI. This is because it is processor-specific whether STI-blocking
90
0
         * blocks NMIs. Hence we *must* check for STI-blocking on NMI delivery
91
0
         * (otherwise vmentry will fail on processors that check for STI-
92
0
         * blocking) but if the processor does not check for STI-blocking then
93
0
         * we may immediately vmexit and hance make no progress!
94
0
         * (see SDM 3B 21.3, "Other Causes of VM Exits").
95
0
         */
96
0
        unsigned long intr_shadow;
97
0
98
0
        __vmread(GUEST_INTERRUPTIBILITY_INFO, &intr_shadow);
99
0
        if ( intr_shadow & VMX_INTR_SHADOW_STI )
100
0
        {
101
0
            /* Having both STI-blocking and MOV-SS-blocking fails vmentry. */
102
0
            intr_shadow &= ~VMX_INTR_SHADOW_STI;
103
0
            intr_shadow |= VMX_INTR_SHADOW_MOV_SS;
104
0
            __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow);
105
0
        }
106
0
        ctl = CPU_BASED_VIRTUAL_NMI_PENDING;
107
0
    }
108
2.02M
109
2.02M
    if ( !(v->arch.hvm_vmx.exec_control & ctl) )
110
99.1k
    {
111
99.1k
        v->arch.hvm_vmx.exec_control |= ctl;
112
99.1k
        vmx_update_cpu_exec_control(v);
113
99.1k
    }
114
2.02M
}
115
116
/*
117
 * Injecting interrupts for nested virtualization
118
 *
119
 *  When injecting virtual interrupts (originated from L0), there are
120
 *  two major possibilities, within L1 context and within L2 context
121
 *   1. L1 context (in_nesting == 0)
122
 *     Everything is the same as without nested, check RFLAGS.IF to
123
 *     see if the injection can be done, using VMCS to inject the
124
 *     interrupt
125
 *
126
 *   2. L2 context (in_nesting == 1)
127
 *     Causes a virtual VMExit, RFLAGS.IF is ignored, whether to ack
128
 *     irq according to intr_ack_on_exit, shouldn't block normally,
129
 *     except for:
130
 *    a. context transition
131
 *     interrupt needs to be blocked at virtual VMEntry time
132
 *    b. L2 idtv reinjection
133
 *     if L2 idtv is handled within L0 (e.g. L0 shadow page fault),
134
 *     it needs to be reinjected without exiting to L1, interrupt
135
 *     injection should be blocked as well at this point.
136
 *
137
 *  Unfortunately, interrupt blocking in L2 won't work with simple
138
 *  intr_window_open (which depends on L2's IF). To solve this,
139
 *  the following algorithm can be used:
140
 *   v->arch.hvm_vmx.exec_control.VIRTUAL_INTR_PENDING now denotes
141
 *   only L0 control, physical control may be different from it.
142
 *       - if in L1, it behaves normally, intr window is written
143
 *         to physical control as it is
144
 *       - if in L2, replace it to MTF (or NMI window) if possible
145
 *       - if MTF/NMI window is not used, intr window can still be
146
 *         used but may have negative impact on interrupt performance.
147
 */
148
149
enum hvm_intblk nvmx_intr_blocked(struct vcpu *v)
150
2.05M
{
151
2.05M
    int r = hvm_intblk_none;
152
2.05M
    struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
153
2.05M
154
2.05M
    if ( nestedhvm_vcpu_in_guestmode(v) )
155
0
    {
156
0
        if ( nvcpu->nv_vmexit_pending ||
157
0
             nvcpu->nv_vmswitch_in_progress )
158
0
            r = hvm_intblk_rflags_ie;
159
0
        else
160
0
        {
161
0
            unsigned long intr_info;
162
0
163
0
            __vmread(VM_ENTRY_INTR_INFO, &intr_info);
164
0
            if ( intr_info & INTR_INFO_VALID_MASK )
165
0
                r = hvm_intblk_rflags_ie;
166
0
        }
167
0
    }
168
2.05M
    else if ( nvcpu->nv_vmentry_pending )
169
0
        r = hvm_intblk_rflags_ie;
170
2.05M
171
2.05M
    return r;
172
2.05M
}
173
174
static int nvmx_intr_intercept(struct vcpu *v, struct hvm_intack intack)
175
2.07M
{
176
2.07M
    u32 ctrl;
177
2.07M
178
2.07M
    /* If blocked by L1's tpr, then nothing to do. */
179
2.07M
    if ( nestedhvm_vcpu_in_guestmode(v) &&
180
0
         hvm_interrupt_blocked(v, intack) == hvm_intblk_tpr )
181
0
        return 1;
182
2.07M
183
2.07M
    if ( nvmx_intr_blocked(v) != hvm_intblk_none )
184
0
    {
185
0
        vmx_enable_intr_window(v, intack);
186
0
        return 1;
187
0
    }
188
2.07M
189
2.07M
    if ( nestedhvm_vcpu_in_guestmode(v) )
190
0
    {
191
0
        ctrl = get_vvmcs(v, PIN_BASED_VM_EXEC_CONTROL);
192
0
        if ( !(ctrl & PIN_BASED_EXT_INTR_MASK) )
193
0
            return 0;
194
0
195
0
        if ( intack.source == hvm_intsrc_pic ||
196
0
                 intack.source == hvm_intsrc_lapic )
197
0
        {
198
0
            vmx_inject_extint(intack.vector, intack.source);
199
0
200
0
            ctrl = get_vvmcs(v, VM_EXIT_CONTROLS);
201
0
            if ( ctrl & VM_EXIT_ACK_INTR_ON_EXIT )
202
0
            {
203
0
                /* for now, duplicate the ack path in vmx_intr_assist */
204
0
                hvm_vcpu_ack_pending_irq(v, intack);
205
0
                pt_intr_post(v, intack);
206
0
207
0
                intack = hvm_vcpu_has_pending_irq(v);
208
0
                if ( unlikely(intack.source != hvm_intsrc_none) )
209
0
                    vmx_enable_intr_window(v, intack);
210
0
            }
211
0
            else
212
0
                vmx_enable_intr_window(v, intack);
213
0
214
0
            return 1;
215
0
        }
216
0
        else if ( intack.source == hvm_intsrc_vector )
217
0
        {
218
0
            vmx_inject_extint(intack.vector, intack.source);
219
0
            return 1;
220
0
        }
221
0
    }
222
2.07M
223
2.07M
    return 0;
224
2.07M
}
225
226
void vmx_intr_assist(void)
227
9.85M
{
228
9.85M
    struct hvm_intack intack;
229
9.85M
    struct vcpu *v = current;
230
9.85M
    unsigned int tpr_threshold = 0;
231
9.85M
    enum hvm_intblk intblk;
232
9.85M
    int pt_vector = -1;
233
9.85M
234
9.85M
    /* Block event injection when single step with MTF. */
235
9.85M
    if ( unlikely(v->arch.hvm_vcpu.single_step) )
236
0
    {
237
0
        v->arch.hvm_vmx.exec_control |= CPU_BASED_MONITOR_TRAP_FLAG;
238
0
        vmx_update_cpu_exec_control(v);
239
0
        return;
240
0
    }
241
9.85M
242
9.85M
    /* Crank the handle on interrupt state. */
243
9.85M
    if ( is_hvm_vcpu(v) )
244
9.83M
        pt_vector = pt_update_irq(v);
245
9.85M
246
9.85M
    do {
247
9.85M
        unsigned long intr_info;
248
9.85M
249
9.85M
        intack = hvm_vcpu_has_pending_irq(v);
250
9.85M
        if ( likely(intack.source == hvm_intsrc_none) )
251
8.04M
            goto out;
252
9.85M
253
1.80M
        if ( unlikely(nvmx_intr_intercept(v, intack)) )
254
0
            goto out;
255
1.80M
256
1.80M
        intblk = hvm_interrupt_blocked(v, intack);
257
1.80M
        if ( cpu_has_vmx_virtual_intr_delivery )
258
2.05M
        {
259
2.05M
            /* Set "Interrupt-window exiting" for ExtINT and NMI. */
260
2.05M
            if ( (intblk != hvm_intblk_none) &&
261
1.91M
                 (intack.source == hvm_intsrc_pic ||
262
1.92M
                  intack.source == hvm_intsrc_vector ||
263
134
                  intack.source == hvm_intsrc_nmi) )
264
1.92M
            {
265
1.92M
                vmx_enable_intr_window(v, intack);
266
1.92M
                goto out;
267
1.92M
            }
268
2.05M
269
130k
            __vmread(VM_ENTRY_INTR_INFO, &intr_info);
270
130k
            if ( intr_info & INTR_INFO_VALID_MASK )
271
43.0k
            {
272
43.0k
                if ( (intack.source == hvm_intsrc_pic) ||
273
43.0k
                     (intack.source == hvm_intsrc_nmi) ||
274
43.1k
                     (intack.source == hvm_intsrc_mce) )
275
0
                    vmx_enable_intr_window(v, intack);
276
43.0k
277
43.0k
                goto out;
278
43.0k
            }
279
18.4E
        } else if ( intblk == hvm_intblk_tpr )
280
0
        {
281
0
            ASSERT(vlapic_enabled(vcpu_vlapic(v)));
282
0
            ASSERT(intack.source == hvm_intsrc_lapic);
283
0
            tpr_threshold = intack.vector >> 4;
284
0
            goto out;
285
0
        }
286
18.4E
        else if ( intblk != hvm_intblk_none )
287
0
        {
288
0
            vmx_enable_intr_window(v, intack);
289
0
            goto out;
290
0
        }
291
18.4E
        else
292
18.4E
        {
293
18.4E
            __vmread(VM_ENTRY_INTR_INFO, &intr_info);
294
18.4E
            if ( intr_info & INTR_INFO_VALID_MASK )
295
0
            {
296
0
                vmx_enable_intr_window(v, intack);
297
0
                goto out;
298
0
            }
299
18.4E
        }
300
1.80M
301
18.4E
        intack = hvm_vcpu_ack_pending_irq(v, intack);
302
18.4E
    } while ( intack.source == hvm_intsrc_none );
303
9.85M
304
18.4E
    if ( intack.source == hvm_intsrc_nmi )
305
0
    {
306
0
        vmx_inject_nmi();
307
0
    }
308
18.4E
    else if ( intack.source == hvm_intsrc_mce )
309
0
    {
310
0
        hvm_inject_hw_exception(TRAP_machine_check, X86_EVENT_NO_EC);
311
0
    }
312
18.4E
    else if ( cpu_has_vmx_virtual_intr_delivery &&
313
102k
              intack.source != hvm_intsrc_pic &&
314
102k
              intack.source != hvm_intsrc_vector )
315
4.21k
    {
316
4.21k
        unsigned long status;
317
4.21k
        unsigned int i, n;
318
4.21k
319
4.21k
       /*
320
4.21k
        * intack.vector is the highest priority vector. So we set eoi_exit_bitmap
321
4.21k
        * for intack.vector - give a chance to post periodic time interrupts when
322
4.21k
        * periodic time interrupts become the highest one
323
4.21k
        */
324
4.21k
        if ( pt_vector != -1 )
325
0
        {
326
0
#ifndef NDEBUG
327
0
            /*
328
0
             * We assert that intack.vector is the highest priority vector for
329
0
             * only an interrupt from vlapic can reach this point and the
330
0
             * highest vector is chosen in hvm_vcpu_has_pending_irq().
331
0
             * But, in fact, the assertion failed sometimes. It is suspected
332
0
             * that PIR is not synced to vIRR which makes pt_vector is left in
333
0
             * PIR. In order to verify this suspicion, dump some information
334
0
             * when the assertion fails.
335
0
             */
336
0
            if ( unlikely(intack.vector < pt_vector) )
337
0
            {
338
0
                const struct vlapic *vlapic;
339
0
                const struct pi_desc *pi_desc;
340
0
                const uint32_t *word;
341
0
                unsigned int i;
342
0
343
0
                printk(XENLOG_ERR "%pv: intack: %u:%02x pt: %02x\n",
344
0
                       current, intack.source, intack.vector, pt_vector);
345
0
346
0
                vlapic = vcpu_vlapic(v);
347
0
                if ( vlapic && vlapic->regs )
348
0
                {
349
0
                    word = (const void *)&vlapic->regs->data[APIC_IRR];
350
0
                    printk(XENLOG_ERR "vIRR:");
351
0
                    for ( i = NR_VECTORS / 32; i-- ; )
352
0
                        printk(" %08x", word[i*4]);
353
0
                    printk("\n");
354
0
                }
355
0
356
0
                pi_desc = &v->arch.hvm_vmx.pi_desc;
357
0
                if ( pi_desc )
358
0
                {
359
0
                    word = (const void *)&pi_desc->pir;
360
0
                    printk(XENLOG_ERR " PIR:");
361
0
                    for ( i = NR_VECTORS / 32; i-- ; )
362
0
                        printk(" %08x", word[i]);
363
0
                    printk("\n");
364
0
                }
365
0
            }
366
0
#endif
367
0
            ASSERT(intack.vector >= pt_vector);
368
0
            vmx_set_eoi_exit_bitmap(v, intack.vector);
369
0
        }
370
4.21k
371
4.21k
        /* we need update the RVI field */
372
4.21k
        __vmread(GUEST_INTR_STATUS, &status);
373
4.21k
        status &= ~VMX_GUEST_INTR_STATUS_SUBFIELD_BITMASK;
374
4.21k
        status |= VMX_GUEST_INTR_STATUS_SUBFIELD_BITMASK &
375
4.21k
                    intack.vector;
376
4.21k
        __vmwrite(GUEST_INTR_STATUS, status);
377
4.21k
378
4.21k
        n = ARRAY_SIZE(v->arch.hvm_vmx.eoi_exit_bitmap);
379
4.21k
        while ( (i = find_first_bit(&v->arch.hvm_vmx.eoi_exitmap_changed,
380
4.21k
                                    n)) < n )
381
3
        {
382
3
            clear_bit(i, &v->arch.hvm_vmx.eoi_exitmap_changed);
383
3
            __vmwrite(EOI_EXIT_BITMAP(i), v->arch.hvm_vmx.eoi_exit_bitmap[i]);
384
3
        }
385
4.21k
386
4.21k
        pt_intr_post(v, intack);
387
4.21k
    }
388
18.4E
    else
389
18.4E
    {
390
18.4E
        HVMTRACE_2D(INJ_VIRQ, intack.vector, /*fake=*/ 0);
391
18.4E
        vmx_inject_extint(intack.vector, intack.source);
392
18.4E
        pt_intr_post(v, intack);
393
18.4E
    }
394
18.4E
395
18.4E
    /* Is there another IRQ to queue up behind this one? */
396
18.4E
    intack = hvm_vcpu_has_pending_irq(v);
397
18.4E
    if ( !cpu_has_vmx_virtual_intr_delivery ||
398
102k
         intack.source == hvm_intsrc_pic ||
399
102k
         intack.source == hvm_intsrc_vector )
400
98.0k
    {
401
98.0k
        if ( unlikely(intack.source != hvm_intsrc_none) )
402
98.2k
            vmx_enable_intr_window(v, intack);
403
98.0k
    }
404
18.4E
405
10.1M
 out:
406
10.1M
    if ( !nestedhvm_vcpu_in_guestmode(v) &&
407
10.0M
         !cpu_has_vmx_virtual_intr_delivery &&
408
0
         cpu_has_vmx_tpr_shadow )
409
0
        __vmwrite(TPR_THRESHOLD, tpr_threshold);
410
10.1M
}
411
412
/*
413
 * Local variables:
414
 * mode: C
415
 * c-file-style: "BSD"
416
 * c-basic-offset: 4
417
 * tab-width: 4
418
 * indent-tabs-mode: nil
419
 * End:
420
 */