VirtualBox

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

Last change on this file since 96945 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.3 KB
Line 
1/* $Id: SELMAll.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * SELM All contexts.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_SELM
33#include <VBox/vmm/selm.h>
34#include <VBox/vmm/stam.h>
35#include <VBox/vmm/em.h>
36#include <VBox/vmm/mm.h>
37#include <VBox/vmm/hm.h>
38#include <VBox/vmm/pgm.h>
39#include <VBox/vmm/hm.h>
40#include "SELMInternal.h"
41#include <VBox/vmm/vmcc.h>
42#include <VBox/err.h>
43#include <VBox/param.h>
44#include <iprt/assert.h>
45#include <VBox/vmm/vmm.h>
46#include <iprt/x86.h>
47#include <iprt/string.h>
48
49
50
51/**
52 * Converts a GC selector based address to a flat address.
53 *
54 * No limit checks are done. Use the SELMToFlat*() or SELMValidate*() functions
55 * for that.
56 *
57 * @returns Flat address.
58 * @param pVM The cross context VM structure.
59 * @param SelReg Selector register
60 * @param pCtxCore CPU context
61 * @param Addr Address part.
62 */
63VMMDECL(RTGCPTR) SELMToFlat(PVMCC pVM, DISSELREG SelReg, PCPUMCTXCORE pCtxCore, RTGCPTR Addr)
64{
65 PCPUMSELREG pSReg;
66 PVMCPUCC pVCpu = VMMGetCpu(pVM);
67
68 int rc = DISFetchRegSegEx(pCtxCore, SelReg, &pSReg); AssertRC(rc);
69
70 /*
71 * Deal with real & v86 mode first.
72 */
73 if ( pCtxCore->eflags.Bits.u1VM
74 || CPUMIsGuestInRealMode(pVCpu))
75 {
76 uint32_t uFlat = (uint32_t)Addr & 0xffff;
77 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
78 uFlat += (uint32_t)pSReg->u64Base;
79 else
80 uFlat += (uint32_t)pSReg->Sel << 4;
81 return (RTGCPTR)uFlat;
82 }
83
84 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
85 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pCtxCore->cs));
86
87 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
88 (Intel(r) 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
89 if ( pCtxCore->cs.Attr.n.u1Long
90 && CPUMIsGuestInLongMode(pVCpu))
91 {
92 switch (SelReg)
93 {
94 case DISSELREG_FS:
95 case DISSELREG_GS:
96 return (RTGCPTR)(pSReg->u64Base + Addr);
97
98 default:
99 return Addr; /* base 0 */
100 }
101 }
102
103 /* AMD64 manual: compatibility mode ignores the high 32 bits when calculating an effective address. */
104 Assert(pSReg->u64Base <= 0xffffffff);
105 return (uint32_t)pSReg->u64Base + (uint32_t)Addr;
106}
107
108
109/**
110 * Converts a GC selector based address to a flat address.
111 *
112 * Some basic checking is done, but not all kinds yet.
113 *
114 * @returns VBox status
115 * @param pVCpu The cross context virtual CPU structure.
116 * @param SelReg Selector register.
117 * @param pCtxCore CPU context.
118 * @param Addr Address part.
119 * @param fFlags SELMTOFLAT_FLAGS_*
120 * GDT entires are valid.
121 * @param ppvGC Where to store the GC flat address.
122 */
123VMMDECL(int) SELMToFlatEx(PVMCPU pVCpu, DISSELREG SelReg, PCPUMCTXCORE pCtxCore, RTGCPTR Addr, uint32_t fFlags, PRTGCPTR ppvGC)
124{
125 /*
126 * Fetch the selector first.
127 */
128 PCPUMSELREG pSReg;
129 int rc = DISFetchRegSegEx(pCtxCore, SelReg, &pSReg);
130 AssertRCReturn(rc, rc); AssertPtr(pSReg);
131
132 /*
133 * Deal with real & v86 mode first.
134 */
135 if ( pCtxCore->eflags.Bits.u1VM
136 || CPUMIsGuestInRealMode(pVCpu))
137 {
138 if (ppvGC)
139 {
140 uint32_t uFlat = (uint32_t)Addr & 0xffff;
141 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
142 *ppvGC = (uint32_t)pSReg->u64Base + uFlat;
143 else
144 *ppvGC = ((uint32_t)pSReg->Sel << 4) + uFlat;
145 }
146 return VINF_SUCCESS;
147 }
148
149 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
150 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pCtxCore->cs));
151
152 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
153 (Intel(r) 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
154 RTGCPTR pvFlat;
155 bool fCheckLimit = true;
156 if ( pCtxCore->cs.Attr.n.u1Long
157 && CPUMIsGuestInLongMode(pVCpu))
158 {
159 fCheckLimit = false;
160 switch (SelReg)
161 {
162 case DISSELREG_FS:
163 case DISSELREG_GS:
164 pvFlat = pSReg->u64Base + Addr;
165 break;
166
167 default:
168 pvFlat = Addr;
169 break;
170 }
171 }
172 else
173 {
174 /* AMD64 manual: compatibility mode ignores the high 32 bits when calculating an effective address. */
175 Assert(pSReg->u64Base <= UINT32_C(0xffffffff));
176 pvFlat = (uint32_t)pSReg->u64Base + (uint32_t)Addr;
177 Assert(pvFlat <= UINT32_MAX);
178 }
179
180 /*
181 * Check type if present.
182 */
183 if (pSReg->Attr.n.u1Present)
184 {
185 switch (pSReg->Attr.n.u4Type)
186 {
187 /* Read only selector type. */
188 case X86_SEL_TYPE_RO:
189 case X86_SEL_TYPE_RO_ACC:
190 case X86_SEL_TYPE_RW:
191 case X86_SEL_TYPE_RW_ACC:
192 case X86_SEL_TYPE_EO:
193 case X86_SEL_TYPE_EO_ACC:
194 case X86_SEL_TYPE_ER:
195 case X86_SEL_TYPE_ER_ACC:
196 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
197 {
198 /** @todo fix this mess */
199 }
200 /* check limit. */
201 if (fCheckLimit && Addr > pSReg->u32Limit)
202 return VERR_OUT_OF_SELECTOR_BOUNDS;
203 /* ok */
204 if (ppvGC)
205 *ppvGC = pvFlat;
206 return VINF_SUCCESS;
207
208 case X86_SEL_TYPE_EO_CONF:
209 case X86_SEL_TYPE_EO_CONF_ACC:
210 case X86_SEL_TYPE_ER_CONF:
211 case X86_SEL_TYPE_ER_CONF_ACC:
212 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
213 {
214 /** @todo fix this mess */
215 }
216 /* check limit. */
217 if (fCheckLimit && Addr > pSReg->u32Limit)
218 return VERR_OUT_OF_SELECTOR_BOUNDS;
219 /* ok */
220 if (ppvGC)
221 *ppvGC = pvFlat;
222 return VINF_SUCCESS;
223
224 case X86_SEL_TYPE_RO_DOWN:
225 case X86_SEL_TYPE_RO_DOWN_ACC:
226 case X86_SEL_TYPE_RW_DOWN:
227 case X86_SEL_TYPE_RW_DOWN_ACC:
228 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
229 {
230 /** @todo fix this mess */
231 }
232 /* check limit. */
233 if (fCheckLimit)
234 {
235 if (!pSReg->Attr.n.u1Granularity && Addr > UINT32_C(0xffff))
236 return VERR_OUT_OF_SELECTOR_BOUNDS;
237 if (Addr <= pSReg->u32Limit)
238 return VERR_OUT_OF_SELECTOR_BOUNDS;
239 }
240 /* ok */
241 if (ppvGC)
242 *ppvGC = pvFlat;
243 return VINF_SUCCESS;
244
245 default:
246 return VERR_INVALID_SELECTOR;
247
248 }
249 }
250 return VERR_SELECTOR_NOT_PRESENT;
251}
252
253
254
255/**
256 * Validates and converts a GC selector based code address to a flat
257 * address when in real or v8086 mode.
258 *
259 * @returns VINF_SUCCESS.
260 * @param pVCpu The cross context virtual CPU structure.
261 * @param SelCS Selector part.
262 * @param pSReg The hidden CS register part. Optional.
263 * @param Addr Address part.
264 * @param ppvFlat Where to store the flat address.
265 */
266DECLINLINE(int) selmValidateAndConvertCSAddrRealMode(PVMCPU pVCpu, RTSEL SelCS, PCCPUMSELREGHID pSReg, RTGCPTR Addr,
267 PRTGCPTR ppvFlat)
268{
269 NOREF(pVCpu);
270 uint32_t uFlat = Addr & 0xffff;
271 if (!pSReg || !CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
272 uFlat += (uint32_t)SelCS << 4;
273 else
274 uFlat += (uint32_t)pSReg->u64Base;
275 *ppvFlat = uFlat;
276 return VINF_SUCCESS;
277}
278
279
280/**
281 * Validates and converts a GC selector based code address to a flat address
282 * when in protected/long mode using the standard hidden selector registers
283 *
284 * @returns VBox status code.
285 * @param pVCpu The cross context virtual CPU structure.
286 * @param SelCPL Current privilege level. Get this from SS - CS might be
287 * conforming! A full selector can be passed, we'll only
288 * use the RPL part.
289 * @param SelCS Selector part.
290 * @param pSRegCS The full CS selector register.
291 * @param Addr The address (think IP/EIP/RIP).
292 * @param ppvFlat Where to store the flat address upon successful return.
293 */
294DECLINLINE(int) selmValidateAndConvertCSAddrHidden(PVMCPU pVCpu, RTSEL SelCPL, RTSEL SelCS, PCCPUMSELREGHID pSRegCS,
295 RTGCPTR Addr, PRTGCPTR ppvFlat)
296{
297 NOREF(SelCPL); NOREF(SelCS);
298
299 /*
300 * Check if present.
301 */
302 if (pSRegCS->Attr.n.u1Present)
303 {
304 /*
305 * Type check.
306 */
307 if ( pSRegCS->Attr.n.u1DescType == 1
308 && (pSRegCS->Attr.n.u4Type & X86_SEL_TYPE_CODE))
309 {
310 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
311 (Intel(r) 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
312 if ( pSRegCS->Attr.n.u1Long
313 && CPUMIsGuestInLongMode(pVCpu))
314 {
315 *ppvFlat = Addr;
316 return VINF_SUCCESS;
317 }
318
319 /*
320 * Limit check. Note that the limit in the hidden register is the
321 * final value. The granularity bit was included in its calculation.
322 */
323 uint32_t u32Limit = pSRegCS->u32Limit;
324 if ((uint32_t)Addr <= u32Limit)
325 {
326 *ppvFlat = (uint32_t)Addr + (uint32_t)pSRegCS->u64Base;
327 return VINF_SUCCESS;
328 }
329
330 return VERR_OUT_OF_SELECTOR_BOUNDS;
331 }
332 return VERR_NOT_CODE_SELECTOR;
333 }
334 return VERR_SELECTOR_NOT_PRESENT;
335}
336
337
338/**
339 * Validates and converts a GC selector based code address to a flat address.
340 *
341 * @returns VBox status code.
342 * @param pVCpu The cross context virtual CPU structure.
343 * @param Efl Current EFLAGS.
344 * @param SelCPL Current privilege level. Get this from SS - CS might be
345 * conforming! A full selector can be passed, we'll only
346 * use the RPL part.
347 * @param SelCS Selector part.
348 * @param pSRegCS The full CS selector register.
349 * @param Addr The address (think IP/EIP/RIP).
350 * @param ppvFlat Where to store the flat address upon successful return.
351 */
352VMMDECL(int) SELMValidateAndConvertCSAddr(PVMCPU pVCpu, X86EFLAGS Efl, RTSEL SelCPL, RTSEL SelCS, PCPUMSELREG pSRegCS,
353 RTGCPTR Addr, PRTGCPTR ppvFlat)
354{
355 if ( Efl.Bits.u1VM
356 || CPUMIsGuestInRealMode(pVCpu))
357 return selmValidateAndConvertCSAddrRealMode(pVCpu, SelCS, pSRegCS, Addr, ppvFlat);
358
359 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSRegCS));
360 Assert(pSRegCS->Sel == SelCS);
361
362 return selmValidateAndConvertCSAddrHidden(pVCpu, SelCPL, SelCS, pSRegCS, Addr, ppvFlat);
363}
364
365
366/**
367 * Gets info about the current TSS.
368 *
369 * @returns VBox status code.
370 * @retval VINF_SUCCESS if we've got a TSS loaded.
371 * @retval VERR_SELM_NO_TSS if we haven't got a TSS (rather unlikely).
372 *
373 * @param pVM The cross context VM structure.
374 * @param pVCpu The cross context virtual CPU structure.
375 * @param pGCPtrTss Where to store the TSS address.
376 * @param pcbTss Where to store the TSS size limit.
377 * @param pfCanHaveIOBitmap Where to store the can-have-I/O-bitmap indicator. (optional)
378 */
379VMMDECL(int) SELMGetTSSInfo(PVM pVM, PVMCPU pVCpu, PRTGCUINTPTR pGCPtrTss, PRTGCUINTPTR pcbTss, bool *pfCanHaveIOBitmap)
380{
381 NOREF(pVM);
382
383 /*
384 * The TR hidden register is always valid.
385 */
386 CPUMSELREGHID trHid;
387 RTSEL tr = CPUMGetGuestTR(pVCpu, &trHid);
388 if (!(tr & X86_SEL_MASK_OFF_RPL))
389 return VERR_SELM_NO_TSS;
390
391 *pGCPtrTss = trHid.u64Base;
392 *pcbTss = trHid.u32Limit + (trHid.u32Limit != UINT32_MAX); /* be careful. */
393 if (pfCanHaveIOBitmap)
394 *pfCanHaveIOBitmap = trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_AVAIL
395 || trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY;
396 return VINF_SUCCESS;
397}
398
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