VirtualBox

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

Last change on this file since 12559 was 12404, checked in by vboxsync, 16 years ago

Cut off calculated addresses when not in 64 bits mode. (fixes OS/2 guests #3115)

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