direct-io.hg

view xen/arch/x86/hvm/svm/vmcb.c @ 11135:88e6bd5e2b54

Whitespace clean-ups.

Signed-off-by: Steven Hand <steven@xensource.com>
author shand@kneesaa.uk.xensource.com
date Wed Aug 16 11:36:13 2006 +0100 (2006-08-16)
parents d20e1835c24b
children e2e7f4c17b77
line source
1 /*
2 * vmcb.c: VMCB management
3 * Copyright (c) 2005, AMD Corporation.
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 <xen/shadow.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/svm/svm.h>
34 #include <asm/hvm/svm/intr.h>
35 #include <xen/event.h>
36 #include <xen/kernel.h>
37 #include <xen/domain_page.h>
38 #include <xen/keyhandler.h>
40 extern int svm_dbg_on;
41 extern int asidpool_assign_next( struct vmcb_struct *vmcb, int retire_current,
42 int oldcore, int newcore);
44 #define GUEST_SEGMENT_LIMIT 0xffffffff
46 #define IOPM_SIZE (12 * 1024)
47 #define MSRPM_SIZE (8 * 1024)
49 /* VMCBs and HSAs are architecturally defined to be a 4K page each */
50 #define VMCB_ORDER 0
51 #define HSA_ORDER 0
54 struct vmcb_struct *alloc_vmcb(void)
55 {
56 struct vmcb_struct *vmcb = alloc_xenheap_pages(VMCB_ORDER);
58 if (!vmcb) {
59 printk("Warning: failed to allocate vmcb.\n");
60 return NULL;
61 }
63 memset(vmcb, 0, (PAGE_SIZE << VMCB_ORDER));
64 return vmcb;
65 }
68 void free_vmcb(struct vmcb_struct *vmcb)
69 {
70 ASSERT(vmcb);
71 free_xenheap_pages(vmcb, VMCB_ORDER);
72 }
75 struct host_save_area *alloc_host_save_area(void)
76 {
77 struct host_save_area *hsa = alloc_xenheap_pages(HSA_ORDER);
79 if (!hsa) {
80 printk("Warning: failed to allocate vmcb.\n");
81 return NULL;
82 }
84 memset(hsa, 0, (PAGE_SIZE << HSA_ORDER));
85 return hsa;
86 }
89 void free_host_save_area(struct host_save_area *hsa)
90 {
91 ASSERT(hsa);
92 free_xenheap_pages(hsa, HSA_ORDER);
93 }
96 /* Set up intercepts to exit the guest into the hypervisor when we want it. */
97 static int construct_vmcb_controls(struct arch_svm_struct *arch_svm)
98 {
99 struct vmcb_struct *vmcb;
100 u32 *iopm;
101 u32 *msrpm;
103 vmcb = arch_svm->vmcb;
105 ASSERT(vmcb);
107 /* mask off all general 1 intercepts except those listed here */
108 vmcb->general1_intercepts =
109 GENERAL1_INTERCEPT_INTR | GENERAL1_INTERCEPT_NMI |
110 GENERAL1_INTERCEPT_SMI | GENERAL1_INTERCEPT_INIT |
111 GENERAL1_INTERCEPT_CPUID | GENERAL1_INTERCEPT_INVD |
112 GENERAL1_INTERCEPT_HLT | GENERAL1_INTERCEPT_INVLPG |
113 GENERAL1_INTERCEPT_INVLPGA | GENERAL1_INTERCEPT_IOIO_PROT |
114 GENERAL1_INTERCEPT_MSR_PROT | GENERAL1_INTERCEPT_SHUTDOWN_EVT;
116 /* turn on the general 2 intercepts */
117 vmcb->general2_intercepts =
118 GENERAL2_INTERCEPT_VMRUN | GENERAL2_INTERCEPT_VMMCALL |
119 GENERAL2_INTERCEPT_VMLOAD | GENERAL2_INTERCEPT_VMSAVE |
120 GENERAL2_INTERCEPT_STGI | GENERAL2_INTERCEPT_CLGI |
121 GENERAL2_INTERCEPT_SKINIT | GENERAL2_INTERCEPT_RDTSCP;
123 /* read or write all debug registers 0 - 15 */
124 vmcb->dr_intercepts = 0;
126 /* RD/WR all control registers 0 - 15, but not read CR2 */
127 vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | CR_INTERCEPT_CR2_WRITE);
129 /* The following is for I/O and MSR permision map */
130 iopm = alloc_xenheap_pages(get_order_from_bytes(IOPM_SIZE));
131 if (iopm)
132 {
133 memset(iopm, 0xff, IOPM_SIZE);
134 clear_bit(PC_DEBUG_PORT, iopm);
135 }
136 msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE));
137 if (msrpm)
138 memset(msrpm, 0xff, MSRPM_SIZE);
140 arch_svm->iopm = iopm;
141 arch_svm->msrpm = msrpm;
143 if (! iopm || ! msrpm)
144 return 1;
146 vmcb->iopm_base_pa = (u64) virt_to_maddr(iopm);
147 vmcb->msrpm_base_pa = (u64) virt_to_maddr(msrpm);
149 return 0;
150 }
153 /*
154 * Initially set the same environement as host.
155 */
156 static int construct_init_vmcb_guest(struct arch_svm_struct *arch_svm,
157 struct cpu_user_regs *regs )
158 {
159 int error = 0;
160 unsigned long crn;
161 segment_attributes_t attrib;
162 unsigned long dr7;
163 unsigned long eflags;
164 unsigned long shadow_cr;
165 struct vmcb_struct *vmcb = arch_svm->vmcb;
167 /* Allows IRQs to be shares */
168 vmcb->vintr.fields.intr_masking = 1;
170 /* Set up event injection entry in VMCB. Just clear it. */
171 vmcb->eventinj.bytes = 0;
173 /* TSC */
174 vmcb->tsc_offset = 0;
176 vmcb->cs.sel = regs->cs;
177 vmcb->es.sel = regs->es;
178 vmcb->ss.sel = regs->ss;
179 vmcb->ds.sel = regs->ds;
180 vmcb->fs.sel = regs->fs;
181 vmcb->gs.sel = regs->gs;
183 /* Guest segment Limits. 64K for real mode*/
184 vmcb->cs.limit = GUEST_SEGMENT_LIMIT;
185 vmcb->es.limit = GUEST_SEGMENT_LIMIT;
186 vmcb->ss.limit = GUEST_SEGMENT_LIMIT;
187 vmcb->ds.limit = GUEST_SEGMENT_LIMIT;
188 vmcb->fs.limit = GUEST_SEGMENT_LIMIT;
189 vmcb->gs.limit = GUEST_SEGMENT_LIMIT;
191 /* Base address for segments */
192 vmcb->cs.base = 0;
193 vmcb->es.base = 0;
194 vmcb->ss.base = 0;
195 vmcb->ds.base = 0;
196 vmcb->fs.base = 0;
197 vmcb->gs.base = 0;
199 /* Guest Interrupt descriptor table */
200 vmcb->idtr.base = 0;
201 vmcb->idtr.limit = 0;
203 /* Set up segment attributes */
204 attrib.bytes = 0;
205 attrib.fields.type = 0x3; /* type = 3 */
206 attrib.fields.s = 1; /* code or data, i.e. not system */
207 attrib.fields.dpl = 0; /* DPL = 0 */
208 attrib.fields.p = 1; /* segment present */
209 attrib.fields.db = 1; /* 32-bit */
210 attrib.fields.g = 1; /* 4K pages in limit */
212 /* Data selectors */
213 vmcb->es.attributes = attrib;
214 vmcb->ss.attributes = attrib;
215 vmcb->ds.attributes = attrib;
216 vmcb->fs.attributes = attrib;
217 vmcb->gs.attributes = attrib;
219 /* Code selector */
220 attrib.fields.type = 0xb; /* type=0xb -> executable/readable, accessed */
221 vmcb->cs.attributes = attrib;
223 /* Guest Global descriptor table */
224 vmcb->gdtr.base = 0;
225 vmcb->gdtr.limit = 0;
227 /* Guest Local Descriptor Table */
228 attrib.fields.s = 0; /* not code or data segement */
229 attrib.fields.type = 0x2; /* LDT */
230 attrib.fields.db = 0; /* 16-bit */
231 attrib.fields.g = 0;
232 vmcb->ldtr.attributes = attrib;
234 attrib.fields.type = 0xb; /* 32-bit TSS (busy) */
235 vmcb->tr.attributes = attrib;
236 vmcb->tr.base = 0;
237 vmcb->tr.limit = 0xff;
239 __asm__ __volatile__ ("mov %%cr0,%0" : "=r" (crn) :);
240 vmcb->cr0 = crn;
242 /* Initally PG, PE are not set*/
243 shadow_cr = vmcb->cr0;
244 shadow_cr &= ~X86_CR0_PG;
245 arch_svm->cpu_shadow_cr0 = shadow_cr;
247 /* CR3 is set in svm_final_setup_guest */
249 __asm__ __volatile__ ("mov %%cr4,%0" : "=r" (crn) :);
250 crn &= ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE);
251 arch_svm->cpu_shadow_cr4 = crn;
252 vmcb->cr4 = crn | SVM_CR4_HOST_MASK;
254 vmcb->rsp = 0;
255 vmcb->rip = regs->eip;
257 eflags = regs->eflags & ~HVM_EFLAGS_RESERVED_0; /* clear 0s */
258 eflags |= HVM_EFLAGS_RESERVED_1; /* set 1s */
260 vmcb->rflags = eflags;
262 __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
263 vmcb->dr7 = dr7;
265 return error;
266 }
269 /*
270 * destroy the vmcb.
271 */
273 void destroy_vmcb(struct arch_svm_struct *arch_svm)
274 {
275 if(arch_svm->vmcb != NULL)
276 {
277 asidpool_retire(arch_svm->vmcb, arch_svm->asid_core);
278 free_vmcb(arch_svm->vmcb);
279 }
280 if(arch_svm->iopm != NULL) {
281 free_xenheap_pages(
282 arch_svm->iopm, get_order_from_bytes(IOPM_SIZE));
283 arch_svm->iopm = NULL;
284 }
285 if(arch_svm->msrpm != NULL) {
286 free_xenheap_pages(
287 arch_svm->msrpm, get_order_from_bytes(MSRPM_SIZE));
288 arch_svm->msrpm = NULL;
289 }
290 arch_svm->vmcb = NULL;
291 }
294 /*
295 * construct the vmcb.
296 */
298 int construct_vmcb(struct arch_svm_struct *arch_svm,
299 struct cpu_user_regs *regs)
300 {
301 int error;
302 long rc=0;
304 memset(arch_svm, 0, sizeof(struct arch_svm_struct));
306 if (!(arch_svm->vmcb = alloc_vmcb())) {
307 printk("Failed to create a new VMCB\n");
308 rc = -ENOMEM;
309 goto err_out;
310 }
312 arch_svm->vmcb_pa = (u64) virt_to_maddr(arch_svm->vmcb);
314 if ((error = construct_vmcb_controls(arch_svm)))
315 {
316 printk("construct_vmcb: construct_vmcb_controls failed\n");
317 rc = -EINVAL;
318 goto err_out;
319 }
321 /* guest selectors */
322 if ((error = construct_init_vmcb_guest(arch_svm, regs)))
323 {
324 printk("construct_vmcb: construct_vmcb_guest failed\n");
325 rc = -EINVAL;
326 goto err_out;
327 }
329 arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP;
330 if (regs->eflags & EF_TF)
331 arch_svm->vmcb->exception_intercepts |= EXCEPTION_BITMAP_DB;
332 else
333 arch_svm->vmcb->exception_intercepts &= ~EXCEPTION_BITMAP_DB;
335 return 0;
337 err_out:
338 destroy_vmcb(arch_svm);
339 return rc;
340 }
343 void svm_do_launch(struct vcpu *v)
344 {
345 struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
346 int core = smp_processor_id();
347 ASSERT(vmcb);
349 /* Update CR3, GDT, LDT, TR */
350 hvm_stts(v);
352 /* current core is the one we intend to perform the VMRUN on */
353 v->arch.hvm_svm.launch_core = v->arch.hvm_svm.asid_core = core;
354 clear_bit(ARCH_SVM_VMCB_ASSIGN_ASID, &v->arch.hvm_svm.flags);
355 if ( !asidpool_assign_next( vmcb, 0, core, core ))
356 BUG();
358 if (v->vcpu_id == 0)
359 hvm_setup_platform(v->domain);
361 if (hvm_apic_support(v->domain))
362 vlapic_init(v);
363 init_timer(&v->arch.hvm_svm.hlt_timer,
364 hlt_timer_fn, v, v->processor);
366 vmcb->ldtr.sel = 0;
367 vmcb->ldtr.base = 0;
368 vmcb->ldtr.limit = 0;
369 vmcb->ldtr.attributes.bytes = 0;
371 vmcb->efer = EFER_SVME; /* Make sure VMRUN won't return with -1 */
373 if (svm_dbg_on)
374 {
375 unsigned long pt;
376 pt = pagetable_get_paddr(v->arch.shadow_table);
377 printk("%s: shadow_table = %lx\n", __func__, pt);
378 pt = pagetable_get_paddr(v->arch.guest_table);
379 printk("%s: guest_table = %lx\n", __func__, pt);
380 pt = pagetable_get_paddr(v->domain->arch.phys_table);
381 printk("%s: phys_table = %lx\n", __func__, pt);
382 }
384 /* At launch we always use the phys_table */
385 vmcb->cr3 = pagetable_get_paddr(v->domain->arch.phys_table);
387 if (svm_dbg_on)
388 {
389 printk("%s: cr3 = %lx ", __func__, (unsigned long)vmcb->cr3);
390 printk("init_guest_table: guest_table = 0x%08x, monitor_table = 0x%08x,"
391 " shadow_table = 0x%08x\n", (int)v->arch.guest_table.pfn,
392 (int)v->arch.monitor_table.pfn, (int)v->arch.shadow_table.pfn);
393 }
395 v->arch.schedule_tail = arch_svm_do_resume;
397 v->arch.hvm_svm.saved_irq_vector = -1;
399 hvm_set_guest_time(v, 0);
401 if (svm_dbg_on)
402 svm_dump_vmcb(__func__, vmcb);
404 vmcb->tlb_control = 1;
405 }
409 static void svm_dump_sel(char *name, segment_selector_t *s)
410 {
411 printf("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n",
412 name, s->sel, s->attributes.bytes, s->limit,
413 (unsigned long long)s->base);
414 }
417 void svm_dump_vmcb(const char *from, struct vmcb_struct *vmcb)
418 {
419 printf("Dumping guest's current state at %s...\n", from);
420 printf("Size of VMCB = %d, address = %p\n",
421 (int) sizeof(struct vmcb_struct), vmcb);
423 printf("cr_intercepts = 0x%08x dr_intercepts = 0x%08x "
424 "exception_intercepts = 0x%08x\n",
425 vmcb->cr_intercepts, vmcb->dr_intercepts,
426 vmcb->exception_intercepts);
427 printf("general1_intercepts = 0x%08x general2_intercepts = 0x%08x\n",
428 vmcb->general1_intercepts, vmcb->general2_intercepts);
429 printf("iopm_base_pa = %016llx msrpm_base_pa = 0x%016llx tsc_offset = "
430 "0x%016llx\n",
431 (unsigned long long) vmcb->iopm_base_pa,
432 (unsigned long long) vmcb->msrpm_base_pa,
433 (unsigned long long) vmcb->tsc_offset);
434 printf("tlb_control = 0x%08x vintr = 0x%016llx interrupt_shadow = "
435 "0x%016llx\n", vmcb->tlb_control,
436 (unsigned long long) vmcb->vintr.bytes,
437 (unsigned long long) vmcb->interrupt_shadow);
438 printf("exitcode = 0x%016llx exitintinfo = 0x%016llx\n",
439 (unsigned long long) vmcb->exitcode,
440 (unsigned long long) vmcb->exitintinfo.bytes);
441 printf("exitinfo1 = 0x%016llx exitinfo2 = 0x%016llx \n",
442 (unsigned long long) vmcb->exitinfo1,
443 (unsigned long long) vmcb->exitinfo2);
444 printf("np_enable = 0x%016llx guest_asid = 0x%03x\n",
445 (unsigned long long) vmcb->np_enable, vmcb->guest_asid);
446 printf("cpl = %d efer = 0x%016llx star = 0x%016llx lstar = 0x%016llx\n",
447 vmcb->cpl, (unsigned long long) vmcb->efer,
448 (unsigned long long) vmcb->star, (unsigned long long) vmcb->lstar);
449 printf("CR0 = 0x%016llx CR2 = 0x%016llx\n",
450 (unsigned long long) vmcb->cr0, (unsigned long long) vmcb->cr2);
451 printf("CR3 = 0x%016llx CR4 = 0x%016llx\n",
452 (unsigned long long) vmcb->cr3, (unsigned long long) vmcb->cr4);
453 printf("RSP = 0x%016llx RIP = 0x%016llx\n",
454 (unsigned long long) vmcb->rsp, (unsigned long long) vmcb->rip);
455 printf("RAX = 0x%016llx RFLAGS=0x%016llx\n",
456 (unsigned long long) vmcb->rax, (unsigned long long) vmcb->rflags);
457 printf("DR6 = 0x%016llx, DR7 = 0x%016llx\n",
458 (unsigned long long) vmcb->dr6, (unsigned long long) vmcb->dr7);
459 printf("CSTAR = 0x%016llx SFMask = 0x%016llx\n",
460 (unsigned long long) vmcb->cstar,
461 (unsigned long long) vmcb->sfmask);
462 printf("KernGSBase = 0x%016llx PAT = 0x%016llx \n",
463 (unsigned long long) vmcb->kerngsbase,
464 (unsigned long long) vmcb->g_pat);
466 /* print out all the selectors */
467 svm_dump_sel("CS", &vmcb->cs);
468 svm_dump_sel("DS", &vmcb->ds);
469 svm_dump_sel("SS", &vmcb->ss);
470 svm_dump_sel("ES", &vmcb->es);
471 svm_dump_sel("FS", &vmcb->fs);
472 svm_dump_sel("GS", &vmcb->gs);
473 svm_dump_sel("GDTR", &vmcb->gdtr);
474 svm_dump_sel("LDTR", &vmcb->ldtr);
475 svm_dump_sel("IDTR", &vmcb->idtr);
476 svm_dump_sel("TR", &vmcb->tr);
477 }
479 static void vmcb_dump(unsigned char ch)
480 {
481 struct domain *d;
482 struct vcpu *v;
484 printk("*********** VMCB Areas **************\n");
485 for_each_domain(d) {
486 printk("\n>>> Domain %d <<<\n", d->domain_id);
487 for_each_vcpu(d, v) {
489 /*
490 * Presumably, if a domain is not an HVM guest,
491 * the very first CPU will not pass this test
492 */
493 if (!hvm_guest(v)) {
494 printk("\t\tNot HVM guest\n");
495 break;
496 }
497 printk("\tVCPU %d\n", v->vcpu_id);
499 svm_dump_vmcb("key_handler", v->arch.hvm_svm.vmcb);
500 }
501 }
503 printk("**************************************\n");
504 }
506 void setup_vmcb_dump(void)
507 {
508 register_keyhandler('v', vmcb_dump, "dump AMD-V VMCBs");
509 }
511 /*
512 * Local variables:
513 * mode: C
514 * c-set-style: "BSD"
515 * c-basic-offset: 4
516 * tab-width: 4
517 * indent-tabs-mode: nil
518 * End:
519 */