1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
/* $Id: SELMInternal.h $ */
/** @file
* SELM - Internal header file.
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#ifndef ___SELMInternal_h
#define ___SELMInternal_h
#include <VBox/cdefs.h>
#include <VBox/types.h>
#include <VBox/vmm/stam.h>
#include <VBox/vmm/cpum.h>
#include <VBox/log.h>
#include <iprt/x86.h>
/** @defgroup grp_selm_int Internals
* @ingroup grp_selm
* @internal
* @{
*/
/** Enable or disable tracking of Shadow GDT/LDT/TSS.
* @{
*/
#if defined(VBOX_WITH_RAW_MODE) || defined(DOXYGEN_RUNNING)
# define SELM_TRACK_SHADOW_GDT_CHANGES
# define SELM_TRACK_SHADOW_LDT_CHANGES
# define SELM_TRACK_SHADOW_TSS_CHANGES
#endif
/** @} */
/** Enable or disable tracking of Guest GDT/LDT/TSS.
* @{
*/
#if defined(VBOX_WITH_RAW_MODE) || defined(DOXYGEN_RUNNING)
# define SELM_TRACK_GUEST_GDT_CHANGES
# define SELM_TRACK_GUEST_LDT_CHANGES
# define SELM_TRACK_GUEST_TSS_CHANGES
#endif
/** @} */
/** The number of GDTS allocated for our GDT. (full size) */
#define SELM_GDT_ELEMENTS 8192
/** aHyperSel index to retrieve hypervisor selectors */
/** The Flat CS selector used by the VMM inside the GC. */
#define SELM_HYPER_SEL_CS 0
/** The Flat DS selector used by the VMM inside the GC. */
#define SELM_HYPER_SEL_DS 1
/** The 64-bit mode CS selector used by the VMM inside the GC. */
#define SELM_HYPER_SEL_CS64 2
/** The TSS selector used by the VMM inside the GC. */
#define SELM_HYPER_SEL_TSS 3
/** The TSS selector for taking trap 08 (\#DF). */
#define SELM_HYPER_SEL_TSS_TRAP08 4
/** Number of GDTs we need for internal use */
#define SELM_HYPER_SEL_MAX (SELM_HYPER_SEL_TSS_TRAP08 + 1)
/** Default GDT selectors we use for the hypervisor. */
#define SELM_HYPER_DEFAULT_SEL_CS ((SELM_GDT_ELEMENTS - 0x1) << 3)
#define SELM_HYPER_DEFAULT_SEL_DS ((SELM_GDT_ELEMENTS - 0x2) << 3)
#define SELM_HYPER_DEFAULT_SEL_CS64 ((SELM_GDT_ELEMENTS - 0x3) << 3)
#define SELM_HYPER_DEFAULT_SEL_TSS ((SELM_GDT_ELEMENTS - 0x4) << 3)
#define SELM_HYPER_DEFAULT_SEL_TSS_TRAP08 ((SELM_GDT_ELEMENTS - 0x5) << 3)
/** The lowest value default we use. */
#define SELM_HYPER_DEFAULT_BASE SELM_HYPER_DEFAULT_SEL_TSS_TRAP08
/**
* Converts a SELM pointer into a VM pointer.
* @returns Pointer to the VM structure the SELM is part of.
* @param pSELM Pointer to SELM instance data.
*/
#define SELM2VM(pSELM) ( (PVM)((char *)pSELM - pSELM->offVM) )
/**
* SELM Data (part of VM)
*/
typedef struct SELM
{
/** Offset to the VM structure.
* See SELM2VM(). */
RTINT offVM;
/** Flat CS, DS, 64 bit mode CS, TSS & trap 8 TSS. */
RTSEL aHyperSel[SELM_HYPER_SEL_MAX];
/** Pointer to the GCs - R3 Ptr.
* This size is governed by SELM_GDT_ELEMENTS. */
R3PTRTYPE(PX86DESC) paGdtR3;
/** Pointer to the GCs - RC Ptr.
* This is not initialized until the first relocation because it's used to
* check if the shadow GDT virtual handler requires deregistration. */
RCPTRTYPE(PX86DESC) paGdtRC;
/** Current (last) Guest's GDTR.
* The pGdt member is set to RTRCPTR_MAX if we're not monitoring the guest GDT. */
VBOXGDTR GuestGdtr;
/** The current (last) effective Guest GDT size. */
RTUINT cbEffGuestGdtLimit;
uint32_t padding0;
/** R3 pointer to the LDT shadow area in HMA. */
R3PTRTYPE(void *) pvLdtR3;
/** RC pointer to the LDT shadow area in HMA. */
RCPTRTYPE(void *) pvLdtRC;
#if GC_ARCH_BITS == 64
RTRCPTR padding1;
#endif
/** The address of the guest LDT.
* RTRCPTR_MAX if not monitored. */
RTGCPTR GCPtrGuestLdt;
/** Current LDT limit, both Guest and Shadow. */
RTUINT cbLdtLimit;
/** Current LDT offset relative to pvLdtR3/pvLdtRC. */
RTUINT offLdtHyper;
#if HC_ARCH_BITS == 32 && GC_ARCH_BITS == 64
uint32_t padding2[2];
#endif
/** TSS. (This is 16 byte aligned!)
* @todo I/O bitmap & interrupt redirection table? */
VBOXTSS Tss;
/** TSS for trap 08 (\#DF). */
VBOXTSS TssTrap08;
/** Monitored shadow TSS address. */
RCPTRTYPE(void *) pvMonShwTssRC;
#if GC_ARCH_BITS == 64
RTRCPTR padding3;
#endif
/** GC Pointer to the current Guest's TSS.
* RTRCPTR_MAX if not monitored. */
RTGCPTR GCPtrGuestTss;
/** The size of the guest TSS. */
RTUINT cbGuestTss;
/** Set if it's a 32-bit TSS. */
bool fGuestTss32Bit;
/** The size of the Guest's TSS part we're monitoring. */
RTUINT cbMonitoredGuestTss;
/** The guest TSS selector at last sync (part of monitoring).
* Contains RTSEL_MAX if not set. */
RTSEL GCSelTss;
/** The last known offset of the I/O bitmap.
* This is only used if we monitor the bitmap. */
uint16_t offGuestIoBitmap;
/** Indicates that the Guest GDT access handler have been registered. */
bool fGDTRangeRegistered;
/** Indicates whether the TSS stack selector & base address need to be refreshed. */
bool fSyncTSSRing0Stack;
bool fPadding2[4];
/** SELMR3UpdateFromCPUM() profiling. */
STAMPROFILE StatUpdateFromCPUM;
/** SELMR3SyncTSS() profiling. */
STAMPROFILE StatTSSSync;
/** GC: The number of handled writes to the Guest's GDT. */
STAMCOUNTER StatRCWriteGuestGDTHandled;
/** GC: The number of unhandled write to the Guest's GDT. */
STAMCOUNTER StatRCWriteGuestGDTUnhandled;
/** GC: The number of times writes to Guest's LDT was detected. */
STAMCOUNTER StatRCWriteGuestLDT;
/** GC: The number of handled writes to the Guest's TSS. */
STAMCOUNTER StatRCWriteGuestTSSHandled;
/** GC: The number of handled writes to the Guest's TSS where we detected a change. */
STAMCOUNTER StatRCWriteGuestTSSHandledChanged;
/** GC: The number of handled redir writes to the Guest's TSS where we detected a change. */
STAMCOUNTER StatRCWriteGuestTSSRedir;
/** GC: The number of unhandled writes to the Guest's TSS. */
STAMCOUNTER StatRCWriteGuestTSSUnhandled;
/** The number of times we had to relocate our hypervisor selectors. */
STAMCOUNTER StatHyperSelsChanged;
/** The number of times we had find free hypervisor selectors. */
STAMCOUNTER StatScanForHyperSels;
/** Counts the times we detected state selectors in SELMR3UpdateFromCPUM. */
STAMCOUNTER aStatDetectedStaleSReg[X86_SREG_COUNT];
/** Counts the times we were called with already state selectors in
* SELMR3UpdateFromCPUM. */
STAMCOUNTER aStatAlreadyStaleSReg[X86_SREG_COUNT];
/** Counts the times we found a stale selector becomming valid again. */
STAMCOUNTER StatStaleToUnstaleSReg;
#ifdef VBOX_WITH_STATISTICS
/** Times we updated hidden selector registers in CPUMR3UpdateFromCPUM. */
STAMCOUNTER aStatUpdatedSReg[X86_SREG_COUNT];
STAMCOUNTER StatLoadHidSelGst;
STAMCOUNTER StatLoadHidSelShw;
#endif
STAMCOUNTER StatLoadHidSelReadErrors;
STAMCOUNTER StatLoadHidSelGstNoGood;
} SELM, *PSELM;
RT_C_DECLS_BEGIN
VMMRCDECL(int) selmRCGuestGDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange);
VMMRCDECL(int) selmRCGuestLDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange);
VMMRCDECL(int) selmRCGuestTSSWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange);
VMMRCDECL(int) selmRCShadowGDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange);
VMMRCDECL(int) selmRCShadowLDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange);
VMMRCDECL(int) selmRCShadowTSSWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange);
void selmSetRing1Stack(PVM pVM, uint32_t ss, RTGCPTR32 esp);
#ifdef VBOX_WITH_RAW_RING1
void selmSetRing2Stack(PVM pVM, uint32_t ss, RTGCPTR32 esp);
#endif
RT_C_DECLS_END
/** @} */
#endif
|