VirtualBox

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

Last change on this file since 5070 was 4776, checked in by vboxsync, 17 years ago

Stricter type checking. Removed unnecessary code from the ring 0 module.

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