VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/SELMAll.cpp@ 62606

Last change on this file since 62606 was 62606, checked in by vboxsync, 9 years ago

VMM: Unused parameters.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 39.7 KB
Line 
1/* $Id: SELMAll.cpp 62606 2016-07-27 16:33:40Z vboxsync $ */
2/** @file
3 * SELM All contexts.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_SELM
23#include <VBox/vmm/selm.h>
24#include <VBox/vmm/stam.h>
25#include <VBox/vmm/em.h>
26#include <VBox/vmm/mm.h>
27#include <VBox/vmm/hm.h>
28#include <VBox/vmm/pgm.h>
29#include <VBox/vmm/hm.h>
30#include "SELMInternal.h"
31#include <VBox/vmm/vm.h>
32#include <VBox/err.h>
33#include <VBox/param.h>
34#include <iprt/assert.h>
35#include <VBox/vmm/vmm.h>
36#include <iprt/x86.h>
37#include <iprt/string.h>
38
39#include "SELMInline.h"
40
41
42/*********************************************************************************************************************************
43* Global Variables *
44*********************************************************************************************************************************/
45#if defined(LOG_ENABLED) && defined(VBOX_WITH_RAW_MODE_NOT_R0)
46/** Segment register names. */
47static char const g_aszSRegNms[X86_SREG_COUNT][4] = { "ES", "CS", "SS", "DS", "FS", "GS" };
48#endif
49
50
51#ifndef IN_RING0
52
53# ifdef SELM_TRACK_GUEST_GDT_CHANGES
54/**
55 * @callback_method_impl{FNPGMVIRTHANDLER}
56 */
57PGM_ALL_CB2_DECL(VBOXSTRICTRC)
58selmGuestGDTWriteHandler(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf,
59 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
60{
61 Assert(enmAccessType == PGMACCESSTYPE_WRITE); NOREF(enmAccessType);
62 Log(("selmGuestGDTWriteHandler: write to %RGv size %d\n", GCPtr, cbBuf)); NOREF(GCPtr); NOREF(cbBuf);
63 NOREF(pvPtr); NOREF(pvBuf); NOREF(enmOrigin); NOREF(pvUser);
64
65# ifdef IN_RING3
66 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_GDT);
67 return VINF_PGM_HANDLER_DO_DEFAULT;
68
69# else /* IN_RC: */
70 /*
71 * Execute the write, doing necessary pre and post shadow GDT checks.
72 */
73 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
74 uint32_t offGuestGdt = pCtx->gdtr.pGdt - GCPtr;
75 selmRCGuestGdtPreWriteCheck(pVM, pVCpu, offGuestGdt, cbBuf, pCtx);
76 memcpy(pvBuf, pvPtr, cbBuf);
77 VBOXSTRICTRC rcStrict = selmRCGuestGdtPostWriteCheck(pVM, pVCpu, offGuestGdt, cbBuf, pCtx);
78 if (!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_SELM_SYNC_GDT))
79 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestGDTHandled);
80 else
81 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestGDTUnhandled);
82 return rcStrict;
83# endif
84}
85# endif
86
87
88# ifdef SELM_TRACK_GUEST_LDT_CHANGES
89/**
90 * @callback_method_impl{FNPGMVIRTHANDLER}
91 */
92PGM_ALL_CB2_DECL(VBOXSTRICTRC)
93selmGuestLDTWriteHandler(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf,
94 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
95{
96 Assert(enmAccessType == PGMACCESSTYPE_WRITE); NOREF(enmAccessType);
97 Log(("selmGuestLDTWriteHandler: write to %RGv size %d\n", GCPtr, cbBuf)); NOREF(GCPtr); NOREF(cbBuf);
98 NOREF(pvPtr); NOREF(pvBuf); NOREF(enmOrigin); NOREF(pvUser); RT_NOREF_PV(pVM);
99
100 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_LDT);
101# ifdef IN_RING3
102 return VINF_PGM_HANDLER_DO_DEFAULT;
103# else
104 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestLDT);
105 return VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT;
106# endif
107}
108# endif
109
110
111# ifdef SELM_TRACK_GUEST_TSS_CHANGES
112/**
113 * @callback_method_impl{FNPGMVIRTHANDLER}
114 */
115PGM_ALL_CB2_DECL(VBOXSTRICTRC)
116selmGuestTSSWriteHandler(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf,
117 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
118{
119 Assert(enmAccessType == PGMACCESSTYPE_WRITE); NOREF(enmAccessType);
120 Log(("selmGuestTSSWriteHandler: write %.*Rhxs to %RGv size %d\n", RT_MIN(8, cbBuf), pvBuf, GCPtr, cbBuf));
121 NOREF(pvBuf); NOREF(GCPtr); NOREF(cbBuf); NOREF(enmOrigin); NOREF(pvUser); NOREF(pvPtr);
122
123# ifdef IN_RING3
124 /** @todo This can be optimized by checking for the ESP0 offset and tracking TR
125 * reloads in REM (setting VM_FF_SELM_SYNC_TSS if TR is reloaded). We
126 * should probably also deregister the virtual handler if TR.base/size
127 * changes while we're in REM. May also share
128 * selmRCGuestTssPostWriteCheck code. */
129 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);
130 return VINF_PGM_HANDLER_DO_DEFAULT;
131
132# else /* IN_RC */
133 /*
134 * Do the write and check if anything relevant changed.
135 */
136 Assert(pVM->selm.s.GCPtrGuestTss != (uintptr_t)RTRCPTR_MAX);
137 memcpy(pvPtr, pvBuf, cbBuf);
138 return selmRCGuestTssPostWriteCheck(pVM, pVCpu, GCPtr - pVM->selm.s.GCPtrGuestTss, cbBuf);
139# endif
140}
141# endif
142
143#endif /* IN_RING0 */
144
145
146#ifdef VBOX_WITH_RAW_MODE_NOT_R0
147/**
148 * Converts a GC selector based address to a flat address.
149 *
150 * No limit checks are done. Use the SELMToFlat*() or SELMValidate*() functions
151 * for that.
152 *
153 * @returns Flat address.
154 * @param pVM The cross context VM structure.
155 * @param Sel Selector part.
156 * @param Addr Address part.
157 * @remarks Don't use when in long mode.
158 */
159VMMDECL(RTGCPTR) SELMToFlatBySel(PVM pVM, RTSEL Sel, RTGCPTR Addr)
160{
161 Assert(pVM->cCpus == 1 && !CPUMIsGuestInLongMode(VMMGetCpu(pVM))); /* DON'T USE! */
162 Assert(!HMIsEnabled(pVM));
163
164 /** @todo check the limit. */
165 X86DESC Desc;
166 if (!(Sel & X86_SEL_LDT))
167 Desc = pVM->selm.s.CTX_SUFF(paGdt)[Sel >> X86_SEL_SHIFT];
168 else
169 {
170 /** @todo handle LDT pages not present! */
171 PX86DESC paLDT = (PX86DESC)((char *)pVM->selm.s.CTX_SUFF(pvLdt) + pVM->selm.s.offLdtHyper);
172 Desc = paLDT[Sel >> X86_SEL_SHIFT];
173 }
174
175 return (RTGCPTR)(((RTGCUINTPTR)Addr + X86DESC_BASE(&Desc)) & 0xffffffff);
176}
177#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
178
179
180/**
181 * Converts a GC selector based address to a flat address.
182 *
183 * No limit checks are done. Use the SELMToFlat*() or SELMValidate*() functions
184 * for that.
185 *
186 * @returns Flat address.
187 * @param pVM The cross context VM structure.
188 * @param SelReg Selector register
189 * @param pCtxCore CPU context
190 * @param Addr Address part.
191 */
192VMMDECL(RTGCPTR) SELMToFlat(PVM pVM, DISSELREG SelReg, PCPUMCTXCORE pCtxCore, RTGCPTR Addr)
193{
194 PCPUMSELREG pSReg;
195 PVMCPU pVCpu = VMMGetCpu(pVM);
196
197 int rc = DISFetchRegSegEx(pCtxCore, SelReg, &pSReg); AssertRC(rc);
198
199 /*
200 * Deal with real & v86 mode first.
201 */
202 if ( pCtxCore->eflags.Bits.u1VM
203 || CPUMIsGuestInRealMode(pVCpu))
204 {
205 uint32_t uFlat = (uint32_t)Addr & 0xffff;
206 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
207 uFlat += (uint32_t)pSReg->u64Base;
208 else
209 uFlat += (uint32_t)pSReg->Sel << 4;
210 return (RTGCPTR)uFlat;
211 }
212
213#ifdef VBOX_WITH_RAW_MODE_NOT_R0
214 /** @todo when we're in 16 bits mode, we should cut off the address as well?? */
215 if (!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
216 CPUMGuestLazyLoadHiddenSelectorReg(pVCpu, pSReg);
217 if (!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pCtxCore->cs))
218 CPUMGuestLazyLoadHiddenSelectorReg(pVCpu, &pCtxCore->cs);
219#else
220 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
221 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pCtxCore->cs));
222#endif
223
224 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
225 (Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
226 if ( pCtxCore->cs.Attr.n.u1Long
227 && CPUMIsGuestInLongMode(pVCpu))
228 {
229 switch (SelReg)
230 {
231 case DISSELREG_FS:
232 case DISSELREG_GS:
233 return (RTGCPTR)(pSReg->u64Base + Addr);
234
235 default:
236 return Addr; /* base 0 */
237 }
238 }
239
240 /* AMD64 manual: compatibility mode ignores the high 32 bits when calculating an effective address. */
241 Assert(pSReg->u64Base <= 0xffffffff);
242 return (uint32_t)pSReg->u64Base + (uint32_t)Addr;
243}
244
245
246/**
247 * Converts a GC selector based address to a flat address.
248 *
249 * Some basic checking is done, but not all kinds yet.
250 *
251 * @returns VBox status
252 * @param pVCpu The cross context virtual CPU structure.
253 * @param SelReg Selector register.
254 * @param pCtxCore CPU context.
255 * @param Addr Address part.
256 * @param fFlags SELMTOFLAT_FLAGS_*
257 * GDT entires are valid.
258 * @param ppvGC Where to store the GC flat address.
259 */
260VMMDECL(int) SELMToFlatEx(PVMCPU pVCpu, DISSELREG SelReg, PCPUMCTXCORE pCtxCore, RTGCPTR Addr, uint32_t fFlags, PRTGCPTR ppvGC)
261{
262 /*
263 * Fetch the selector first.
264 */
265 PCPUMSELREG pSReg;
266 int rc = DISFetchRegSegEx(pCtxCore, SelReg, &pSReg);
267 AssertRCReturn(rc, rc); AssertPtr(pSReg);
268
269 /*
270 * Deal with real & v86 mode first.
271 */
272 if ( pCtxCore->eflags.Bits.u1VM
273 || CPUMIsGuestInRealMode(pVCpu))
274 {
275 if (ppvGC)
276 {
277 uint32_t uFlat = (uint32_t)Addr & 0xffff;
278 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
279 *ppvGC = (uint32_t)pSReg->u64Base + uFlat;
280 else
281 *ppvGC = ((uint32_t)pSReg->Sel << 4) + uFlat;
282 }
283 return VINF_SUCCESS;
284 }
285
286#ifdef VBOX_WITH_RAW_MODE_NOT_R0
287 if (!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
288 CPUMGuestLazyLoadHiddenSelectorReg(pVCpu, pSReg);
289 if (!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pCtxCore->cs))
290 CPUMGuestLazyLoadHiddenSelectorReg(pVCpu, &pCtxCore->cs);
291#else
292 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
293 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pCtxCore->cs));
294#endif
295
296 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
297 (Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
298 RTGCPTR pvFlat;
299 bool fCheckLimit = true;
300 if ( pCtxCore->cs.Attr.n.u1Long
301 && CPUMIsGuestInLongMode(pVCpu))
302 {
303 fCheckLimit = false;
304 switch (SelReg)
305 {
306 case DISSELREG_FS:
307 case DISSELREG_GS:
308 pvFlat = pSReg->u64Base + Addr;
309 break;
310
311 default:
312 pvFlat = Addr;
313 break;
314 }
315 }
316 else
317 {
318 /* AMD64 manual: compatibility mode ignores the high 32 bits when calculating an effective address. */
319 Assert(pSReg->u64Base <= UINT32_C(0xffffffff));
320 pvFlat = (uint32_t)pSReg->u64Base + (uint32_t)Addr;
321 Assert(pvFlat <= UINT32_MAX);
322 }
323
324 /*
325 * Check type if present.
326 */
327 if (pSReg->Attr.n.u1Present)
328 {
329 switch (pSReg->Attr.n.u4Type)
330 {
331 /* Read only selector type. */
332 case X86_SEL_TYPE_RO:
333 case X86_SEL_TYPE_RO_ACC:
334 case X86_SEL_TYPE_RW:
335 case X86_SEL_TYPE_RW_ACC:
336 case X86_SEL_TYPE_EO:
337 case X86_SEL_TYPE_EO_ACC:
338 case X86_SEL_TYPE_ER:
339 case X86_SEL_TYPE_ER_ACC:
340 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
341 {
342 /** @todo fix this mess */
343 }
344 /* check limit. */
345 if (fCheckLimit && Addr > pSReg->u32Limit)
346 return VERR_OUT_OF_SELECTOR_BOUNDS;
347 /* ok */
348 if (ppvGC)
349 *ppvGC = pvFlat;
350 return VINF_SUCCESS;
351
352 case X86_SEL_TYPE_EO_CONF:
353 case X86_SEL_TYPE_EO_CONF_ACC:
354 case X86_SEL_TYPE_ER_CONF:
355 case X86_SEL_TYPE_ER_CONF_ACC:
356 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
357 {
358 /** @todo fix this mess */
359 }
360 /* check limit. */
361 if (fCheckLimit && Addr > pSReg->u32Limit)
362 return VERR_OUT_OF_SELECTOR_BOUNDS;
363 /* ok */
364 if (ppvGC)
365 *ppvGC = pvFlat;
366 return VINF_SUCCESS;
367
368 case X86_SEL_TYPE_RO_DOWN:
369 case X86_SEL_TYPE_RO_DOWN_ACC:
370 case X86_SEL_TYPE_RW_DOWN:
371 case X86_SEL_TYPE_RW_DOWN_ACC:
372 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
373 {
374 /** @todo fix this mess */
375 }
376 /* check limit. */
377 if (fCheckLimit)
378 {
379 if (!pSReg->Attr.n.u1Granularity && Addr > UINT32_C(0xffff))
380 return VERR_OUT_OF_SELECTOR_BOUNDS;
381 if (Addr <= pSReg->u32Limit)
382 return VERR_OUT_OF_SELECTOR_BOUNDS;
383 }
384 /* ok */
385 if (ppvGC)
386 *ppvGC = pvFlat;
387 return VINF_SUCCESS;
388
389 default:
390 return VERR_INVALID_SELECTOR;
391
392 }
393 }
394 return VERR_SELECTOR_NOT_PRESENT;
395}
396
397
398#ifdef VBOX_WITH_RAW_MODE_NOT_R0
399/**
400 * Converts a GC selector based address to a flat address.
401 *
402 * Some basic checking is done, but not all kinds yet.
403 *
404 * @returns VBox status
405 * @param pVCpu The cross context virtual CPU structure.
406 * @param eflags Current eflags
407 * @param Sel Selector part.
408 * @param Addr Address part.
409 * @param fFlags SELMTOFLAT_FLAGS_*
410 * GDT entires are valid.
411 * @param ppvGC Where to store the GC flat address.
412 * @param pcb Where to store the bytes from *ppvGC which can be accessed according to
413 * the selector. NULL is allowed.
414 * @remarks Don't use when in long mode.
415 */
416VMMDECL(int) SELMToFlatBySelEx(PVMCPU pVCpu, X86EFLAGS eflags, RTSEL Sel, RTGCPTR Addr,
417 uint32_t fFlags, PRTGCPTR ppvGC, uint32_t *pcb)
418{
419 Assert(!CPUMIsGuestInLongMode(pVCpu)); /* DON'T USE! (Accessing shadow GDT/LDT.) */
420 Assert(!HMIsEnabled(pVCpu->CTX_SUFF(pVM)));
421
422 /*
423 * Deal with real & v86 mode first.
424 */
425 if ( eflags.Bits.u1VM
426 || CPUMIsGuestInRealMode(pVCpu))
427 {
428 RTGCUINTPTR uFlat = (RTGCUINTPTR)Addr & 0xffff;
429 if (ppvGC)
430 *ppvGC = ((RTGCUINTPTR)Sel << 4) + uFlat;
431 if (pcb)
432 *pcb = 0x10000 - uFlat;
433 return VINF_SUCCESS;
434 }
435
436 /** @todo when we're in 16 bits mode, we should cut off the address as well?? */
437 X86DESC Desc;
438 PVM pVM = pVCpu->CTX_SUFF(pVM);
439 if (!(Sel & X86_SEL_LDT))
440 {
441 if ( !(fFlags & SELMTOFLAT_FLAGS_HYPER)
442 && (Sel | X86_SEL_RPL_LDT) > pVM->selm.s.GuestGdtr.cbGdt)
443 return VERR_INVALID_SELECTOR;
444 Desc = pVM->selm.s.CTX_SUFF(paGdt)[Sel >> X86_SEL_SHIFT];
445 }
446 else
447 {
448 if ((Sel | X86_SEL_RPL_LDT) > pVM->selm.s.cbLdtLimit)
449 return VERR_INVALID_SELECTOR;
450
451 /** @todo handle LDT page(s) not present! */
452 PX86DESC paLDT = (PX86DESC)((char *)pVM->selm.s.CTX_SUFF(pvLdt) + pVM->selm.s.offLdtHyper);
453 Desc = paLDT[Sel >> X86_SEL_SHIFT];
454 }
455
456 /* calc limit. */
457 uint32_t u32Limit = X86DESC_LIMIT_G(&Desc);
458
459 /* calc address assuming straight stuff. */
460 RTGCPTR pvFlat = Addr + X86DESC_BASE(&Desc);
461
462 /* Cut the address to 32 bits. */
463 Assert(!CPUMIsGuestInLongMode(pVCpu));
464 pvFlat &= 0xffffffff;
465
466 uint8_t u1Present = Desc.Gen.u1Present;
467 uint8_t u1Granularity = Desc.Gen.u1Granularity;
468 uint8_t u1DescType = Desc.Gen.u1DescType;
469 uint8_t u4Type = Desc.Gen.u4Type;
470
471 /*
472 * Check if present.
473 */
474 if (u1Present)
475 {
476 /*
477 * Type check.
478 */
479#define BOTH(a, b) ((a << 16) | b)
480 switch (BOTH(u1DescType, u4Type))
481 {
482
483 /** Read only selector type. */
484 case BOTH(1,X86_SEL_TYPE_RO):
485 case BOTH(1,X86_SEL_TYPE_RO_ACC):
486 case BOTH(1,X86_SEL_TYPE_RW):
487 case BOTH(1,X86_SEL_TYPE_RW_ACC):
488 case BOTH(1,X86_SEL_TYPE_EO):
489 case BOTH(1,X86_SEL_TYPE_EO_ACC):
490 case BOTH(1,X86_SEL_TYPE_ER):
491 case BOTH(1,X86_SEL_TYPE_ER_ACC):
492 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
493 {
494 /** @todo fix this mess */
495 }
496 /* check limit. */
497 if ((RTGCUINTPTR)Addr > u32Limit)
498 return VERR_OUT_OF_SELECTOR_BOUNDS;
499 /* ok */
500 if (ppvGC)
501 *ppvGC = pvFlat;
502 if (pcb)
503 *pcb = u32Limit - (uint32_t)Addr + 1;
504 return VINF_SUCCESS;
505
506 case BOTH(1,X86_SEL_TYPE_EO_CONF):
507 case BOTH(1,X86_SEL_TYPE_EO_CONF_ACC):
508 case BOTH(1,X86_SEL_TYPE_ER_CONF):
509 case BOTH(1,X86_SEL_TYPE_ER_CONF_ACC):
510 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
511 {
512 /** @todo fix this mess */
513 }
514 /* check limit. */
515 if ((RTGCUINTPTR)Addr > u32Limit)
516 return VERR_OUT_OF_SELECTOR_BOUNDS;
517 /* ok */
518 if (ppvGC)
519 *ppvGC = pvFlat;
520 if (pcb)
521 *pcb = u32Limit - (uint32_t)Addr + 1;
522 return VINF_SUCCESS;
523
524 case BOTH(1,X86_SEL_TYPE_RO_DOWN):
525 case BOTH(1,X86_SEL_TYPE_RO_DOWN_ACC):
526 case BOTH(1,X86_SEL_TYPE_RW_DOWN):
527 case BOTH(1,X86_SEL_TYPE_RW_DOWN_ACC):
528 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
529 {
530 /** @todo fix this mess */
531 }
532 /* check limit. */
533 if (!u1Granularity && (RTGCUINTPTR)Addr > (RTGCUINTPTR)0xffff)
534 return VERR_OUT_OF_SELECTOR_BOUNDS;
535 if ((RTGCUINTPTR)Addr <= u32Limit)
536 return VERR_OUT_OF_SELECTOR_BOUNDS;
537
538 /* ok */
539 if (ppvGC)
540 *ppvGC = pvFlat;
541 if (pcb)
542 *pcb = (RTGCUINTPTR)(u1Granularity ? 0xffffffff : 0xffff) - (RTGCUINTPTR)Addr + 1;
543 return VINF_SUCCESS;
544
545 case BOTH(0,X86_SEL_TYPE_SYS_286_TSS_AVAIL):
546 case BOTH(0,X86_SEL_TYPE_SYS_LDT):
547 case BOTH(0,X86_SEL_TYPE_SYS_286_TSS_BUSY):
548 case BOTH(0,X86_SEL_TYPE_SYS_286_CALL_GATE):
549 case BOTH(0,X86_SEL_TYPE_SYS_TASK_GATE):
550 case BOTH(0,X86_SEL_TYPE_SYS_286_INT_GATE):
551 case BOTH(0,X86_SEL_TYPE_SYS_286_TRAP_GATE):
552 case BOTH(0,X86_SEL_TYPE_SYS_386_TSS_AVAIL):
553 case BOTH(0,X86_SEL_TYPE_SYS_386_TSS_BUSY):
554 case BOTH(0,X86_SEL_TYPE_SYS_386_CALL_GATE):
555 case BOTH(0,X86_SEL_TYPE_SYS_386_INT_GATE):
556 case BOTH(0,X86_SEL_TYPE_SYS_386_TRAP_GATE):
557 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
558 {
559 /** @todo fix this mess */
560 }
561 /* check limit. */
562 if ((RTGCUINTPTR)Addr > u32Limit)
563 return VERR_OUT_OF_SELECTOR_BOUNDS;
564 /* ok */
565 if (ppvGC)
566 *ppvGC = pvFlat;
567 if (pcb)
568 *pcb = 0xffffffff - (RTGCUINTPTR)pvFlat + 1; /* Depends on the type.. fixme if we care. */
569 return VINF_SUCCESS;
570
571 default:
572 return VERR_INVALID_SELECTOR;
573
574 }
575#undef BOTH
576 }
577 return VERR_SELECTOR_NOT_PRESENT;
578}
579#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
580
581
582#ifdef VBOX_WITH_RAW_MODE_NOT_R0
583
584static void selLoadHiddenSelectorRegFromGuestTable(PVMCPU pVCpu, PCCPUMCTX pCtx, PCPUMSELREG pSReg,
585 RTGCPTR GCPtrDesc, RTSEL const Sel, uint32_t const iSReg)
586{
587 Assert(!HMIsEnabled(pVCpu->CTX_SUFF(pVM)));
588 RT_NOREF_PV(pCtx); RT_NOREF_PV(Sel);
589
590 /*
591 * Try read the entry.
592 */
593 X86DESC GstDesc;
594 VBOXSTRICTRC rcStrict = PGMPhysReadGCPtr(pVCpu, &GstDesc, GCPtrDesc, sizeof(GstDesc), PGMACCESSORIGIN_SELM);
595 if (rcStrict == VINF_SUCCESS)
596 {
597 /*
598 * Validate it and load it.
599 */
600 if (selmIsGstDescGoodForSReg(pVCpu, pSReg, &GstDesc, iSReg, CPUMGetGuestCPL(pVCpu)))
601 {
602 selmLoadHiddenSRegFromGuestDesc(pVCpu, pSReg, &GstDesc);
603 Log(("SELMLoadHiddenSelectorReg: loaded %s=%#x:{b=%llx, l=%x, a=%x, vs=%x} (gst)\n",
604 g_aszSRegNms[iSReg], Sel, pSReg->u64Base, pSReg->u32Limit, pSReg->Attr.u, pSReg->ValidSel));
605 STAM_COUNTER_INC(&pVCpu->CTX_SUFF(pVM)->selm.s.StatLoadHidSelGst);
606 }
607 else
608 {
609 Log(("SELMLoadHiddenSelectorReg: Guest table entry is no good (%s=%#x): %.8Rhxs\n", g_aszSRegNms[iSReg], Sel, &GstDesc));
610 STAM_REL_COUNTER_INC(&pVCpu->CTX_SUFF(pVM)->selm.s.StatLoadHidSelGstNoGood);
611 }
612 }
613 else
614 {
615 AssertMsg(RT_FAILURE_NP(rcStrict), ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
616 Log(("SELMLoadHiddenSelectorReg: Error reading descriptor %s=%#x: %Rrc\n",
617 g_aszSRegNms[iSReg], Sel, VBOXSTRICTRC_VAL(rcStrict) ));
618 STAM_REL_COUNTER_INC(&pVCpu->CTX_SUFF(pVM)->selm.s.StatLoadHidSelReadErrors);
619 }
620}
621
622
623/**
624 * CPUM helper that loads the hidden selector register from the descriptor table
625 * when executing with raw-mode.
626 *
627 * @remarks This is only used when in legacy protected mode!
628 *
629 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
630 * @param pCtx The guest CPU context.
631 * @param pSReg The selector register.
632 *
633 * @todo Deal 100% correctly with stale selectors. What's more evil is
634 * invalid page table entries, which isn't impossible to imagine for
635 * LDT entries for instance, though unlikely. Currently, we turn a
636 * blind eye to these issues and return the old hidden registers,
637 * though we don't set the valid flag, so that we'll try loading them
638 * over and over again till we succeed loading something.
639 */
640VMM_INT_DECL(void) SELMLoadHiddenSelectorReg(PVMCPU pVCpu, PCCPUMCTX pCtx, PCPUMSELREG pSReg)
641{
642 Assert(pCtx->cr0 & X86_CR0_PE);
643 Assert(!(pCtx->msrEFER & MSR_K6_EFER_LMA));
644
645 PVM pVM = pVCpu->CTX_SUFF(pVM);
646 Assert(pVM->cCpus == 1);
647 Assert(!HMIsEnabled(pVM));
648
649
650 /*
651 * Get the shadow descriptor table entry and validate it.
652 * Should something go amiss, try the guest table.
653 */
654 RTSEL const Sel = pSReg->Sel;
655 uint32_t const iSReg = pSReg - CPUMCTX_FIRST_SREG(pCtx); Assert(iSReg < X86_SREG_COUNT);
656 PCX86DESC pShwDesc;
657 if (!(Sel & X86_SEL_LDT))
658 {
659 /** @todo this shall not happen, we shall check for these things when executing
660 * LGDT */
661 AssertReturnVoid((Sel | X86_SEL_RPL | X86_SEL_LDT) <= pCtx->gdtr.cbGdt);
662
663 pShwDesc = &pVM->selm.s.CTX_SUFF(paGdt)[Sel >> X86_SEL_SHIFT];
664 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_SELM_SYNC_GDT)
665 || !selmIsShwDescGoodForSReg(pSReg, pShwDesc, iSReg, CPUMGetGuestCPL(pVCpu)))
666 {
667 selLoadHiddenSelectorRegFromGuestTable(pVCpu, pCtx, pSReg, pCtx->gdtr.pGdt + (Sel & X86_SEL_MASK), Sel, iSReg);
668 return;
669 }
670 }
671 else
672 {
673 /** @todo this shall not happen, we shall check for these things when executing
674 * LLDT */
675 AssertReturnVoid((Sel | X86_SEL_RPL | X86_SEL_LDT) <= pCtx->ldtr.u32Limit);
676
677 pShwDesc = (PCX86DESC)((uintptr_t)pVM->selm.s.CTX_SUFF(pvLdt) + pVM->selm.s.offLdtHyper + (Sel & X86_SEL_MASK));
678 if ( VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_SELM_SYNC_LDT)
679 || !selmIsShwDescGoodForSReg(pSReg, pShwDesc, iSReg, CPUMGetGuestCPL(pVCpu)))
680 {
681 selLoadHiddenSelectorRegFromGuestTable(pVCpu, pCtx, pSReg, pCtx->ldtr.u64Base + (Sel & X86_SEL_MASK), Sel, iSReg);
682 return;
683 }
684 }
685
686 /*
687 * All fine, load it.
688 */
689 selmLoadHiddenSRegFromShadowDesc(pSReg, pShwDesc);
690 STAM_COUNTER_INC(&pVCpu->CTX_SUFF(pVM)->selm.s.StatLoadHidSelShw);
691 Log(("SELMLoadHiddenSelectorReg: loaded %s=%#x:{b=%llx, l=%x, a=%x, vs=%x} (shw)\n",
692 g_aszSRegNms[iSReg], Sel, pSReg->u64Base, pSReg->u32Limit, pSReg->Attr.u, pSReg->ValidSel));
693}
694
695#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
696
697/**
698 * Validates and converts a GC selector based code address to a flat
699 * address when in real or v8086 mode.
700 *
701 * @returns VINF_SUCCESS.
702 * @param pVCpu The cross context virtual CPU structure.
703 * @param SelCS Selector part.
704 * @param pSReg The hidden CS register part. Optional.
705 * @param Addr Address part.
706 * @param ppvFlat Where to store the flat address.
707 */
708DECLINLINE(int) selmValidateAndConvertCSAddrRealMode(PVMCPU pVCpu, RTSEL SelCS, PCCPUMSELREGHID pSReg, RTGCPTR Addr,
709 PRTGCPTR ppvFlat)
710{
711 NOREF(pVCpu);
712 uint32_t uFlat = Addr & 0xffff;
713 if (!pSReg || !CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
714 uFlat += (uint32_t)SelCS << 4;
715 else
716 uFlat += (uint32_t)pSReg->u64Base;
717 *ppvFlat = uFlat;
718 return VINF_SUCCESS;
719}
720
721
722#ifdef VBOX_WITH_RAW_MODE_NOT_R0
723/**
724 * Validates and converts a GC selector based code address to a flat address
725 * when in protected/long mode using the raw-mode algorithm.
726 *
727 * @returns VBox status code.
728 * @param pVM The cross context VM structure.
729 * @param pVCpu The cross context virtual CPU structure.
730 * @param SelCPL Current privilege level. Get this from SS - CS might be
731 * conforming! A full selector can be passed, we'll only
732 * use the RPL part.
733 * @param SelCS Selector part.
734 * @param Addr Address part.
735 * @param ppvFlat Where to store the flat address.
736 * @param pcBits Where to store the segment bitness (16/32/64). Optional.
737 */
738DECLINLINE(int) selmValidateAndConvertCSAddrRawMode(PVM pVM, PVMCPU pVCpu, RTSEL SelCPL, RTSEL SelCS, RTGCPTR Addr,
739 PRTGCPTR ppvFlat, uint32_t *pcBits)
740{
741 NOREF(pVCpu);
742 Assert(!HMIsEnabled(pVM));
743
744 /** @todo validate limit! */
745 X86DESC Desc;
746 if (!(SelCS & X86_SEL_LDT))
747 Desc = pVM->selm.s.CTX_SUFF(paGdt)[SelCS >> X86_SEL_SHIFT];
748 else
749 {
750 /** @todo handle LDT page(s) not present! */
751 PX86DESC paLDT = (PX86DESC)((char *)pVM->selm.s.CTX_SUFF(pvLdt) + pVM->selm.s.offLdtHyper);
752 Desc = paLDT[SelCS >> X86_SEL_SHIFT];
753 }
754
755 /*
756 * Check if present.
757 */
758 if (Desc.Gen.u1Present)
759 {
760 /*
761 * Type check.
762 */
763 if ( Desc.Gen.u1DescType == 1
764 && (Desc.Gen.u4Type & X86_SEL_TYPE_CODE))
765 {
766 /*
767 * Check level.
768 */
769 unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, SelCS & X86_SEL_RPL);
770 if ( !(Desc.Gen.u4Type & X86_SEL_TYPE_CONF)
771 ? uLevel <= Desc.Gen.u2Dpl
772 : uLevel >= Desc.Gen.u2Dpl /* hope I got this right now... */
773 )
774 {
775 /*
776 * Limit check.
777 */
778 uint32_t u32Limit = X86DESC_LIMIT_G(&Desc);
779 if ((RTGCUINTPTR)Addr <= u32Limit)
780 {
781 *ppvFlat = (RTGCPTR)((RTGCUINTPTR)Addr + X86DESC_BASE(&Desc));
782 /* Cut the address to 32 bits. */
783 *ppvFlat &= 0xffffffff;
784
785 if (pcBits)
786 *pcBits = Desc.Gen.u1DefBig ? 32 : 16; /** @todo GUEST64 */
787 return VINF_SUCCESS;
788 }
789 return VERR_OUT_OF_SELECTOR_BOUNDS;
790 }
791 return VERR_INVALID_RPL;
792 }
793 return VERR_NOT_CODE_SELECTOR;
794 }
795 return VERR_SELECTOR_NOT_PRESENT;
796}
797#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
798
799
800/**
801 * Validates and converts a GC selector based code address to a flat address
802 * when in protected/long mode using the standard hidden selector registers
803 *
804 * @returns VBox status code.
805 * @param pVCpu The cross context virtual CPU structure.
806 * @param SelCPL Current privilege level. Get this from SS - CS might be
807 * conforming! A full selector can be passed, we'll only
808 * use the RPL part.
809 * @param SelCS Selector part.
810 * @param pSRegCS The full CS selector register.
811 * @param Addr The address (think IP/EIP/RIP).
812 * @param ppvFlat Where to store the flat address upon successful return.
813 */
814DECLINLINE(int) selmValidateAndConvertCSAddrHidden(PVMCPU pVCpu, RTSEL SelCPL, RTSEL SelCS, PCCPUMSELREGHID pSRegCS,
815 RTGCPTR Addr, PRTGCPTR ppvFlat)
816{
817 NOREF(SelCPL); NOREF(SelCS);
818
819 /*
820 * Check if present.
821 */
822 if (pSRegCS->Attr.n.u1Present)
823 {
824 /*
825 * Type check.
826 */
827 if ( pSRegCS->Attr.n.u1DescType == 1
828 && (pSRegCS->Attr.n.u4Type & X86_SEL_TYPE_CODE))
829 {
830 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
831 (Intel® 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
832 if ( pSRegCS->Attr.n.u1Long
833 && CPUMIsGuestInLongMode(pVCpu))
834 {
835 *ppvFlat = Addr;
836 return VINF_SUCCESS;
837 }
838
839 /*
840 * Limit check. Note that the limit in the hidden register is the
841 * final value. The granularity bit was included in its calculation.
842 */
843 uint32_t u32Limit = pSRegCS->u32Limit;
844 if ((uint32_t)Addr <= u32Limit)
845 {
846 *ppvFlat = (uint32_t)Addr + (uint32_t)pSRegCS->u64Base;
847 return VINF_SUCCESS;
848 }
849
850 return VERR_OUT_OF_SELECTOR_BOUNDS;
851 }
852 return VERR_NOT_CODE_SELECTOR;
853 }
854 return VERR_SELECTOR_NOT_PRESENT;
855}
856
857
858/**
859 * Validates and converts a GC selector based code address to a flat address.
860 *
861 * @returns VBox status code.
862 * @param pVCpu The cross context virtual CPU structure.
863 * @param Efl Current EFLAGS.
864 * @param SelCPL Current privilege level. Get this from SS - CS might be
865 * conforming! A full selector can be passed, we'll only
866 * use the RPL part.
867 * @param SelCS Selector part.
868 * @param pSRegCS The full CS selector register.
869 * @param Addr The address (think IP/EIP/RIP).
870 * @param ppvFlat Where to store the flat address upon successful return.
871 */
872VMMDECL(int) SELMValidateAndConvertCSAddr(PVMCPU pVCpu, X86EFLAGS Efl, RTSEL SelCPL, RTSEL SelCS, PCPUMSELREG pSRegCS,
873 RTGCPTR Addr, PRTGCPTR ppvFlat)
874{
875 if ( Efl.Bits.u1VM
876 || CPUMIsGuestInRealMode(pVCpu))
877 return selmValidateAndConvertCSAddrRealMode(pVCpu, SelCS, pSRegCS, Addr, ppvFlat);
878
879#ifdef VBOX_WITH_RAW_MODE_NOT_R0
880 /* Use the hidden registers when possible, updating them if outdate. */
881 if (!pSRegCS)
882 return selmValidateAndConvertCSAddrRawMode(pVCpu->CTX_SUFF(pVM), pVCpu, SelCPL, SelCS, Addr, ppvFlat, NULL);
883
884 if (!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSRegCS))
885 CPUMGuestLazyLoadHiddenSelectorReg(pVCpu, pSRegCS);
886
887 /* Undo ring compression. */
888 if ((SelCPL & X86_SEL_RPL) == 1 && !HMIsEnabled(pVCpu->CTX_SUFF(pVM)))
889 SelCPL &= ~X86_SEL_RPL;
890 Assert(pSRegCS->Sel == SelCS);
891 if ((SelCS & X86_SEL_RPL) == 1 && !HMIsEnabled(pVCpu->CTX_SUFF(pVM)))
892 SelCS &= ~X86_SEL_RPL;
893#else
894 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSRegCS));
895 Assert(pSRegCS->Sel == SelCS);
896#endif
897
898 return selmValidateAndConvertCSAddrHidden(pVCpu, SelCPL, SelCS, pSRegCS, Addr, ppvFlat);
899}
900
901
902/**
903 * Returns Hypervisor's Trap 08 (\#DF) selector.
904 *
905 * @returns Hypervisor's Trap 08 (\#DF) selector.
906 * @param pVM The cross context VM structure.
907 */
908VMMDECL(RTSEL) SELMGetTrap8Selector(PVM pVM)
909{
910 return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08];
911}
912
913
914/**
915 * Sets EIP of Hypervisor's Trap 08 (\#DF) TSS.
916 *
917 * @param pVM The cross context VM structure.
918 * @param u32EIP EIP of Trap 08 handler.
919 */
920VMMDECL(void) SELMSetTrap8EIP(PVM pVM, uint32_t u32EIP)
921{
922 pVM->selm.s.TssTrap08.eip = u32EIP;
923}
924
925
926/**
927 * Sets ss:esp for ring1 in main Hypervisor's TSS.
928 *
929 * @param pVM The cross context VM structure.
930 * @param ss Ring1 SS register value. Pass 0 if invalid.
931 * @param esp Ring1 ESP register value.
932 */
933void selmSetRing1Stack(PVM pVM, uint32_t ss, RTGCPTR32 esp)
934{
935 Assert(!HMIsEnabled(pVM));
936 Assert((ss & 1) || esp == 0);
937 pVM->selm.s.Tss.ss1 = ss;
938 pVM->selm.s.Tss.esp1 = (uint32_t)esp;
939}
940
941
942#ifdef VBOX_WITH_RAW_RING1
943/**
944 * Sets ss:esp for ring1 in main Hypervisor's TSS.
945 *
946 * @param pVM The cross context VM structure.
947 * @param ss Ring2 SS register value. Pass 0 if invalid.
948 * @param esp Ring2 ESP register value.
949 */
950void selmSetRing2Stack(PVM pVM, uint32_t ss, RTGCPTR32 esp)
951{
952 Assert(!HMIsEnabled(pVM));
953 Assert((ss & 3) == 2 || esp == 0);
954 pVM->selm.s.Tss.ss2 = ss;
955 pVM->selm.s.Tss.esp2 = (uint32_t)esp;
956}
957#endif
958
959
960#ifdef VBOX_WITH_RAW_MODE_NOT_R0
961/**
962 * Gets ss:esp for ring1 in main Hypervisor's TSS.
963 *
964 * Returns SS=0 if the ring-1 stack isn't valid.
965 *
966 * @returns VBox status code.
967 * @param pVM The cross context VM structure.
968 * @param pSS Ring1 SS register value.
969 * @param pEsp Ring1 ESP register value.
970 */
971VMMDECL(int) SELMGetRing1Stack(PVM pVM, uint32_t *pSS, PRTGCPTR32 pEsp)
972{
973 Assert(!HMIsEnabled(pVM));
974 Assert(pVM->cCpus == 1);
975 PVMCPU pVCpu = &pVM->aCpus[0];
976
977#ifdef SELM_TRACK_GUEST_TSS_CHANGES
978 if (pVM->selm.s.fSyncTSSRing0Stack)
979 {
980#endif
981 RTGCPTR GCPtrTss = pVM->selm.s.GCPtrGuestTss;
982 int rc;
983 VBOXTSS tss;
984
985 Assert(pVM->selm.s.GCPtrGuestTss && pVM->selm.s.cbMonitoredGuestTss);
986
987# ifdef IN_RC
988 bool fTriedAlready = false;
989
990l_tryagain:
991 PVBOXTSS pTss = (PVBOXTSS)(uintptr_t)GCPtrTss;
992 rc = MMGCRamRead(pVM, &tss.ss0, &pTss->ss0, sizeof(tss.ss0));
993 rc |= MMGCRamRead(pVM, &tss.esp0, &pTss->esp0, sizeof(tss.esp0));
994# ifdef DEBUG
995 rc |= MMGCRamRead(pVM, &tss.offIoBitmap, &pTss->offIoBitmap, sizeof(tss.offIoBitmap));
996# endif
997
998 if (RT_FAILURE(rc))
999 {
1000 if (!fTriedAlready)
1001 {
1002 /* Shadow page might be out of sync. Sync and try again */
1003 /** @todo might cross page boundary */
1004 fTriedAlready = true;
1005 rc = PGMPrefetchPage(pVCpu, (RTGCPTR)GCPtrTss);
1006 if (rc != VINF_SUCCESS)
1007 return rc;
1008 goto l_tryagain;
1009 }
1010 AssertMsgFailed(("Unable to read TSS structure at %08X\n", GCPtrTss));
1011 return rc;
1012 }
1013
1014# else /* !IN_RC */
1015 /* Reading too much. Could be cheaper than two separate calls though. */
1016 rc = PGMPhysSimpleReadGCPtr(pVCpu, &tss, GCPtrTss, sizeof(VBOXTSS));
1017 if (RT_FAILURE(rc))
1018 {
1019 AssertReleaseMsgFailed(("Unable to read TSS structure at %08X\n", GCPtrTss));
1020 return rc;
1021 }
1022# endif /* !IN_RC */
1023
1024# ifdef LOG_ENABLED
1025 uint32_t ssr0 = pVM->selm.s.Tss.ss1;
1026 uint32_t espr0 = pVM->selm.s.Tss.esp1;
1027 ssr0 &= ~1;
1028
1029 if (ssr0 != tss.ss0 || espr0 != tss.esp0)
1030 Log(("SELMGetRing1Stack: Updating TSS ring 0 stack to %04X:%08X\n", tss.ss0, tss.esp0));
1031
1032 Log(("offIoBitmap=%#x\n", tss.offIoBitmap));
1033# endif
1034 /* Update our TSS structure for the guest's ring 1 stack */
1035 selmSetRing1Stack(pVM, tss.ss0 | 1, (RTGCPTR32)tss.esp0);
1036 pVM->selm.s.fSyncTSSRing0Stack = false;
1037#ifdef SELM_TRACK_GUEST_TSS_CHANGES
1038 }
1039#endif
1040
1041 *pSS = pVM->selm.s.Tss.ss1;
1042 *pEsp = (RTGCPTR32)pVM->selm.s.Tss.esp1;
1043
1044 return VINF_SUCCESS;
1045}
1046#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
1047
1048
1049#if defined(VBOX_WITH_RAW_MODE) || (HC_ARCH_BITS != 64 && defined(VBOX_WITH_64_BITS_GUESTS))
1050
1051/**
1052 * Gets the hypervisor code selector (CS).
1053 * @returns CS selector.
1054 * @param pVM The cross context VM structure.
1055 */
1056VMMDECL(RTSEL) SELMGetHyperCS(PVM pVM)
1057{
1058 return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS];
1059}
1060
1061
1062/**
1063 * Gets the 64-mode hypervisor code selector (CS64).
1064 * @returns CS selector.
1065 * @param pVM The cross context VM structure.
1066 */
1067VMMDECL(RTSEL) SELMGetHyperCS64(PVM pVM)
1068{
1069 return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS64];
1070}
1071
1072
1073/**
1074 * Gets the hypervisor data selector (DS).
1075 * @returns DS selector.
1076 * @param pVM The cross context VM structure.
1077 */
1078VMMDECL(RTSEL) SELMGetHyperDS(PVM pVM)
1079{
1080 return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS];
1081}
1082
1083
1084/**
1085 * Gets the hypervisor TSS selector.
1086 * @returns TSS selector.
1087 * @param pVM The cross context VM structure.
1088 */
1089VMMDECL(RTSEL) SELMGetHyperTSS(PVM pVM)
1090{
1091 return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS];
1092}
1093
1094
1095/**
1096 * Gets the hypervisor TSS Trap 8 selector.
1097 * @returns TSS Trap 8 selector.
1098 * @param pVM The cross context VM structure.
1099 */
1100VMMDECL(RTSEL) SELMGetHyperTSSTrap08(PVM pVM)
1101{
1102 return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08];
1103}
1104
1105/**
1106 * Gets the address for the hypervisor GDT.
1107 *
1108 * @returns The GDT address.
1109 * @param pVM The cross context VM structure.
1110 * @remark This is intended only for very special use, like in the world
1111 * switchers. Don't exploit this API!
1112 */
1113VMMDECL(RTRCPTR) SELMGetHyperGDT(PVM pVM)
1114{
1115 /*
1116 * Always convert this from the HC pointer since we can be
1117 * called before the first relocation and have to work correctly
1118 * without having dependencies on the relocation order.
1119 */
1120 return (RTRCPTR)MMHyperR3ToRC(pVM, pVM->selm.s.paGdtR3);
1121}
1122
1123#endif /* defined(VBOX_WITH_RAW_MODE) || (HC_ARCH_BITS != 64 && defined(VBOX_WITH_64_BITS_GUESTS)) */
1124
1125/**
1126 * Gets info about the current TSS.
1127 *
1128 * @returns VBox status code.
1129 * @retval VINF_SUCCESS if we've got a TSS loaded.
1130 * @retval VERR_SELM_NO_TSS if we haven't got a TSS (rather unlikely).
1131 *
1132 * @param pVM The cross context VM structure.
1133 * @param pVCpu The cross context virtual CPU structure.
1134 * @param pGCPtrTss Where to store the TSS address.
1135 * @param pcbTss Where to store the TSS size limit.
1136 * @param pfCanHaveIOBitmap Where to store the can-have-I/O-bitmap indicator. (optional)
1137 */
1138VMMDECL(int) SELMGetTSSInfo(PVM pVM, PVMCPU pVCpu, PRTGCUINTPTR pGCPtrTss, PRTGCUINTPTR pcbTss, bool *pfCanHaveIOBitmap)
1139{
1140 NOREF(pVM);
1141
1142 /*
1143 * The TR hidden register is always valid.
1144 */
1145 CPUMSELREGHID trHid;
1146 RTSEL tr = CPUMGetGuestTR(pVCpu, &trHid);
1147 if (!(tr & X86_SEL_MASK_OFF_RPL))
1148 return VERR_SELM_NO_TSS;
1149
1150 *pGCPtrTss = trHid.u64Base;
1151 *pcbTss = trHid.u32Limit + (trHid.u32Limit != UINT32_MAX); /* be careful. */
1152 if (pfCanHaveIOBitmap)
1153 *pfCanHaveIOBitmap = trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_AVAIL
1154 || trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY;
1155 return VINF_SUCCESS;
1156}
1157
1158
1159
1160/**
1161 * Notification callback which is called whenever there is a chance that a CR3
1162 * value might have changed.
1163 * This is called by PGM.
1164 *
1165 * @param pVM The cross context VM structure.
1166 * @param pVCpu The cross context virtual CPU structure.
1167 */
1168VMMDECL(void) SELMShadowCR3Changed(PVM pVM, PVMCPU pVCpu)
1169{
1170 /** @todo SMP support!! (64-bit guest scenario, primarily) */
1171 pVM->selm.s.Tss.cr3 = PGMGetHyperCR3(pVCpu);
1172 pVM->selm.s.TssTrap08.cr3 = PGMGetInterRCCR3(pVM, pVCpu);
1173}
1174
Note: See TracBrowser for help on using the repository browser.

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