VirtualBox

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

Last change on this file since 10196 was 10171, checked in by vboxsync, 16 years ago

small fix

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