Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/hvm/svm/vmcb.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * vmcb.c: VMCB management
3
 * Copyright (c) 2005-2007, Advanced Micro Devices, 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, see <http://www.gnu.org/licenses/>.
17
 *
18
 */
19
20
#include <xen/init.h>
21
#include <xen/lib.h>
22
#include <xen/keyhandler.h>
23
#include <xen/mm.h>
24
#include <xen/rcupdate.h>
25
#include <xen/sched.h>
26
#include <asm/hvm/svm/vmcb.h>
27
#include <asm/msr-index.h>
28
#include <asm/p2m.h>
29
#include <asm/hvm/support.h>
30
#include <asm/hvm/svm/svm.h>
31
#include <asm/hvm/svm/svmdebug.h>
32
33
struct vmcb_struct *alloc_vmcb(void) 
34
0
{
35
0
    struct vmcb_struct *vmcb;
36
0
37
0
    vmcb = alloc_xenheap_page();
38
0
    if ( vmcb == NULL )
39
0
    {
40
0
        printk(XENLOG_WARNING "Warning: failed to allocate vmcb.\n");
41
0
        return NULL;
42
0
    }
43
0
44
0
    clear_page(vmcb);
45
0
    return vmcb;
46
0
}
47
48
void free_vmcb(struct vmcb_struct *vmcb)
49
0
{
50
0
    free_xenheap_page(vmcb);
51
0
}
52
53
/* This function can directly access fields which are covered by clean bits. */
54
static int construct_vmcb(struct vcpu *v)
55
0
{
56
0
    struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
57
0
    struct vmcb_struct *vmcb = arch_svm->vmcb;
58
0
59
0
    /* Build-time check of the size of VMCB AMD structure. */
60
0
    BUILD_BUG_ON(sizeof(*vmcb) != PAGE_SIZE);
61
0
62
0
    vmcb->_general1_intercepts = 
63
0
        GENERAL1_INTERCEPT_INTR        | GENERAL1_INTERCEPT_NMI         |
64
0
        GENERAL1_INTERCEPT_SMI         | GENERAL1_INTERCEPT_INIT        |
65
0
        GENERAL1_INTERCEPT_CPUID       | GENERAL1_INTERCEPT_INVD        |
66
0
        GENERAL1_INTERCEPT_HLT         | GENERAL1_INTERCEPT_INVLPG      | 
67
0
        GENERAL1_INTERCEPT_INVLPGA     | GENERAL1_INTERCEPT_IOIO_PROT   |
68
0
        GENERAL1_INTERCEPT_MSR_PROT    | GENERAL1_INTERCEPT_SHUTDOWN_EVT|
69
0
        GENERAL1_INTERCEPT_TASK_SWITCH;
70
0
    vmcb->_general2_intercepts = 
71
0
        GENERAL2_INTERCEPT_VMRUN       | GENERAL2_INTERCEPT_VMMCALL     |
72
0
        GENERAL2_INTERCEPT_VMLOAD      | GENERAL2_INTERCEPT_VMSAVE      |
73
0
        GENERAL2_INTERCEPT_STGI        | GENERAL2_INTERCEPT_CLGI        |
74
0
        GENERAL2_INTERCEPT_SKINIT      | GENERAL2_INTERCEPT_MWAIT       |
75
0
        GENERAL2_INTERCEPT_WBINVD      | GENERAL2_INTERCEPT_MONITOR     |
76
0
        GENERAL2_INTERCEPT_XSETBV;
77
0
78
0
    /* Intercept all debug-register writes. */
79
0
    vmcb->_dr_intercepts = ~0u;
80
0
81
0
    /* Intercept all control-register accesses except for CR2 and CR8. */
82
0
    vmcb->_cr_intercepts = ~(CR_INTERCEPT_CR2_READ |
83
0
                             CR_INTERCEPT_CR2_WRITE |
84
0
                             CR_INTERCEPT_CR8_READ |
85
0
                             CR_INTERCEPT_CR8_WRITE);
86
0
87
0
    /* I/O and MSR permission bitmaps. */
88
0
    arch_svm->msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE), 0);
89
0
    if ( arch_svm->msrpm == NULL )
90
0
        return -ENOMEM;
91
0
    memset(arch_svm->msrpm, 0xff, MSRPM_SIZE);
92
0
93
0
    svm_disable_intercept_for_msr(v, MSR_FS_BASE);
94
0
    svm_disable_intercept_for_msr(v, MSR_GS_BASE);
95
0
    svm_disable_intercept_for_msr(v, MSR_SHADOW_GS_BASE);
96
0
    svm_disable_intercept_for_msr(v, MSR_CSTAR);
97
0
    svm_disable_intercept_for_msr(v, MSR_LSTAR);
98
0
    svm_disable_intercept_for_msr(v, MSR_STAR);
99
0
    svm_disable_intercept_for_msr(v, MSR_SYSCALL_MASK);
100
0
101
0
    /* LWP_CBADDR MSR is saved and restored by FPU code. So SVM doesn't need to
102
0
     * intercept it. */
