VirtualBox

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

Last change on this file since 22997 was 22890, checked in by vboxsync, 15 years ago

VM::cCPUs -> VM::cCpus so it matches all the other cCpus and aCpus members.

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