VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/HWACCMR0.cpp@ 1

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.4 KB
Line 
1/** @file
2 *
3 * HWACCM - Host Context Ring 0.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_HWACCM
27#include <VBox/hwaccm.h>
28#include "HWACCMInternal.h"
29#include <VBox/vm.h>
30#include <VBox/x86.h>
31#include <VBox/hwacc_vmx.h>
32#include <VBox/hwacc_svm.h>
33#include <VBox/pgm.h>
34#include <VBox/pdm.h>
35#include <VBox/err.h>
36#include <VBox/log.h>
37#include <VBox/selm.h>
38#include <VBox/iom.h>
39#include <iprt/param.h>
40#include <iprt/assert.h>
41#include <iprt/asm.h>
42#include "HWVMXR0.h"
43#include "HWSVMR0.h"
44
45/**
46 * Does Ring-0 HWACCM initialization.
47 *
48 * This is mainly to check that the Host CPU mode is compatible
49 * with VMX.
50 *
51 * @returns VBox status code.
52 * @param pVM The VM to operate on.
53 */
54HWACCMR0DECL(int) HWACCMR0Init(PVM pVM)
55{
56 LogComFlow(("HWACCMR0Init: %p\n", pVM));
57
58 pVM->hwaccm.s.vmx.fSupported = false;;
59 pVM->hwaccm.s.svm.fSupported = false;;
60
61 /*
62 * Check for VMX capabilities
63 */
64 if (ASMHasCpuId())
65 {
66 uint32_t u32FeaturesECX;
67 uint32_t u32Dummy;
68 uint32_t u32FeaturesEDX;
69 uint32_t u32Vendor1, u32Vendor2, u32Vendor3;
70
71 ASMCpuId(0, &u32Dummy, &u32Vendor1, &u32Vendor3, &u32Vendor2);
72 ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
73 /* Query AMD features. */
74 ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &pVM->hwaccm.s.cpuid.u32AMDFeatureECX, &pVM->hwaccm.s.cpuid.u32AMDFeatureEDX);
75
76 if ( u32Vendor1 == 0x756e6547 /* Genu */
77 && u32Vendor2 == 0x49656e69 /* ineI */
78 && u32Vendor3 == 0x6c65746e /* ntel */
79 )
80 {
81 /*
82 * Read all VMX MSRs if VMX is available. (same goes for RDMSR/WRMSR)
83 * We also assume all VMX-enabled CPUs support fxsave/fxrstor.
84 */
85 if ( (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
86 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
87 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
88 )
89 {
90 pVM->hwaccm.s.vmx.msr.feature_ctrl = ASMRdMsr(MSR_IA32_FEATURE_CONTROL);
91 /*
92 * Both the LOCK and VMXON bit must be set; otherwise VMXON will generate a #GP.
93 * Once the lock bit is set, this MSR can no longer be modified.
94 */
95 if ( (pVM->hwaccm.s.vmx.msr.feature_ctrl & (MSR_IA32_FEATURE_CONTROL_VMXON|MSR_IA32_FEATURE_CONTROL_LOCK))
96 == (MSR_IA32_FEATURE_CONTROL_VMXON|MSR_IA32_FEATURE_CONTROL_LOCK))
97 {
98 pVM->hwaccm.s.vmx.fSupported = true;
99 pVM->hwaccm.s.vmx.msr.vmx_basic_info = ASMRdMsr(MSR_IA32_VMX_BASIC_INFO);
100 pVM->hwaccm.s.vmx.msr.vmx_pin_ctls = ASMRdMsr(MSR_IA32_VMX_PINBASED_CTLS);
101 pVM->hwaccm.s.vmx.msr.vmx_proc_ctls = ASMRdMsr(MSR_IA32_VMX_PROCBASED_CTLS);
102 pVM->hwaccm.s.vmx.msr.vmx_exit = ASMRdMsr(MSR_IA32_VMX_EXIT_CTLS);
103 pVM->hwaccm.s.vmx.msr.vmx_entry = ASMRdMsr(MSR_IA32_VMX_ENTRY_CTLS);
104 pVM->hwaccm.s.vmx.msr.vmx_misc = ASMRdMsr(MSR_IA32_VMX_MISC);
105 pVM->hwaccm.s.vmx.msr.vmx_cr0_fixed0 = ASMRdMsr(MSR_IA32_VMX_CR0_FIXED0);
106 pVM->hwaccm.s.vmx.msr.vmx_cr0_fixed1 = ASMRdMsr(MSR_IA32_VMX_CR0_FIXED1);
107 pVM->hwaccm.s.vmx.msr.vmx_cr4_fixed0 = ASMRdMsr(MSR_IA32_VMX_CR4_FIXED0);
108 pVM->hwaccm.s.vmx.msr.vmx_cr4_fixed1 = ASMRdMsr(MSR_IA32_VMX_CR4_FIXED1);
109 pVM->hwaccm.s.vmx.msr.vmx_vmcs_enum = ASMRdMsr(MSR_IA32_VMX_VMCS_ENUM);
110
111 /*
112 * Check CR4.VMXE
113 */
114 pVM->hwaccm.s.vmx.hostCR4 = ASMGetCR4();
115 if (!(pVM->hwaccm.s.vmx.hostCR4 & X86_CR4_VMXE))
116 {
117 /* In theory this bit could be cleared behind our back. Which would cause #UD faults when we
118 * try to execute the VMX instructions...
119 */
120 ASMSetCR4(pVM->hwaccm.s.vmx.hostCR4 | X86_CR4_VMXE);
121 }
122 }
123 }
124 }
125 else
126 if ( u32Vendor1 == 0x68747541 /* Auth */
127 && u32Vendor2 == 0x69746e65 /* enti */
128 && u32Vendor3 == 0x444d4163 /* cAMD */
129 )
130 {
131 /*
132 * Read all SVM MSRs if SVM is available. (same goes for RDMSR/WRMSR)
133 * We also assume all SVM-enabled CPUs support fxsave/fxrstor.
134 */
135 if ( (pVM->hwaccm.s.cpuid.u32AMDFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
136 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
137 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
138 )
139 {
140 uint64_t val;
141
142 /* Turn on SVM in the EFER MSR. */
143 val = ASMRdMsr(MSR_K6_EFER);
144 if (!(val & MSR_K6_EFER_SVME))
145 {
146 ASMWrMsr(MSR_K6_EFER, val | MSR_K6_EFER_SVME);
147 }
148 /* Paranoia. */
149 val = ASMRdMsr(MSR_K6_EFER);
150 if (val & MSR_K6_EFER_SVME)
151 {
152 /* Query AMD features. */
153 ASMCpuId(0x8000000A, &pVM->hwaccm.s.svm.u32Rev, &pVM->hwaccm.s.svm.u32MaxASID, &u32Dummy, &u32Dummy);
154
155 pVM->hwaccm.s.svm.fSupported = true;
156 }
157 else
158 AssertFailed();
159 }
160 }
161 }
162 return VINF_SUCCESS;
163}
164
165
166/**
167 * Sets up and activates VMX
168 *
169 * @returns VBox status code.
170 * @param pVM The VM to operate on.
171 */
172HWACCMR0DECL(int) HWACCMR0SetupVMX(PVM pVM)
173{
174 int rc = VINF_SUCCESS;
175
176 if (pVM == NULL)
177 return VERR_INVALID_PARAMETER;
178
179 /* Setup Intel VMX. */
180 if (pVM->hwaccm.s.vmx.fSupported)
181 rc = VMXR0Setup(pVM);
182 else
183 rc = SVMR0Setup(pVM);
184
185 return rc;
186}
187
188
189/**
190 * Enable VMX or SVN
191 *
192 * @returns VBox status code.
193 * @param pVM The VM to operate on.
194 */
195HWACCMR0DECL(int) HWACCMR0Enable(PVM pVM)
196{
197 CPUMCTX *pCtx;
198 int rc;
199
200 rc = CPUMQueryGuestCtxPtr(pVM, &pCtx);
201 if (VBOX_FAILURE(rc))
202 return rc;
203
204 /* Always load the guest's FPU/XMM state on-demand. */
205 CPUMDeactivateGuestFPUState(pVM);
206
207 /* Always reload the host context and the guest's CR0 register. (!!!!) */
208 pVM->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0 | HWACCM_CHANGED_HOST_CONTEXT;
209
210 if (pVM->hwaccm.s.vmx.fSupported)
211 {
212 rc = VMXR0Enable(pVM);
213 AssertRC(rc);
214 rc |= VMXR0SaveHostState(pVM);
215 AssertRC(rc);
216 rc |= VMXR0LoadGuestState(pVM, pCtx);
217 AssertRC(rc);
218 if (rc != VINF_SUCCESS)
219 return rc;
220 }
221 else
222 {
223 Assert(pVM->hwaccm.s.svm.fSupported);
224 rc = SVMR0Enable(pVM);
225 AssertRC(rc);
226 rc |= SVMR0LoadGuestState(pVM, pCtx);
227 AssertRC(rc);
228 if (rc != VINF_SUCCESS)
229 return rc;
230
231 }
232 return VINF_SUCCESS;
233}
234
235
236/**
237 * Disable VMX or SVN
238 *
239 * @returns VBox status code.
240 * @param pVM The VM to operate on.
241 */
242HWACCMR0DECL(int) HWACCMR0Disable(PVM pVM)
243{
244 CPUMCTX *pCtx;
245 int rc;
246
247 rc = CPUMQueryGuestCtxPtr(pVM, &pCtx);
248 if (VBOX_FAILURE(rc))
249 return rc;
250
251 /** @note It's rather tricky with longjmps done by e.g. Log statements or the page fault handler. */
252 /* We must restore the host FPU here to make absolutely sure we don't leave the guest FPU state active
253 * or trash somebody else's FPU state.
254 */
255
256 /* Restore host FPU and XMM state if necessary. */
257 if (CPUMIsGuestFPUStateActive(pVM))
258 {
259 Log2(("CPUMRestoreHostFPUState\n"));
260 /** @note CPUMRestoreHostFPUState keeps the current CR0 intact. */
261 CPUMRestoreHostFPUState(pVM);
262
263 pVM->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
264 }
265
266 if (pVM->hwaccm.s.vmx.fSupported)
267 {
268 return VMXR0Disable(pVM);
269 }
270 else
271 {
272 Assert(pVM->hwaccm.s.svm.fSupported);
273 return SVMR0Disable(pVM);
274 }
275}
276
277/**
278 * Runs guest code in a hardware accelerated VM.
279 *
280 * @returns VBox status code.
281 * @param pVM The VM to operate on.
282 */
283HWACCMR0DECL(int) HWACCMR0RunGuestCode(PVM pVM)
284{
285 CPUMCTX *pCtx;
286 int rc;
287
288 rc = CPUMQueryGuestCtxPtr(pVM, &pCtx);
289 if (VBOX_FAILURE(rc))
290 return rc;
291
292 if (pVM->hwaccm.s.vmx.fSupported)
293 {
294 return VMXR0RunGuestCode(pVM, pCtx);
295 }
296 else
297 {
298 Assert(pVM->hwaccm.s.svm.fSupported);
299 return SVMR0RunGuestCode(pVM, pCtx);
300 }
301}
302
303
304#ifdef VBOX_STRICT
305#include <string.h>
306#include <iprt/string.h>
307/**
308 * Dumps a descriptor.
309 *
310 * @param Desc Descriptor to dump.
311 * @param Sel Selector number.
312 * @param pszMsg Message to prepend the log entry with.
313 */
314HWACCMR0DECL(void) HWACCMR0DumpDescriptor(PVBOXDESC Desc, RTSEL Sel, const char *pszMsg)
315{
316 /*
317 * Make variable description string.
318 */
319 static struct
320 {
321 unsigned cch;
322 const char *psz;
323 } const aTypes[32] =
324 {
325 #define STRENTRY(str) { sizeof(str) - 1, str }
326 /* system */
327 STRENTRY("Reserved0 "), /* 0x00 */
328 STRENTRY("TSS16Avail "), /* 0x01 */
329 STRENTRY("LDT "), /* 0x02 */
330 STRENTRY("TSS16Busy "), /* 0x03 */
331 STRENTRY("Call16 "), /* 0x04 */
332 STRENTRY("Task "), /* 0x05 */
333 STRENTRY("Int16 "), /* 0x06 */
334 STRENTRY("Trap16 "), /* 0x07 */
335 STRENTRY("Reserved8 "), /* 0x08 */
336 STRENTRY("TSS32Avail "), /* 0x09 */
337 STRENTRY("ReservedA "), /* 0x0a */
338 STRENTRY("TSS32Busy "), /* 0x0b */
339 STRENTRY("Call32 "), /* 0x0c */
340 STRENTRY("ReservedD "), /* 0x0d */
341 STRENTRY("Int32 "), /* 0x0e */
342 STRENTRY("Trap32 "), /* 0x0f */
343 /* non system */
344 STRENTRY("DataRO "), /* 0x10 */
345 STRENTRY("DataRO Accessed "), /* 0x11 */
346 STRENTRY("DataRW "), /* 0x12 */
347 STRENTRY("DataRW Accessed "), /* 0x13 */
348 STRENTRY("DataDownRO "), /* 0x14 */
349 STRENTRY("DataDownRO Accessed "), /* 0x15 */
350 STRENTRY("DataDownRW "), /* 0x16 */
351 STRENTRY("DataDownRW Accessed "), /* 0x17 */
352 STRENTRY("CodeEO "), /* 0x18 */
353 STRENTRY("CodeEO Accessed "), /* 0x19 */
354 STRENTRY("CodeER "), /* 0x1a */
355 STRENTRY("CodeER Accessed "), /* 0x1b */
356 STRENTRY("CodeConfEO "), /* 0x1c */
357 STRENTRY("CodeConfEO Accessed "), /* 0x1d */
358 STRENTRY("CodeConfER "), /* 0x1e */
359 STRENTRY("CodeConfER Accessed ") /* 0x1f */
360 #undef SYSENTRY
361 };
362 #define ADD_STR(psz, pszAdd) do { strcpy(psz, pszAdd); psz += strlen(pszAdd); } while (0)
363 char szMsg[128];
364 char *psz = &szMsg[0];
365 unsigned i = Desc->Gen.u1DescType << 4 | Desc->Gen.u4Type;
366 memcpy(psz, aTypes[i].psz, aTypes[i].cch);
367 psz += aTypes[i].cch;
368
369 if (Desc->Gen.u1Present)
370 ADD_STR(psz, "Present ");
371 else
372 ADD_STR(psz, "Not-Present ");
373 if (Desc->Gen.u1Granularity)
374 ADD_STR(psz, "Page ");
375 if (Desc->Gen.u1DefBig)
376 ADD_STR(psz, "32-bit ");
377 else
378 ADD_STR(psz, "16-bit ");
379 #undef ADD_STR
380 *psz = '\0';
381
382 /*
383 * Limit and Base and format the output.
384 */
385 uint32_t u32Limit = Desc->Gen.u4LimitHigh << 16 | Desc->Gen.u16LimitLow;
386 if (Desc->Gen.u1Granularity)
387 u32Limit = u32Limit << PAGE_SHIFT | PAGE_OFFSET_MASK;
388 uint32_t u32Base = Desc->Gen.u8BaseHigh2 << 24 | Desc->Gen.u8BaseHigh1 << 16 | Desc->Gen.u16BaseLow;
389
390 Log(("%s %04x - %08x %08x - base=%08x limit=%08x dpl=%d %s\n", pszMsg,
391 Sel, Desc->au32[0], Desc->au32[1], u32Base, u32Limit, Desc->Gen.u2Dpl, szMsg));
392}
393
394/**
395 * Formats a full register dump.
396 *
397 * @param pCtx The context to format.
398 */
399HWACCMR0DECL(void) HWACCMDumpRegs(PCPUMCTX pCtx)
400{
401 /*
402 * Format the flags.
403 */
404 static struct
405 {
406 const char *pszSet; const char *pszClear; uint32_t fFlag;
407 } aFlags[] =
408 {
409 { "vip",NULL, X86_EFL_VIP },
410 { "vif",NULL, X86_EFL_VIF },
411 { "ac", NULL, X86_EFL_AC },
412 { "vm", NULL, X86_EFL_VM },
413 { "rf", NULL, X86_EFL_RF },
414 { "nt", NULL, X86_EFL_NT },
415 { "ov", "nv", X86_EFL_OF },
416 { "dn", "up", X86_EFL_DF },
417 { "ei", "di", X86_EFL_IF },
418 { "tf", NULL, X86_EFL_TF },
419 { "nt", "pl", X86_EFL_SF },
420 { "nz", "zr", X86_EFL_ZF },
421 { "ac", "na", X86_EFL_AF },
422 { "po", "pe", X86_EFL_PF },
423 { "cy", "nc", X86_EFL_CF },
424 };
425 char szEFlags[80];
426 char *psz = szEFlags;
427 uint32_t efl = pCtx->eflags.u32;
428 for (unsigned i = 0; i < ELEMENTS(aFlags); i++)
429 {
430 const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;
431 if (pszAdd)
432 {
433 strcpy(psz, pszAdd);
434 psz += strlen(pszAdd);
435 *psz++ = ' ';
436 }
437 }
438 psz[-1] = '\0';
439
440
441 /*
442 * Format the registers.
443 */
444 Log(("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"
445 "eip=%08x esp=%08x ebp=%08x iopl=%d %*s\n"
446 "cs={%04x base=%08x limit=%08x flags=%08x} dr0=%08x dr1=%08x\n"
447 "ds={%04x base=%08x limit=%08x flags=%08x} dr2=%08x dr3=%08x\n"
448 "es={%04x base=%08x limit=%08x flags=%08x} dr4=%08x dr5=%08x\n"
449 "fs={%04x base=%08x limit=%08x flags=%08x} dr6=%08x dr7=%08x\n"
450 ,
451 pCtx->eax, pCtx->ebx, pCtx->ecx, pCtx->edx, pCtx->esi, pCtx->edi,
452 pCtx->eip, pCtx->esp, pCtx->ebp, X86_EFL_GET_IOPL(efl), 31, szEFlags,
453 (RTSEL)pCtx->cs, pCtx->csHid.u32Base, pCtx->csHid.u32Limit, pCtx->csHid.Attr.u, pCtx->dr0, pCtx->dr1,
454 (RTSEL)pCtx->ds, pCtx->dsHid.u32Base, pCtx->dsHid.u32Limit, pCtx->dsHid.Attr.u, pCtx->dr2, pCtx->dr3,
455 (RTSEL)pCtx->es, pCtx->esHid.u32Base, pCtx->esHid.u32Limit, pCtx->esHid.Attr.u, pCtx->dr4, pCtx->dr5,
456 (RTSEL)pCtx->fs, pCtx->fsHid.u32Base, pCtx->fsHid.u32Limit, pCtx->fsHid.Attr.u, pCtx->dr6, pCtx->dr7));
457
458 Log(("gs={%04x base=%08x limit=%08x flags=%08x} cr0=%08x cr2=%08x\n"
459 "ss={%04x base=%08x limit=%08x flags=%08x} cr3=%08x cr4=%08x\n"
460 "gdtr=%08x:%04x idtr=%08x:%04x eflags=%08x\n"
461 "ldtr={%04x base=%08x limit=%08x flags=%08x}\n"
462 "tr ={%04x base=%08x limit=%08x flags=%08x}\n"
463 "SysEnter={cs=%04llx eip=%08llx esp=%08llx}\n"
464 "FCW=%04x FSW=%04x FTW=%04x\n",
465 (RTSEL)pCtx->gs, pCtx->gsHid.u32Base, pCtx->gsHid.u32Limit, pCtx->gsHid.Attr.u, pCtx->cr0, pCtx->cr2,
466 (RTSEL)pCtx->ss, pCtx->ssHid.u32Base, pCtx->ssHid.u32Limit, pCtx->ssHid.Attr.u, pCtx->cr3, pCtx->cr4,
467 pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt, pCtx->idtr.pIdt, pCtx->idtr.cbIdt, efl,
468 (RTSEL)pCtx->ldtr, pCtx->ldtrHid.u32Base, pCtx->ldtrHid.u32Limit, pCtx->ldtrHid.Attr.u,
469 (RTSEL)pCtx->tr, pCtx->trHid.u32Base, pCtx->trHid.u32Limit, pCtx->trHid.Attr.u,
470 pCtx->SysEnter.cs, pCtx->SysEnter.eip, pCtx->SysEnter.esp,
471 pCtx->fpu.FCW, pCtx->fpu.FSW, pCtx->fpu.FTW));
472
473
474}
475#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette