debuggers.hg

view xen/arch/x86/hvm/svm/vmcb.c @ 13651:fde9e1d474b7

hvm: Define a global I/O access bitmap, allowing direct access to port 0x80.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Jan 25 18:20:58 2007 +0000 (2007-01-25)
parents baa9b76ea3e1
children 625aa1547cb6
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;
42 #define GUEST_SEGMENT_LIMIT 0xffffffff
44 #define IOPM_SIZE (12 * 1024)
45 #define MSRPM_SIZE (8 * 1024)
47 struct vmcb_struct *alloc_vmcb(void)
48 {
49 struct vmcb_struct *vmcb;
51 vmcb = alloc_xenheap_page();
52 if ( vmcb == NULL )
53 {
54 printk(XENLOG_WARNING "Warning: failed to allocate vmcb.\n");
55 return NULL;
56 }
58 memset(vmcb, 0, PAGE_SIZE);
59 return vmcb;
60 }
62 void free_vmcb(struct vmcb_struct *vmcb)
63 {
64 free_xenheap_page(vmcb);
65 }
67 struct host_save_area *alloc_host_save_area(void)
68 {
69 struct host_save_area *hsa;
71 hsa = alloc_xenheap_page();
72 if ( hsa == NULL )
73 {
74 printk(XENLOG_WARNING "Warning: failed to allocate vmcb.\n");
75 return NULL;
76 }
78 memset(hsa, 0, PAGE_SIZE);
79 return hsa;
80 }
82 void free_host_save_area(struct host_save_area *hsa)
83 {
84 free_xenheap_page(hsa);
85 }
87 static int construct_vmcb(struct vcpu *v)
88 {
89 struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
90 struct vmcb_struct *vmcb = arch_svm->vmcb;
91 svm_segment_attributes_t attrib;
93 /* Always flush the TLB on VMRUN. All guests share a single ASID (1). */
94 vmcb->tlb_control = 1;
95 vmcb->guest_asid = 1;
97 /* SVM intercepts. */
98 vmcb->general1_intercepts =
99 GENERAL1_INTERCEPT_INTR | GENERAL1_INTERCEPT_NMI |
100 GENERAL1_INTERCEPT_SMI | GENERAL1_INTERCEPT_INIT |
101 GENERAL1_INTERCEPT_CPUID | GENERAL1_INTERCEPT_INVD |
102 GENERAL1_INTERCEPT_HLT | GENERAL1_INTERCEPT_INVLPG |
103 GENERAL1_INTERCEPT_INVLPGA | GENERAL1_INTERCEPT_IOIO_PROT |
104 GENERAL1_INTERCEPT_MSR_PROT | GENERAL1_INTERCEPT_SHUTDOWN_EVT;
105 vmcb->general2_intercepts =
106 GENERAL2_INTERCEPT_VMRUN | GENERAL2_INTERCEPT_VMMCALL |
107 GENERAL2_INTERCEPT_VMLOAD | GENERAL2_INTERCEPT_VMSAVE |
108 GENERAL2_INTERCEPT_STGI | GENERAL2_INTERCEPT_CLGI |
109 GENERAL2_INTERCEPT_SKINIT | GENERAL2_INTERCEPT_RDTSCP;
111 /* Intercept all debug-register writes. */
112 vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
114 /* Intercept all control-register accesses, except to CR2. */
115 vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ | CR_INTERCEPT_CR2_WRITE);
117 /* I/O and MSR permission bitmaps. */
118 arch_svm->msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE));
119 if ( arch_svm->msrpm == NULL )
120 return -ENOMEM;
121 memset(arch_svm->msrpm, 0xff, MSRPM_SIZE);
122 vmcb->msrpm_base_pa = (u64)virt_to_maddr(arch_svm->msrpm);
123 vmcb->iopm_base_pa = (u64)virt_to_maddr(hvm_io_bitmap);
125 /* Virtualise EFLAGS.IF and LAPIC TPR (CR8). */
126 vmcb->vintr.fields.intr_masking = 1;
128 /* Initialise event injection to no-op. */
129 vmcb->eventinj.bytes = 0;
131 /* TSC. */
132 vmcb->tsc_offset = 0;
134 /* Guest EFER: *must* contain SVME or VMRUN will fail. */
135 vmcb->efer = EFER_SVME;
137 /* Guest segment limits. */
138 vmcb->cs.limit = GUEST_SEGMENT_LIMIT;
139 vmcb->es.limit = GUEST_SEGMENT_LIMIT;
140 vmcb->ss.limit = GUEST_SEGMENT_LIMIT;
141 vmcb->ds.limit = GUEST_SEGMENT_LIMIT;
142 vmcb->fs.limit = GUEST_SEGMENT_LIMIT;
143 vmcb->gs.limit = GUEST_SEGMENT_LIMIT;
145 /* Guest segment bases. */
146 vmcb->cs.base = 0;
147 vmcb->es.base = 0;
148 vmcb->ss.base = 0;
149 vmcb->ds.base = 0;
150 vmcb->fs.base = 0;
151 vmcb->gs.base = 0;
153 /* Guest segment AR bytes. */
154 attrib.bytes = 0;
155 attrib.fields.type = 0x3; /* type = 3 */
156 attrib.fields.s = 1; /* code or data, i.e. not system */
157 attrib.fields.dpl = 0; /* DPL = 0 */
158 attrib.fields.p = 1; /* segment present */
159 attrib.fields.db = 1; /* 32-bit */
160 attrib.fields.g = 1; /* 4K pages in limit */
161 vmcb->es.attr = attrib;
162 vmcb->ss.attr = attrib;
163 vmcb->ds.attr = attrib;
164 vmcb->fs.attr = attrib;
165 vmcb->gs.attr = attrib;
166 attrib.fields.type = 0xb; /* type=0xb -> executable/readable, accessed */
167 vmcb->cs.attr = attrib;
169 /* Guest IDT. */
170 vmcb->idtr.base = 0;
171 vmcb->idtr.limit = 0;
173 /* Guest GDT. */
174 vmcb->gdtr.base = 0;
175 vmcb->gdtr.limit = 0;
177 /* Guest LDT. */
178 vmcb->ldtr.sel = 0;
179 vmcb->ldtr.base = 0;
180 vmcb->ldtr.limit = 0;
181 vmcb->ldtr.attr.bytes = 0;
183 /* Guest TSS. */
184 attrib.fields.type = 0xb; /* 32-bit TSS (busy) */
185 vmcb->tr.attr = attrib;
186 vmcb->tr.base = 0;
187 vmcb->tr.limit = 0xff;
189 /* Guest CR0. */
190 vmcb->cr0 = read_cr0();
191 arch_svm->cpu_shadow_cr0 = vmcb->cr0 & ~(X86_CR0_PG | X86_CR0_TS);
192 vmcb->cr0 |= X86_CR0_WP;
194 /* Guest CR4. */
195 arch_svm->cpu_shadow_cr4 =
196 read_cr4() & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE);
197 vmcb->cr4 = arch_svm->cpu_shadow_cr4 | SVM_CR4_HOST_MASK;
199 shadow_update_paging_modes(v);
200 vmcb->cr3 = v->arch.hvm_vcpu.hw_cr3;
202 arch_svm->vmcb->exception_intercepts = MONITOR_DEFAULT_EXCEPTION_BITMAP;
204 return 0;
205 }
207 int svm_create_vmcb(struct vcpu *v)
208 {
209 struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
210 int rc;
212 if ( (arch_svm->vmcb = alloc_vmcb()) == NULL )
213 {
214 printk("Failed to create a new VMCB\n");
215 return -ENOMEM;
216 }
218 if ( (rc = construct_vmcb(v)) != 0 )
219 {
220 free_vmcb(arch_svm->vmcb);
221 arch_svm->vmcb = NULL;
222 return rc;
223 }
225 arch_svm->vmcb_pa = virt_to_maddr(arch_svm->vmcb);
227 return 0;
228 }
230 void svm_destroy_vmcb(struct vcpu *v)
231 {
232 struct arch_svm_struct *arch_svm = &v->arch.hvm_svm;
234 if ( arch_svm->vmcb != NULL )
235 free_vmcb(arch_svm->vmcb);
237 if ( arch_svm->msrpm != NULL )
238 {
239 free_xenheap_pages(
240 arch_svm->msrpm, get_order_from_bytes(MSRPM_SIZE));
241 arch_svm->msrpm = NULL;
242 }
244 arch_svm->vmcb = NULL;
245 }
247 void svm_do_launch(struct vcpu *v)
248 {
249 hvm_stts(v);
251 /* current core is the one we intend to perform the VMRUN on */
252 v->arch.hvm_svm.launch_core = smp_processor_id();
254 v->arch.schedule_tail = arch_svm_do_resume;
255 }
257 static void svm_dump_sel(char *name, svm_segment_register_t *s)
258 {
259 printk("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n",
260 name, s->sel, s->attr.bytes, s->limit,
261 (unsigned long long)s->base);
262 }
264 void svm_dump_vmcb(const char *from, struct vmcb_struct *vmcb)
265 {
266 printk("Dumping guest's current state at %s...\n", from);
267 printk("Size of VMCB = %d, address = %p\n",
268 (int) sizeof(struct vmcb_struct), vmcb);
270 printk("cr_intercepts = 0x%08x dr_intercepts = 0x%08x "
271 "exception_intercepts = 0x%08x\n",
272 vmcb->cr_intercepts, vmcb->dr_intercepts,
273 vmcb->exception_intercepts);
274 printk("general1_intercepts = 0x%08x general2_intercepts = 0x%08x\n",
275 vmcb->general1_intercepts, vmcb->general2_intercepts);
276 printk("iopm_base_pa = %016llx msrpm_base_pa = 0x%016llx tsc_offset = "
277 "0x%016llx\n",
278 (unsigned long long) vmcb->iopm_base_pa,
279 (unsigned long long) vmcb->msrpm_base_pa,
280 (unsigned long long) vmcb->tsc_offset);
281 printk("tlb_control = 0x%08x vintr = 0x%016llx interrupt_shadow = "
282 "0x%016llx\n", vmcb->tlb_control,
283 (unsigned long long) vmcb->vintr.bytes,
284 (unsigned long long) vmcb->interrupt_shadow);
285 printk("exitcode = 0x%016llx exitintinfo = 0x%016llx\n",
286 (unsigned long long) vmcb->exitcode,
287 (unsigned long long) vmcb->exitintinfo.bytes);
288 printk("exitinfo1 = 0x%016llx exitinfo2 = 0x%016llx \n",
289 (unsigned long long) vmcb->exitinfo1,
290 (unsigned long long) vmcb->exitinfo2);
291 printk("np_enable = 0x%016llx guest_asid = 0x%03x\n",
292 (unsigned long long) vmcb->np_enable, vmcb->guest_asid);
293 printk("cpl = %d efer = 0x%016llx star = 0x%016llx lstar = 0x%016llx\n",
294 vmcb->cpl, (unsigned long long) vmcb->efer,
295 (unsigned long long) vmcb->star, (unsigned long long) vmcb->lstar);
296 printk("CR0 = 0x%016llx CR2 = 0x%016llx\n",
297 (unsigned long long) vmcb->cr0, (unsigned long long) vmcb->cr2);
298 printk("CR3 = 0x%016llx CR4 = 0x%016llx\n",
299 (unsigned long long) vmcb->cr3, (unsigned long long) vmcb->cr4);
300 printk("RSP = 0x%016llx RIP = 0x%016llx\n",
301 (unsigned long long) vmcb->rsp, (unsigned long long) vmcb->rip);
302 printk("RAX = 0x%016llx RFLAGS=0x%016llx\n",
303 (unsigned long long) vmcb->rax, (unsigned long long) vmcb->rflags);
304 printk("DR6 = 0x%016llx, DR7 = 0x%016llx\n",
305 (unsigned long long) vmcb->dr6, (unsigned long long) vmcb->dr7);
306 printk("CSTAR = 0x%016llx SFMask = 0x%016llx\n",
307 (unsigned long long) vmcb->cstar,
308 (unsigned long long) vmcb->sfmask);
309 printk("KernGSBase = 0x%016llx PAT = 0x%016llx \n",
310 (unsigned long long) vmcb->kerngsbase,
311 (unsigned long long) vmcb->g_pat);
313 /* print out all the selectors */
314 svm_dump_sel("CS", &vmcb->cs);
315 svm_dump_sel("DS", &vmcb->ds);
316 svm_dump_sel("SS", &vmcb->ss);
317 svm_dump_sel("ES", &vmcb->es);
318 svm_dump_sel("FS", &vmcb->fs);
319 svm_dump_sel("GS", &vmcb->gs);
320 svm_dump_sel("GDTR", &vmcb->gdtr);
321 svm_dump_sel("LDTR", &vmcb->ldtr);
322 svm_dump_sel("IDTR", &vmcb->idtr);
323 svm_dump_sel("TR", &vmcb->tr);
324 }
326 static void vmcb_dump(unsigned char ch)
327 {
328 struct domain *d;
329 struct vcpu *v;
331 printk("*********** VMCB Areas **************\n");
332 for_each_domain ( d )
333 {
334 if ( !is_hvm_domain(d) )
335 continue;
336 printk("\n>>> Domain %d <<<\n", d->domain_id);
337 for_each_vcpu ( d, v )
338 {
339 printk("\tVCPU %d\n", v->vcpu_id);
340 svm_dump_vmcb("key_handler", v->arch.hvm_svm.vmcb);
341 }
342 }
344 printk("**************************************\n");
345 }
347 void setup_vmcb_dump(void)
348 {
349 register_keyhandler('v', vmcb_dump, "dump AMD-V VMCBs");
350 }
352 /*
353 * Local variables:
354 * mode: C
355 * c-set-style: "BSD"
356 * c-basic-offset: 4
357 * tab-width: 4
358 * indent-tabs-mode: nil
359 * End:
360 */