VirtualBox

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

Last change on this file since 8170 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

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