SELMAll.cpp revision 19964cb6303141f460ac94ae46782cdb3df48d9a
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/* $Id$ */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/** @file
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * SELM All contexts.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
4bc1bbf45f30ff3ca38c2ad006836e490972c7ccvboxsync/*
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * available from http://www.virtualbox.org. This file is free software;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * you can redistribute it and/or modify it under the terms of the GNU
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * General Public License (GPL) as published by the Free Software
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * additional information or have any questions.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/*******************************************************************************
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync* Header Files *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync*******************************************************************************/
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#define LOG_GROUP LOG_GROUP_SELM
88350256a6c78b8631aba5aa5ce249d90a8514a2vboxsync#include <VBox/selm.h>
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#include <VBox/stam.h>
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#include <VBox/mm.h>
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#include <VBox/pgm.h>
943d182735b76ecae26ea011cb7b87e449aafea8vboxsync#include "SELMInternal.h"
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#include <VBox/vm.h>
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#include <VBox/x86.h>
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#include <VBox/err.h>
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#include <VBox/param.h>
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#include <iprt/assert.h>
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#include <VBox/log.h>
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/**
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Converts a GC selector based address to a flat address.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * No limit checks are done. Use the SELMToFlat*() or SELMValidate*() functions
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * for that.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @returns Flat address.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param pVM VM Handle.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param Sel Selector part.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param Addr Address part.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @remarks Don't use when in long mode.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsyncSELMDECL(RTGCPTR) SELMToFlatBySel(PVM pVM, RTSEL Sel, RTGCPTR Addr)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync{
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync Assert(!CPUMIsGuestInLongMode(pVM)); /* DON'T USE! */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** @todo check the limit. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync VBOXDESC Desc;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (!(Sel & X86_SEL_LDT))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync Desc = pVM->selm.s.CTXSUFF(paGdt)[Sel >> X86_SEL_SHIFT];
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync else
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** @todo handle LDT pages not present! */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#ifdef IN_GC
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.GCPtrLdt + pVM->selm.s.offLdtHyper);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#else
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.HCPtrLdt + pVM->selm.s.offLdtHyper);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#endif
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync Desc = paLDT[Sel >> X86_SEL_SHIFT];
c6adb272ec43d5eaadb1493cb2bf45f2f8adf588vboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return (RTGCPTR)((RTGCUINTPTR)Addr + X86DESC_BASE(Desc));
58b7773f17a933ab8d53f450bed0afcf2f003508vboxsync}
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/**
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Converts a GC selector based address to a flat address.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * No limit checks are done. Use the SELMToFlat*() or SELMValidate*() functions
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * for that.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @returns Flat address.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param pVM VM Handle.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param SelReg Selector register
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param pCtxCore CPU context
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param Addr Address part.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsyncSELMDECL(RTGCPTR) SELMToFlat(PVM pVM, DIS_SELREG SelReg, PCPUMCTXCORE pCtxCore, RTGCPTR Addr)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync{
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync PCPUMSELREGHID pHiddenSel;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync RTSEL Sel;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync int rc;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync rc = DISFetchRegSegEx(pCtxCore, SelReg, &Sel, &pHiddenSel); AssertRC(rc);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /*
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Deal with real & v86 mode first.
c6adb272ec43d5eaadb1493cb2bf45f2f8adf588vboxsync */
b28fef07fef379ecc179e0bc0d5d1be753e482b5vboxsync if ( CPUMIsGuestInRealMode(pVM)
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync || pCtxCore->eflags.Bits.u1VM)
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync {
257927abbaa6d9774427049fcbea552cda362281vboxsync RTGCUINTPTR uFlat = (RTGCUINTPTR)Addr & 0xffff;
257927abbaa6d9774427049fcbea552cda362281vboxsync
257927abbaa6d9774427049fcbea552cda362281vboxsync if (CPUMAreHiddenSelRegsValid(pVM))
257927abbaa6d9774427049fcbea552cda362281vboxsync uFlat += pHiddenSel->u64Base;
24a8dd4360c4b4588fd2c340dd7687379a45e02evboxsync else
3c49234930c10a52368b992781dae0306a72b5f5vboxsync uFlat += ((RTGCUINTPTR)Sel << 4);
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync return (RTGCPTR)uFlat;
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync }
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync /** @todo when we're in 16 bits mode, we should cut off the address as well.. */
1d17a5f9688f3622ffe088b664588629b1e95801vboxsync if (!CPUMAreHiddenSelRegsValid(pVM))
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync return SELMToFlatBySel(pVM, Sel, Addr);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0 (Intel� 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync if ( CPUMIsGuestInLongMode(pVM)
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync && pCtxCore->csHid.Attr.n.u1Long)
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync {
81d1b221c2dfff6900e970e273dbb4e81ef6b5d9vboxsync switch (SelReg)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
4bc1bbf45f30ff3ca38c2ad006836e490972c7ccvboxsync case DIS_SELREG_FS:
4bc1bbf45f30ff3ca38c2ad006836e490972c7ccvboxsync case DIS_SELREG_GS:
4bc1bbf45f30ff3ca38c2ad006836e490972c7ccvboxsync return (RTGCPTR)(pHiddenSel->u64Base + Addr);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync default:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return Addr; /* base 0 */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
73e8df2e481cb3697372a3cf4acffd068a7f1296vboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return (RTGCPTR)(pHiddenSel->u64Base + (RTGCUINTPTR)Addr);
d293c8e7a1adaf427e7a361add878676749b7da6vboxsync}
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
73e8df2e481cb3697372a3cf4acffd068a7f1296vboxsync/**
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Converts a GC selector based address to a flat address.
d293c8e7a1adaf427e7a361add878676749b7da6vboxsync *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Some basic checking is done, but not all kinds yet.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *
73e8df2e481cb3697372a3cf4acffd068a7f1296vboxsync * @returns VBox status
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param pVM VM Handle.
d293c8e7a1adaf427e7a361add878676749b7da6vboxsync * @param SelReg Selector register
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param pCtxCore CPU context
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param Addr Address part.
73e8df2e481cb3697372a3cf4acffd068a7f1296vboxsync * @param fFlags SELMTOFLAT_FLAGS_*
9704f1d0180960069e2c4eb8fe2ddee350910e5dvboxsync * GDT entires are valid.
d293c8e7a1adaf427e7a361add878676749b7da6vboxsync * @param ppvGC Where to store the GC flat address.
9704f1d0180960069e2c4eb8fe2ddee350910e5dvboxsync */
9704f1d0180960069e2c4eb8fe2ddee350910e5dvboxsyncSELMDECL(int) SELMToFlatEx(PVM pVM, DIS_SELREG SelReg, PCCPUMCTXCORE pCtxCore, RTGCPTR Addr, unsigned fFlags, PRTGCPTR ppvGC)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync{
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync PCPUMSELREGHID pHiddenSel;
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync RTSEL Sel;
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync int rc;
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync rc = DISFetchRegSegEx(pCtxCore, SelReg, &Sel, &pHiddenSel); AssertRC(rc);
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync /*
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync * Deal with real & v86 mode first.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if ( CPUMIsGuestInRealMode(pVM)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync || pCtxCore->eflags.Bits.u1VM)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync RTGCUINTPTR uFlat = (RTGCUINTPTR)Addr & 0xffff;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (ppvGC)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if ( pHiddenSel
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync && CPUMAreHiddenSelRegsValid(pVM))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *ppvGC = (RTGCPTR)(pHiddenSel->u64Base + uFlat);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync else
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync *ppvGC = (RTGCPTR)(((RTGCUINTPTR)Sel << 4) + uFlat);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VINF_SUCCESS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
58b7773f17a933ab8d53f450bed0afcf2f003508vboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
58b7773f17a933ab8d53f450bed0afcf2f003508vboxsync uint32_t u32Limit;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync RTGCPTR pvFlat;
58b7773f17a933ab8d53f450bed0afcf2f003508vboxsync uint32_t u1Present, u1DescType, u1Granularity, u4Type;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** @todo when we're in 16 bits mode, we should cut off the address as well.. */
58b7773f17a933ab8d53f450bed0afcf2f003508vboxsync#ifndef IN_GC
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync if ( pHiddenSel
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync && CPUMAreHiddenSelRegsValid(pVM))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync bool fCheckLimit = true;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync u1Present = pHiddenSel->Attr.n.u1Present;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync u1Granularity = pHiddenSel->Attr.n.u1Granularity;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync u1DescType = pHiddenSel->Attr.n.u1DescType;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync u4Type = pHiddenSel->Attr.n.u4Type;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync u32Limit = pHiddenSel->u32Limit;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync /* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0 (Intel� 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
cf5af7fccfec4bef83f4ec21662d6a6e6cbe3835vboxsync if ( CPUMIsGuestInLongMode(pVM)
cf5af7fccfec4bef83f4ec21662d6a6e6cbe3835vboxsync && pCtxCore->csHid.Attr.n.u1Long)
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync {
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync fCheckLimit = false;
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync switch (SelReg)
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync {
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync case DIS_SELREG_FS:
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync case DIS_SELREG_GS:
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync pvFlat = (pHiddenSel->u64Base + Addr);
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync break;
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync default:
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync pvFlat = Addr;
cf5af7fccfec4bef83f4ec21662d6a6e6cbe3835vboxsync break;
cf5af7fccfec4bef83f4ec21662d6a6e6cbe3835vboxsync }
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync }
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync else
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync pvFlat = (RTGCPTR)(pHiddenSel->u64Base + (RTGCUINTPTR)Addr);
cf5af7fccfec4bef83f4ec21662d6a6e6cbe3835vboxsync
cf5af7fccfec4bef83f4ec21662d6a6e6cbe3835vboxsync /*
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Check if present.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (u1Present)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /*
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Type check.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync switch (u4Type)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** Read only selector type. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_RO:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_RO_ACC:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_RW:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_RW_ACC:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_EO:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_EO_ACC:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_ER:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_ER_ACC:
9704f1d0180960069e2c4eb8fe2ddee350910e5dvboxsync if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** @todo fix this mess */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* check limit. */
f1acc1e99894e016bd1a6ee65c56b3fc064fa4ebvboxsync if (fCheckLimit && (RTGCUINTPTR)Addr > u32Limit)
09ed5ee011f3a6cd9d4742216ad3bb7dbf855641vboxsync return VERR_OUT_OF_SELECTOR_BOUNDS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* ok */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (ppvGC)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *ppvGC = pvFlat;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VINF_SUCCESS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_EO_CONF:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_EO_CONF_ACC:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_ER_CONF:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_ER_CONF_ACC:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** @todo fix this mess */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* check limit. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (fCheckLimit && (RTGCUINTPTR)Addr > u32Limit)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VERR_OUT_OF_SELECTOR_BOUNDS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* ok */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (ppvGC)
45c2de093cddc990b8d1583aa49b9a40de7a3d97vboxsync *ppvGC = pvFlat;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VINF_SUCCESS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_RO_DOWN:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_RO_DOWN_ACC:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_RW_DOWN:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case X86_SEL_TYPE_RW_DOWN_ACC:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** @todo fix this mess */
d15e1d56958bda40cd12a7c3a71c962b5a710be2vboxsync }
d15e1d56958bda40cd12a7c3a71c962b5a710be2vboxsync /* check limit. */
d15e1d56958bda40cd12a7c3a71c962b5a710be2vboxsync if (fCheckLimit)
d15e1d56958bda40cd12a7c3a71c962b5a710be2vboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (!u1Granularity && (RTGCUINTPTR)Addr > (RTGCUINTPTR)0xffff)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VERR_OUT_OF_SELECTOR_BOUNDS;
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync if ((RTGCUINTPTR)Addr <= u32Limit)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VERR_OUT_OF_SELECTOR_BOUNDS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* ok */
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync if (ppvGC)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *ppvGC = pvFlat;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VINF_SUCCESS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync default:
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync return VERR_INVALID_SELECTOR;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync }
47eb60db91f50291b3bd9b72b64d36341972a155vboxsync else
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync#endif /* !IN_GC */
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync#ifndef IN_RING0
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync VBOXDESC Desc;
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync if (!(Sel & X86_SEL_LDT))
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync {
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync if ( !(fFlags & SELMTOFLAT_FLAGS_HYPER)
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync && (unsigned)(Sel & X86_SEL_MASK) >= pVM->selm.s.GuestGdtr.cbGdt)
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync return VERR_INVALID_SELECTOR;
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync Desc = pVM->selm.s.CTXSUFF(paGdt)[Sel >> X86_SEL_SHIFT];
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync else
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if ((unsigned)(Sel & X86_SEL_MASK) >= pVM->selm.s.cbLdtLimit)
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync return VERR_INVALID_SELECTOR;
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** @todo handle LDT page(s) not present! */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#ifdef IN_GC
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.GCPtrLdt + pVM->selm.s.offLdtHyper);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#else
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.HCPtrLdt + pVM->selm.s.offLdtHyper);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#endif
9704f1d0180960069e2c4eb8fe2ddee350910e5dvboxsync Desc = paLDT[Sel >> X86_SEL_SHIFT];
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync /* calc limit. */
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync u32Limit = X86DESC_LIMIT(Desc);
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync if (Desc.Gen.u1Granularity)
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync u32Limit = (u32Limit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync /* calc address assuming straight stuff. */
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync pvFlat = (RTGCPTR)((RTGCUINTPTR)Addr + X86DESC_BASE(Desc));
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync u1Present = Desc.Gen.u1Present;
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync u1Granularity = Desc.Gen.u1Granularity;
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync u1DescType = Desc.Gen.u1DescType;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync u4Type = Desc.Gen.u4Type;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync /*
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync * Check if present.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (u1Present)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync /*
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync * Type check.
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync */
aca7a56d52c58d8b388343450503c22822fd6620vboxsync#define BOTH(a, b) ((a << 16) | b)
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync switch (BOTH(u1DescType, u4Type))
aca7a56d52c58d8b388343450503c22822fd6620vboxsync {
aca7a56d52c58d8b388343450503c22822fd6620vboxsync
aca7a56d52c58d8b388343450503c22822fd6620vboxsync /** Read only selector type. */
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync case BOTH(1,X86_SEL_TYPE_RO):
aca7a56d52c58d8b388343450503c22822fd6620vboxsync case BOTH(1,X86_SEL_TYPE_RO_ACC):
aca7a56d52c58d8b388343450503c22822fd6620vboxsync case BOTH(1,X86_SEL_TYPE_RW):
aca7a56d52c58d8b388343450503c22822fd6620vboxsync case BOTH(1,X86_SEL_TYPE_RW_ACC):
aca7a56d52c58d8b388343450503c22822fd6620vboxsync case BOTH(1,X86_SEL_TYPE_EO):
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync case BOTH(1,X86_SEL_TYPE_EO_ACC):
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync case BOTH(1,X86_SEL_TYPE_ER):
aca7a56d52c58d8b388343450503c22822fd6620vboxsync case BOTH(1,X86_SEL_TYPE_ER_ACC):
aca7a56d52c58d8b388343450503c22822fd6620vboxsync if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
aca7a56d52c58d8b388343450503c22822fd6620vboxsync {
aca7a56d52c58d8b388343450503c22822fd6620vboxsync /** @todo fix this mess */
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync }
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync /* check limit. */
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync if ((RTGCUINTPTR)Addr > u32Limit)
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync return VERR_OUT_OF_SELECTOR_BOUNDS;
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync /* ok */
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync if (ppvGC)
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync *ppvGC = pvFlat;
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync return VINF_SUCCESS;
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync case BOTH(1,X86_SEL_TYPE_EO_CONF):
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync case BOTH(1,X86_SEL_TYPE_EO_CONF_ACC):
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync case BOTH(1,X86_SEL_TYPE_ER_CONF):
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync case BOTH(1,X86_SEL_TYPE_ER_CONF_ACC):
cf5af7fccfec4bef83f4ec21662d6a6e6cbe3835vboxsync if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** @todo fix this mess */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* check limit. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if ((RTGCUINTPTR)Addr > u32Limit)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VERR_OUT_OF_SELECTOR_BOUNDS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* ok */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (ppvGC)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *ppvGC = pvFlat;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VINF_SUCCESS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(1,X86_SEL_TYPE_RO_DOWN):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(1,X86_SEL_TYPE_RO_DOWN_ACC):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(1,X86_SEL_TYPE_RW_DOWN):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(1,X86_SEL_TYPE_RW_DOWN_ACC):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** @todo fix this mess */
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* check limit. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (!u1Granularity && (RTGCUINTPTR)Addr > (RTGCUINTPTR)0xffff)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VERR_OUT_OF_SELECTOR_BOUNDS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if ((RTGCUINTPTR)Addr <= u32Limit)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VERR_OUT_OF_SELECTOR_BOUNDS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* ok */
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync if (ppvGC)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *ppvGC = pvFlat;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VINF_SUCCESS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(0,X86_SEL_TYPE_SYS_286_TSS_AVAIL):
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync case BOTH(0,X86_SEL_TYPE_SYS_LDT):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(0,X86_SEL_TYPE_SYS_286_TSS_BUSY):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(0,X86_SEL_TYPE_SYS_286_CALL_GATE):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(0,X86_SEL_TYPE_SYS_TASK_GATE):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(0,X86_SEL_TYPE_SYS_286_INT_GATE):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(0,X86_SEL_TYPE_SYS_286_TRAP_GATE):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(0,X86_SEL_TYPE_SYS_386_TSS_AVAIL):
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case BOTH(0,X86_SEL_TYPE_SYS_386_TSS_BUSY):
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync case BOTH(0,X86_SEL_TYPE_SYS_386_CALL_GATE):
47eb60db91f50291b3bd9b72b64d36341972a155vboxsync case BOTH(0,X86_SEL_TYPE_SYS_386_INT_GATE):
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync case BOTH(0,X86_SEL_TYPE_SYS_386_TRAP_GATE):
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
4d5da2bfd5523ad009912e6e0cfb8bf480160e32vboxsync {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** @todo fix this mess */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* check limit. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if ((RTGCUINTPTR)Addr > u32Limit)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VERR_OUT_OF_SELECTOR_BOUNDS;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* ok */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (ppvGC)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *ppvGC = pvFlat;
a0fb1a3d470c09467cd37844f38cf7152c9d2f75vboxsync return VINF_SUCCESS;
a0fb1a3d470c09467cd37844f38cf7152c9d2f75vboxsync
8e5c5c9547558e845335d3077d17422b4ee85b89vboxsync default:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VERR_INVALID_SELECTOR;
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#undef BOTH
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync }
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync#endif /* !IN_RING0 */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync return VERR_SELECTOR_NOT_PRESENT;
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync}
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#ifndef IN_RING0
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/**
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Converts a GC selector based address to a flat address.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync *
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync * Some basic checking is done, but not all kinds yet.
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @returns VBox status
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @param pVM VM Handle.
* @param eflags Current eflags
* @param Sel Selector part.
* @param Addr Address part.
* @param pHiddenSel Hidden selector register (can be NULL)
* @param fFlags SELMTOFLAT_FLAGS_*
* GDT entires are valid.
* @param ppvGC Where to store the GC flat address.
* @param pcb Where to store the bytes from *ppvGC which can be accessed according to
* the selector. NULL is allowed.
* @remarks Don't use when in long mode.
*/
SELMDECL(int) SELMToFlatBySelEx(PVM pVM, X86EFLAGS eflags, RTSEL Sel, RTGCPTR Addr, CPUMSELREGHID *pHiddenSel, unsigned fFlags, PRTGCPTR ppvGC, uint32_t *pcb)
{
Assert(!CPUMIsGuestInLongMode(pVM)); /* DON'T USE! */
/*
* Deal with real & v86 mode first.
*/
if ( CPUMIsGuestInRealMode(pVM)
|| eflags.Bits.u1VM)
{
RTGCUINTPTR uFlat = (RTGCUINTPTR)Addr & 0xffff;
if (ppvGC)
{
if ( pHiddenSel
&& CPUMAreHiddenSelRegsValid(pVM))
*ppvGC = (RTGCPTR)(pHiddenSel->u64Base + uFlat);
else
*ppvGC = (RTGCPTR)(((RTGCUINTPTR)Sel << 4) + uFlat);
}
if (pcb)
*pcb = 0x10000 - uFlat;
return VINF_SUCCESS;
}
uint32_t u32Limit;
RTGCPTR pvFlat;
uint32_t u1Present, u1DescType, u1Granularity, u4Type;
/** @todo when we're in 16 bits mode, we should cut off the address as well.. */
if ( pHiddenSel
&& CPUMAreHiddenSelRegsValid(pVM))
{
u1Present = pHiddenSel->Attr.n.u1Present;
u1Granularity = pHiddenSel->Attr.n.u1Granularity;
u1DescType = pHiddenSel->Attr.n.u1DescType;
u4Type = pHiddenSel->Attr.n.u4Type;
u32Limit = pHiddenSel->u32Limit;
pvFlat = (RTGCPTR)(pHiddenSel->u64Base + (RTGCUINTPTR)Addr);
}
else
{
VBOXDESC Desc;
if (!(Sel & X86_SEL_LDT))
{
if ( !(fFlags & SELMTOFLAT_FLAGS_HYPER)
&& (unsigned)(Sel & X86_SEL_MASK) >= pVM->selm.s.GuestGdtr.cbGdt)
return VERR_INVALID_SELECTOR;
Desc = pVM->selm.s.CTXSUFF(paGdt)[Sel >> X86_SEL_SHIFT];
}
else
{
if ((unsigned)(Sel & X86_SEL_MASK) >= pVM->selm.s.cbLdtLimit)
return VERR_INVALID_SELECTOR;
/** @todo handle LDT page(s) not present! */
#ifdef IN_GC
PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.GCPtrLdt + pVM->selm.s.offLdtHyper);
#else
PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.HCPtrLdt + pVM->selm.s.offLdtHyper);
#endif
Desc = paLDT[Sel >> X86_SEL_SHIFT];
}
/* calc limit. */
u32Limit = X86DESC_LIMIT(Desc);
if (Desc.Gen.u1Granularity)
u32Limit = (u32Limit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
/* calc address assuming straight stuff. */
pvFlat = (RTGCPTR)((RTGCUINTPTR)Addr + X86DESC_BASE(Desc));
u1Present = Desc.Gen.u1Present;
u1Granularity = Desc.Gen.u1Granularity;
u1DescType = Desc.Gen.u1DescType;
u4Type = Desc.Gen.u4Type;
}
/*
* Check if present.
*/
if (u1Present)
{
/*
* Type check.
*/
#define BOTH(a, b) ((a << 16) | b)
switch (BOTH(u1DescType, u4Type))
{
/** Read only selector type. */
case BOTH(1,X86_SEL_TYPE_RO):
case BOTH(1,X86_SEL_TYPE_RO_ACC):
case BOTH(1,X86_SEL_TYPE_RW):
case BOTH(1,X86_SEL_TYPE_RW_ACC):
case BOTH(1,X86_SEL_TYPE_EO):
case BOTH(1,X86_SEL_TYPE_EO_ACC):
case BOTH(1,X86_SEL_TYPE_ER):
case BOTH(1,X86_SEL_TYPE_ER_ACC):
if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
{
/** @todo fix this mess */
}
/* check limit. */
if ((RTGCUINTPTR)Addr > u32Limit)
return VERR_OUT_OF_SELECTOR_BOUNDS;
/* ok */
if (ppvGC)
*ppvGC = pvFlat;
if (pcb)
*pcb = u32Limit - (uint32_t)Addr + 1;
return VINF_SUCCESS;
case BOTH(1,X86_SEL_TYPE_EO_CONF):
case BOTH(1,X86_SEL_TYPE_EO_CONF_ACC):
case BOTH(1,X86_SEL_TYPE_ER_CONF):
case BOTH(1,X86_SEL_TYPE_ER_CONF_ACC):
if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
{
/** @todo fix this mess */
}
/* check limit. */
if ((RTGCUINTPTR)Addr > u32Limit)
return VERR_OUT_OF_SELECTOR_BOUNDS;
/* ok */
if (ppvGC)
*ppvGC = pvFlat;
if (pcb)
*pcb = u32Limit - (uint32_t)Addr + 1;
return VINF_SUCCESS;
case BOTH(1,X86_SEL_TYPE_RO_DOWN):
case BOTH(1,X86_SEL_TYPE_RO_DOWN_ACC):
case BOTH(1,X86_SEL_TYPE_RW_DOWN):
case BOTH(1,X86_SEL_TYPE_RW_DOWN_ACC):
if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
{
/** @todo fix this mess */
}
/* check limit. */
if (!u1Granularity && (RTGCUINTPTR)Addr > (RTGCUINTPTR)0xffff)
return VERR_OUT_OF_SELECTOR_BOUNDS;
if ((RTGCUINTPTR)Addr <= u32Limit)
return VERR_OUT_OF_SELECTOR_BOUNDS;
/* ok */
if (ppvGC)
*ppvGC = pvFlat;
if (pcb)
*pcb = (RTGCUINTPTR)(u1Granularity ? 0xffffffff : 0xffff) - (RTGCUINTPTR)Addr + 1;
return VINF_SUCCESS;
case BOTH(0,X86_SEL_TYPE_SYS_286_TSS_AVAIL):
case BOTH(0,X86_SEL_TYPE_SYS_LDT):
case BOTH(0,X86_SEL_TYPE_SYS_286_TSS_BUSY):
case BOTH(0,X86_SEL_TYPE_SYS_286_CALL_GATE):
case BOTH(0,X86_SEL_TYPE_SYS_TASK_GATE):
case BOTH(0,X86_SEL_TYPE_SYS_286_INT_GATE):
case BOTH(0,X86_SEL_TYPE_SYS_286_TRAP_GATE):
case BOTH(0,X86_SEL_TYPE_SYS_386_TSS_AVAIL):
case BOTH(0,X86_SEL_TYPE_SYS_386_TSS_BUSY):
case BOTH(0,X86_SEL_TYPE_SYS_386_CALL_GATE):
case BOTH(0,X86_SEL_TYPE_SYS_386_INT_GATE):
case BOTH(0,X86_SEL_TYPE_SYS_386_TRAP_GATE):
if (!(fFlags & SELMTOFLAT_FLAGS_NO_PL))
{
/** @todo fix this mess */
}
/* check limit. */
if ((RTGCUINTPTR)Addr > u32Limit)
return VERR_OUT_OF_SELECTOR_BOUNDS;
/* ok */
if (ppvGC)
*ppvGC = pvFlat;
if (pcb)
*pcb = 0xffffffff - (RTGCUINTPTR)pvFlat + 1; /* Depends on the type.. fixme if we care. */
return VINF_SUCCESS;
default:
return VERR_INVALID_SELECTOR;
}
#undef BOTH
}
return VERR_SELECTOR_NOT_PRESENT;
}
#endif /* !IN_RING0 */
/**
* Validates and converts a GC selector based code address to a flat
* address when in real or v8086 mode.
*
* @returns VINF_SUCCESS.
* @param pVM VM Handle.
* @param SelCS Selector part.
* @param pHidCS The hidden CS register part. Optional.
* @param Addr Address part.
* @param ppvFlat Where to store the flat address.
*/
DECLINLINE(int) selmValidateAndConvertCSAddrRealMode(PVM pVM, RTSEL SelCS, PCPUMSELREGHID pHidCS, RTGCPTR Addr, PRTGCPTR ppvFlat)
{
RTGCUINTPTR uFlat = (RTGCUINTPTR)Addr & 0xffff;
if (!pHidCS || !CPUMAreHiddenSelRegsValid(pVM))
uFlat += ((RTGCUINTPTR)SelCS << 4);
else
uFlat += pHidCS->u64Base;
*ppvFlat = (RTGCPTR)uFlat;
return VINF_SUCCESS;
}
/**
* Validates and converts a GC selector based code address to a flat
* address when in protected/long mode using the standard algorithm.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param SelCPL Current privilege level. Get this from SS - CS might be conforming!
* A full selector can be passed, we'll only use the RPL part.
* @param SelCS Selector part.
* @param Addr Address part.
* @param ppvFlat Where to store the flat address.
* @param pcBits Where to store the segment bitness (16/32/64). Optional.
*/
DECLINLINE(int) selmValidateAndConvertCSAddrStd(PVM pVM, RTSEL SelCPL, RTSEL SelCS, RTGCPTR Addr, PRTGCPTR ppvFlat, uint32_t *pcBits)
{
Assert(!CPUMAreHiddenSelRegsValid(pVM));
/** @todo validate limit! */
VBOXDESC Desc;
if (!(SelCS & X86_SEL_LDT))
Desc = pVM->selm.s.CTXSUFF(paGdt)[SelCS >> X86_SEL_SHIFT];
else
{
/** @todo handle LDT page(s) not present! */
#ifdef IN_GC
PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.GCPtrLdt + pVM->selm.s.offLdtHyper);
#else
PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.HCPtrLdt + pVM->selm.s.offLdtHyper);
#endif
Desc = paLDT[SelCS >> X86_SEL_SHIFT];
}
/*
* Check if present.
*/
if (Desc.Gen.u1Present)
{
/*
* Type check.
*/
if ( Desc.Gen.u1DescType == 1
&& (Desc.Gen.u4Type & X86_SEL_TYPE_CODE))
{
/*
* Check level.
*/
unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, SelCS & X86_SEL_RPL);
if ( !(Desc.Gen.u4Type & X86_SEL_TYPE_CONF)
? uLevel <= Desc.Gen.u2Dpl
: uLevel >= Desc.Gen.u2Dpl /* hope I got this right now... */
)
{
/*
* Limit check.
*/
uint32_t u32Limit = X86DESC_LIMIT(Desc);
if (Desc.Gen.u1Granularity)
u32Limit = (u32Limit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
if ((RTGCUINTPTR)Addr <= u32Limit)
{
*ppvFlat = (RTGCPTR)((RTGCUINTPTR)Addr + X86DESC_BASE(Desc));
if (pcBits)
*pcBits = Desc.Gen.u1DefBig ? 32 : 16; /** @todo GUEST64 */
return VINF_SUCCESS;
}
return VERR_OUT_OF_SELECTOR_BOUNDS;
}
return VERR_INVALID_RPL;
}
return VERR_NOT_CODE_SELECTOR;
}
return VERR_SELECTOR_NOT_PRESENT;
}
/**
* Validates and converts a GC selector based code address to a flat
* address when in protected/long mode using the standard algorithm.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param SelCPL Current privilege level. Get this from SS - CS might be conforming!
* A full selector can be passed, we'll only use the RPL part.
* @param SelCS Selector part.
* @param Addr Address part.
* @param ppvFlat Where to store the flat address.
*/
DECLINLINE(int) selmValidateAndConvertCSAddrHidden(PVM pVM, RTSEL SelCPL, RTSEL SelCS, PCPUMSELREGHID pHidCS, RTGCPTR Addr, PRTGCPTR ppvFlat)
{
/*
* Check if present.
*/
if (pHidCS->Attr.n.u1Present)
{
/*
* Type check.
*/
if ( pHidCS->Attr.n.u1DescType == 1
&& (pHidCS->Attr.n.u4Type & X86_SEL_TYPE_CODE))
{
/*
* Check level.
*/
unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, SelCS & X86_SEL_RPL);
if ( !(pHidCS->Attr.n.u4Type & X86_SEL_TYPE_CONF)
? uLevel <= pHidCS->Attr.n.u2Dpl
: uLevel >= pHidCS->Attr.n.u2Dpl /* hope I got this right now... */
)
{
/* 64 bits mode: CS, DS, ES and SS are treated as if each segment base is 0 (Intel� 64 and IA-32 Architectures Software Developer's Manual: 3.4.2.1). */
if ( CPUMIsGuestInLongMode(pVM)
&& pHidCS->Attr.n.u1Long)
{
*ppvFlat = Addr;
return VINF_SUCCESS;
}
/*
* Limit check. Note that the limit in the hidden register is the
* final value. The granularity bit was included in its calculation.
*/
uint32_t u32Limit = pHidCS->u32Limit;
if ((RTGCUINTPTR)Addr <= u32Limit)
{
*ppvFlat = (RTGCPTR)( (RTGCUINTPTR)Addr + pHidCS->u64Base );
return VINF_SUCCESS;
}
return VERR_OUT_OF_SELECTOR_BOUNDS;
}
Log(("Invalid RPL Attr.n.u4Type=%x cpl=%x dpl=%x\n", pHidCS->Attr.n.u4Type, uLevel, pHidCS->Attr.n.u2Dpl));
return VERR_INVALID_RPL;
}
return VERR_NOT_CODE_SELECTOR;
}
return VERR_SELECTOR_NOT_PRESENT;
}
/**
* Validates and converts a GC selector based code address to a flat address.
*
* This is like SELMValidateAndConvertCSAddr + SELMIsSelector32Bit but with
* invalid hidden CS data. It's customized for dealing efficiently with CS
* at GC trap time.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param eflags Current eflags
* @param SelCPL Current privilege level. Get this from SS - CS might be conforming!
* A full selector can be passed, we'll only use the RPL part.
* @param SelCS Selector part.
* @param Addr Address part.
* @param ppvFlat Where to store the flat address.
* @param pcBits Where to store the 64-bit/32-bit/16-bit indicator.
*/
SELMDECL(int) SELMValidateAndConvertCSAddrGCTrap(PVM pVM, X86EFLAGS eflags, RTSEL SelCPL, RTSEL SelCS, RTGCPTR Addr, PRTGCPTR ppvFlat, uint32_t *pcBits)
{
if ( CPUMIsGuestInRealMode(pVM)
|| eflags.Bits.u1VM)
{
*pcBits = 16;
return selmValidateAndConvertCSAddrRealMode(pVM, SelCS, NULL, Addr, ppvFlat);
}
return selmValidateAndConvertCSAddrStd(pVM, SelCPL, SelCS, Addr, ppvFlat, pcBits);
}
/**
* Validates and converts a GC selector based code address to a flat address.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param eflags Current eflags
* @param SelCPL Current privilege level. Get this from SS - CS might be conforming!
* A full selector can be passed, we'll only use the RPL part.
* @param SelCS Selector part.
* @param pHiddenSel The hidden CS selector register.
* @param Addr Address part.
* @param ppvFlat Where to store the flat address.
*/
SELMDECL(int) SELMValidateAndConvertCSAddr(PVM pVM, X86EFLAGS eflags, RTSEL SelCPL, RTSEL SelCS, CPUMSELREGHID *pHiddenCSSel, RTGCPTR Addr, PRTGCPTR ppvFlat)
{
if ( CPUMIsGuestInRealMode(pVM)
|| eflags.Bits.u1VM)
return selmValidateAndConvertCSAddrRealMode(pVM, SelCS, pHiddenCSSel, Addr, ppvFlat);
/** @todo when we're in 16 bits mode, we should cut off the address as well? (like in selmValidateAndConvertCSAddrRealMode) */
if (!CPUMAreHiddenSelRegsValid(pVM))
return selmValidateAndConvertCSAddrStd(pVM, SelCPL, SelCS, Addr, ppvFlat, NULL);
return selmValidateAndConvertCSAddrHidden(pVM, SelCPL, SelCS, pHiddenCSSel, Addr, ppvFlat);
}
/**
* Return the cpu mode corresponding to the (CS) selector
*
* @returns DISCPUMODE according to the selector type (16, 32 or 64 bits)
* @param pVM VM Handle.
* @param Sel The selector.
*/
static DISCPUMODE selmGetCpuModeFromSelector(PVM pVM, RTSEL Sel)
{
Assert(!CPUMAreHiddenSelRegsValid(pVM));
/** @todo validate limit! */
VBOXDESC Desc;
if (!(Sel & X86_SEL_LDT))
Desc = pVM->selm.s.CTXSUFF(paGdt)[Sel >> X86_SEL_SHIFT];
else
{
/** @todo handle LDT page(s) not present! */
PVBOXDESC paLDT = (PVBOXDESC)((char *)pVM->selm.s.CTXMID(,PtrLdt) + pVM->selm.s.offLdtHyper);
Desc = paLDT[Sel >> X86_SEL_SHIFT];
}
return (Desc.Gen.u1DefBig) ? CPUMODE_32BIT : CPUMODE_16BIT;
}
/**
* Return the cpu mode corresponding to the (CS) selector
*
* @returns DISCPUMODE according to the selector type (16, 32 or 64 bits)
* @param pVM VM Handle.
* @param eflags Current eflags register
* @param Sel The selector.
* @param pHiddenSel The hidden selector register.
*/
SELMDECL(DISCPUMODE) SELMGetCpuModeFromSelector(PVM pVM, X86EFLAGS eflags, RTSEL Sel, CPUMSELREGHID *pHiddenSel)
{
if (!CPUMAreHiddenSelRegsValid(pVM))
{
/*
* Deal with real & v86 mode first.
*/
if ( CPUMIsGuestInRealMode(pVM)
|| eflags.Bits.u1VM)
return CPUMODE_16BIT;
return selmGetCpuModeFromSelector(pVM, Sel);
}
if ( CPUMIsGuestInLongMode(pVM)
&& pHiddenSel->Attr.n.u1Long)
return CPUMODE_64BIT;
/* Else compatibility or 32 bits mode. */
return (pHiddenSel->Attr.n.u1DefBig) ? CPUMODE_32BIT : CPUMODE_16BIT;
}
/**
* Returns Hypervisor's Trap 08 (\#DF) selector.
*
* @returns Hypervisor's Trap 08 (\#DF) selector.
* @param pVM VM Handle.
*/
SELMDECL(RTSEL) SELMGetTrap8Selector(PVM pVM)
{
return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08];
}
/**
* Sets EIP of Hypervisor's Trap 08 (\#DF) TSS.
*
* @param pVM VM Handle.
* @param u32EIP EIP of Trap 08 handler.
*/
SELMDECL(void) SELMSetTrap8EIP(PVM pVM, uint32_t u32EIP)
{
pVM->selm.s.TssTrap08.eip = u32EIP;
}
/**
* Sets ss:esp for ring1 in main Hypervisor's TSS.
*
* @param pVM VM Handle.
* @param ss Ring1 SS register value.
* @param esp Ring1 ESP register value.
*/
SELMDECL(void) SELMSetRing1Stack(PVM pVM, uint32_t ss, RTGCPTR32 esp)
{
pVM->selm.s.Tss.ss1 = ss;
pVM->selm.s.Tss.esp1 = (uint32_t)esp;
}
#ifndef IN_RING0
/**
* Gets ss:esp for ring1 in main Hypervisor's TSS.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param pSS Ring1 SS register value.
* @param pEsp Ring1 ESP register value.
*/
SELMDECL(int) SELMGetRing1Stack(PVM pVM, uint32_t *pSS, PRTGCPTR32 pEsp)
{
if (pVM->selm.s.fSyncTSSRing0Stack)
{
RTGCPTR GCPtrTss = pVM->selm.s.GCPtrGuestTss;
int rc;
VBOXTSS tss;
Assert(pVM->selm.s.GCPtrGuestTss && pVM->selm.s.cbMonitoredGuestTss);
#ifdef IN_GC
bool fTriedAlready = false;
l_tryagain:
rc = MMGCRamRead(pVM, &tss.ss0, (RCPTRTYPE(void *))(GCPtrTss + RT_OFFSETOF(VBOXTSS, ss0)), sizeof(tss.ss0));
rc |= MMGCRamRead(pVM, &tss.esp0, (RCPTRTYPE(void *))(GCPtrTss + RT_OFFSETOF(VBOXTSS, esp0)), sizeof(tss.esp0));
#ifdef DEBUG
rc |= MMGCRamRead(pVM, &tss.offIoBitmap, (RCPTRTYPE(void *))(GCPtrTss + RT_OFFSETOF(VBOXTSS, offIoBitmap)), sizeof(tss.offIoBitmap));
#endif
if (VBOX_FAILURE(rc))
{
if (!fTriedAlready)
{
/* Shadow page might be out of sync. Sync and try again */
/** @todo might cross page boundary */
fTriedAlready = true;
rc = PGMPrefetchPage(pVM, (RTGCPTR)GCPtrTss);
if (rc != VINF_SUCCESS)
return rc;
goto l_tryagain;
}
AssertMsgFailed(("Unable to read TSS structure at %08X\n", GCPtrTss));
return rc;
}
#else /* !IN_GC */
/* Reading too much. Could be cheaper than two seperate calls though. */
rc = PGMPhysReadGCPtr(pVM, &tss, GCPtrTss, sizeof(VBOXTSS));
if (VBOX_FAILURE(rc))
{
AssertReleaseMsgFailed(("Unable to read TSS structure at %08X\n", GCPtrTss));
return rc;
}
#endif /* !IN_GC */
#ifdef LOG_ENABLED
uint32_t ssr0 = pVM->selm.s.Tss.ss1;
uint32_t espr0 = pVM->selm.s.Tss.esp1;
ssr0 &= ~1;
if (ssr0 != tss.ss0 || espr0 != tss.esp0)
Log(("SELMGetRing1Stack: Updating TSS ring 0 stack to %04X:%08X\n", tss.ss0, tss.esp0));
Log(("offIoBitmap=%#x\n", tss.offIoBitmap));
#endif
/* Update our TSS structure for the guest's ring 1 stack */
SELMSetRing1Stack(pVM, tss.ss0 | 1, (RTGCPTR32)tss.esp0);
pVM->selm.s.fSyncTSSRing0Stack = false;
}
*pSS = pVM->selm.s.Tss.ss1;
*pEsp = (RTGCPTR32)pVM->selm.s.Tss.esp1;
return VINF_SUCCESS;
}
#endif
/**
* Returns Guest TSS pointer
*
* @param pVM VM Handle.
*/
SELMDECL(RTGCPTR) SELMGetGuestTSS(PVM pVM)
{
return (RTGCPTR)pVM->selm.s.GCPtrGuestTss;
}
/**
* Validates a CS selector.
*
* @returns VBox status code.
* @param pSelInfo Pointer to the selector information for the CS selector.
* @param SelCPL The selector defining the CPL (SS).
*/
SELMDECL(int) SELMSelInfoValidateCS(PCSELMSELINFO pSelInfo, RTSEL SelCPL)
{
/*
* Check if present.
*/
if (pSelInfo->Raw.Gen.u1Present)
{
/*
* Type check.
*/
if ( pSelInfo->Raw.Gen.u1DescType == 1
&& (pSelInfo->Raw.Gen.u4Type & X86_SEL_TYPE_CODE))
{
/*
* Check level.
*/
unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, pSelInfo->Sel & X86_SEL_RPL);
if ( !(pSelInfo->Raw.Gen.u4Type & X86_SEL_TYPE_CONF)
? uLevel <= pSelInfo->Raw.Gen.u2Dpl
: uLevel >= pSelInfo->Raw.Gen.u2Dpl /* hope I got this right now... */
)
return VINF_SUCCESS;
return VERR_INVALID_RPL;
}
return VERR_NOT_CODE_SELECTOR;
}
return VERR_SELECTOR_NOT_PRESENT;
}
#ifndef IN_RING0
/**
* Gets the hypervisor code selector (CS).
* @returns CS selector.
* @param pVM The VM handle.
*/
SELMDECL(RTSEL) SELMGetHyperCS(PVM pVM)
{
return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS];
}
/**
* Gets the 64-mode hypervisor code selector (CS64).
* @returns CS selector.
* @param pVM The VM handle.
*/
SELMDECL(RTSEL) SELMGetHyperCS64(PVM pVM)
{
return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_CS64];
}
/**
* Gets the hypervisor data selector (DS).
* @returns DS selector.
* @param pVM The VM handle.
*/
SELMDECL(RTSEL) SELMGetHyperDS(PVM pVM)
{
return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_DS];
}
/**
* Gets the hypervisor TSS selector.
* @returns TSS selector.
* @param pVM The VM handle.
*/
SELMDECL(RTSEL) SELMGetHyperTSS(PVM pVM)
{
return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS];
}
/**
* Gets the hypervisor TSS Trap 8 selector.
* @returns TSS Trap 8 selector.
* @param pVM The VM handle.
*/
SELMDECL(RTSEL) SELMGetHyperTSSTrap08(PVM pVM)
{
return pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS_TRAP08];
}
/**
* Gets the address for the hypervisor GDT.
*
* @returns The GDT address.
* @param pVM The VM handle.
* @remark This is intended only for very special use, like in the world
* switchers. Don't exploit this API!
*/
SELMDECL(RTGCPTR) SELMGetHyperGDT(PVM pVM)
{
/*
* Always convert this from the HC pointer since. We're can be
* called before the first relocation and have to work correctly
* without having dependencies on the relocation order.
*/
return (RTGCPTR)MMHyperHC2GC(pVM, pVM->selm.s.paGdtHC);
}
#endif /* IN_RING0 */
/**
* Gets info about the current TSS.
*
* @returns VBox status code.
* @retval VINF_SUCCESS if we've got a TSS loaded.
* @retval VERR_SELM_NO_TSS if we haven't got a TSS (rather unlikely).
*
* @param pVM The VM handle.
* @param pGCPtrTss Where to store the TSS address.
* @param pcbTss Where to store the TSS size limit.
* @param pfCanHaveIOBitmap Where to store the can-have-I/O-bitmap indicator. (optional)
*/
SELMDECL(int) SELMGetTSSInfo(PVM pVM, PRTGCUINTPTR pGCPtrTss, PRTGCUINTPTR pcbTss, bool *pfCanHaveIOBitmap)
{
if (!CPUMAreHiddenSelRegsValid(pVM))
{
/*
* Do we have a valid TSS?
*/
if ( pVM->selm.s.GCSelTss == (RTSEL)~0
|| !pVM->selm.s.fGuestTss32Bit)
return VERR_SELM_NO_TSS;
/*
* Fill in return values.
*/
*pGCPtrTss = (RTGCUINTPTR)pVM->selm.s.GCPtrGuestTss;
*pcbTss = pVM->selm.s.cbGuestTss;
if (pfCanHaveIOBitmap)
*pfCanHaveIOBitmap = pVM->selm.s.fGuestTss32Bit;
}
else
{
CPUMSELREGHID *pHiddenTRReg;
pHiddenTRReg = CPUMGetGuestTRHid(pVM);
*pGCPtrTss = pHiddenTRReg->u64Base;
*pcbTss = pHiddenTRReg->u32Limit;
if (pfCanHaveIOBitmap)
*pfCanHaveIOBitmap = pHiddenTRReg->Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_AVAIL
|| pHiddenTRReg->Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY;
}
return VINF_SUCCESS;
}