687 lines
17 KiB
C
687 lines
17 KiB
C
|
/*********************************************************
|
||
|
* Copyright (C) 2011-2015 VMware, Inc. All rights reserved.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify it
|
||
|
* under the terms of the GNU Lesser General Public License as published
|
||
|
* by the Free Software Foundation version 2.1 and no later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful, but
|
||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
|
||
|
* License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public License
|
||
|
* along with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
*
|
||
|
*********************************************************/
|
||
|
|
||
|
/*
|
||
|
* hostinfoHV.c --
|
||
|
*
|
||
|
* Code to detect different hypervisors and features.
|
||
|
*/
|
||
|
|
||
|
#include <string.h>
|
||
|
#include "vmware.h"
|
||
|
#if defined(__i386__) || defined(__x86_64__)
|
||
|
# include "cpuid_info.h"
|
||
|
# include "backdoor_def.h"
|
||
|
# include "backdoor_types.h"
|
||
|
#endif
|
||
|
#include "hostinfo.h"
|
||
|
#include "util.h"
|
||
|
|
||
|
#define LGPFX "HOSTINFO:"
|
||
|
/*
|
||
|
* #define LOGLEVEL_MODULE hostinfo
|
||
|
* #include "loglevel_user.h"
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_HypervisorCPUIDSig --
|
||
|
*
|
||
|
* Get the hypervisor signature string from CPUID.
|
||
|
*
|
||
|
* Results:
|
||
|
* Unqualified 16 byte nul-terminated hypervisor string
|
||
|
* String may contain garbage and caller must free
|
||
|
*
|
||
|
* Side effects:
|
||
|
* None
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
char *
|
||
|
Hostinfo_HypervisorCPUIDSig(void)
|
||
|
{
|
||
|
uint32 *name = NULL;
|
||
|
#if defined(__i386__) || defined(__x86_64__)
|
||
|
CPUIDRegs regs;
|
||
|
|
||
|
__GET_CPUID(1, ®s);
|
||
|
if (!CPUID_ISSET(1, ECX, HYPERVISOR, regs.ecx)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
regs.ebx = 0;
|
||
|
regs.ecx = 0;
|
||
|
regs.edx = 0;
|
||
|
|
||
|
__GET_CPUID(0x40000000, ®s);
|
||
|
|
||
|
if (regs.eax < 0x40000000) {
|
||
|
Log(LGPFX" CPUID hypervisor bit is set, but no "
|
||
|
"hypervisor vendor signature is present\n");
|
||
|
}
|
||
|
|
||
|
name = Util_SafeMalloc(4 * sizeof *name);
|
||
|
|
||
|
name[0] = regs.ebx;
|
||
|
name[1] = regs.ecx;
|
||
|
name[2] = regs.edx;
|
||
|
name[3] = 0;
|
||
|
#endif // defined(__i386__) || defined(__x86_64__)
|
||
|
|
||
|
return (char *)name;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_TouchXen --
|
||
|
*
|
||
|
* Check for Xen.
|
||
|
*
|
||
|
* Official way is to call Hostinfo_HypervisorCPUIDSig(), which
|
||
|
* returns a hypervisor string. This is a secondary check
|
||
|
* that guards against a backdoor failure. See PR156185,
|
||
|
* http://xenbits.xensource.com/xen-unstable.hg?file/6a383beedf83/tools/misc/xen-detect.c
|
||
|
* (Canonical way is /proc/xen, but CPUID is better).
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if we are running in a Xen dom0 or domU.
|
||
|
* Linux:
|
||
|
* Illegal instruction exception on real hardware.
|
||
|
* Obscure Xen implementations might return FALSE.
|
||
|
* Windows:
|
||
|
* FALSE on real hardware.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Linux: Will raise exception on native hardware.
|
||
|
* Windows: None.
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_TouchXen(void)
|
||
|
{
|
||
|
#if defined(linux) && (defined(__i386__) || defined(__x86_64__))
|
||
|
#define XEN_CPUID 0x40000000
|
||
|
CPUIDRegs regs;
|
||
|
uint32 name[4];
|
||
|
|
||
|
/*
|
||
|
* PV mode: ud2a "xen" cpuid (faults on native hardware).
|
||
|
* (Only Linux can run PV, so skip others here).
|
||
|
* Since PV cannot trap CPUID, this is a Xen hook.
|
||
|
*/
|
||
|
|
||
|
regs.eax = XEN_CPUID;
|
||
|
__asm__ __volatile__(
|
||
|
"xchgl %%ebx, %0" "\n\t"
|
||
|
"ud2a ; .ascii \"xen\" ; cpuid" "\n\t"
|
||
|
"xchgl %%ebx, %0"
|
||
|
: "=&r" (regs.ebx), "=&c" (regs.ecx), "=&d" (regs.edx)
|
||
|
: "a" (regs.eax)
|
||
|
);
|
||
|
|
||
|
name[0] = regs.ebx;
|
||
|
name[1] = regs.ecx;
|
||
|
name[2] = regs.edx;
|
||
|
name[3] = 0;
|
||
|
|
||
|
if (0 == strcmp(CPUID_XEN_HYPERVISOR_VENDOR_STRING, (const char*)name)) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* Passed checks. But native and anything non-Xen would #UD before here. */
|
||
|
NOT_TESTED();
|
||
|
Log("Xen detected but hypervisor unrecognized (Xen variant?)\n");
|
||
|
Log("CPUID 0x4000 0000: eax=%x ebx=%x ecx=%x edx=%x\n",
|
||
|
regs.eax, regs.ebx, regs.ecx, regs.edx);
|
||
|
#endif
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_SLC64Supported --
|
||
|
*
|
||
|
* Access the backdoor with an SLC64 control query. This is used
|
||
|
* to determine if we are running in a VM that supports SLC64.
|
||
|
* This function should only be called after determining that the
|
||
|
* backdoor is present with Hostinfo_TouchBackdoor().
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if the outer VM supports SLC64.
|
||
|
* FALSE otherwise.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM, so don't do that!
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_SLC64Supported(void)
|
||
|
{
|
||
|
#if defined(__i386__) || defined(__x86_64__)
|
||
|
return Hostinfo_VCPUInfoBackdoor(BDOOR_CMD_VCPU_SLC64);
|
||
|
#else
|
||
|
return FALSE;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_NestedHVReplaySupported --
|
||
|
*
|
||
|
* Access the backdoor with a HV replay control query. This is used
|
||
|
* to determine if we are running in a VM that supports nested HV replay.
|
||
|
* This function should only be called after determining that the
|
||
|
* backdoor is present with Hostinfo_TouchBackdoor().
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if the outer VM supports nexted HV replay.
|
||
|
* FALSE otherwise.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM, so don't do that!
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_NestedHVReplaySupported(void)
|
||
|
{
|
||
|
#if defined(__i386__) || defined(__x86_64__)
|
||
|
return Hostinfo_VCPUInfoBackdoor(BDOOR_CMD_VCPU_HV_REPLAY_OK);
|
||
|
#else
|
||
|
return FALSE;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_SynchronizedVTSCs --
|
||
|
*
|
||
|
* Access the backdoor to determine if the VCPUs' TSCs are
|
||
|
* synchronized.
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if the outer VM provides synchronized VTSCs.
|
||
|
* FALSE otherwise.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM, so don't do that!
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_SynchronizedVTSCs(void)
|
||
|
{
|
||
|
#if defined(__i386__) || defined(__x86_64__)
|
||
|
return Hostinfo_VCPUInfoBackdoor(BDOOR_CMD_VCPU_SYNC_VTSCS);
|
||
|
#else
|
||
|
return FALSE;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
#if defined(_WIN32)
|
||
|
|
||
|
#if defined(_WIN64)
|
||
|
// from touchBackdoorMasm64.asm
|
||
|
void Hostinfo_BackdoorInOut(Backdoor_proto *myBp);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_TouchBackDoor --
|
||
|
*
|
||
|
* Access the backdoor. This is used to determine if we are
|
||
|
* running in a VM or on a physical host. On a physical host
|
||
|
* this should generate a GP which we catch and thereby determine
|
||
|
* that we are not in a VM. However some OSes do not handle the
|
||
|
* GP correctly and the process continues running returning garbage.
|
||
|
* In this case we check the EBX register which should be
|
||
|
* BDOOR_MAGIC if the IN was handled in a VM. Based on this we
|
||
|
* return either TRUE or FALSE.
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if we succesfully accessed the backdoor, FALSE or segfault
|
||
|
* if not.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM.
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_TouchBackDoor(void)
|
||
|
{
|
||
|
uint32 ebxval;
|
||
|
|
||
|
#if defined(_WIN64)
|
||
|
Backdoor_proto bp;
|
||
|
|
||
|
bp.in.ax.quad = BDOOR_MAGIC;
|
||
|
bp.in.size = ~BDOOR_MAGIC;
|
||
|
bp.in.cx.quad = BDOOR_CMD_GETVERSION;
|
||
|
bp.in.dx.quad = BDOOR_PORT;
|
||
|
|
||
|
Hostinfo_BackdoorInOut(&bp);
|
||
|
|
||
|
ebxval = bp.out.bx.words.low;
|
||
|
#else // _WIN64
|
||
|
_asm {
|
||
|
push edx
|
||
|
push ecx
|
||
|
push ebx
|
||
|
mov ecx, BDOOR_CMD_GETVERSION
|
||
|
mov ebx, ~BDOOR_MAGIC
|
||
|
mov eax, BDOOR_MAGIC
|
||
|
mov dx, BDOOR_PORT
|
||
|
in eax, dx
|
||
|
mov ebxval, ebx
|
||
|
pop ebx
|
||
|
pop ecx
|
||
|
pop edx
|
||
|
}
|
||
|
#endif // _WIN64
|
||
|
|
||
|
return (ebxval == BDOOR_MAGIC) ? TRUE : FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_TouchVirtualPC --
|
||
|
*
|
||
|
* Access MS Virtual PC's backdoor. This is used to determine if
|
||
|
* we are running in a MS Virtual PC or on a physical host. Works
|
||
|
* the same as Hostinfo_TouchBackDoor, except the entry to MS VPC
|
||
|
* is an invalid opcode instead or writing to a port. Since
|
||
|
* MS VPC is 32-bit only, the WIN64 path returns FALSE.
|
||
|
* See: See: http://www.codeproject.com/KB/system/VmDetect.aspx
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if we succesfully accessed MS Virtual PC, FALSE or
|
||
|
* segfault if not.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM.
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_TouchVirtualPC(void)
|
||
|
{
|
||
|
#if defined(_WIN64)
|
||
|
return FALSE; // MS Virtual PC is 32-bit only
|
||
|
#else // _WIN32
|
||
|
uint32 ebxval;
|
||
|
|
||
|
_asm {
|
||
|
push ebx
|
||
|
mov ebx, 0
|
||
|
|
||
|
mov eax, 1 // Virtual PC function number
|
||
|
|
||
|
// execute invalid opcode to call into MS Virtual PC
|
||
|
|
||
|
__emit 0Fh
|
||
|
__emit 3Fh
|
||
|
__emit 07h
|
||
|
__emit 0Bh
|
||
|
|
||
|
mov ebxval, ebx
|
||
|
pop ebx
|
||
|
}
|
||
|
return !ebxval; // ebx is zero if inside Virtual PC
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_NestingSupported --
|
||
|
*
|
||
|
* Access the backdoor with a nesting control query. This is used
|
||
|
* to determine if we are running in a VM that supports nesting.
|
||
|
* This function should only be called after determining that the
|
||
|
* backdoor is present with Hostinfo_TouchBackdoor().
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if the outer VM supports nesting.
|
||
|
* FALSE otherwise.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM, so don't do that!
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_NestingSupported(void)
|
||
|
{
|
||
|
uint32 cmd = NESTING_CONTROL_QUERY << 16 | BDOOR_CMD_NESTING_CONTROL;
|
||
|
uint32 result;
|
||
|
|
||
|
#if defined(_WIN64)
|
||
|
Backdoor_proto bp;
|
||
|
|
||
|
bp.in.ax.quad = BDOOR_MAGIC;
|
||
|
bp.in.cx.quad = cmd;
|
||
|
bp.in.dx.quad = BDOOR_PORT;
|
||
|
|
||
|
Hostinfo_BackdoorInOut(&bp);
|
||
|
|
||
|
result = bp.out.ax.words.low;
|
||
|
#else
|
||
|
_asm {
|
||
|
push edx
|
||
|
push ecx
|
||
|
mov ecx, cmd
|
||
|
mov eax, BDOOR_MAGIC
|
||
|
mov dx, BDOOR_PORT
|
||
|
in eax, dx
|
||
|
mov result, eax
|
||
|
pop ecx
|
||
|
pop edx
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (result >= NESTING_CONTROL_QUERY && result != ~0U) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_VCPUInfoBackdoor --
|
||
|
*
|
||
|
* Access the backdoor with an VCPU info query. This is used to
|
||
|
* determine whether a VCPU supports a particular feature,
|
||
|
* determined by 'bit'. This function should only be called after
|
||
|
* determining that the backdoor is present with
|
||
|
* Hostinfo_TouchBackdoor().
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if the outer VM supports the feature.
|
||
|
* FALSE otherwise.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM, so don't do that!
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_VCPUInfoBackdoor(unsigned bit)
|
||
|
{
|
||
|
uint32 cmd = BDOOR_CMD_GET_VCPU_INFO;
|
||
|
uint32 result;
|
||
|
|
||
|
#if defined(_WIN64)
|
||
|
Backdoor_proto bp;
|
||
|
|
||
|
bp.in.ax.quad = BDOOR_MAGIC;
|
||
|
bp.in.cx.quad = cmd;
|
||
|
bp.in.dx.quad = BDOOR_PORT;
|
||
|
|
||
|
Hostinfo_BackdoorInOut(&bp);
|
||
|
|
||
|
result = bp.out.ax.words.low;
|
||
|
#else
|
||
|
_asm {
|
||
|
push edx
|
||
|
push ecx
|
||
|
mov ecx, cmd
|
||
|
mov eax, BDOOR_MAGIC
|
||
|
mov dx, BDOOR_PORT
|
||
|
in eax, dx
|
||
|
mov result, eax
|
||
|
pop ecx
|
||
|
pop edx
|
||
|
}
|
||
|
#endif
|
||
|
/* If reserved bit is 1, this command wasn't implemented. */
|
||
|
return (result & (1 << BDOOR_CMD_VCPU_RESERVED)) == 0 &&
|
||
|
(result & (1 << bit)) != 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
#else
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_TouchBackDoor --
|
||
|
*
|
||
|
* Access the backdoor. This is used to determine if we are
|
||
|
* running in a VM or on a physical host. On a physical host
|
||
|
* this should generate a GP which we catch and thereby determine
|
||
|
* that we are not in a VM. However some OSes do not handle the
|
||
|
* GP correctly and the process continues running returning garbage.
|
||
|
* In this case we check the EBX register which should be
|
||
|
* BDOOR_MAGIC if the IN was handled in a VM. Based on this we
|
||
|
* return either TRUE or FALSE.
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if we succesfully accessed the backdoor, FALSE or segfault
|
||
|
* if not.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM.
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_TouchBackDoor(void)
|
||
|
{
|
||
|
#if defined(__i386__) || defined(__x86_64__)
|
||
|
uint32 eax;
|
||
|
uint32 ebx;
|
||
|
uint32 ecx;
|
||
|
|
||
|
__asm__ __volatile__(
|
||
|
# if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
|
||
|
"xchgl %%ebx, %1" "\n\t"
|
||
|
"inl %%dx, %%eax" "\n\t"
|
||
|
"xchgl %%ebx, %1"
|
||
|
: "=a" (eax),
|
||
|
"=&rm" (ebx),
|
||
|
# else
|
||
|
"inl %%dx, %%eax"
|
||
|
: "=a" (eax),
|
||
|
"=b" (ebx),
|
||
|
# endif
|
||
|
"=c" (ecx)
|
||
|
: "0" (BDOOR_MAGIC),
|
||
|
"1" (~BDOOR_MAGIC),
|
||
|
"2" (BDOOR_CMD_GETVERSION),
|
||
|
"d" (BDOOR_PORT)
|
||
|
);
|
||
|
if (ebx == BDOOR_MAGIC) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_TouchVirtualPC --
|
||
|
*
|
||
|
* Access MS Virtual PC's backdoor. This is used to determine if
|
||
|
* we are running in a MS Virtual PC or on a physical host. Works
|
||
|
* the same as Hostinfo_TouchBackDoor, except the entry to MS VPC
|
||
|
* is an invalid opcode instead or writing to a port. Since
|
||
|
* MS VPC is 32-bit only, the 64-bit path returns FALSE.
|
||
|
* See: http://www.codeproject.com/KB/system/VmDetect.aspx
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if we succesfully accessed MS Virtual PC, FALSE or
|
||
|
* segfault if not.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM.
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_TouchVirtualPC(void)
|
||
|
{
|
||
|
#if defined vm_x86_64
|
||
|
return FALSE;
|
||
|
#else
|
||
|
|
||
|
uint32 ebxval;
|
||
|
|
||
|
__asm__ __volatile__ (
|
||
|
# if defined __PIC__ // %ebx is reserved by the compiler.
|
||
|
"xchgl %%ebx, %1" "\n\t"
|
||
|
".long 0x0B073F0F" "\n\t"
|
||
|
"xchgl %%ebx, %1"
|
||
|
: "=&rm" (ebxval)
|
||
|
: "a" (1),
|
||
|
"0" (0)
|
||
|
# else
|
||
|
".long 0x0B073F0F"
|
||
|
: "=b" (ebxval)
|
||
|
: "a" (1),
|
||
|
"b" (0)
|
||
|
# endif
|
||
|
);
|
||
|
return !ebxval; // %%ebx is zero if inside Virtual PC
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_NestingSupported --
|
||
|
*
|
||
|
* Access the backdoor with a nesting control query. This is used
|
||
|
* to determine if we are running inside a VM that supports nesting.
|
||
|
* This function should only be called after determining that the
|
||
|
* backdoor is present with Hostinfo_TouchBackdoor().
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if the outer VM supports nesting.
|
||
|
* FALSE otherwise.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM, so don't do that!
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_NestingSupported(void)
|
||
|
{
|
||
|
#if defined(__i386__) || defined(__x86_64__)
|
||
|
uint32 cmd = NESTING_CONTROL_QUERY << 16 | BDOOR_CMD_NESTING_CONTROL;
|
||
|
uint32 result;
|
||
|
|
||
|
__asm__ __volatile__(
|
||
|
"inl %%dx, %%eax"
|
||
|
: "=a" (result)
|
||
|
: "0" (BDOOR_MAGIC),
|
||
|
"c" (cmd),
|
||
|
"d" (BDOOR_PORT)
|
||
|
);
|
||
|
|
||
|
if (result >= NESTING_CONTROL_QUERY && result != ~0U) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*----------------------------------------------------------------------
|
||
|
*
|
||
|
* Hostinfo_VCPUInfoBackdoor --
|
||
|
*
|
||
|
* Access the backdoor with an VCPU info query. This is used to
|
||
|
* determine whether a VCPU supports a particular feature,
|
||
|
* determined by 'bit'. This function should only be called after
|
||
|
* determining that the backdoor is present with
|
||
|
* Hostinfo_TouchBackdoor().
|
||
|
*
|
||
|
* Results:
|
||
|
* TRUE if the outer VM supports the feature.
|
||
|
* FALSE otherwise.
|
||
|
*
|
||
|
* Side effects:
|
||
|
* Exception if not in a VM, so don't do that!
|
||
|
*
|
||
|
*----------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
Bool
|
||
|
Hostinfo_VCPUInfoBackdoor(unsigned bit)
|
||
|
{
|
||
|
#if defined(__i386__) || defined(__x86_64__)
|
||
|
uint32 result;
|
||
|
__asm__ __volatile__(
|
||
|
"inl %%dx, %%eax"
|
||
|
: "=a" (result)
|
||
|
: "0" (BDOOR_MAGIC),
|
||
|
"c" (BDOOR_CMD_GET_VCPU_INFO),
|
||
|
"d" (BDOOR_PORT)
|
||
|
);
|
||
|
/* If reserved bit is 1, this command wasn't implemented. */
|
||
|
return (result & (1 << BDOOR_CMD_VCPU_RESERVED)) == 0 &&
|
||
|
(result & (1 << bit)) != 0;
|
||
|
#endif
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|