VirtualBox

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

Last change on this file since 1507 was 1443, checked in by vboxsync, 18 years ago

cast the uint16_t selector value before shifting it, just a precaution.

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