VirtualBox

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

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

SELMToFlatBySelEx not used in our ring 0 module.

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