VirtualBox

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

Last change on this file since 9871 was 9817, checked in by vboxsync, 17 years ago

fs & gs base cleanup

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