VirtualBox

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

Last change on this file since 9776 was 9710, checked in by vboxsync, 16 years ago

doxygen.

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