VirtualBox

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

Last change on this file since 2191 was 2189, checked in by vboxsync, 18 years ago

Bugfix

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