VirtualBox

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

Last change on this file since 2128 was 2119, checked in by vboxsync, 18 years ago

Finished hidden selector case.

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