103
0
    if ( cpu_has_lwp )
104
0
        svm_disable_intercept_for_msr(v, MSR_AMD64_LWP_CBADDR);
105
0
106
0
    vmcb->_msrpm_base_pa = (u64)virt_to_maddr(arch_svm->msrpm);
107
0
    vmcb->_iopm_base_pa = __pa(v->domain->arch.hvm_domain.io_bitmap);
108
0
109
0
    /* Virtualise EFLAGS.IF and LAPIC TPR (CR8). */
110
0
    vmcb->_vintr.fields.intr_masking = 1;
111
0
  
112
0
    /* Initialise event injection to no-op. */
113
0
    vmcb->eventinj.bytes = 0;
114
0
115
0
    /* TSC. */
116
0
    vmcb->_tsc_offset = 0;
117
0
118
0
    /* Don't need to intercept RDTSC if CPU supports TSC rate scaling */
119
0
    if ( v->domain->arch.vtsc && !cpu_has_tsc_ratio )
120
0
    {
121
0
        vmcb->_general1_intercepts |= GENERAL1_INTERCEPT_RDTSC;
122
0
        vmcb->_general2_intercepts |= GENERAL2_INTERCEPT_RDTSCP;
123
0
    }
124
0
125
0
    /* Guest EFER. */
126
0
    v->arch.hvm_vcpu.guest_efer = 0;
127
0
    hvm_update_guest_efer(v);
128
0
129
0
    /* Guest segment limits. */
130
0
    vmcb->cs.limit = ~0u;
131
0
    vmcb->es.limit = ~0u;
132
0
    vmcb->ss.limit = ~0u;
133
0
    vmcb->ds.limit = ~0u;
134
0
    vmcb->fs.limit = ~0u;
135
0
    vmcb->gs.limit = ~0u;
136
0
137
0
    /* Guest segment bases. */
138
0
    vmcb->cs.base = 0;
139
0
    vmcb->es.base = 0;
140
0
    vmcb->ss.base = 0;
141
0
    vmcb->ds.base = 0;
142
0
    vmcb->fs.base = 0;
143
0
    vmcb->gs.base = 0;
144
0
145
0
    /* Guest segment AR bytes. */
146
0
    vmcb->es.attr = 0xc93; /* read/write, accessed */
147
0
    vmcb->ss.attr = 0xc93;
148
0
    vmcb->ds.attr = 0xc93;
149
0
    vmcb->fs.attr = 0xc93;
150
0
    vmcb->gs.attr = 0xc93;
151
0
    vmcb->cs.attr = 0xc9b; /* exec/read, accessed */
152
0
153
0
    /* Guest IDT. */
154
0
    vmcb->idtr.base = 0;
155
0
    vmcb->idtr.limit = 0;
156
0
157
0
    /* Guest GDT. */
158
0
    vmcb->gdtr.base = 0;
159
0
    vmcb->gdtr.limit = 0;
160
0
161
0
    /* Guest LDT. */
162
0
    vmcb->ldtr.sel = 0;
163
0
    vmcb->ldtr.base = 0;
164
0
    vmcb->ldtr.limit = 0;
165
0
    vmcb->ldtr.attr = 0;
166
0
167
0
    /* Guest TSS. */
168
0
    vmcb->tr.attr = 0x08b; /* 32-bit TSS (busy) */
169
0
    vmcb->tr.base = 0;
170
0
    vmcb->tr.limit = 0xff;
171
0
172
0
    v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_PE | X86_CR0_ET;
173
0
    hvm_update_guest_cr(v, 0);
174
0
175
0
    v->arch.hvm_vcpu.guest_cr[4] = 0;
176
0
    hvm_update_guest_cr(v, 4);
177
0
178
0
    paging_update_paging_modes(v);
179
0
180
0
    vmcb->_exception_intercepts =
181
0
        HVM_TRAP_MASK
182
0
        | (1U << TRAP_no_device);
183
0
184
0
    if ( paging_mode_hap(v->domain) )
185
0
    {
186
0
        vmcb->_np_enable = 1; /* enable nested paging */
187
0
        vmcb->_g_pat = MSR_IA32_CR_PAT_RESET; /* guest PAT */
188
0
        vmcb->_h_cr3 = pagetable_get_paddr(
189
0
            p2m_get_pagetable(p2m_get_hostp2m(v->domain)));
190
0
191
0
        /* No point in intercepting CR3 reads/writes. */
192
0
        vmcb->_cr_intercepts &=
193
0
            ~(CR_INTERCEPT_CR3_READ|CR_INTERCEPT_CR3_WRITE);
194
0
195
0
        /*
196
0
         * No point in intercepting INVLPG if we don't have shadow pagetables
197
0
         * that need to be fixed up.
198
0
         */
199
0
        vmcb->_general1_intercepts &= ~GENERAL1_INTERCEPT_INVLPG;
200
0
201
0
        /* PAT is under complete control of SVM when using nested paging. */
202
0
        svm_disable_intercept_for_msr(v, MSR_IA32_CR_PAT);
203
0
    }
