~ubuntu-branches/ubuntu/gutsy/virtualbox-ose/gutsy

« back to all changes in this revision

Viewing changes to src/VBox/VMM/VMMAll/SELMAll.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-09-08 16:44:58 UTC
  • Revision ID: james.westby@ubuntu.com-20070908164458-wao29470vqtr8ksy
Tags: upstream-1.5.0-dfsg2
ImportĀ upstreamĀ versionĀ 1.5.0-dfsg2

Show diffs side-by-side

added added

removed removed

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