VirtualBox

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

Last change on this file since 9657 was 9656, checked in by vboxsync, 17 years ago

Changed u1Reserved to u1Long in the selector attributes field.

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