VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.3 KB
Line 
1/* $Id: SELMAll.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * SELM All contexts.
4 */
5
6/*
7 * Copyright (C) 2006-2023 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 pVCpu The cross context virtual CPU structure.
59 * @param idxSeg The selector register to use (X86_SREG_XXX).
60 * @param pCtx Pointer to the register context for the CPU.
61 * @param Addr Address part.
62 */
63VMMDECL(RTGCPTR) SELMToFlat(PVMCPUCC pVCpu, unsigned idxSeg, PCPUMCTX pCtx, RTGCPTR Addr)
64{
65 Assert(idxSeg < RT_ELEMENTS(pCtx->aSRegs));
66 PCPUMSELREG pSReg = &pCtx->aSRegs[idxSeg];
67
68 /*
69 * Deal with real & v86 mode first.
70 */
71 if ( pCtx->eflags.Bits.u1VM
72 || CPUMIsGuestInRealMode(pVCpu))
73 {
74 uint32_t uFlat = (uint32_t)Addr & 0xffff;
75 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
76 uFlat += (uint32_t)pSReg->u64Base;
77 else
78 uFlat += (uint32_t)pSReg->Sel << 4;
79 return (RTGCPTR)uFlat;
80 }
81
82 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
83 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pCtx->cs));
84
85 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
86 (Intel(r) 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
87 if ( pCtx->cs.Attr.n.u1Long
88 && CPUMIsGuestInLongMode(pVCpu))
89 {
90 switch (idxSeg)
91 {
92 case X86_SREG_FS:
93 case X86_SREG_GS:
94 return (RTGCPTR)(pSReg->u64Base + Addr);
95
96 default:
97 return Addr; /* base 0 */
98 }
99 }
100
101 /* AMD64 manual: compatibility mode ignores the high 32 bits when calculating an effective address. */
102 Assert(pSReg->u64Base <= 0xffffffff);
103 return (uint32_t)pSReg->u64Base + (uint32_t)Addr;
104}
105
106
107/**
108 * Converts a GC selector based address to a flat address.
109 *
110 * Some basic checking is done, but not all kinds yet.
111 *
112 * @returns VBox status
113 * @param pVCpu The cross context virtual CPU structure.
114 * @param idxSeg The selector register to use (X86_SREG_XXX).
115 * @param pCtx Pointer to the register context for the CPU.
116 * @param Addr Address part.
117 * @param fFlags SELMTOFLAT_FLAGS_*
118 * GDT entires are valid.
119 * @param ppvGC Where to store the GC flat address.
120 */
121VMMDECL(int) SELMToFlatEx(PVMCPU pVCpu, unsigned idxSeg, PCPUMCTX pCtx, RTGCPTR Addr, uint32_t fFlags, PRTGCPTR ppvGC)
122{
123 AssertReturn(idxSeg < RT_ELEMENTS(pCtx->aSRegs), VERR_INVALID_PARAMETER);
124 PCPUMSELREG pSReg = &pCtx->aSRegs[idxSeg];
125
126 /*
127 * Deal with real & v86 mode first.
128 */
129 if ( pCtx->eflags.Bits.u1VM
130 || CPUMIsGuestInRealMode(pVCpu))
131 {
132 if (ppvGC)
133 {
134 uint32_t uFlat = (uint32_t)Addr & 0xffff;
135 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
136 *ppvGC = (uint32_t)pSReg->u64Base + uFlat;
137 else
138 *ppvGC = ((uint32_t)pSReg->Sel << 4) + uFlat;
139 }
140 return VINF_SUCCESS;
141 }
142
143 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
144 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pCtx->cs));
145
146 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
147 (Intel(r) 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
148 RTGCPTR pvFlat;
149 bool fCheckLimit = true;
150 if ( pCtx->cs.Attr.n.u1Long
151 && CPUMIsGuestInLongMode(pVCpu))
152 {
153 fCheckLimit = false;
154 switch (idxSeg)
155 {
156 case X86_SREG_FS:
157 case X86_SREG_GS:
158 pvFlat = pSReg->u64Base + Addr;
159 break;
160
161 default:
162 pvFlat = Addr;
163 break;
164 }
165 }
166 else
167 {
168 /* AMD64 manual: compatibility mode ignores the high 32 bits when calculating an effective address. */
169 Assert(pSReg->u64Base <= UINT32_C(0xffffffff));
170 pvFlat = (uint32_t)pSReg->u64Base + (uint32_t)Addr;
171 Assert(pvFlat <= UINT32_MAX);
172 }
173
174 /*
175 * Check type if present.
176 */
177 if (pSReg->Attr.n.u1Present)
178 {
179 switch (pSReg->Attr.n.u4Type)
180 {
181 /* Read only selector type. */
182 case X86_SEL_TYPE_RO:
183 case X86_SEL_TYPE_RO_ACC:
184 case X86_SEL_TYPE_RW:
185 case X86_SEL_TYPE_RW_ACC:
186 case X86_SEL_TYPE_EO:
187 case X86_SEL_TYPE_EO_ACC:
188 case X86_SEL_TYPE_ER:
189 case X86_SEL_TYPE_ER_ACC:
190 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
191 {
192 /** @todo fix this mess */
193 }
194 /* check limit. */
195 if (fCheckLimit && Addr > pSReg->u32Limit)
196 return VERR_OUT_OF_SELECTOR_BOUNDS;
197 /* ok */
198 if (ppvGC)
199 *ppvGC = pvFlat;
200 return VINF_SUCCESS;
201
202 case X86_SEL_TYPE_EO_CONF:
203 case X86_SEL_TYPE_EO_CONF_ACC:
204 case X86_SEL_TYPE_ER_CONF:
205 case X86_SEL_TYPE_ER_CONF_ACC:
206 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
207 {
208 /** @todo fix this mess */
209 }
210 /* check limit. */
211 if (fCheckLimit && Addr > pSReg->u32Limit)
212 return VERR_OUT_OF_SELECTOR_BOUNDS;
213 /* ok */
214 if (ppvGC)
215 *ppvGC = pvFlat;
216 return VINF_SUCCESS;
217
218 case X86_SEL_TYPE_RO_DOWN:
219 case X86_SEL_TYPE_RO_DOWN_ACC:
220 case X86_SEL_TYPE_RW_DOWN:
221 case X86_SEL_TYPE_RW_DOWN_ACC:
222 if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
223 {
224 /** @todo fix this mess */
225 }
226 /* check limit. */
227 if (fCheckLimit)
228 {
229 if (!pSReg->Attr.n.u1Granularity && Addr > UINT32_C(0xffff))
230 return VERR_OUT_OF_SELECTOR_BOUNDS;
231 if (Addr <= pSReg->u32Limit)
232 return VERR_OUT_OF_SELECTOR_BOUNDS;
233 }
234 /* ok */
235 if (ppvGC)
236 *ppvGC = pvFlat;
237 return VINF_SUCCESS;
238
239 default:
240 return VERR_INVALID_SELECTOR;
241
242 }
243 }
244 return VERR_SELECTOR_NOT_PRESENT;
245}
246
247
248
249/**
250 * Validates and converts a GC selector based code address to a flat
251 * address when in real or v8086 mode.
252 *
253 * @returns VINF_SUCCESS.
254 * @param pVCpu The cross context virtual CPU structure.
255 * @param SelCS Selector part.
256 * @param pSReg The hidden CS register part. Optional.
257 * @param Addr Address part.
258 * @param ppvFlat Where to store the flat address.
259 */
260DECLINLINE(int) selmValidateAndConvertCSAddrRealMode(PVMCPU pVCpu, RTSEL SelCS, PCCPUMSELREGHID pSReg, RTGCPTR Addr,
261 PRTGCPTR ppvFlat)
262{
263 NOREF(pVCpu);
264 uint32_t uFlat = Addr & 0xffff;
265 if (!pSReg || !CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
266 uFlat += (uint32_t)SelCS << 4;
267 else
268 uFlat += (uint32_t)pSReg->u64Base;
269 *ppvFlat = uFlat;
270 return VINF_SUCCESS;
271}
272
273
274/**
275 * Validates and converts a GC selector based code address to a flat address
276 * when in protected/long mode using the standard hidden selector registers
277 *
278 * @returns VBox status code.
279 * @param pVCpu The cross context virtual CPU structure.
280 * @param SelCPL Current privilege level. Get this from SS - CS might be
281 * conforming! A full selector can be passed, we'll only
282 * use the RPL part.
283 * @param SelCS Selector part.
284 * @param pSRegCS The full CS selector register.
285 * @param Addr The address (think IP/EIP/RIP).
286 * @param ppvFlat Where to store the flat address upon successful return.
287 */
288DECLINLINE(int) selmValidateAndConvertCSAddrHidden(PVMCPU pVCpu, RTSEL SelCPL, RTSEL SelCS, PCCPUMSELREGHID pSRegCS,
289 RTGCPTR Addr, PRTGCPTR ppvFlat)
290{
291 NOREF(SelCPL); NOREF(SelCS);
292
293 /*
294 * Check if present.
295 */
296 if (pSRegCS->Attr.n.u1Present)
297 {
298 /*
299 * Type check.
300 */
301 if ( pSRegCS->Attr.n.u1DescType == 1
302 && (pSRegCS->Attr.n.u4Type & X86_SEL_TYPE_CODE))
303 {
304 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
305 (Intel(r) 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
306 if ( pSRegCS->Attr.n.u1Long
307 && CPUMIsGuestInLongMode(pVCpu))
308 {
309 *ppvFlat = Addr;
310 return VINF_SUCCESS;
311 }
312
313 /*
314 * Limit check. Note that the limit in the hidden register is the
315 * final value. The granularity bit was included in its calculation.
316 */
317 uint32_t u32Limit = pSRegCS->u32Limit;
318 if ((uint32_t)Addr <= u32Limit)
319 {
320 *ppvFlat = (uint32_t)Addr + (uint32_t)pSRegCS->u64Base;
321 return VINF_SUCCESS;
322 }
323
324 return VERR_OUT_OF_SELECTOR_BOUNDS;
325 }
326 return VERR_NOT_CODE_SELECTOR;
327 }
328 return VERR_SELECTOR_NOT_PRESENT;
329}
330
331
332/**
333 * Validates and converts a GC selector based code address to a flat address.
334 *
335 * @returns VBox status code.
336 * @param pVCpu The cross context virtual CPU structure.
337 * @param fEFlags Current EFLAGS.
338 * @param SelCPL Current privilege level. Get this from SS - CS might be
339 * conforming! A full selector can be passed, we'll only
340 * use the RPL part.
341 * @param SelCS Selector part.
342 * @param pSRegCS The full CS selector register.
343 * @param Addr The address (think IP/EIP/RIP).
344 * @param ppvFlat Where to store the flat address upon successful return.
345 */
346VMMDECL(int) SELMValidateAndConvertCSAddr(PVMCPU pVCpu, uint32_t fEFlags, RTSEL SelCPL, RTSEL SelCS, PCPUMSELREG pSRegCS,
347 RTGCPTR Addr, PRTGCPTR ppvFlat)
348{
349 if ( (fEFlags & X86_EFL_VM)
350 || CPUMIsGuestInRealMode(pVCpu))
351 return selmValidateAndConvertCSAddrRealMode(pVCpu, SelCS, pSRegCS, Addr, ppvFlat);
352
353 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSRegCS));
354 Assert(pSRegCS->Sel == SelCS);
355
356 return selmValidateAndConvertCSAddrHidden(pVCpu, SelCPL, SelCS, pSRegCS, Addr, ppvFlat);
357}
358
359
360/**
361 * Gets info about the current TSS.
362 *
363 * @returns VBox status code.
364 * @retval VINF_SUCCESS if we've got a TSS loaded.
365 * @retval VERR_SELM_NO_TSS if we haven't got a TSS (rather unlikely).
366 *
367 * @param pVM The cross context VM structure.
368 * @param pVCpu The cross context virtual CPU structure.
369 * @param pGCPtrTss Where to store the TSS address.
370 * @param pcbTss Where to store the TSS size limit.
371 * @param pfCanHaveIOBitmap Where to store the can-have-I/O-bitmap indicator. (optional)
372 */
373VMMDECL(int) SELMGetTSSInfo(PVM pVM, PVMCPU pVCpu, PRTGCUINTPTR pGCPtrTss, PRTGCUINTPTR pcbTss, bool *pfCanHaveIOBitmap)
374{
375 NOREF(pVM);
376
377 /*
378 * The TR hidden register is always valid.
379 */
380 CPUMSELREGHID trHid;
381 RTSEL tr = CPUMGetGuestTR(pVCpu, &trHid);
382 if (!(tr & X86_SEL_MASK_OFF_RPL))
383 return VERR_SELM_NO_TSS;
384
385 *pGCPtrTss = trHid.u64Base;
386 *pcbTss = trHid.u32Limit + (trHid.u32Limit != UINT32_MAX); /* be careful. */
387 if (pfCanHaveIOBitmap)
388 *pfCanHaveIOBitmap = trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_AVAIL
389 || trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY;
390 return VINF_SUCCESS;
391}
392
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use