VirtualBox

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

Last change on this file since 2018 was 2009, checked in by vboxsync, 18 years ago

Fixed segment limit calculation for expand-down segments.

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