VirtualBox

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

Last change on this file since 850 was 105, checked in by vboxsync, 18 years ago

style

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.5 KB
Line 
1/* $Id: SELMAll.cpp 105 2007-01-17 15:29:08Z vboxsync $ */
2/** @file
3 * SELM All contexts.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
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 */
52static RTGCPTR selmToFlat(PVM pVM, RTSEL Sel, RTGCPTR Addr)
53{
54 Assert(!CPUMAreHiddenSelRegsValid(pVM));
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
72 + ( (Desc.Gen.u8BaseHigh2 << 24)
73 | (Desc.Gen.u8BaseHigh1 << 16)
74 | Desc.Gen.u16BaseLow));
75}
76
77
78/**
79 * Converts a GC selector based address to a flat address.
80 *
81 * No limit checks are done. Use the SELMToFlat*() or SELMValidate*() functions
82 * for that.
83 *
84 * @returns Flat address.
85 * @param pVM VM Handle.
86 * @param Sel Selector part.
87 * @param Addr Address part.
88 */
89SELMDECL(RTGCPTR) SELMToFlat(PVM pVM, RTSEL Sel, CPUMSELREGHID *pHiddenSel, RTGCPTR Addr)
90{
91 if (!CPUMAreHiddenSelRegsValid(pVM))
92 return selmToFlat(pVM, Sel, Addr);
93
94 return (RTGCPTR)(pHiddenSel->u32Base + (RTGCUINTPTR)Addr);
95}
96
97
98/**
99 * Converts a GC selector based address to a flat address.
100 *
101 * Some basic checking is done, but not all kinds yet.
102 *
103 * @returns VBox status
104 * @param pVM VM Handle.
105 * @param Sel Selector part.
106 * @param Addr Address part.
107 * @param fFlags SELMTOFLAT_FLAGS_*
108 * GDT entires are valid.
109 * @param ppvGC Where to store the GC flat address.
110 * @param pcb Where to store the bytes from *ppvGC which can be accessed according to
111 * the selector. NULL is allowed.
112 */
113SELMDECL(int) SELMToFlatEx(PVM pVM, RTSEL Sel, RTGCPTR Addr, unsigned fFlags, PRTGCPTR ppvGC, uint32_t *pcb)
114{
115 /*
116 * Deal with real mode first.
117 */
118 if (CPUMIsGuestInRealMode(pVM)
119 /** @todo || (fFlags & SELMTOFLAT_FLAGS_V86)*/)
120 {
121 if (pcb)
122 *pcb = 0x10000 - ((RTGCUINTPTR)Addr & 0xffff);
123 if (ppvGC)
124 {
125 RTGCUINTPTR uFlat = ((RTGCUINTPTR)Addr & 0xffff) + (Sel << 4);
126 *ppvGC = (RTGCPTR)uFlat;
127 }
128 return VINF_SUCCESS;
129 }
130
131 Assert(!CPUMAreHiddenSelRegsValid(pVM));
132
133 VBOXDESC Desc;
134 if (!(Sel & X86_SEL_LDT))
135 {
136 if ( !(fFlags & SELMTOFLAT_FLAGS_HYPER)
137 && (unsigned)(Sel & X86_SEL_MASK) >= pVM->selm.s.GuestGdtr.cbGdt)
138 return VERR_INVALID_SELECTOR;
139 Desc = pVM->selm.s.CTXSUFF(paGdt)[Sel >> X86_SEL_SHIFT];
140 }
141 else
142 {
143 if ((unsigned)(Sel & X86_SEL_MASK) >= pVM->selm.s.cbLdtLimit)
144 return VERR_INVALID_SELECTOR;
145
146 /** @todo handle LDT page(s) not present! */
147 #ifdef IN_GC
148 PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.GCPtrLdt + pVM->selm.s.offLdtHyper);
149 #else
150 PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.HCPtrLdt + pVM->selm.s.offLdtHyper);
151 #endif
152 Desc = paLDT[Sel >> X86_SEL_SHIFT];
153 }
154
155 /*
156 * Check if present.
157 */
158 if (Desc.Gen.u1Present)
159 {
160 /* calc limit. */
161 uint32_t u32Limit = Desc.Gen.u4LimitHigh << 16 | Desc.Gen.u16LimitLow;
162 if (Desc.Gen.u1Granularity)
163 u32Limit = (u32Limit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
164
165 /* calc address assuming straight stuff. */
166 RTGCPTR pvFlat = (RTGCPTR)( (RTGCUINTPTR)Addr
167 + ( (Desc.Gen.u8BaseHigh2 << 24)
168 | (Desc.Gen.u8BaseHigh1 << 16)
169 | Desc.Gen.u16BaseLow )
170 );
171 /*
172 * Type check.
173 */
174 #define BOTH(a, b) ((a << 16) | b)
175 switch (BOTH(Desc.Gen.u1DescType, Desc.Gen.u4Type))
176 {
177
178 /** Read only selector type. */
179 case BOTH(1,X86_SEL_TYPE_RO):
180 case BOTH(1,X86_SEL_TYPE_RO_ACC):
181 case BOTH(1,X86_SEL_TYPE_RW):
182 case BOTH(1,X86_SEL_TYPE_RW_ACC):
183 case BOTH(1,X86_SEL_TYPE_EO):
184 case BOTH(1,X86_SEL_TYPE_EO_ACC):
185 case BOTH(1,X86_SEL_TYPE_ER):
186 case BOTH(1,X86_SEL_TYPE_ER_ACC):
187 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
188 {
189 /** @todo fix this mess */
190 }
191 /* check limit. */
192 if ((RTGCUINTPTR)Addr > u32Limit)
193 return VERR_OUT_OF_SELECTOR_BOUNDS;
194 /* ok */
195 if (ppvGC)
196 *ppvGC = pvFlat;
197 if (pcb)
198 *pcb = u32Limit - (uint32_t)Addr + 1;
199 return VINF_SUCCESS;
200 case BOTH(1,X86_SEL_TYPE_EO_CONF):
201 case BOTH(1,X86_SEL_TYPE_EO_CONF_ACC):
202 case BOTH(1,X86_SEL_TYPE_ER_CONF):
203 case BOTH(1,X86_SEL_TYPE_ER_CONF_ACC):
204 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
205 {
206 /** @todo fix this mess */
207 }
208 /* check limit. */
209 if ((RTGCUINTPTR)Addr > u32Limit)
210 return VERR_OUT_OF_SELECTOR_BOUNDS;
211 /* ok */
212 if (ppvGC)
213 *ppvGC = pvFlat;
214 if (pcb)
215 *pcb = u32Limit - (uint32_t)Addr + 1;
216 return VINF_SUCCESS;
217
218 case BOTH(1,X86_SEL_TYPE_RO_DOWN):
219 case BOTH(1,X86_SEL_TYPE_RO_DOWN_ACC):
220 case BOTH(1,X86_SEL_TYPE_RW_DOWN):
221 case BOTH(1,X86_SEL_TYPE_RW_DOWN_ACC):
222 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
223 {
224 /** @todo fix this mess */
225 }
226 /* check limit. */
227 /** @todo check the manual on this!!! */
228 if ((RTGCUINTPTR)(Desc.Gen.u1Granularity ? 0xffffffff : 0xfffff) - (RTGCUINTPTR)Addr > u32Limit)
229 return VERR_OUT_OF_SELECTOR_BOUNDS;
230
231 /* ok */
232 if (ppvGC)
233 *ppvGC = pvFlat;
234 if (pcb)
235 *pcb = (Desc.Gen.u1Granularity ? 0xffffffff : 0xfffff) - (RTGCUINTPTR)Addr + 1;
236 return VINF_SUCCESS;
237
238 case BOTH(0,X86_SEL_TYPE_SYS_286_TSS_AVAIL):
239 case BOTH(0,X86_SEL_TYPE_SYS_LDT):
240 case BOTH(0,X86_SEL_TYPE_SYS_286_TSS_BUSY):
241 case BOTH(0,X86_SEL_TYPE_SYS_286_CALL_GATE):
242 case BOTH(0,X86_SEL_TYPE_SYS_TASK_GATE):
243 case BOTH(0,X86_SEL_TYPE_SYS_286_INT_GATE):
244 case BOTH(0,X86_SEL_TYPE_SYS_286_TRAP_GATE):
245 case BOTH(0,X86_SEL_TYPE_SYS_386_TSS_AVAIL):
246 case BOTH(0,X86_SEL_TYPE_SYS_386_TSS_BUSY):
247 case BOTH(0,X86_SEL_TYPE_SYS_386_CALL_GATE):
248 case BOTH(0,X86_SEL_TYPE_SYS_386_INT_GATE):
249 case BOTH(0,X86_SEL_TYPE_SYS_386_TRAP_GATE):
250 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
251 {
252 /** @todo fix this mess */
253 }
254 /* check limit. */
255 if ((RTGCUINTPTR)Addr > u32Limit)
256 return VERR_OUT_OF_SELECTOR_BOUNDS;
257 /* ok */
258 if (ppvGC)
259 *ppvGC = pvFlat;
260 if (pcb)
261 *pcb = 0xffffffff - (RTGCUINTPTR)pvFlat + 1; /* Depends on the type.. fixme if we care. */
262 return VINF_SUCCESS;
263
264 default:
265 return VERR_INVALID_SELECTOR;
266
267 }
268 #undef BOTH
269 }
270 return VERR_SELECTOR_NOT_PRESENT;
271}
272
273
274/**
275 * Validates and converts a GC selector based code address to a flat address.
276 *
277 * @returns Flat address.
278 * @param pVM VM Handle.
279 * @param SelCPL Current privilege level. Get this from SS - CS might be conforming!
280 * A full selector can be passed, we'll only use the RPL part.
281 * @param SelCS Selector part.
282 * @param Addr Address part.
283 * @param ppvFlat Where to store the flat address.
284 */
285static int selmValidateAndConvertCSAddr(PVM pVM, RTSEL SelCPL, RTSEL SelCS, RTGCPTR Addr, PRTGCPTR ppvFlat)
286{
287 Assert(!CPUMAreHiddenSelRegsValid(pVM));
288
289 /** @todo validate limit! */
290 VBOXDESC Desc;
291 if (!(SelCS & X86_SEL_LDT))
292 Desc = pVM->selm.s.CTXSUFF(paGdt)[SelCS >> X86_SEL_SHIFT];
293 else
294 {
295 /** @todo handle LDT page(s) not present! */
296 #ifdef IN_GC
297 PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.GCPtrLdt + pVM->selm.s.offLdtHyper);
298 #else
299 PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.HCPtrLdt + pVM->selm.s.offLdtHyper);
300 #endif
301 Desc = paLDT[SelCS >> X86_SEL_SHIFT];
302 }
303
304 /*
305 * Check if present.
306 */
307 if (Desc.Gen.u1Present)
308 {
309 /*
310 * Type check.
311 */
312 if ( Desc.Gen.u1DescType == 1
313 && (Desc.Gen.u4Type & X86_SEL_TYPE_CODE))
314 {
315 /*
316 * Check level.
317 */
318 unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, SelCS & X86_SEL_RPL);
319 if ( !(Desc.Gen.u4Type & X86_SEL_TYPE_CONF)
320 ? uLevel <= Desc.Gen.u2Dpl
321 : uLevel >= Desc.Gen.u2Dpl /* hope I got this right now... */
322 )
323 {
324 /*
325 * Limit check.
326 */
327 uint32_t u32Limit = Desc.Gen.u4LimitHigh << 16 | Desc.Gen.u16LimitLow;
328 if (Desc.Gen.u1Granularity)
329 u32Limit = (u32Limit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
330 if ((RTGCUINTPTR)Addr <= u32Limit)
331 {
332 if (ppvFlat)
333 *ppvFlat = (RTGCPTR)( (RTGCUINTPTR)Addr
334 + ( (Desc.Gen.u8BaseHigh2 << 24)
335 | (Desc.Gen.u8BaseHigh1 << 16)
336 | Desc.Gen.u16BaseLow)
337 );
338 return VINF_SUCCESS;
339 }
340 return VERR_OUT_OF_SELECTOR_BOUNDS;
341 }
342 return VERR_INVALID_RPL;
343 }
344 return VERR_NOT_CODE_SELECTOR;
345 }
346 return VERR_SELECTOR_NOT_PRESENT;
347}
348
349
350/**
351 * Validates and converts a GC selector based code address to a flat address.
352 *
353 * @returns Flat address.
354 * @param pVM VM Handle.
355 * @param SelCPL Current privilege level. Get this from SS - CS might be conforming!
356 * A full selector can be passed, we'll only use the RPL part.
357 * @param SelCS Selector part.
358 * @param pHiddenSel The hidden CS selector register.
359 * @param Addr Address part.
360 * @param ppvFlat Where to store the flat address.
361 */
362SELMDECL(int) SELMValidateAndConvertCSAddr(PVM pVM, RTSEL SelCPL, RTSEL SelCS, CPUMSELREGHID *pHiddenCSSel, RTGCPTR Addr, PRTGCPTR ppvFlat)
363{
364 if (!CPUMAreHiddenSelRegsValid(pVM))
365 return selmValidateAndConvertCSAddr(pVM, SelCPL, SelCS, Addr, ppvFlat);
366
367 /*
368 * Check if present.
369 */
370 if (pHiddenCSSel->Attr.n.u1Present)
371 {
372 /*
373 * Type check.
374 */
375 if ( pHiddenCSSel->Attr.n.u1DescType == 1
376 && (pHiddenCSSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
377 {
378 /*
379 * Check level.
380 */
381 unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, SelCS & X86_SEL_RPL);
382 if ( !(pHiddenCSSel->Attr.n.u4Type & X86_SEL_TYPE_CONF)
383 ? uLevel <= pHiddenCSSel->Attr.n.u2Dpl
384 : uLevel >= pHiddenCSSel->Attr.n.u2Dpl /* hope I got this right now... */
385 )
386 {
387 /*
388 * Limit check.
389 */
390 uint32_t u32Limit = pHiddenCSSel->u32Limit;
391 /** @todo correct with hidden limit value?? */
392 if (pHiddenCSSel->Attr.n.u1Granularity)
393 u32Limit = (u32Limit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
394 if ((RTGCUINTPTR)Addr <= u32Limit)
395 {
396 if (ppvFlat)
397 *ppvFlat = (RTGCPTR)( (RTGCUINTPTR)Addr + pHiddenCSSel->u32Base );
398
399 return VINF_SUCCESS;
400 }
401 return VERR_OUT_OF_SELECTOR_BOUNDS;
402 }
403 return VERR_INVALID_RPL;
404 }
405 return VERR_NOT_CODE_SELECTOR;
406 }
407 return VERR_SELECTOR_NOT_PRESENT;
408}
409
410
411/**
412 * Checks if a selector is 32-bit or 16-bit.
413 *
414 * @returns True if it is 32-bit.
415 * @returns False if it is 16-bit.
416 * @param pVM VM Handle.
417 * @param Sel The selector.
418 */
419static bool selmIsSelector32Bit(PVM pVM, RTSEL Sel)
420{
421 Assert(!CPUMAreHiddenSelRegsValid(pVM));
422
423 /** @todo validate limit! */
424 VBOXDESC Desc;
425 if (!(Sel & X86_SEL_LDT))
426 Desc = pVM->selm.s.CTXSUFF(paGdt)[Sel >> X86_SEL_SHIFT];
427 else
428 {
429 /** @todo handle LDT page(s) not present! */
430 PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.CTXMID(,PtrLdt) + pVM->selm.s.offLdtHyper);
431 Desc = paLDT[Sel >> X86_SEL_SHIFT];
432 }
433 return Desc.Gen.u1DefBig;
434}
435
436
437/**
438 * Checks if a selector is 32-bit or 16-bit.
439 *
440 * @returns True if it is 32-bit.
441 * @returns False if it is 16-bit.
442 * @param pVM VM Handle.
443 * @param Sel The selector.
444 * @param pHiddenSel The hidden selector register.
445 */
446SELMDECL(bool) SELMIsSelector32Bit(PVM pVM, RTSEL Sel, CPUMSELREGHID *pHiddenSel)
447{
448 if (!CPUMAreHiddenSelRegsValid(pVM))
449 return selmIsSelector32Bit(pVM, Sel);
450
451 return pHiddenSel->Attr.n.u1DefBig;
452}
453
454
455/**
456 * Returns Hypervisor's Trap 08 (\#DF) selector.
457 *
458 * @returns Hypervisor's Trap 08 (\#DF) selector.
459 * @param pVM VM Handle.
460 */
461SELMDECL(RTSEL) SELMGetTrap8Selector(PVM pVM)
462{
463 return pVM->selm.s.SelTSSTrap08;
464}
465
466
467/**
468 * Sets EIP of Hypervisor's Trap 08 (\#DF) TSS.
469 *
470 * @param pVM VM Handle.
471 * @param u32EIP EIP of Trap 08 handler.
472 */
473SELMDECL(void) SELMSetTrap8EIP(PVM pVM, uint32_t u32EIP)
474{
475 pVM->selm.s.TssTrap08.eip = u32EIP;
476}
477
478
479/**
480 * Sets ss:esp for ring1 in main Hypervisor's TSS.
481 *
482 * @param pVM VM Handle.
483 * @param ss Ring1 SS register value.
484 * @param esp Ring1 ESP register value.
485 */
486SELMDECL(void) SELMSetRing1Stack(PVM pVM, uint32_t ss, uint32_t esp)
487{
488 pVM->selm.s.Tss.ss1 = ss;
489 pVM->selm.s.Tss.esp1 = esp;
490}
491
492
493/**
494 * Gets ss:esp for ring1 in main Hypervisor's TSS.
495 *
496 * @returns VBox status code.
497 * @param pVM VM Handle.
498 * @param pSS Ring1 SS register value.
499 * @param pEsp Ring1 ESP register value.
500 */
501SELMDECL(int) SELMGetRing1Stack(PVM pVM, uint32_t *pSS, uint32_t *pEsp)
502{
503 if (pVM->selm.s.fSyncTSSRing0Stack)
504 {
505 GCPTRTYPE(uint8_t *) GCPtrTss = (GCPTRTYPE(uint8_t *))pVM->selm.s.GCPtrGuestTss;
506 int rc;
507 VBOXTSS tss;
508
509 Assert(pVM->selm.s.GCPtrGuestTss && pVM->selm.s.cbMonitoredGuestTss);
510
511#ifdef IN_GC
512 bool fTriedAlready = false;
513
514l_tryagain:
515 rc = MMGCRamRead(pVM, &tss.ss0, GCPtrTss + RT_OFFSETOF(VBOXTSS, ss0), sizeof(tss.ss0));
516 rc |= MMGCRamRead(pVM, &tss.esp0, GCPtrTss + RT_OFFSETOF(VBOXTSS, esp0), sizeof(tss.esp0));
517 #ifdef DEBUG
518 rc |= MMGCRamRead(pVM, &tss.offIoBitmap, GCPtrTss + RT_OFFSETOF(VBOXTSS, offIoBitmap), sizeof(tss.offIoBitmap));
519 #endif
520
521 if (VBOX_FAILURE(rc))
522 {
523 if (!fTriedAlready)
524 {
525 /* Shadow page might be out of sync. Sync and try again */
526 /** @todo might cross page boundary */
527 fTriedAlready = true;
528 rc = PGMPrefetchPage(pVM, GCPtrTss);
529 if (rc != VINF_SUCCESS)
530 return rc;
531 goto l_tryagain;
532 }
533 AssertMsgFailed(("Unable to read TSS structure at %08X\n", GCPtrTss));
534 return rc;
535 }
536
537#else /* !IN_GC */
538 /* Reading too much. Could be cheaper than two seperate calls though. */
539 rc = PGMPhysReadGCPtr(pVM, &tss, GCPtrTss, sizeof(VBOXTSS));
540 if (VBOX_FAILURE(rc))
541 {
542 AssertReleaseMsgFailed(("Unable to read TSS structure at %08X\n", GCPtrTss));
543 return rc;
544 }
545#endif /* !IN_GC */
546
547#ifdef LOG_ENABLED
548 uint32_t ssr0 = pVM->selm.s.Tss.ss1;
549 uint32_t espr0 = pVM->selm.s.Tss.esp1;
550 ssr0 &= ~1;
551
552 if (ssr0 != tss.ss0 || espr0 != tss.esp0)
553 Log(("SELMGetRing1Stack: Updating TSS ring 0 stack to %04X:%08X\n", tss.ss0, tss.esp0));
554
555 Log(("offIoBitmap=%#x\n", tss.offIoBitmap));
556#endif
557 /* Update our TSS structure for the guest's ring 1 stack */
558 SELMSetRing1Stack(pVM, tss.ss0 | 1, tss.esp0);
559 pVM->selm.s.fSyncTSSRing0Stack = false;
560 }
561
562 *pSS = pVM->selm.s.Tss.ss1;
563 *pEsp = pVM->selm.s.Tss.esp1;
564
565 return VINF_SUCCESS;
566}
567
568
569/**
570 * Returns Guest TSS pointer
571 *
572 * @param pVM VM Handle.
573 */
574SELMDECL(RTGCPTR) SELMGetGuestTSS(PVM pVM)
575{
576 return (RTGCPTR)pVM->selm.s.GCPtrGuestTss;
577}
578
579
580/**
581 * Validates a CS selector.
582 *
583 * @returns VBox status code.
584 * @param pSelInfo Pointer to the selector information for the CS selector.
585 * @param SelCPL The selector defining the CPL (SS).
586 */
587SELMDECL(int) SELMSelInfoValidateCS(PCSELMSELINFO pSelInfo, RTSEL SelCPL)
588{
589 /*
590 * Check if present.
591 */
592 if (pSelInfo->Raw.Gen.u1Present)
593 {
594 /*
595 * Type check.
596 */
597 if ( pSelInfo->Raw.Gen.u1DescType == 1
598 && (pSelInfo->Raw.Gen.u4Type & X86_SEL_TYPE_CODE))
599 {
600 /*
601 * Check level.
602 */
603 unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, pSelInfo->Sel & X86_SEL_RPL);
604 if ( !(pSelInfo->Raw.Gen.u4Type & X86_SEL_TYPE_CONF)
605 ? uLevel <= pSelInfo->Raw.Gen.u2Dpl
606 : uLevel >= pSelInfo->Raw.Gen.u2Dpl /* hope I got this right now... */
607 )
608 return VINF_SUCCESS;
609 return VERR_INVALID_RPL;
610 }
611 return VERR_NOT_CODE_SELECTOR;
612 }
613 return VERR_SELECTOR_NOT_PRESENT;
614}
615
616
617/**
618 * Gets the hypervisor code selector (CS).
619 * @returns CS selector.
620 * @param pVM The VM handle.
621 */
622SELMDECL(RTSEL) SELMGetHyperCS(PVM pVM)
623{
624 return pVM->selm.s.SelCS;
625}
626
627
628/**
629 * Gets the 64-mode hypervisor code selector (CS64).
630 * @returns CS selector.
631 * @param pVM The VM handle.
632 */
633SELMDECL(RTSEL) SELMGetHyperCS64(PVM pVM)
634{
635 return pVM->selm.s.SelCS64;
636}
637
638
639/**
640 * Gets the hypervisor data selector (DS).
641 * @returns DS selector.
642 * @param pVM The VM handle.
643 */
644SELMDECL(RTSEL) SELMGetHyperDS(PVM pVM)
645{
646 return pVM->selm.s.SelDS;
647}
648
649
650/**
651 * Gets the hypervisor TSS selector.
652 * @returns TSS selector.
653 * @param pVM The VM handle.
654 */
655SELMDECL(RTSEL) SELMGetHyperTSS(PVM pVM)
656{
657 return pVM->selm.s.SelTSS;
658}
659
660
661/**
662 * Gets the hypervisor TSS Trap 8 selector.
663 * @returns TSS Trap 8 selector.
664 * @param pVM The VM handle.
665 */
666SELMDECL(RTSEL) SELMGetHyperTSSTrap08(PVM pVM)
667{
668 return pVM->selm.s.SelTSSTrap08;
669}
670
671
672/**
673 * Gets the address for the hypervisor GDT.
674 *
675 * @returns The GDT address.
676 * @param pVM The VM handle.
677 * @remark This is intended only for very special use, like in the world
678 * switchers. Don't exploit this API!
679 */
680SELMDECL(RTGCPTR) SELMGetHyperGDT(PVM pVM)
681{
682 /*
683 * Always convert this from the HC pointer since. We're can be
684 * called before the first relocation and have to work correctly
685 * without having dependencies on the relocation order.
686 */
687 return MMHyperHC2GC(pVM, pVM->selm.s.paGdtHC);
688}
689
690
691/**
692 * Gets info about the current TSS.
693 *
694 * @returns VBox status code.
695 * @retval VINF_SUCCESS if we've got a TSS loaded.
696 * @retval VERR_SELM_NO_TSS if we haven't got a TSS (rather unlikely).
697 *
698 * @param pVM The VM handle.
699 * @param pGCPtrTss Where to store the TSS address.
700 * @param pcbTss Where to store the TSS size limit.
701 * @param pfCanHaveIOBitmap Where to store the can-have-I/O-bitmap indicator. (optional)
702 */
703SELMDECL(int) SELMGetTSSInfo(PVM pVM, PRTGCUINTPTR pGCPtrTss, PRTGCUINTPTR pcbTss, bool *pfCanHaveIOBitmap)
704{
705 if (!CPUMAreHiddenSelRegsValid(pVM))
706 {
707 /*
708 * Do we have a valid TSS?
709 */
710 if ( pVM->selm.s.GCSelTss == (RTSEL)~0
711 || !pVM->selm.s.fGuestTss32Bit)
712 return VERR_SELM_NO_TSS;
713
714 /*
715 * Fill in return values.
716 */
717 *pGCPtrTss = (RTGCUINTPTR)pVM->selm.s.GCPtrGuestTss;
718 *pcbTss = pVM->selm.s.cbGuestTss;
719 if (pfCanHaveIOBitmap)
720 *pfCanHaveIOBitmap = pVM->selm.s.fGuestTss32Bit;
721 }
722 else
723 {
724 CPUMSELREGHID *pHiddenTRReg;
725
726 pHiddenTRReg = CPUMGetGuestTRHid(pVM);
727
728 *pGCPtrTss = pHiddenTRReg->u32Base;
729 *pcbTss = pHiddenTRReg->u32Limit;
730
731 if (pfCanHaveIOBitmap)
732 *pfCanHaveIOBitmap = pHiddenTRReg->Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_AVAIL
733 || pHiddenTRReg->Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY;
734 }
735 return VINF_SUCCESS;
736}
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