VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp@ 1828

Last change on this file since 1828 was 1828, checked in by vboxsync, 18 years ago

Cleaned up cpl checking.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 37.4 KB
Line 
1/* $Id: CPUMAllRegs.cpp 1828 2007-03-30 12:52:55Z vboxsync $ */
2/** @file
3 * CPUM - CPU Monitor(/Manager) - Gets and Sets.
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_CPUM
27#include <VBox/cpum.h>
28#include <VBox/patm.h>
29#include <VBox/dbgf.h>
30#include <VBox/mm.h>
31#include "CPUMInternal.h"
32#include <VBox/vm.h>
33#include <VBox/err.h>
34#include <VBox/dis.h>
35#include <VBox/log.h>
36#include <iprt/assert.h>
37#include <iprt/asm.h>
38
39
40
41/** Disable stack frame pointer generation here. */
42#if defined(_MSC_VER) && !defined(DEBUG)
43# pragma optimize("y", off)
44#endif
45
46
47/**
48 * Sets or resets an alternative hypervisor context core.
49 *
50 * This is called when we get a hypervisor trap set switch the context
51 * core with the trap frame on the stack. It is called again to reset
52 * back to the default context core when resuming hypervisor execution.
53 *
54 * @param pVM The VM handle.
55 * @param pCtxCore Pointer to the alternative context core or NULL
56 * to go back to the default context core.
57 */
58CPUMDECL(void) CPUMHyperSetCtxCore(PVM pVM, PCPUMCTXCORE pCtxCore)
59{
60 LogFlow(("CPUMHyperSetCtxCore: %p -> %p\n", pVM->cpum.s.CTXSUFF(pHyperCore), pCtxCore));
61 if (!pCtxCore)
62 {
63 pCtxCore = CPUMCTX2CORE(&pVM->cpum.s.Hyper);
64#ifdef IN_GC
65 pVM->cpum.s.pHyperCoreHC = VM_HOST_ADDR(pVM, pCtxCore);
66#else
67 pVM->cpum.s.pHyperCoreGC = VM_GUEST_ADDR(pVM, pCtxCore);
68#endif
69 }
70 else
71 {
72#ifdef IN_GC
73 pVM->cpum.s.pHyperCoreHC = MMHyperGC2HC(pVM, pCtxCore);
74#else
75 pVM->cpum.s.pHyperCoreGC = MMHyperHC2GC(pVM, pCtxCore);
76#endif
77 }
78 pVM->cpum.s.CTXSUFF(pHyperCore) = pCtxCore;
79}
80
81
82/**
83 * Gets the pointer to the internal CPUMCTXCORE structure for the hypervisor.
84 * This is only for reading in order to save a few calls.
85 *
86 * @param pVM Handle to the virtual machine.
87 */
88CPUMDECL(PCCPUMCTXCORE) CPUMGetHyperCtxCore(PVM pVM)
89{
90 return pVM->cpum.s.CTXSUFF(pHyperCore);
91}
92
93
94/**
95 * Queries the pointer to the internal CPUMCTX structure for the hypervisor.
96 *
97 * @returns VBox status code.
98 * @param pVM Handle to the virtual machine.
99 * @param ppCtx Receives the hyper CPUMCTX pointer when successful.
100 *
101 * @deprecated This will *not* (and has never) given the right picture of the
102 * hypervisor register state. With CPUMHyperSetCtxCore() this is
103 * getting much worse. So, use the individual functions for getting
104 * and esp. setting the hypervisor registers.
105 */
106CPUMDECL(int) CPUMQueryHyperCtxPtr(PVM pVM, PCPUMCTX *ppCtx)
107{
108 *ppCtx = &pVM->cpum.s.Hyper;
109 return VINF_SUCCESS;
110}
111
112CPUMDECL(void) CPUMSetHyperGDTR(PVM pVM, uint32_t addr, uint16_t limit)
113{
114 pVM->cpum.s.Hyper.gdtr.cbGdt = limit;
115 pVM->cpum.s.Hyper.gdtr.pGdt = addr;
116 pVM->cpum.s.Hyper.gdtrPadding = 0;
117 pVM->cpum.s.Hyper.gdtrPadding64 = 0;
118}
119
120CPUMDECL(void) CPUMSetHyperIDTR(PVM pVM, uint32_t addr, uint16_t limit)
121{
122 pVM->cpum.s.Hyper.idtr.cbIdt = limit;
123 pVM->cpum.s.Hyper.idtr.pIdt = addr;
124 pVM->cpum.s.Hyper.idtrPadding = 0;
125 pVM->cpum.s.Hyper.idtrPadding64 = 0;
126}
127
128CPUMDECL(void) CPUMSetHyperCR3(PVM pVM, uint32_t cr3)
129{
130 pVM->cpum.s.Hyper.cr3 = cr3;
131}
132
133CPUMDECL(void) CPUMSetHyperCS(PVM pVM, RTSEL SelCS)
134{
135 pVM->cpum.s.CTXSUFF(pHyperCore)->cs = SelCS;
136}
137
138CPUMDECL(void) CPUMSetHyperDS(PVM pVM, RTSEL SelDS)
139{
140 pVM->cpum.s.CTXSUFF(pHyperCore)->ds = SelDS;
141}
142
143CPUMDECL(void) CPUMSetHyperES(PVM pVM, RTSEL SelES)
144{
145 pVM->cpum.s.CTXSUFF(pHyperCore)->es = SelES;
146}
147
148CPUMDECL(void) CPUMSetHyperFS(PVM pVM, RTSEL SelFS)
149{
150 pVM->cpum.s.CTXSUFF(pHyperCore)->fs = SelFS;
151}
152
153CPUMDECL(void) CPUMSetHyperGS(PVM pVM, RTSEL SelGS)
154{
155 pVM->cpum.s.CTXSUFF(pHyperCore)->gs = SelGS;
156}
157
158CPUMDECL(void) CPUMSetHyperSS(PVM pVM, RTSEL SelSS)
159{
160 pVM->cpum.s.CTXSUFF(pHyperCore)->ss = SelSS;
161}
162
163CPUMDECL(void) CPUMSetHyperESP(PVM pVM, uint32_t u32ESP)
164{
165 pVM->cpum.s.CTXSUFF(pHyperCore)->esp = u32ESP;
166}
167
168CPUMDECL(int) CPUMSetHyperEFlags(PVM pVM, uint32_t Efl)
169{
170 pVM->cpum.s.CTXSUFF(pHyperCore)->eflags.u32 = Efl;
171 return VINF_SUCCESS;
172}
173
174CPUMDECL(void) CPUMSetHyperEIP(PVM pVM, uint32_t u32EIP)
175{
176 pVM->cpum.s.CTXSUFF(pHyperCore)->eip = u32EIP;
177}
178
179CPUMDECL(void) CPUMSetHyperTR(PVM pVM, RTSEL SelTR)
180{
181 pVM->cpum.s.Hyper.tr = SelTR;
182}
183
184CPUMDECL(void) CPUMSetHyperLDTR(PVM pVM, RTSEL SelLDTR)
185{
186 pVM->cpum.s.Hyper.ldtr = SelLDTR;
187}
188
189CPUMDECL(void) CPUMSetHyperDR0(PVM pVM, RTGCUINTREG uDr0)
190{
191 pVM->cpum.s.Hyper.dr0 = uDr0;
192 /** @todo in GC we must load it! */
193}
194
195CPUMDECL(void) CPUMSetHyperDR1(PVM pVM, RTGCUINTREG uDr1)
196{
197 pVM->cpum.s.Hyper.dr1 = uDr1;
198 /** @todo in GC we must load it! */
199}
200
201CPUMDECL(void) CPUMSetHyperDR2(PVM pVM, RTGCUINTREG uDr2)
202{
203 pVM->cpum.s.Hyper.dr2 = uDr2;
204 /** @todo in GC we must load it! */
205}
206
207CPUMDECL(void) CPUMSetHyperDR3(PVM pVM, RTGCUINTREG uDr3)
208{
209 pVM->cpum.s.Hyper.dr3 = uDr3;
210 /** @todo in GC we must load it! */
211}
212
213CPUMDECL(void) CPUMSetHyperDR6(PVM pVM, RTGCUINTREG uDr6)
214{
215 pVM->cpum.s.Hyper.dr6 = uDr6;
216 /** @todo in GC we must load it! */
217}
218
219CPUMDECL(void) CPUMSetHyperDR7(PVM pVM, RTGCUINTREG uDr7)
220{
221 pVM->cpum.s.Hyper.dr7 = uDr7;
222 /** @todo in GC we must load it! */
223}
224
225
226CPUMDECL(RTSEL) CPUMGetHyperCS(PVM pVM)
227{
228 return pVM->cpum.s.CTXSUFF(pHyperCore)->cs;
229}
230
231CPUMDECL(RTSEL) CPUMGetHyperDS(PVM pVM)
232{
233 return pVM->cpum.s.CTXSUFF(pHyperCore)->ds;
234}
235
236CPUMDECL(RTSEL) CPUMGetHyperES(PVM pVM)
237{
238 return pVM->cpum.s.CTXSUFF(pHyperCore)->es;
239}
240
241CPUMDECL(RTSEL) CPUMGetHyperFS(PVM pVM)
242{
243 return pVM->cpum.s.CTXSUFF(pHyperCore)->fs;
244}
245
246CPUMDECL(RTSEL) CPUMGetHyperGS(PVM pVM)
247{
248 return pVM->cpum.s.CTXSUFF(pHyperCore)->gs;
249}
250
251CPUMDECL(RTSEL) CPUMGetHyperSS(PVM pVM)
252{
253 return pVM->cpum.s.CTXSUFF(pHyperCore)->ss;
254}
255
256#if 0 /* these are not correct. */
257
258CPUMDECL(uint32_t) CPUMGetHyperCR0(PVM pVM)
259{
260 return pVM->cpum.s.Hyper.cr0;
261}
262
263CPUMDECL(uint32_t) CPUMGetHyperCR2(PVM pVM)
264{
265 return pVM->cpum.s.Hyper.cr2;
266}
267
268CPUMDECL(uint32_t) CPUMGetHyperCR3(PVM pVM)
269{
270 return pVM->cpum.s.Hyper.cr3;
271}
272
273CPUMDECL(uint32_t) CPUMGetHyperCR4(PVM pVM)
274{
275 return pVM->cpum.s.Hyper.cr4;
276}
277
278#endif /* not correct */
279
280CPUMDECL(uint32_t) CPUMGetHyperEAX(PVM pVM)
281{
282 return pVM->cpum.s.CTXSUFF(pHyperCore)->eax;
283}
284
285CPUMDECL(uint32_t) CPUMGetHyperEBX(PVM pVM)
286{
287 return pVM->cpum.s.CTXSUFF(pHyperCore)->ebx;
288}
289
290CPUMDECL(uint32_t) CPUMGetHyperECX(PVM pVM)
291{
292 return pVM->cpum.s.CTXSUFF(pHyperCore)->ecx;
293}
294
295CPUMDECL(uint32_t) CPUMGetHyperEDX(PVM pVM)
296{
297 return pVM->cpum.s.CTXSUFF(pHyperCore)->edx;
298}
299
300CPUMDECL(uint32_t) CPUMGetHyperESI(PVM pVM)
301{
302 return pVM->cpum.s.CTXSUFF(pHyperCore)->esi;
303}
304
305CPUMDECL(uint32_t) CPUMGetHyperEDI(PVM pVM)
306{
307 return pVM->cpum.s.CTXSUFF(pHyperCore)->edi;
308}
309
310CPUMDECL(uint32_t) CPUMGetHyperEBP(PVM pVM)
311{
312 return pVM->cpum.s.CTXSUFF(pHyperCore)->ebp;
313}
314
315CPUMDECL(uint32_t) CPUMGetHyperESP(PVM pVM)
316{
317 return pVM->cpum.s.CTXSUFF(pHyperCore)->esp;
318}
319
320CPUMDECL(uint32_t) CPUMGetHyperEFlags(PVM pVM)
321{
322 return pVM->cpum.s.CTXSUFF(pHyperCore)->eflags.u32;
323}
324
325CPUMDECL(uint32_t) CPUMGetHyperEIP(PVM pVM)
326{
327 return pVM->cpum.s.CTXSUFF(pHyperCore)->eip;
328}
329
330CPUMDECL(uint32_t) CPUMGetHyperIDTR(PVM pVM, uint16_t *pcbLimit)
331{
332 if (pcbLimit)
333 *pcbLimit = pVM->cpum.s.Hyper.idtr.cbIdt;
334 return pVM->cpum.s.Hyper.idtr.pIdt;
335}
336
337CPUMDECL(uint32_t) CPUMGetHyperGDTR(PVM pVM, uint16_t *pcbLimit)
338{
339 if (pcbLimit)
340 *pcbLimit = pVM->cpum.s.Hyper.gdtr.cbGdt;
341 return pVM->cpum.s.Hyper.gdtr.pGdt;
342}
343
344CPUMDECL(RTSEL) CPUMGetHyperLDTR(PVM pVM)
345{
346 return pVM->cpum.s.Hyper.ldtr;
347}
348
349CPUMDECL(RTGCUINTREG) CPUMGetHyperDR0(PVM pVM)
350{
351 return pVM->cpum.s.Hyper.dr0;
352}
353
354CPUMDECL(RTGCUINTREG) CPUMGetHyperDR1(PVM pVM)
355{
356 return pVM->cpum.s.Hyper.dr1;
357}
358
359CPUMDECL(RTGCUINTREG) CPUMGetHyperDR2(PVM pVM)
360{
361 return pVM->cpum.s.Hyper.dr2;
362}
363
364CPUMDECL(RTGCUINTREG) CPUMGetHyperDR3(PVM pVM)
365{
366 return pVM->cpum.s.Hyper.dr3;
367}
368
369CPUMDECL(RTGCUINTREG) CPUMGetHyperDR6(PVM pVM)
370{
371 return pVM->cpum.s.Hyper.dr6;
372}
373
374CPUMDECL(RTGCUINTREG) CPUMGetHyperDR7(PVM pVM)
375{
376 return pVM->cpum.s.Hyper.dr7;
377}
378
379
380/**
381 * Gets the pointer to the internal CPUMCTXCORE structure.
382 * This is only for reading in order to save a few calls.
383 *
384 * @param pVM Handle to the virtual machine.
385 */
386CPUMDECL(PCCPUMCTXCORE) CPUMGetGuestCtxCore(PVM pVM)
387{
388 return CPUMCTX2CORE(&pVM->cpum.s.Guest);
389}
390
391
392/**
393 * Sets the guest context core registers.
394 *
395 * @param pVM Handle to the virtual machine.
396 * @param pCtxCore The new context core values.
397 */
398CPUMDECL(void) CPUMSetGuestCtxCore(PVM pVM, PCCPUMCTXCORE pCtxCore)
399{
400 /** @todo #1410 requires selectors to be checked. */
401
402 PCPUMCTXCORE pCtxCoreDst CPUMCTX2CORE(&pVM->cpum.s.Guest);
403 *pCtxCoreDst = *pCtxCore;
404}
405
406
407/**
408 * Queries the pointer to the internal CPUMCTX structure
409 *
410 * @returns VBox status code.
411 * @param pVM Handle to the virtual machine.
412 * @param ppCtx Receives the CPUMCTX pointer when successful.
413 */
414CPUMDECL(int) CPUMQueryGuestCtxPtr(PVM pVM, PCPUMCTX *ppCtx)
415{
416 *ppCtx = &pVM->cpum.s.Guest;
417 return VINF_SUCCESS;
418}
419
420
421CPUMDECL(int) CPUMSetGuestGDTR(PVM pVM, uint32_t addr, uint16_t limit)
422{
423 pVM->cpum.s.Guest.gdtr.cbGdt = limit;
424 pVM->cpum.s.Guest.gdtr.pGdt = addr;
425 pVM->cpum.s.fChanged |= CPUM_CHANGED_GDTR;
426 return VINF_SUCCESS;
427}
428
429CPUMDECL(int) CPUMSetGuestIDTR(PVM pVM, uint32_t addr, uint16_t limit)
430{
431 pVM->cpum.s.Guest.idtr.cbIdt = limit;
432 pVM->cpum.s.Guest.idtr.pIdt = addr;
433 pVM->cpum.s.fChanged |= CPUM_CHANGED_IDTR;
434 return VINF_SUCCESS;
435}
436
437CPUMDECL(int) CPUMSetGuestTR(PVM pVM, uint16_t tr)
438{
439 pVM->cpum.s.Guest.tr = tr;
440 pVM->cpum.s.fChanged |= CPUM_CHANGED_TR;
441 return VINF_SUCCESS;
442}
443
444CPUMDECL(int) CPUMSetGuestLDTR(PVM pVM, uint16_t ldtr)
445{
446 pVM->cpum.s.Guest.ldtr = ldtr;
447 pVM->cpum.s.fChanged |= CPUM_CHANGED_LDTR;
448 return VINF_SUCCESS;
449}
450
451
452CPUMDECL(int) CPUMSetGuestCR0(PVM pVM, uint32_t cr0)
453{
454 if ( (cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))
455 != (pVM->cpum.s.Guest.cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)))
456 pVM->cpum.s.fChanged |= CPUM_CHANGED_GLOBAL_TLB_FLUSH;
457 pVM->cpum.s.fChanged |= CPUM_CHANGED_CR0;
458 pVM->cpum.s.Guest.cr0 = cr0 | X86_CR0_ET;
459 return VINF_SUCCESS;
460}
461
462CPUMDECL(int) CPUMSetGuestCR2(PVM pVM, uint32_t cr2)
463{
464 pVM->cpum.s.Guest.cr2 = cr2;
465 return VINF_SUCCESS;
466}
467
468CPUMDECL(int) CPUMSetGuestCR3(PVM pVM, uint32_t cr3)
469{
470 pVM->cpum.s.Guest.cr3 = cr3;
471 pVM->cpum.s.fChanged |= CPUM_CHANGED_CR3;
472 return VINF_SUCCESS;
473}
474
475CPUMDECL(int) CPUMSetGuestCR4(PVM pVM, uint32_t cr4)
476{
477 if ( (cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE))
478 != (pVM->cpum.s.Guest.cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE)))
479 pVM->cpum.s.fChanged |= CPUM_CHANGED_GLOBAL_TLB_FLUSH;
480 pVM->cpum.s.fChanged |= CPUM_CHANGED_CR4;
481 if (!CPUMSupportsFXSR(pVM))
482 cr4 &= ~X86_CR4_OSFSXR;
483 pVM->cpum.s.Guest.cr4 = cr4;
484 return VINF_SUCCESS;
485}
486
487CPUMDECL(int) CPUMSetGuestEFlags(PVM pVM, uint32_t eflags)
488{
489 pVM->cpum.s.Guest.eflags.u32 = eflags;
490 return VINF_SUCCESS;
491}
492
493CPUMDECL(int) CPUMSetGuestEIP(PVM pVM, uint32_t eip)
494{
495 pVM->cpum.s.Guest.eip = eip;
496 return VINF_SUCCESS;
497}
498
499CPUMDECL(int) CPUMSetGuestEAX(PVM pVM, uint32_t eax)
500{
501 pVM->cpum.s.Guest.eax = eax;
502 return VINF_SUCCESS;
503}
504
505CPUMDECL(int) CPUMSetGuestEBX(PVM pVM, uint32_t ebx)
506{
507 pVM->cpum.s.Guest.ebx = ebx;
508 return VINF_SUCCESS;
509}
510
511CPUMDECL(int) CPUMSetGuestECX(PVM pVM, uint32_t ecx)
512{
513 pVM->cpum.s.Guest.ecx = ecx;
514 return VINF_SUCCESS;
515}
516
517CPUMDECL(int) CPUMSetGuestEDX(PVM pVM, uint32_t edx)
518{
519 pVM->cpum.s.Guest.edx = edx;
520 return VINF_SUCCESS;
521}
522
523CPUMDECL(int) CPUMSetGuestESP(PVM pVM, uint32_t esp)
524{
525 pVM->cpum.s.Guest.esp = esp;
526 return VINF_SUCCESS;
527}
528
529CPUMDECL(int) CPUMSetGuestEBP(PVM pVM, uint32_t ebp)
530{
531 pVM->cpum.s.Guest.ebp = ebp;
532 return VINF_SUCCESS;
533}
534
535CPUMDECL(int) CPUMSetGuestESI(PVM pVM, uint32_t esi)
536{
537 pVM->cpum.s.Guest.esi = esi;
538 return VINF_SUCCESS;
539}
540
541CPUMDECL(int) CPUMSetGuestEDI(PVM pVM, uint32_t edi)
542{
543 pVM->cpum.s.Guest.edi = edi;
544 return VINF_SUCCESS;
545}
546
547CPUMDECL(int) CPUMSetGuestSS(PVM pVM, uint16_t ss)
548{
549 pVM->cpum.s.Guest.ss = ss;
550 return VINF_SUCCESS;
551}
552
553CPUMDECL(int) CPUMSetGuestCS(PVM pVM, uint16_t cs)
554{
555 pVM->cpum.s.Guest.cs = cs;
556 return VINF_SUCCESS;
557}
558
559CPUMDECL(int) CPUMSetGuestDS(PVM pVM, uint16_t ds)
560{
561 pVM->cpum.s.Guest.ds = ds;
562 return VINF_SUCCESS;
563}
564
565CPUMDECL(int) CPUMSetGuestES(PVM pVM, uint16_t es)
566{
567 pVM->cpum.s.Guest.es = es;
568 return VINF_SUCCESS;
569}
570
571CPUMDECL(int) CPUMSetGuestFS(PVM pVM, uint16_t fs)
572{
573 pVM->cpum.s.Guest.fs = fs;
574 return VINF_SUCCESS;
575}
576
577CPUMDECL(int) CPUMSetGuestGS(PVM pVM, uint16_t gs)
578{
579 pVM->cpum.s.Guest.gs = gs;
580 return VINF_SUCCESS;
581}
582
583
584CPUMDECL(uint32_t) CPUMGetGuestIDTR(PVM pVM, uint16_t *pcbLimit)
585{
586 if (pcbLimit)
587 *pcbLimit = pVM->cpum.s.Guest.idtr.cbIdt;
588 return pVM->cpum.s.Guest.idtr.pIdt;
589}
590
591CPUMDECL(RTSEL) CPUMGetGuestTR(PVM pVM)
592{
593 return pVM->cpum.s.Guest.tr;
594}
595
596CPUMDECL(RTSEL) CPUMGetGuestCS(PVM pVM)
597{
598 return pVM->cpum.s.Guest.cs;
599}
600
601CPUMDECL(RTSEL) CPUMGetGuestDS(PVM pVM)
602{
603 return pVM->cpum.s.Guest.ds;
604}
605
606CPUMDECL(RTSEL) CPUMGetGuestES(PVM pVM)
607{
608 return pVM->cpum.s.Guest.es;
609}
610
611CPUMDECL(RTSEL) CPUMGetGuestFS(PVM pVM)
612{
613 return pVM->cpum.s.Guest.fs;
614}
615
616CPUMDECL(RTSEL) CPUMGetGuestGS(PVM pVM)
617{
618 return pVM->cpum.s.Guest.gs;
619}
620
621CPUMDECL(RTSEL) CPUMGetGuestSS(PVM pVM)
622{
623 return pVM->cpum.s.Guest.ss;
624}
625
626CPUMDECL(RTSEL) CPUMGetGuestLDTR(PVM pVM)
627{
628 return pVM->cpum.s.Guest.ldtr;
629}
630
631
632CPUMDECL(uint32_t) CPUMGetGuestCR0(PVM pVM)
633{
634 return pVM->cpum.s.Guest.cr0;
635}
636
637CPUMDECL(uint32_t) CPUMGetGuestCR2(PVM pVM)
638{
639 return pVM->cpum.s.Guest.cr2;
640}
641
642CPUMDECL(uint32_t) CPUMGetGuestCR3(PVM pVM)
643{
644 return pVM->cpum.s.Guest.cr3;
645}
646
647CPUMDECL(uint32_t) CPUMGetGuestCR4(PVM pVM)
648{
649 return pVM->cpum.s.Guest.cr4;
650}
651
652CPUMDECL(void) CPUMGetGuestGDTR(PVM pVM, PVBOXGDTR pGDTR)
653{
654 *pGDTR = pVM->cpum.s.Guest.gdtr;
655}
656
657CPUMDECL(uint32_t) CPUMGetGuestEIP(PVM pVM)
658{
659 return pVM->cpum.s.Guest.eip;
660}
661
662CPUMDECL(uint32_t) CPUMGetGuestEAX(PVM pVM)
663{
664 return pVM->cpum.s.Guest.eax;
665}
666
667CPUMDECL(uint32_t) CPUMGetGuestEBX(PVM pVM)
668{
669 return pVM->cpum.s.Guest.ebx;
670}
671
672CPUMDECL(uint32_t) CPUMGetGuestECX(PVM pVM)
673{
674 return pVM->cpum.s.Guest.ecx;
675}
676
677CPUMDECL(uint32_t) CPUMGetGuestEDX(PVM pVM)
678{
679 return pVM->cpum.s.Guest.edx;
680}
681
682CPUMDECL(uint32_t) CPUMGetGuestESI(PVM pVM)
683{
684 return pVM->cpum.s.Guest.esi;
685}
686
687CPUMDECL(uint32_t) CPUMGetGuestEDI(PVM pVM)
688{
689 return pVM->cpum.s.Guest.edi;
690}
691
692CPUMDECL(uint32_t) CPUMGetGuestESP(PVM pVM)
693{
694 return pVM->cpum.s.Guest.esp;
695}
696
697CPUMDECL(uint32_t) CPUMGetGuestEBP(PVM pVM)
698{
699 return pVM->cpum.s.Guest.ebp;
700}
701
702CPUMDECL(uint32_t) CPUMGetGuestEFlags(PVM pVM)
703{
704 return pVM->cpum.s.Guest.eflags.u32;
705}
706
707CPUMDECL(CPUMSELREGHID *) CPUMGetGuestTRHid(PVM pVM)
708{
709 return &pVM->cpum.s.Guest.trHid;
710}
711
712//@todo: crx should be an array
713CPUMDECL(int) CPUMGetGuestCRx(PVM pVM, uint32_t iReg, uint32_t *pValue)
714{
715 switch (iReg)
716 {
717 case USE_REG_CR0:
718 *pValue = pVM->cpum.s.Guest.cr0;
719 break;
720 case USE_REG_CR2:
721 *pValue = pVM->cpum.s.Guest.cr2;
722 break;
723 case USE_REG_CR3:
724 *pValue = pVM->cpum.s.Guest.cr3;
725 break;
726 case USE_REG_CR4:
727 *pValue = pVM->cpum.s.Guest.cr4;
728 break;
729 default:
730 return VERR_INVALID_PARAMETER;
731 }
732 return VINF_SUCCESS;
733}
734
735CPUMDECL(RTUINTREG) CPUMGetGuestDR0(PVM pVM)
736{
737 return pVM->cpum.s.Guest.dr0;
738}
739
740CPUMDECL(RTUINTREG) CPUMGetGuestDR1(PVM pVM)
741{
742 return pVM->cpum.s.Guest.dr1;
743}
744
745CPUMDECL(RTUINTREG) CPUMGetGuestDR2(PVM pVM)
746{
747 return pVM->cpum.s.Guest.dr2;
748}
749
750CPUMDECL(RTUINTREG) CPUMGetGuestDR3(PVM pVM)
751{
752 return pVM->cpum.s.Guest.dr3;
753}
754
755CPUMDECL(RTUINTREG) CPUMGetGuestDR6(PVM pVM)
756{
757 return pVM->cpum.s.Guest.dr6;
758}
759
760CPUMDECL(RTUINTREG) CPUMGetGuestDR7(PVM pVM)
761{
762 return pVM->cpum.s.Guest.dr7;
763}
764
765/** @todo drx should be an array */
766CPUMDECL(int) CPUMGetGuestDRx(PVM pVM, uint32_t iReg, uint32_t *pValue)
767{
768 switch (iReg)
769 {
770 case USE_REG_DR0:
771 *pValue = pVM->cpum.s.Guest.dr0;
772 break;
773 case USE_REG_DR1:
774 *pValue = pVM->cpum.s.Guest.dr1;
775 break;
776 case USE_REG_DR2:
777 *pValue = pVM->cpum.s.Guest.dr2;
778 break;
779 case USE_REG_DR3:
780 *pValue = pVM->cpum.s.Guest.dr3;
781 break;
782 case USE_REG_DR4:
783 case USE_REG_DR6:
784 *pValue = pVM->cpum.s.Guest.dr6;
785 break;
786 case USE_REG_DR5:
787 case USE_REG_DR7:
788 *pValue = pVM->cpum.s.Guest.dr7;
789 break;
790
791 default:
792 return VERR_INVALID_PARAMETER;
793 }
794 return VINF_SUCCESS;
795}
796
797/**
798 * Gets a CpuId leaf.
799 *
800 * @param pVM The VM handle.
801 * @param iLeaf The CPUID leaf to get.
802 * @param pEax Where to store the EAX value.
803 * @param pEbx Where to store the EBX value.
804 * @param pEcx Where to store the ECX value.
805 * @param pEdx Where to store the EDX value.
806 */
807CPUMDECL(void) CPUMGetGuestCpuId(PVM pVM, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)
808{
809 PCCPUMCPUID pCpuId;
810 if (iLeaf < ELEMENTS(pVM->cpum.s.aGuestCpuIdStd))
811 pCpuId = &pVM->cpum.s.aGuestCpuIdStd[iLeaf];
812 else if (iLeaf - UINT32_C(0x80000000) < ELEMENTS(pVM->cpum.s.aGuestCpuIdExt))
813 pCpuId = &pVM->cpum.s.aGuestCpuIdExt[iLeaf - UINT32_C(0x80000000)];
814 else
815 pCpuId = &pVM->cpum.s.GuestCpuIdDef;
816
817 *pEax = pCpuId->eax;
818 *pEbx = pCpuId->ebx;
819 *pEcx = pCpuId->ecx;
820 *pEdx = pCpuId->edx;
821 Log2(("CPUMGetGuestCpuId: iLeaf=%#010x %RX32 %RX32 %RX32 %RX32\n", iLeaf, *pEax, *pEbx, *pEcx, *pEdx));
822}
823
824/**
825 * Gets a pointer to the array of standard CPUID leafs.
826 *
827 * CPUMGetGuestCpuIdStdMax() give the size of the array.
828 *
829 * @returns Pointer to the standard CPUID leafs (read-only).
830 * @param pVM The VM handle.
831 * @remark Intended for PATM.
832 */
833CPUMDECL(GCPTRTYPE(PCCPUMCPUID)) CPUMGetGuestCpuIdStdGCPtr(PVM pVM)
834{
835 return GCPTRTYPE(PCCPUMCPUID)VM_GUEST_ADDR(pVM, &pVM->cpum.s.aGuestCpuIdStd[0]);
836}
837
838/**
839 * Gets a pointer to the array of extended CPUID leafs.
840 *
841 * CPUMGetGuestCpuIdExtMax() give the size of the array.
842 *
843 * @returns Pointer to the extended CPUID leafs (read-only).
844 * @param pVM The VM handle.
845 * @remark Intended for PATM.
846 */
847CPUMDECL(GCPTRTYPE(PCCPUMCPUID)) CPUMGetGuestCpuIdExtGCPtr(PVM pVM)
848{
849 return GCPTRTYPE(PCCPUMCPUID)VM_GUEST_ADDR(pVM, &pVM->cpum.s.aGuestCpuIdExt[0]);
850}
851
852/**
853 * Gets a pointer to the default CPUID leaf.
854 *
855 * @returns Pointer to the default CPUID leaf (read-only).
856 * @param pVM The VM handle.
857 * @remark Intended for PATM.
858 */
859CPUMDECL(GCPTRTYPE(PCCPUMCPUID)) CPUMGetGuestCpuIdDefGCPtr(PVM pVM)
860{
861 return GCPTRTYPE(PCCPUMCPUID)VM_GUEST_ADDR(pVM, &pVM->cpum.s.GuestCpuIdDef);
862}
863
864/**
865 * Gets a number of standard CPUID leafs.
866 *
867 * @returns Number of leafs.
868 * @param pVM The VM handle.
869 * @remark Intended for PATM.
870 */
871CPUMDECL(uint32_t) CPUMGetGuestCpuIdStdMax(PVM pVM)
872{
873 return ELEMENTS(pVM->cpum.s.aGuestCpuIdStd);
874}
875
876/**
877 * Gets a number of extended CPUID leafs.
878 *
879 * @returns Number of leafs.
880 * @param pVM The VM handle.
881 * @remark Intended for PATM.
882 */
883CPUMDECL(uint32_t) CPUMGetGuestCpuIdExtMax(PVM pVM)
884{
885 return ELEMENTS(pVM->cpum.s.aGuestCpuIdStd);
886}
887
888/**
889 * Sets a CPUID feature bit.
890 *
891 * @param pVM The VM Handle.
892 * @param enmFeature The feature to set.
893 */
894CPUMDECL(void) CPUMSetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
895{
896 switch (enmFeature)
897 {
898 /*
899 * Set the APIC bit in both feature masks.
900 */
901 case CPUMCPUIDFEATURE_APIC:
902 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
903 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_APIC;
904 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
905 && pVM->cpum.s.aGuestCpuIdExt[1].edx)
906 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_APIC;
907 Log(("CPUMSetGuestCpuIdFeature: Enabled APIC\n"));
908 break;
909
910 /*
911 * Set the sysenter/sysexit bit in both feature masks.
912 * Assumes the caller knows what it's doing! (host must support these)
913 */
914 case CPUMCPUIDFEATURE_SEP:
915 {
916 uint32_t ulEdx, ulDummy;
917
918 ASMCpuId(1, &ulDummy, &ulDummy, &ulDummy, &ulEdx);
919 if (!(ulEdx & X86_CPUID_FEATURE_EDX_SEP))
920 {
921 AssertMsgFailed(("ERROR: Can't turn on SEP when the host doesn't support it!!\n"));
922 return;
923 }
924
925 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
926 pVM->cpum.s.aGuestCpuIdStd[1].edx |= X86_CPUID_FEATURE_EDX_SEP;
927 if ( pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001
928 && pVM->cpum.s.aGuestCpuIdExt[1].edx)
929 pVM->cpum.s.aGuestCpuIdExt[1].edx |= X86_CPUID_AMD_FEATURE_EDX_SEP;
930 Log(("CPUMSetGuestCpuIdFeature: Enabled sysenter/exit\n"));
931 break;
932 }
933
934 default:
935 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
936 break;
937 }
938}
939
940/**
941 * Clears a CPUID feature bit.
942 *
943 * @param pVM The VM Handle.
944 * @param enmFeature The feature to clear.
945 */
946CPUMDECL(void) CPUMClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature)
947{
948 switch (enmFeature)
949 {
950 /*
951 * Set the APIC bit in both feature masks.
952 */
953 case CPUMCPUIDFEATURE_APIC:
954 if (pVM->cpum.s.aGuestCpuIdStd[0].eax >= 1)
955 pVM->cpum.s.aGuestCpuIdStd[1].edx &= ~X86_CPUID_FEATURE_EDX_APIC;
956 if (pVM->cpum.s.aGuestCpuIdExt[0].eax >= 0x80000001)
957 pVM->cpum.s.aGuestCpuIdExt[1].edx &= ~X86_CPUID_AMD_FEATURE_EDX_APIC;
958 Log(("CPUMSetGuestCpuIdFeature: Disabled APIC\n"));
959 break;
960
961 default:
962 AssertMsgFailed(("enmFeature=%d\n", enmFeature));
963 break;
964 }
965}
966
967
968
969CPUMDECL(int) CPUMSetGuestDR0(PVM pVM, RTGCUINTREG uDr0)
970{
971 pVM->cpum.s.Guest.dr0 = uDr0;
972 return CPUMRecalcHyperDRx(pVM);
973}
974
975CPUMDECL(int) CPUMSetGuestDR1(PVM pVM, RTGCUINTREG uDr1)
976{
977 pVM->cpum.s.Guest.dr1 = uDr1;
978 return CPUMRecalcHyperDRx(pVM);
979}
980
981CPUMDECL(int) CPUMSetGuestDR2(PVM pVM, RTGCUINTREG uDr2)
982{
983 pVM->cpum.s.Guest.dr2 = uDr2;
984 return CPUMRecalcHyperDRx(pVM);
985}
986
987CPUMDECL(int) CPUMSetGuestDR3(PVM pVM, RTGCUINTREG uDr3)
988{
989 pVM->cpum.s.Guest.dr3 = uDr3;
990 return CPUMRecalcHyperDRx(pVM);
991}
992
993CPUMDECL(int) CPUMSetGuestDR6(PVM pVM, RTGCUINTREG uDr6)
994{
995 pVM->cpum.s.Guest.dr6 = uDr6;
996 return CPUMRecalcHyperDRx(pVM);
997}
998
999CPUMDECL(int) CPUMSetGuestDR7(PVM pVM, RTGCUINTREG uDr7)
1000{
1001 pVM->cpum.s.Guest.dr7 = uDr7;
1002 return CPUMRecalcHyperDRx(pVM);
1003}
1004
1005/** @todo drx should be an array */
1006CPUMDECL(int) CPUMSetGuestDRx(PVM pVM, uint32_t iReg, uint32_t Value)
1007{
1008 switch (iReg)
1009 {
1010 case USE_REG_DR0:
1011 pVM->cpum.s.Guest.dr0 = Value;
1012 break;
1013 case USE_REG_DR1:
1014 pVM->cpum.s.Guest.dr1 = Value;
1015 break;
1016 case USE_REG_DR2:
1017 pVM->cpum.s.Guest.dr2 = Value;
1018 break;
1019 case USE_REG_DR3:
1020 pVM->cpum.s.Guest.dr3 = Value;
1021 break;
1022 case USE_REG_DR4:
1023 case USE_REG_DR6:
1024 pVM->cpum.s.Guest.dr6 = Value;
1025 break;
1026 case USE_REG_DR5:
1027 case USE_REG_DR7:
1028 pVM->cpum.s.Guest.dr7 = Value;
1029 break;
1030
1031 default:
1032 return VERR_INVALID_PARAMETER;
1033 }
1034 return CPUMRecalcHyperDRx(pVM);
1035}
1036
1037
1038/**
1039 * Recalculates the hypvervisor DRx register values based on
1040 * current guest registers and DBGF breakpoints.
1041 *
1042 * This is called whenever a guest DRx register is modified and when DBGF
1043 * sets a hardware breakpoint. In guest context this function will reload
1044 * any (hyper) DRx registers which comes out with a different value.
1045 *
1046 * @returns VINF_SUCCESS.
1047 * @param pVM The VM handle.
1048 */
1049CPUMDECL(int) CPUMRecalcHyperDRx(PVM pVM)
1050{
1051 /*
1052 * Compare the DR7s first.
1053 *
1054 * We only care about the enabled flags. The GE and LE flags are always
1055 * set and we don't care if the guest doesn't set them. GD is virtualized
1056 * when we dispatch #DB, we never enable it.
1057 */
1058 const RTGCUINTREG uDbgfDr7 = DBGFBpGetDR7(pVM);
1059#ifdef CPUM_VIRTUALIZE_DRX
1060 const RTGCUINTREG uGstDr7 = CPUMGetGuestDR7(pVM);
1061#else
1062 const RTGCUINTREG uGstDr7 = 0;
1063#endif
1064 if ((uGstDr7 | uDbgfDr7) & X86_DR7_ENABLED_MASK)
1065 {
1066 /*
1067 * Ok, something is enabled. Recalc each of the breakpoints.
1068 * Straight forward code, not optimized/minimized in any way.
1069 */
1070 RTGCUINTREG uNewDr7 = X86_DR7_GE | X86_DR7_LE | X86_DR7_MB1_MASK;
1071
1072 /* bp 0 */
1073 RTGCUINTREG uNewDr0;
1074 if (uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0))
1075 {
1076 uNewDr7 |= uDbgfDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
1077 uNewDr0 = DBGFBpGetDR0(pVM);
1078 }
1079 else if (uGstDr7 & (X86_DR7_L0 | X86_DR7_G0))
1080 {
1081 uNewDr7 |= uGstDr7 & (X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW0_MASK | X86_DR7_LEN0_MASK);
1082 uNewDr0 = CPUMGetGuestDR0(pVM);
1083 }
1084 else
1085 uNewDr0 = pVM->cpum.s.Hyper.dr0;
1086
1087 /* bp 1 */
1088 RTGCUINTREG uNewDr1;
1089 if (uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1))
1090 {
1091 uNewDr7 |= uDbgfDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
1092 uNewDr1 = DBGFBpGetDR1(pVM);
1093 }
1094 else if (uGstDr7 & (X86_DR7_L1 | X86_DR7_G1))
1095 {
1096 uNewDr7 |= uGstDr7 & (X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW1_MASK | X86_DR7_LEN1_MASK);
1097 uNewDr1 = CPUMGetGuestDR1(pVM);
1098 }
1099 else
1100 uNewDr1 = pVM->cpum.s.Hyper.dr1;
1101
1102 /* bp 2 */
1103 RTGCUINTREG uNewDr2;
1104 if (uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2))
1105 {
1106 uNewDr7 |= uDbgfDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
1107 uNewDr2 = DBGFBpGetDR2(pVM);
1108 }
1109 else if (uGstDr7 & (X86_DR7_L2 | X86_DR7_G2))
1110 {
1111 uNewDr7 |= uGstDr7 & (X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW2_MASK | X86_DR7_LEN2_MASK);
1112 uNewDr2 = CPUMGetGuestDR2(pVM);
1113 }
1114 else
1115 uNewDr2 = pVM->cpum.s.Hyper.dr2;
1116
1117 /* bp 3 */
1118 RTGCUINTREG uNewDr3;
1119 if (uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3))
1120 {
1121 uNewDr7 |= uDbgfDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
1122 uNewDr3 = DBGFBpGetDR3(pVM);
1123 }
1124 else if (uGstDr7 & (X86_DR7_L3 | X86_DR7_G3))
1125 {
1126 uNewDr7 |= uGstDr7 & (X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW3_MASK | X86_DR7_LEN3_MASK);
1127 uNewDr3 = CPUMGetGuestDR3(pVM);
1128 }
1129 else
1130 uNewDr3 = pVM->cpum.s.Hyper.dr3;
1131
1132 /*
1133 * Apply the updates.
1134 */
1135#ifdef IN_GC
1136 if (!(pVM->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS))
1137 {
1138 /** @todo save host DBx registers. */
1139 }
1140#endif
1141 pVM->cpum.s.fUseFlags |= CPUM_USE_DEBUG_REGS;
1142 if (uNewDr3 != pVM->cpum.s.Hyper.dr3)
1143 CPUMSetHyperDR3(pVM, uNewDr3);
1144 if (uNewDr2 != pVM->cpum.s.Hyper.dr2)
1145 CPUMSetHyperDR2(pVM, uNewDr2);
1146 if (uNewDr1 != pVM->cpum.s.Hyper.dr1)
1147 CPUMSetHyperDR1(pVM, uNewDr1);
1148 if (uNewDr0 != pVM->cpum.s.Hyper.dr0)
1149 CPUMSetHyperDR0(pVM, uNewDr0);
1150 if (uNewDr7 != pVM->cpum.s.Hyper.dr7)
1151 CPUMSetHyperDR7(pVM, uNewDr7);
1152 }
1153 else
1154 {
1155#ifdef IN_GC
1156 if (pVM->cpum.s.fUseFlags & CPUM_USE_DEBUG_REGS)
1157 {
1158 /** @todo restore host DBx registers. */
1159 }
1160#endif
1161 pVM->cpum.s.fUseFlags &= ~CPUM_USE_DEBUG_REGS;
1162 }
1163 Log2(("CPUMRecalcHyperDRx: fUseFlags=%#x %RGr %RGr %RGr %RGr %RGr %RGr\n",
1164 pVM->cpum.s.fUseFlags, pVM->cpum.s.Hyper.dr0, pVM->cpum.s.Hyper.dr1,
1165 pVM->cpum.s.Hyper.dr2, pVM->cpum.s.Hyper.dr3, pVM->cpum.s.Hyper.dr6,
1166 pVM->cpum.s.Hyper.dr7));
1167
1168 return VINF_SUCCESS;
1169}
1170
1171#ifndef IN_RING0 /** @todo I don't think we need this in R0, so move it to CPUMAll.cpp? */
1172
1173/**
1174 * Transforms the guest CPU state to raw-ring mode.
1175 *
1176 * This function will change the any of the cs and ss register with DPL=0 to DPL=1.
1177 *
1178 * @returns VBox status. (recompiler failure)
1179 * @param pVM VM handle.
1180 * @param pCtxCore The context core (for trap usage).
1181 * @see @ref pg_raw
1182 */
1183CPUMDECL(int) CPUMRawEnter(PVM pVM, PCPUMCTXCORE pCtxCore)
1184{
1185 Assert(!pVM->cpum.s.fRawEntered);
1186 if (!pCtxCore)
1187 pCtxCore = CPUMCTX2CORE(&pVM->cpum.s.Guest);
1188
1189 /*
1190 * Are we in Ring-0?
1191 */
1192 if ( pCtxCore->ss && (pCtxCore->ss & X86_SEL_RPL) == 0
1193 && !pCtxCore->eflags.Bits.u1VM)
1194 {
1195 /*
1196 * Enter execution mode.
1197 */
1198 PATMRawEnter(pVM, pCtxCore);
1199
1200 /*
1201 * Set CPL to Ring-1.
1202 */
1203 pCtxCore->ss |= 1;
1204 if (pCtxCore->cs && (pCtxCore->cs & X86_SEL_RPL) == 0)
1205 pCtxCore->cs |= 1;
1206 }
1207 else
1208 {
1209 AssertMsg((pCtxCore->ss & X86_SEL_RPL) >= 2 || pCtxCore->eflags.Bits.u1VM,
1210 ("ring-1 code not supported\n"));
1211 /*
1212 * PATM takes care of IOPL and IF flags for Ring-3 and Ring-2 code as well.
1213 */
1214 PATMRawEnter(pVM, pCtxCore);
1215 }
1216
1217 /*
1218 * Assert sanity.
1219 */
1220 AssertMsg((pCtxCore->eflags.u32 & X86_EFL_IF), ("X86_EFL_IF is clear\n"));
1221 AssertReleaseMsg( pCtxCore->eflags.Bits.u2IOPL < (unsigned)(pCtxCore->ss & X86_SEL_RPL)
1222 || pCtxCore->eflags.Bits.u1VM,
1223 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss & X86_SEL_RPL));
1224 Assert((pVM->cpum.s.Guest.cr0 & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) == (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP));
1225 pCtxCore->eflags.u32 |= X86_EFL_IF; /* paranoia */
1226
1227 pVM->cpum.s.fRawEntered = true;
1228 return VINF_SUCCESS;
1229}
1230
1231
1232/**
1233 * Transforms the guest CPU state from raw-ring mode to correct values.
1234 *
1235 * This function will change any selector registers with DPL=1 to DPL=0.
1236 *
1237 * @returns Adjusted rc.
1238 * @param pVM VM handle.
1239 * @param rc Raw mode return code
1240 * @param pCtxCore The context core (for trap usage).
1241 * @see @ref pg_raw
1242 */
1243CPUMDECL(int) CPUMRawLeave(PVM pVM, PCPUMCTXCORE pCtxCore, int rc)
1244{
1245 /*
1246 * Don't leave if we've already left (in GC).
1247 */
1248 Assert(pVM->cpum.s.fRawEntered);
1249 if (!pVM->cpum.s.fRawEntered)
1250 return rc;
1251 pVM->cpum.s.fRawEntered = false;
1252
1253 PCPUMCTX pCtx = &pVM->cpum.s.Guest;
1254 if (!pCtxCore)
1255 pCtxCore = CPUMCTX2CORE(pCtx);
1256 Assert(pCtxCore->eflags.Bits.u1VM || (pCtxCore->ss & X86_SEL_RPL));
1257 AssertMsg(pCtxCore->eflags.Bits.u1VM || pCtxCore->eflags.Bits.u2IOPL < (unsigned)(pCtxCore->ss & X86_SEL_RPL),
1258 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss & X86_SEL_RPL));
1259
1260 /*
1261 * Are we executing in raw ring-1?
1262 */
1263 if ( (pCtxCore->ss & X86_SEL_RPL) == 1
1264 && !pCtxCore->eflags.Bits.u1VM)
1265 {
1266 /*
1267 * Leave execution mode.
1268 */
1269 PATMRawLeave(pVM, pCtxCore, rc);
1270 /* Not quite sure if this is really required, but shouldn't harm (too much anyways). */
1271 /** @todo See what happens if we remove this. */
1272 if ((pCtxCore->ds & X86_SEL_RPL) == 1)
1273 pCtxCore->ds &= ~X86_SEL_RPL;
1274 if ((pCtxCore->es & X86_SEL_RPL) == 1)
1275 pCtxCore->es &= ~X86_SEL_RPL;
1276 if ((pCtxCore->fs & X86_SEL_RPL) == 1)
1277 pCtxCore->fs &= ~X86_SEL_RPL;
1278 if ((pCtxCore->gs & X86_SEL_RPL) == 1)
1279 pCtxCore->gs &= ~X86_SEL_RPL;
1280
1281 /*
1282 * Ring-1 selector => Ring-0.
1283 */
1284 pCtxCore->ss &= ~X86_SEL_RPL;
1285 if ((pCtxCore->cs & X86_SEL_RPL) == 1)
1286 pCtxCore->cs &= ~X86_SEL_RPL;
1287 }
1288 else
1289 {
1290 /*
1291 * PATM is taking care of the IOPL and IF flags for us.
1292 */
1293 PATMRawLeave(pVM, pCtxCore, rc);
1294 if (!pCtxCore->eflags.Bits.u1VM)
1295 {
1296 /** @todo See what happens if we remove this. */
1297 if ((pCtxCore->ds & X86_SEL_RPL) == 1)
1298 pCtxCore->ds &= ~X86_SEL_RPL;
1299 if ((pCtxCore->es & X86_SEL_RPL) == 1)
1300 pCtxCore->es &= ~X86_SEL_RPL;
1301 if ((pCtxCore->fs & X86_SEL_RPL) == 1)
1302 pCtxCore->fs &= ~X86_SEL_RPL;
1303 if ((pCtxCore->gs & X86_SEL_RPL) == 1)
1304 pCtxCore->gs &= ~X86_SEL_RPL;
1305 }
1306 }
1307
1308 return rc;
1309}
1310
1311/**
1312 * Updates the EFLAGS while we're in raw-mode.
1313 *
1314 * @param pVM The VM handle.
1315 * @param pCtxCore The context core.
1316 * @param eflags The new EFLAGS value.
1317 */
1318CPUMDECL(void) CPUMRawSetEFlags(PVM pVM, PCPUMCTXCORE pCtxCore, uint32_t eflags)
1319{
1320 if (!pVM->cpum.s.fRawEntered)
1321 {
1322 pCtxCore->eflags.u32 = eflags;
1323 return;
1324 }
1325 PATMRawSetEFlags(pVM, pCtxCore, eflags);
1326}
1327
1328#endif /* !IN_RING0 */
1329
1330/**
1331 * Gets the EFLAGS while we're in raw-mode.
1332 *
1333 * @returns The eflags.
1334 * @param pVM The VM handle.
1335 * @param pCtxCore The context core.
1336 */
1337CPUMDECL(uint32_t) CPUMRawGetEFlags(PVM pVM, PCPUMCTXCORE pCtxCore)
1338{
1339#ifdef IN_RING0
1340 return pCtxCore->eflags.u32;
1341#else
1342 if (!pVM->cpum.s.fRawEntered)
1343 return pCtxCore->eflags.u32;
1344 return PATMRawGetEFlags(pVM, pCtxCore);
1345#endif
1346}
1347
1348
1349
1350
1351/**
1352 * Gets and resets the changed flags (CPUM_CHANGED_*).
1353 * Only REM should call this function.
1354 *
1355 * @returns The changed flags.
1356 * @param pVM The VM handle.
1357 */
1358CPUMDECL(unsigned) CPUMGetAndClearChangedFlagsREM(PVM pVM)
1359{
1360 unsigned fFlags = pVM->cpum.s.fChanged;
1361 pVM->cpum.s.fChanged = 0;
1362 /** @todo change the switcher to use the fChanged flags. */
1363 if (pVM->cpum.s.fUseFlags & CPUM_USED_FPU_SINCE_REM)
1364 {
1365 fFlags |= CPUM_CHANGED_FPU_REM;
1366 pVM->cpum.s.fUseFlags &= ~CPUM_USED_FPU_SINCE_REM;
1367 }
1368 return fFlags;
1369}
1370
1371/**
1372 * Sets the specified changed flags (CPUM_CHANGED_*).
1373 *
1374 * @param pVM The VM handle.
1375 */
1376CPUMDECL(void) CPUMSetChangedFlags(PVM pVM, uint32_t fChangedFlags)
1377{
1378 pVM->cpum.s.fChanged |= fChangedFlags;
1379}
1380
1381/**
1382 * Checks if the CPU supports the FXSAVE and FXRSTOR instruction.
1383 * @returns true if supported.
1384 * @returns false if not supported.
1385 * @param pVM The VM handle.
1386 */
1387CPUMDECL(bool) CPUMSupportsFXSR(PVM pVM)
1388{
1389 return pVM->cpum.s.CPUFeatures.edx.u1FXSR != 0;
1390}
1391
1392
1393/**
1394 * Checks if the host OS uses the SYSENTER / SYSEXIT instructions.
1395 * @returns true if used.
1396 * @returns false if not used.
1397 * @param pVM The VM handle.
1398 */
1399CPUMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM)
1400{
1401 return (pVM->cpum.s.fUseFlags & CPUM_USE_SYSENTER) != 0;
1402}
1403
1404
1405/**
1406 * Checks if the host OS uses the SYSCALL / SYSRET instructions.
1407 * @returns true if used.
1408 * @returns false if not used.
1409 * @param pVM The VM handle.
1410 */
1411CPUMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM)
1412{
1413 return (pVM->cpum.s.fUseFlags & CPUM_USE_SYSCALL) != 0;
1414}
1415
1416/**
1417 * Lazily sync in the FPU/XMM state
1418 *
1419 * @returns VBox status code.
1420 * @param pVM VM handle.
1421 */
1422CPUMDECL(int) CPUMHandleLazyFPU(PVM pVM)
1423{
1424 return CPUMHandleLazyFPUAsm(&pVM->cpum.s);
1425}
1426
1427/**
1428 * Restore host FPU/XMM state
1429 *
1430 * @returns VBox status code.
1431 * @param pVM VM handle.
1432 */
1433CPUMDECL(int) CPUMRestoreHostFPUState(PVM pVM)
1434{
1435 Assert(pVM->cpum.s.CPUFeatures.edx.u1FXSR);
1436 return CPUMRestoreHostFPUStateAsm(&pVM->cpum.s);
1437}
1438
1439/**
1440 * Checks if we activated the FPU/XMM state of the guest OS
1441 * @returns true if we did.
1442 * @returns false if not.
1443 * @param pVM The VM handle.
1444 */
1445CPUMDECL(bool) CPUMIsGuestFPUStateActive(PVM pVM)
1446{
1447 return (pVM->cpum.s.fUseFlags & CPUM_USED_FPU) != 0;
1448}
1449
1450/**
1451 * Deactivate the FPU/XMM state of the guest OS
1452 * @param pVM The VM handle.
1453 */
1454CPUMDECL(void) CPUMDeactivateGuestFPUState(PVM pVM)
1455{
1456 pVM->cpum.s.fUseFlags &= ~CPUM_USED_FPU;
1457}
1458
1459/**
1460 * Checks if the hidden selector registers are valid
1461 * @returns true if they are.
1462 * @returns false if not.
1463 * @param pVM The VM handle.
1464 */
1465CPUMDECL(bool) CPUMAreHiddenSelRegsValid(PVM pVM)
1466{
1467 return !!pVM->cpum.s.fValidHiddenSelRegs; /** @todo change fValidHiddenSelRegs to bool! */
1468}
1469
1470/**
1471 * Checks if the hidden selector registers are valid
1472 * @param pVM The VM handle.
1473 * @param fValid Valid or not
1474 */
1475CPUMDECL(void) CPUMSetHiddenSelRegsValid(PVM pVM, bool fValid)
1476{
1477 pVM->cpum.s.fValidHiddenSelRegs = fValid;
1478}
1479
1480/**
1481 * Get the current privilege level of the guest.
1482 *
1483 * @returns cpl
1484 * @param pVM VM Handle.
1485 * @param pRegFrame Trap register frame.
1486 */
1487CPUMDECL(uint32_t) CPUMGetGuestCPL(PVM pVM, PCPUMCTXCORE pCtxCore)
1488{
1489 uint32_t cpl;
1490
1491 if (!pCtxCore->eflags.Bits.u1VM)
1492 {
1493 cpl = (pCtxCore->ss & X86_SEL_RPL);
1494#ifndef IN_RING0
1495 if (cpl == 1)
1496 cpl = 0;
1497#endif
1498 }
1499 else
1500 cpl = 3;
1501
1502 return cpl;
1503}
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