204
0
    else
205
0
    {
206
0
        vmcb->_exception_intercepts |= (1U << TRAP_page_fault);
207
0
    }
208
0
209
0
    if ( cpu_has_pause_filter )
210
0
    {
211
0
        vmcb->_pause_filter_count = SVM_PAUSEFILTER_INIT;
212
0
        vmcb->_general1_intercepts |= GENERAL1_INTERCEPT_PAUSE;
213
0
    }
214
0
215
0
    vmcb->cleanbits.bytes = 0;
216
0
217
0
    return 0;
218
0
}
219
220
int svm_create_vmcb(struct vcpu *v)
221
0
{
222
0
    struct nestedvcpu *nv = &vcpu_nestedhvm(v);
223
0
    struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
224
0
    int rc;
225
0
226
0
    if ( (nv->nv_n1vmcx == NULL) &&
227
0
         (nv->nv_n1vmcx = alloc_vmcb()) == NULL )
228
0
    {
229
0
        printk("Failed to create a new VMCB\n");
230
0
        return -ENOMEM;
231
0
    }
232
0
233
0
    arch_svm->vmcb = nv->nv_n1vmcx;
234
0
    rc = construct_vmcb(v);
235
0
    if ( rc != 0 )
236
0
    {
237
0
        free_vmcb(nv->nv_n1vmcx);
238
0
        nv->nv_n1vmcx = NULL;
239
0
        arch_svm->vmcb = NULL;
240
0
        return rc;
241
0
    }
242
0
243
0
    arch_svm->vmcb_pa = nv->nv_n1vmcx_pa = virt_to_maddr(arch_svm->vmcb);
244
0
    return 0;
245
0
}
246
247
void svm_destroy_vmcb(struct vcpu *v)
248
0
{
249
0
    struct nestedvcpu *nv = &vcpu_nestedhvm(v);
250
0
    struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
251
0
252
0
    if ( nv->nv_n1vmcx != NULL )
253
0
        free_vmcb(nv->nv_n1vmcx);
254
0
255
0
    if ( arch_svm->msrpm != NULL )
256
0
    {
257
0
        free_xenheap_pages(
258
0
            arch_svm->msrpm, get_order_from_bytes(MSRPM_SIZE));
259
0
        arch_svm->msrpm = NULL;
260
0
    }
261
0
262
0
    nv->nv_n1vmcx = NULL;
263
0
    nv->nv_n1vmcx_pa = INVALID_PADDR;
264
0
    arch_svm->vmcb = NULL;
265
0
}
266
267
static void vmcb_dump(unsigned char ch)
268
0
{
269
0
    struct domain *d;
270
0
    struct vcpu *v;
271
0
    
272
0
    printk("*********** VMCB Areas **************\n");
273
0
274
0
    rcu_read_lock(&domlist_read_lock);
275
0
276
0
    for_each_domain ( d )
277
0
    {
278
0
        if ( !is_hvm_domain(d) )
279
0
            continue;
280
0
        printk("\n>>> Domain %d <<<\n", d->domain_id);
281
0
        for_each_vcpu ( d, v )
282
0
        {
283
0
            printk("\tVCPU %d\n", v->vcpu_id);
284
0
            svm_vmcb_dump("key_handler", v->arch.hvm_svm.vmcb);
285
0
        }
286
0
    }
287
0
288
0
    rcu_read_unlock(&domlist_read_lock);
289
0
290
0
    printk("**************************************\n");
291
0
}
292
293
void __init setup_vmcb_dump(void)
294
0
{
295
0
    register_keyhandler('v', vmcb_dump, "dump AMD-V VMCBs", 1);
296
0
}
297
298
static void __init __maybe_unused build_assertions(void)
299
0
{
300
0
    struct segment_register sreg;
301
0
302
0
    /* Check struct segment_register against the VMCB segment layout. */
303
0
    BUILD_BUG_ON(sizeof(sreg)       != 16);
304
0
    BUILD_BUG_ON(sizeof(sreg.sel)   != 2);
305
0
    BUILD_BUG_ON(sizeof(sreg.attr)  != 2);
306
0
    BUILD_BUG_ON(sizeof(sreg.limit) != 4);
307
0
    BUILD_BUG_ON(sizeof(sreg.base)  != 8);
308
0
    BUILD_BUG_ON(offsetof(struct segment_register, sel)   != 0);
309
0
    BUILD_BUG_ON(offsetof(struct segment_register, attr)  != 2);
310
0
    BUILD_BUG_ON(offsetof(struct segment_register, limit) != 4);
311
0
    BUILD_BUG_ON(offsetof(struct segment_register, base)  != 8);
312
0
}
313
314
/*
315
 * Local variables:
316
 * mode: C
317
 * c-file-style: "BSD"
318
 * c-basic-offset: 4
319
 * tab-width: 4
320
 * indent-tabs-mode: nil
321
 * End:
322
 */