VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 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
RevLine 
[23]1/* $Id: SELMAll.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
[1]2/** @file
3 * SELM All contexts.
4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]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
[1]26 */
27
28
[57358]29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[1]32#define LOG_GROUP LOG_GROUP_SELM
[35346]33#include <VBox/vmm/selm.h>
34#include <VBox/vmm/stam.h>
[45485]35#include <VBox/vmm/em.h>
[35346]36#include <VBox/vmm/mm.h>
[45701]37#include <VBox/vmm/hm.h>
[35346]38#include <VBox/vmm/pgm.h>
[43387]39#include <VBox/vmm/hm.h>
[1]40#include "SELMInternal.h"
[80268]41#include <VBox/vmm/vmcc.h>
[1]42#include <VBox/err.h>
43#include <VBox/param.h>
44#include <iprt/assert.h>
[35346]45#include <VBox/vmm/vmm.h>
[37955]46#include <iprt/x86.h>
[56016]47#include <iprt/string.h>
[1]48
49
50
[56013]51/**
[1]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.
[97203]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.
[2117]61 * @param Addr Address part.
[1]62 */
[97203]63VMMDECL(RTGCPTR) SELMToFlat(PVMCPUCC pVCpu, unsigned idxSeg, PCPUMCTX pCtx, RTGCPTR Addr)
[1]64{
[97203]65 Assert(idxSeg < RT_ELEMENTS(pCtx->aSRegs));
66 PCPUMSELREG pSReg = &pCtx->aSRegs[idxSeg];
[2260]67
[9675]68 /*
69 * Deal with real & v86 mode first.
70 */
[97203]71 if ( pCtx->eflags.Bits.u1VM
[25837]72 || CPUMIsGuestInRealMode(pVCpu))
[1359]73 {
[52363]74 uint32_t uFlat = (uint32_t)Addr & 0xffff;
[42420]75 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
[52363]76 uFlat += (uint32_t)pSReg->u64Base;
[2260]77 else
[52363]78 uFlat += (uint32_t)pSReg->Sel << 4;
[2260]79 return (RTGCPTR)uFlat;
80 }
81
[42407]82 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
[97203]83 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pCtx->cs));
[9675]84
[42186]85 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
[92184]86 (Intel(r) 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
[97203]87 if ( pCtx->cs.Attr.n.u1Long
[25837]88 && CPUMIsGuestInLongMode(pVCpu))
[9675]89 {
[97203]90 switch (idxSeg)
[9675]91 {
[97203]92 case X86_SREG_FS:
93 case X86_SREG_GS:
[42186]94 return (RTGCPTR)(pSReg->u64Base + Addr);
[9675]95
[13577]96 default:
97 return Addr; /* base 0 */
[9675]98 }
99 }
[13577]100
[12404]101 /* AMD64 manual: compatibility mode ignores the high 32 bits when calculating an effective address. */
[42186]102 Assert(pSReg->u64Base <= 0xffffffff);
[52363]103 return (uint32_t)pSReg->u64Base + (uint32_t)Addr;
[1]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
[58123]113 * @param pVCpu The cross context virtual CPU structure.
[97203]114 * @param idxSeg The selector register to use (X86_SREG_XXX).
115 * @param pCtx Pointer to the register context for the CPU.
[9678]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 */
[97203]121VMMDECL(int) SELMToFlatEx(PVMCPU pVCpu, unsigned idxSeg, PCPUMCTX pCtx, RTGCPTR Addr, uint32_t fFlags, PRTGCPTR ppvGC)
[9678]122{
[97203]123 AssertReturn(idxSeg < RT_ELEMENTS(pCtx->aSRegs), VERR_INVALID_PARAMETER);
124 PCPUMSELREG pSReg = &pCtx->aSRegs[idxSeg];
[18927]125
[9678]126 /*
127 * Deal with real & v86 mode first.
128 */
[97203]129 if ( pCtx->eflags.Bits.u1VM
[25837]130 || CPUMIsGuestInRealMode(pVCpu))
[9678]131 {
132 if (ppvGC)
133 {
[52363]134 uint32_t uFlat = (uint32_t)Addr & 0xffff;
[42407]135 if (CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
[52363]136 *ppvGC = (uint32_t)pSReg->u64Base + uFlat;
[9678]137 else
[52363]138 *ppvGC = ((uint32_t)pSReg->Sel << 4) + uFlat;
[9678]139 }
140 return VINF_SUCCESS;
141 }
142
[42407]143 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
[97203]144 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pCtx->cs));
[9678]145
[42186]146 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
[92184]147 (Intel(r) 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
[42186]148 RTGCPTR pvFlat;
149 bool fCheckLimit = true;
[97203]150 if ( pCtx->cs.Attr.n.u1Long
[42186]151 && CPUMIsGuestInLongMode(pVCpu))
[9678]152 {
[42186]153 fCheckLimit = false;
[97203]154 switch (idxSeg)
[9678]155 {
[97203]156 case X86_SREG_FS:
157 case X86_SREG_GS:
[42186]158 pvFlat = pSReg->u64Base + Addr;
159 break;
[9678]160
[42186]161 default:
162 pvFlat = Addr;
163 break;
[9678]164 }
165 }
166 else
167 {
[42186]168 /* AMD64 manual: compatibility mode ignores the high 32 bits when calculating an effective address. */
169 Assert(pSReg->u64Base <= UINT32_C(0xffffffff));
[52363]170 pvFlat = (uint32_t)pSReg->u64Base + (uint32_t)Addr;
171 Assert(pvFlat <= UINT32_MAX);
[42186]172 }
[9678]173
[42186]174 /*
175 * Check type if present.
176 */
177 if (pSReg->Attr.n.u1Present)
178 {
179 switch (pSReg->Attr.n.u4Type)
[9678]180 {
[42186]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;
[9678]201
[42186]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;
[9678]217
[42186]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))
[9678]230 return VERR_OUT_OF_SELECTOR_BOUNDS;
[42186]231 if (Addr <= pSReg->u32Limit)
[9678]232 return VERR_OUT_OF_SELECTOR_BOUNDS;
[42186]233 }
234 /* ok */
235 if (ppvGC)
236 *ppvGC = pvFlat;
237 return VINF_SUCCESS;
[9678]238
[42186]239 default:
240 return VERR_INVALID_SELECTOR;
[9678]241
242 }
243 }
244 return VERR_SELECTOR_NOT_PRESENT;
245}
246
[13577]247
[18927]248
[1]249/**
[5396]250 * Validates and converts a GC selector based code address to a flat
251 * address when in real or v8086 mode.
[1]252 *
[5396]253 * @returns VINF_SUCCESS.
[58123]254 * @param pVCpu The cross context virtual CPU structure.
[5396]255 * @param SelCS Selector part.
[58126]256 * @param pSReg The hidden CS register part. Optional.
[5396]257 * @param Addr Address part.
258 * @param ppvFlat Where to store the flat address.
259 */
[42186]260DECLINLINE(int) selmValidateAndConvertCSAddrRealMode(PVMCPU pVCpu, RTSEL SelCS, PCCPUMSELREGHID pSReg, RTGCPTR Addr,
[30263]261 PRTGCPTR ppvFlat)
[5396]262{
[49482]263 NOREF(pVCpu);
[52363]264 uint32_t uFlat = Addr & 0xffff;
[42407]265 if (!pSReg || !CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg))
[52363]266 uFlat += (uint32_t)SelCS << 4;
[5396]267 else
[52363]268 uFlat += (uint32_t)pSReg->u64Base;
[42186]269 *ppvFlat = uFlat;
[5396]270 return VINF_SUCCESS;
271}
272
273
274/**
[42186]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
[1]277 *
[5396]278 * @returns VBox status code.
[58123]279 * @param pVCpu The cross context virtual CPU structure.
[42186]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.
[1]287 */
[42186]288DECLINLINE(int) selmValidateAndConvertCSAddrHidden(PVMCPU pVCpu, RTSEL SelCPL, RTSEL SelCS, PCCPUMSELREGHID pSRegCS,
[30263]289 RTGCPTR Addr, PRTGCPTR ppvFlat)
[1]290{
[57851]291 NOREF(SelCPL); NOREF(SelCS);
292
[2181]293 /*
[1]294 * Check if present.
295 */
[42186]296 if (pSRegCS->Attr.n.u1Present)
[1]297 {
298 /*
299 * Type check.
300 */
[42186]301 if ( pSRegCS->Attr.n.u1DescType == 1
302 && (pSRegCS->Attr.n.u4Type & X86_SEL_TYPE_CODE))
[1]303 {
[50141]304 /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0
[92184]305 (Intel(r) 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
[50141]306 if ( pSRegCS->Attr.n.u1Long
307 && CPUMIsGuestInLongMode(pVCpu))
308 {
309 *ppvFlat = Addr;
310 return VINF_SUCCESS;
311 }
312
[1]313 /*
[50141]314 * Limit check. Note that the limit in the hidden register is the
315 * final value. The granularity bit was included in its calculation.
[1]316 */
[50141]317 uint32_t u32Limit = pSRegCS->u32Limit;
[52363]318 if ((uint32_t)Addr <= u32Limit)
[1]319 {
[52363]320 *ppvFlat = (uint32_t)Addr + (uint32_t)pSRegCS->u64Base;
[50141]321 return VINF_SUCCESS;
322 }
[9656]323
[50141]324 return VERR_OUT_OF_SELECTOR_BOUNDS;
[1]325 }
326 return VERR_NOT_CODE_SELECTOR;
327 }
328 return VERR_SELECTOR_NOT_PRESENT;
329}
330
331
332/**
[5396]333 * Validates and converts a GC selector based code address to a flat address.
334 *
335 * @returns VBox status code.
[58123]336 * @param pVCpu The cross context virtual CPU structure.
[97218]337 * @param fEFlags Current EFLAGS.
[42186]338 * @param SelCPL Current privilege level. Get this from SS - CS might be
339 * conforming! A full selector can be passed, we'll only
[40449]340 * use the RPL part.
341 * @param SelCS Selector part.
[42186]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.
[5396]345 */
[97218]346VMMDECL(int) SELMValidateAndConvertCSAddr(PVMCPU pVCpu, uint32_t fEFlags, RTSEL SelCPL, RTSEL SelCS, PCPUMSELREG pSRegCS,
[42186]347 RTGCPTR Addr, PRTGCPTR ppvFlat)
[5396]348{
[97218]349 if ( (fEFlags & X86_EFL_VM)
350 || CPUMIsGuestInRealMode(pVCpu))
[42186]351 return selmValidateAndConvertCSAddrRealMode(pVCpu, SelCS, pSRegCS, Addr, ppvFlat);
[5396]352
[42407]353 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSRegCS));
[42186]354 Assert(pSRegCS->Sel == SelCS);
[5396]355
[42186]356 return selmValidateAndConvertCSAddrHidden(pVCpu, SelCPL, SelCS, pSRegCS, Addr, ppvFlat);
[1]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 *
[58122]367 * @param pVM The cross context VM structure.
[58123]368 * @param pVCpu The cross context virtual CPU structure.
[1]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 */
[18927]373VMMDECL(int) SELMGetTSSInfo(PVM pVM, PVMCPU pVCpu, PRTGCUINTPTR pGCPtrTss, PRTGCUINTPTR pcbTss, bool *pfCanHaveIOBitmap)
[1]374{
[39078]375 NOREF(pVM);
376
[17035]377 /*
378 * The TR hidden register is always valid.
379 */
380 CPUMSELREGHID trHid;
[18927]381 RTSEL tr = CPUMGetGuestTR(pVCpu, &trHid);
[42427]382 if (!(tr & X86_SEL_MASK_OFF_RPL))
[17035]383 return VERR_SELM_NO_TSS;
[1]384
[17035]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;
[1]390 return VINF_SUCCESS;
391}
[13577]392
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use