source: trunk/packages/xen-3.1/xen-3.1/xen/arch/x86/hvm/svm/intr.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 4.7 KB
Line 
1/*
2 * intr.c: Interrupt handling for SVM.
3 * Copyright (c) 2005, AMD Inc.
4 * Copyright (c) 2004, Intel Corporation.
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, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 *
19 */
20
21#include <xen/config.h>
22#include <xen/init.h>
23#include <xen/mm.h>
24#include <xen/lib.h>
25#include <xen/trace.h>
26#include <xen/errno.h>
27#include <asm/cpufeature.h>
28#include <asm/processor.h>
29#include <asm/msr.h>
30#include <asm/paging.h>
31#include <asm/hvm/hvm.h>
32#include <asm/hvm/io.h>
33#include <asm/hvm/support.h>
34#include <asm/hvm/svm/svm.h>
35#include <asm/hvm/svm/intr.h>
36#include <xen/event.h>
37#include <xen/kernel.h>
38#include <public/hvm/ioreq.h>
39#include <xen/domain_page.h>
40#include <asm/hvm/trace.h>
41
42/*
43 * Most of this code is copied from vmx_io.c and modified
44 * to be suitable for SVM.
45 */
46
47static inline int svm_inject_extint(struct vcpu *v, int trap)
48{
49    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
50    vintr_t intr = vmcb->vintr;
51
52    /* Update only relevant fields */   
53    intr.fields.irq = 1;
54    intr.fields.intr_masking = 1;
55    intr.fields.vector = trap;
56    intr.fields.prio = 0xF;
57    intr.fields.ign_tpr = 1;
58    vmcb->vintr = intr;
59
60    return 0;
61}
62   
63asmlinkage void svm_intr_assist(void) 
64{
65    struct vcpu *v = current;
66    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
67    int intr_type = APIC_DM_EXTINT;
68    int intr_vector = -1;
69
70    /*
71     * Previous Interrupt delivery caused this intercept?
72     * This will happen if the injection is latched by the processor (hence
73     * clearing vintr.fields.irq) but then subsequently a fault occurs (e.g.,
74     * due to lack of shadow mapping of guest IDT or guest-kernel stack).
75     *
76     * NB. Exceptions that fault during delivery are lost. This needs to be
77     * fixed but we'll usually get away with it since faults are usually
78     * idempotent. But this isn't the case for e.g. software interrupts!
79     */
80    if ( vmcb->exitintinfo.fields.v && (vmcb->exitintinfo.fields.type == 0) )
81    {
82        intr_vector = vmcb->exitintinfo.fields.vector;
83        vmcb->exitintinfo.bytes = 0;
84        HVMTRACE_1D(REINJ_VIRQ, v, intr_vector);
85        svm_inject_extint(v, intr_vector);
86        return;
87    }
88
89    /*
90     * Previous interrupt still pending? This occurs if we return from VMRUN
91     * very early in the entry-to-guest process. Usually this is because an
92     * external physical interrupt was pending when we executed VMRUN.
93     */
94    if ( vmcb->vintr.fields.irq )
95        return;
96
97    /* Crank the handle on interrupt state and check for new interrrupts. */
98    pt_update_irq(v);
99    hvm_set_callback_irq_level();
100    if ( !cpu_has_pending_irq(v) )
101        return;
102
103    /*
104     * If the guest can't take an interrupt right now, create a 'fake'
105     * virtual interrupt on to intercept as soon as the guest _can_ take
106     * interrupts.  Do not obtain the next interrupt from the vlapic/pic
107     * if unable to inject.
108     *
109     * Also do this if there is an exception pending.  This is because
110     * the delivery of the exception can arbitrarily delay the injection
111     * of the vintr (for example, if the exception is handled via an
112     * interrupt gate, hence zeroing RFLAGS.IF). In the meantime:
113     * - the vTPR could be modified upwards, so we need to wait until the
114     *   exception is delivered before we can safely decide that an
115     *   interrupt is deliverable; and
116     * - the guest might look at the APIC/PIC state, so we ought not to have
117     *   cleared the interrupt out of the IRR.
118     */
119    if ( irq_masked(vmcb->rflags) || vmcb->interrupt_shadow
120         || vmcb->eventinj.fields.v ) 
121    {
122        vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR;
123        HVMTRACE_2D(INJ_VIRQ, v, 0x0, /*fake=*/ 1);
124        svm_inject_extint(v, 0x0); /* actual vector doesn't matter */
125        return;
126    }
127
128    /* Okay, we can deliver the interrupt: grab it and update PIC state. */
129    intr_vector = cpu_get_interrupt(v, &intr_type);
130    BUG_ON(intr_vector < 0);
131
132    HVMTRACE_2D(INJ_VIRQ, v, intr_vector, /*fake=*/ 0);
133    svm_inject_extint(v, intr_vector);
134
135    pt_intr_post(v, intr_vector, intr_type);
136}
137
138/*
139 * Local variables:
140 * mode: C
141 * c-set-style: "BSD"
142 * c-basic-offset: 4
143 * tab-width: 4
144 * indent-tabs-mode: nil
145 * End:
146 */
Note: See TracBrowser for help on using the repository browser.