ia64/xen-unstable

view xen/arch/x86/hvm/svm/vmcb.c @ 19107:696351cde9a4

Allow memflags to be specified to alloc_xenheap_pages().

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jan 28 16:58:41 2009 +0000 (2009-01-28)
parents f454f2cac170
children f0e2df69a8eb
line source
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, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 *
19 */
21 #include <xen/config.h>
22 #include <xen/init.h>
23 #include <xen/mm.h>
24 #include <xen/lib.h>
25 #include <xen/errno.h>
26 #include <asm/cpufeature.h>
27 #include <asm/processor.h>
28 #include <asm/msr.h>
29 #include <asm/paging.h>
30 #include <asm/hvm/hvm.h>
31 #include <asm/hvm/io.h>
32 #include <asm/hvm/support.h>
33 #include <asm/hvm/svm/svm.h>
34 #include <asm/hvm/svm/intr.h>
35 #include <asm/hvm/svm/asid.h>
36 #include <xen/event.h>
37 #include <xen/kernel.h>
38 #include <xen/domain_page.h>
39 #include <xen/keyhandler.h>
41 extern int svm_dbg_on;
43 #define IOPM_SIZE (12 * 1024)
44 #define MSRPM_SIZE (8 * 1024)
46 struct vmcb_struct *alloc_vmcb(void)
47 {
48 struct vmcb_struct *vmcb;
50 vmcb = alloc_xenheap_page();
51 if ( vmcb == NULL )
52 {
53 printk(XENLOG_WARNING "Warning: failed to allocate vmcb.\n");
54 return NULL;
55 }
57 clear_page(vmcb);
58 return vmcb;
59 }
61 void free_vmcb(struct vmcb_struct *vmcb)
62 {
63 free_xenheap_page(vmcb);
64 }
66 struct host_save_area *alloc_host_save_area(void)
67 {
68 struct host_save_area *hsa;
70 hsa = alloc_xenheap_page();
71 if ( hsa == NULL )
72 {
73 printk(XENLOG_WARNING "Warning: failed to allocate hsa.\n");
74 return NULL;
75 }
77 clear_page(hsa);
78 return hsa;
79 }
81 void svm_disable_intercept_for_msr(struct vcpu *v, u32 msr)
82 {
83 unsigned long *msr_bitmap = v->arch.hvm_svm.msrpm;
85 /*
86 * See AMD64 Programmers Manual, Vol 2, Section 15.10 (MSR-Bitmap Address).
87 */
88 if ( msr <= 0x1fff )
89 {
90 __clear_bit(msr*2, msr_bitmap + 0x000/BYTES_PER_LONG);
91 __clear_bit(msr*2+1, msr_bitmap + 0x000/BYTES_PER_LONG);
92 }
93 else if ( (msr >= 0xc0000000) && (msr <= 0xc0001fff) )
94 {
95 msr &= 0x1fff;
96 __clear_bit(msr*2, msr_bitmap + 0x800/BYTES_PER_LONG);
97 __clear_bit(msr*2+1, msr_bitmap + 0x800/BYTES_PER_LONG);
98 }
99 else if ( (msr >= 0xc001000) && (msr <= 0xc0011fff) )
100 {
101 msr &= 0x1fff;
102 __clear_bit(msr*2, msr_bitmap + 0x1000/BYTES_PER_LONG);
103 __clear_bit(msr*2+1, msr_bitmap + 0x1000/BYTES_PER_LONG);
104 }
105 }
107 static int construct_vmcb(struct vcpu *v)
108 {
109 struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
110 struct vmcb_struct *vmcb = arch_svm->vmcb;
112 /* TLB control, and ASID assigment. */
113 svm_asid_init_vcpu(v);
115 vmcb->general1_intercepts =
116 GENERAL1_INTERCEPT_INTR | GENERAL1_INTERCEPT_NMI |
117 GENERAL1_INTERCEPT_SMI | GENERAL1_INTERCEPT_INIT |
118 GENERAL1_INTERCEPT_CPUID | GENERAL1_INTERCEPT_INVD |
119 GENERAL1_INTERCEPT_HLT | GENERAL1_INTERCEPT_INVLPG |
120 GENERAL1_INTERCEPT_INVLPGA | GENERAL1_INTERCEPT_IOIO_PROT |
121 GENERAL1_INTERCEPT_MSR_PROT | GENERAL1_INTERCEPT_SHUTDOWN_EVT|
122 GENERAL1_INTERCEPT_TASK_SWITCH;
123 vmcb->general2_intercepts =
124 GENERAL2_INTERCEPT_VMRUN | GENERAL2_INTERCEPT_VMMCALL |
125 GENERAL2_INTERCEPT_VMLOAD | GENERAL2_INTERCEPT_VMSAVE |
126 GENERAL2_INTERCEPT_STGI | GENERAL2_INTERCEPT_CLGI |
127 GENERAL2_INTERCEPT_SKINIT | GENERAL2_INTERCEPT_RDTSCP |
128 GENERAL2_INTERCEPT_WBINVD | GENERAL2_INTERCEPT_MONITOR |
129 GENERAL2_INTERCEPT_MWAIT;
131 /* Intercept all debug-register writes. */
132 vmcb->dr_intercepts = ~0u;
134 /* Intercept all control-register accesses except for CR2 and CR8. */
135 vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ |
136 CR_INTERCEPT_CR2_WRITE |
137 CR_INTERCEPT_CR8_READ |
138 CR_INTERCEPT_CR8_WRITE);
140 /* I/O and MSR permission bitmaps. */
141 arch_svm->msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE), 0);
142 if ( arch_svm->msrpm == NULL )
143 return -ENOMEM;
144 memset(arch_svm->msrpm, 0xff, MSRPM_SIZE);
146 svm_disable_intercept_for_msr(v, MSR_FS_BASE);
147 svm_disable_intercept_for_msr(v, MSR_GS_BASE);
148 svm_disable_intercept_for_msr(v, MSR_SHADOW_GS_BASE);
149 svm_disable_intercept_for_msr(v, MSR_CSTAR);
150 svm_disable_intercept_for_msr(v, MSR_LSTAR);
151 svm_disable_intercept_for_msr(v, MSR_STAR);
152 svm_disable_intercept_for_msr(v, MSR_SYSCALL_MASK);
153 svm_disable_intercept_for_msr(v, MSR_IA32_SYSENTER_CS);
154 svm_disable_intercept_for_msr(v, MSR_IA32_SYSENTER_ESP);
155 svm_disable_intercept_for_msr(v, MSR_IA32_SYSENTER_EIP);
157 vmcb->msrpm_base_pa = (u64)virt_to_maddr(arch_svm->msrpm);
158 vmcb->iopm_base_pa = (u64)virt_to_maddr(hvm_io_bitmap);
160 /* Virtualise EFLAGS.IF and LAPIC TPR (CR8). */
161 vmcb->vintr.fields.intr_masking = 1;
163 /* Initialise event injection to no-op. */
164 vmcb->eventinj.bytes = 0;
166 /* TSC. */
167 vmcb->tsc_offset = 0;
168 if ( opt_softtsc )
169 vmcb->general1_intercepts |= GENERAL1_INTERCEPT_RDTSC;
171 /* Guest EFER: *must* contain SVME or VMRUN will fail. */
172 vmcb->efer = EFER_SVME;
174 /* Guest segment limits. */
175 vmcb->cs.limit = ~0u;
176 vmcb->es.limit = ~0u;
177 vmcb->ss.limit = ~0u;
178 vmcb->ds.limit = ~0u;
179 vmcb->fs.limit = ~0u;
180 vmcb->gs.limit = ~0u;
182 /* Guest segment bases. */
183 vmcb->cs.base = 0;
184 vmcb->es.base = 0;
185 vmcb->ss.base = 0;
186 vmcb->ds.base = 0;
187 vmcb->fs.base = 0;
188 vmcb->gs.base = 0;
190 /* Guest segment AR bytes. */
191 vmcb->es.attr.bytes = 0xc93; /* read/write, accessed */
192 vmcb->ss.attr.bytes = 0xc93;
193 vmcb->ds.attr.bytes = 0xc93;
194 vmcb->fs.attr.bytes = 0xc93;
195 vmcb->gs.attr.bytes = 0xc93;
196 vmcb->cs.attr.bytes = 0xc9b; /* exec/read, accessed */
198 /* Guest IDT. */
199 vmcb->idtr.base = 0;
200 vmcb->idtr.limit = 0;
202 /* Guest GDT. */
203 vmcb->gdtr.base = 0;
204 vmcb->gdtr.limit = 0;
206 /* Guest LDT. */
207 vmcb->ldtr.sel = 0;
208 vmcb->ldtr.base = 0;
209 vmcb->ldtr.limit = 0;
210 vmcb->ldtr.attr.bytes = 0;
212 /* Guest TSS. */
213 vmcb->tr.attr.bytes = 0x08b; /* 32-bit TSS (busy) */
214 vmcb->tr.base = 0;
215 vmcb->tr.limit = 0xff;
217 v->arch.hvm_vcpu.guest_cr[0] = X86_CR0_PE | X86_CR0_ET;
218 hvm_update_guest_cr(v, 0);
220 v->arch.hvm_vcpu.guest_cr[4] = 0;
221 hvm_update_guest_cr(v, 4);
223 paging_update_paging_modes(v);
225 vmcb->exception_intercepts = HVM_TRAP_MASK | (1U << TRAP_no_device);
227 if ( paging_mode_hap(v->domain) )
228 {
229 vmcb->np_enable = 1; /* enable nested paging */
230 vmcb->g_pat = 0x0007040600070406ULL; /* guest PAT */
231 vmcb->h_cr3 = pagetable_get_paddr(v->domain->arch.phys_table);
233 /*
234 * No point in intercepting CR3 reads, because the hardware will return
235 * the guest version anyway.
236 */
237 vmcb->cr_intercepts &= ~CR_INTERCEPT_CR3_READ;
239 /*
240 * No point in intercepting INVLPG if we don't have shadow pagetables
241 * that need to be fixed up.
242 */
243 vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_INVLPG;
244 }
245 else
246 {
247 vmcb->exception_intercepts |= (1U << TRAP_page_fault);
248 }
250 return 0;
251 }
253 int svm_create_vmcb(struct vcpu *v)
254 {
255 struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
256 int rc;
258 if ( (arch_svm->vmcb == NULL) &&
259 (arch_svm->vmcb = alloc_vmcb()) == NULL )
260 {
261 printk("Failed to create a new VMCB\n");
262 return -ENOMEM;
263 }
265 if ( (rc = construct_vmcb(v)) != 0 )
266 {
267 free_vmcb(arch_svm->vmcb);
268 arch_svm->vmcb = NULL;
269 return rc;
270 }
272 arch_svm->vmcb_pa = virt_to_maddr(arch_svm->vmcb);
274 return 0;
275 }
277 void svm_destroy_vmcb(struct vcpu *v)
278 {
279 struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
281 if ( arch_svm->vmcb != NULL )
282 free_vmcb(arch_svm->vmcb);
284 if ( arch_svm->msrpm != NULL )
285 {
286 free_xenheap_pages(
287 arch_svm->msrpm, get_order_from_bytes(MSRPM_SIZE));
288 arch_svm->msrpm = NULL;
289 }
291 arch_svm->vmcb = NULL;
292 }
294 static void svm_dump_sel(char *name, svm_segment_register_t *s)
295 {
296 printk("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n",
297 name, s->sel, s->attr.bytes, s->limit,
298 (unsigned long long)s->base);
299 }
301 void svm_dump_vmcb(const char *from, struct vmcb_struct *vmcb)
302 {
303 printk("Dumping guest's current state at %s...\n", from);
304 printk("Size of VMCB = %d, address = %p\n",
305 (int) sizeof(struct vmcb_struct), vmcb);
307 printk("cr_intercepts = 0x%08x dr_intercepts = 0x%08x "
308 "exception_intercepts = 0x%08x\n",
309 vmcb->cr_intercepts, vmcb->dr_intercepts,
310 vmcb->exception_intercepts);
311 printk("general1_intercepts = 0x%08x general2_intercepts = 0x%08x\n",
312 vmcb->general1_intercepts, vmcb->general2_intercepts);
313 printk("iopm_base_pa = %016llx msrpm_base_pa = 0x%016llx tsc_offset = "
314 "0x%016llx\n",
315 (unsigned long long) vmcb->iopm_base_pa,
316 (unsigned long long) vmcb->msrpm_base_pa,
317 (unsigned long long) vmcb->tsc_offset);
318 printk("tlb_control = 0x%08x vintr = 0x%016llx interrupt_shadow = "
319 "0x%016llx\n", vmcb->tlb_control,
320 (unsigned long long) vmcb->vintr.bytes,
321 (unsigned long long) vmcb->interrupt_shadow);
322 printk("exitcode = 0x%016llx exitintinfo = 0x%016llx\n",
323 (unsigned long long) vmcb->exitcode,
324 (unsigned long long) vmcb->exitintinfo.bytes);
325 printk("exitinfo1 = 0x%016llx exitinfo2 = 0x%016llx \n",
326 (unsigned long long) vmcb->exitinfo1,
327 (unsigned long long) vmcb->exitinfo2);
328 printk("np_enable = 0x%016llx guest_asid = 0x%03x\n",
329 (unsigned long long) vmcb->np_enable, vmcb->guest_asid);
330 printk("cpl = %d efer = 0x%016llx star = 0x%016llx lstar = 0x%016llx\n",
331 vmcb->cpl, (unsigned long long) vmcb->efer,
332 (unsigned long long) vmcb->star, (unsigned long long) vmcb->lstar);
333 printk("CR0 = 0x%016llx CR2 = 0x%016llx\n",
334 (unsigned long long) vmcb->cr0, (unsigned long long) vmcb->cr2);
335 printk("CR3 = 0x%016llx CR4 = 0x%016llx\n",
336 (unsigned long long) vmcb->cr3, (unsigned long long) vmcb->cr4);
337 printk("RSP = 0x%016llx RIP = 0x%016llx\n",
338 (unsigned long long) vmcb->rsp, (unsigned long long) vmcb->rip);
339 printk("RAX = 0x%016llx RFLAGS=0x%016llx\n",
340 (unsigned long long) vmcb->rax, (unsigned long long) vmcb->rflags);
341 printk("DR6 = 0x%016llx, DR7 = 0x%016llx\n",
342 (unsigned long long) vmcb->dr6, (unsigned long long) vmcb->dr7);
343 printk("CSTAR = 0x%016llx SFMask = 0x%016llx\n",
344 (unsigned long long) vmcb->cstar,
345 (unsigned long long) vmcb->sfmask);
346 printk("KernGSBase = 0x%016llx PAT = 0x%016llx \n",
347 (unsigned long long) vmcb->kerngsbase,
348 (unsigned long long) vmcb->g_pat);
349 printk("H_CR3 = 0x%016llx\n", (unsigned long long)vmcb->h_cr3);
351 /* print out all the selectors */
352 svm_dump_sel("CS", &vmcb->cs);
353 svm_dump_sel("DS", &vmcb->ds);
354 svm_dump_sel("SS", &vmcb->ss);
355 svm_dump_sel("ES", &vmcb->es);
356 svm_dump_sel("FS", &vmcb->fs);
357 svm_dump_sel("GS", &vmcb->gs);
358 svm_dump_sel("GDTR", &vmcb->gdtr);
359 svm_dump_sel("LDTR", &vmcb->ldtr);
360 svm_dump_sel("IDTR", &vmcb->idtr);
361 svm_dump_sel("TR", &vmcb->tr);
362 }
364 static void vmcb_dump(unsigned char ch)
365 {
366 struct domain *d;
367 struct vcpu *v;
369 printk("*********** VMCB Areas **************\n");
371 rcu_read_lock(&domlist_read_lock);
373 for_each_domain ( d )
374 {
375 if ( !is_hvm_domain(d) )
376 continue;
377 printk("\n>>> Domain %d <<<\n", d->domain_id);
378 for_each_vcpu ( d, v )
379 {
380 printk("\tVCPU %d\n", v->vcpu_id);
381 svm_dump_vmcb("key_handler", v->arch.hvm_svm.vmcb);
382 }
383 }
385 rcu_read_unlock(&domlist_read_lock);
387 printk("**************************************\n");
388 }
390 void setup_vmcb_dump(void)
391 {
392 register_keyhandler('v', vmcb_dump, "dump AMD-V VMCBs");
393 }
395 /*
396 * Local variables:
397 * mode: C
398 * c-set-style: "BSD"
399 * c-basic-offset: 4
400 * tab-width: 4
401 * indent-tabs-mode: nil
402 * End:
403 */