mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
x86, hvm: Guest CPUID configuration.
CPUID's replies are now pre-calculated in libxc and given to the hypervisor via a new domctl. There are two parts to this feature: - We can overwrite cpuid's replies. - We can check that a vm is compatible with a host's processor. Signed-off-by: Jean Guyader <jean.guyader@eu.citrix.com> Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
This commit is contained in:
1 parent
9fb02748d0
commit
5f14a87ceb
17 files changed
+1001
-133
No files matched your search
@@ -219,3 +219,28 @@ serial='pty'
|
||||
#-----------------------------------------------------------------------------
|
||||
# Set keyboard layout, default is en-us keyboard.
|
||||
#keymap='ja'
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Configure guest CPUID responses:
|
||||
#cpuid=[ '1:ecx=xxxxxxxxxxxxxxxxxxxxxxxxxx1xxxxx,
|
||||
# eax=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' ]
|
||||
# - Set the VMX feature flag in the guest (CPUID_1:ECX:5)
|
||||
# - Default behaviour for all other bits in ECX And EAX registers.
|
||||
#
|
||||
# Each successive character represent a lesser-significant bit:
|
||||
# '1' -> force the corresponding bit to 1
|
||||
# '0' -> force to 0
|
||||
# 'x' -> we don't care (default behaviour)
|
||||
# 'k' -> pass through the host bit value
|
||||
# 's' -> as 'k' but preserve across save/restore and migration
|
||||
#
|
||||
# Configure host CPUID consistency checks, which must be satisfied for this
|
||||
# VM to be allowed to run on this host's processor type:
|
||||
#cpuid_check=[ '1:ecx=xxxxxxxxxxxxxxxxxxxxxxxxxx1xxxxx' ]
|
||||
# - Host must have VMX feature flag set
|
||||
#
|
||||
# The format is similar to the above for 'cpuid':
|
||||
# '1' -> the bit must be '1'
|
||||
# '0' -> the bit must be '0'
|
||||
# 'x' -> we don't care (do not check)
|
||||
# 's' -> the bit must be the same as on the host that started this VM
|
||||
@@ -53,6 +53,7 @@ GUEST_SRCS-y += xc_dom_binloader.c
|
||||
GUEST_SRCS-y += xc_dom_compat_linux.c
|
||||
|
||||
GUEST_SRCS-$(CONFIG_X86) += xc_dom_x86.c
|
||||
GUEST_SRCS-$(CONFIG_X86) += xc_cpuid_x86.c
|
||||
GUEST_SRCS-$(CONFIG_IA64) += xc_dom_ia64.c
|
||||
GUEST_SRCS-$(CONFIG_POWERPC) += xc_dom_powerpc.c
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
#ifndef __LIBXC_CPUFEATURE_H
|
||||
#define __LIBXC_CPUFEATURE_H
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
|
||||
#define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */
|
||||
#define X86_FEATURE_VME (0*32+ 1) /* Virtual Mode Extensions */
|
||||
#define X86_FEATURE_DE (0*32+ 2) /* Debugging Extensions */
|
||||
#define X86_FEATURE_PSE (0*32+ 3) /* Page Size Extensions */
|
||||
#define X86_FEATURE_TSC (0*32+ 4) /* Time Stamp Counter */
|
||||
#define X86_FEATURE_MSR (0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */
|
||||
#define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extensions */
|
||||
#define X86_FEATURE_MCE (0*32+ 7) /* Machine Check Architecture */
|
||||
#define X86_FEATURE_CX8 (0*32+ 8) /* CMPXCHG8 instruction */
|
||||
#define X86_FEATURE_APIC (0*32+ 9) /* Onboard APIC */
|
||||
#define X86_FEATURE_SEP (0*32+11) /* SYSENTER/SYSEXIT */
|
||||
#define X86_FEATURE_MTRR (0*32+12) /* Memory Type Range Registers */
|
||||
#define X86_FEATURE_PGE (0*32+13) /* Page Global Enable */
|
||||
#define X86_FEATURE_MCA (0*32+14) /* Machine Check Architecture */
|
||||
#define X86_FEATURE_CMOV (0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
|
||||
#define X86_FEATURE_PAT (0*32+16) /* Page Attribute Table */
|
||||
#define X86_FEATURE_PSE36 (0*32+17) /* 36-bit PSEs */
|
||||
#define X86_FEATURE_PN (0*32+18) /* Processor serial number */
|
||||
#define X86_FEATURE_CLFLSH (0*32+19) /* Supports the CLFLUSH instruction */
|
||||
#define X86_FEATURE_DS (0*32+21) /* Debug Store */
|
||||
#define X86_FEATURE_ACPI (0*32+22) /* ACPI via MSR */
|
||||
#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */
|
||||
#define X86_FEATURE_FXSR (0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */
|
||||
/* of FPU context), and CR4.OSFXSR available */
|
||||
#define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */
|
||||
#define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */
|
||||
#define X86_FEATURE_SELFSNOOP (0*32+27) /* CPU self snoop */
|
||||
#define X86_FEATURE_HT (0*32+28) /* Hyper-Threading */
|
||||
#define X86_FEATURE_ACC (0*32+29) /* Automatic clock control */
|
||||
#define X86_FEATURE_IA64 (0*32+30) /* IA-64 processor */
|
||||
#define X86_FEATURE_PBE (0*32+31) /* Pending Break Enable */
|
||||
|
||||
/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
|
||||
/* Don't duplicate feature flags which are redundant with Intel! */
|
||||
#define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */
|
||||
#define X86_FEATURE_MP (1*32+19) /* MP Capable. */
|
||||
#define X86_FEATURE_NX (1*32+20) /* Execute Disable */
|
||||
#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
|
||||
#define X86_FEATURE_FFXSR (1*32+25) /* FFXSR instruction optimizations */
|
||||
#define X86_FEATURE_PAGE1GB (1*32+26) /* 1Gb large page support */
|
||||
#define X86_FEATURE_RDTSCP (1*32+27) /* RDTSCP */
|
||||
#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */
|
||||
#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */
|
||||
#define X86_FEATURE_3DNOW (1*32+31) /* 3DNow! */
|
||||
|
||||
/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
|
||||
#define X86_FEATURE_RECOVERY (2*32+ 0) /* CPU in recovery mode */
|
||||
#define X86_FEATURE_LONGRUN (2*32+ 1) /* Longrun power control */
|
||||
#define X86_FEATURE_LRTI (2*32+ 3) /* LongRun table interface */
|
||||
|
||||
/* Other features, Linux-defined mapping, word 3 */
|
||||
/* This range is used for feature bits which conflict or are synthesized */
|
||||
#define X86_FEATURE_CXMMX (3*32+ 0) /* Cyrix MMX extensions */
|
||||
#define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */
|
||||
#define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */
|
||||
#define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */
|
||||
/* cpu types for specific tunings: */
|
||||
#define X86_FEATURE_K8 (3*32+ 4) /* Opteron, Athlon64 */
|
||||
#define X86_FEATURE_K7 (3*32+ 5) /* Athlon */
|
||||
#define X86_FEATURE_P3 (3*32+ 6) /* P3 */
|
||||
#define X86_FEATURE_P4 (3*32+ 7) /* P4 */
|
||||
#define X86_FEATURE_CONSTANT_TSC (3*32+ 8) /* TSC ticks at a constant rate */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
|
||||
#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */
|
||||
#define X86_FEATURE_DTES64 (4*32+ 2) /* 64-bit Debug Store */
|
||||
#define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor/Mwait support */
|
||||
#define X86_FEATURE_DSCPL (4*32+ 4) /* CPL Qualified Debug Store */
|
||||
#define X86_FEATURE_VMXE (4*32+ 5) /* Virtual Machine Extensions */
|
||||
#define X86_FEATURE_SMXE (4*32+ 6) /* Safer Mode Extensions */
|
||||
#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */
|
||||
#define X86_FEATURE_TM2 (4*32+ 8) /* Thermal Monitor 2 */
|
||||
#define X86_FEATURE_SSSE3 (4*32+ 9) /* Supplemental Streaming SIMD Extensions-3 */
|
||||
#define X86_FEATURE_CID (4*32+10) /* Context ID */
|
||||
#define X86_FEATURE_CX16 (4*32+13) /* CMPXCHG16B */
|
||||
#define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */
|
||||
#define X86_FEATURE_PDCM (4*32+15) /* Perf/Debug Capability MSR */
|
||||
#define X86_FEATURE_DCA (4*32+18) /* Direct Cache Access */
|
||||
#define X86_FEATURE_SSE4_1 (4*32+19) /* Streaming SIMD Extensions 4.1 */
|
||||
#define X86_FEATURE_SSE4_2 (4*32+20) /* Streaming SIMD Extensions 4.2 */
|
||||
#define X86_FEATURE_POPCNT (4*32+23) /* POPCNT instruction */
|
||||
|
||||
/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
|
||||
#define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */
|
||||
#define X86_FEATURE_XSTORE_EN (5*32+ 3) /* on-CPU RNG enabled */
|
||||
#define X86_FEATURE_XCRYPT (5*32+ 6) /* on-CPU crypto (xcrypt insn) */
|
||||
#define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* on-CPU crypto enabled */
|
||||
#define X86_FEATURE_ACE2 (5*32+ 8) /* Advanced Cryptography Engine v2 */
|
||||
#define X86_FEATURE_ACE2_EN (5*32+ 9) /* ACE v2 enabled */
|
||||
#define X86_FEATURE_PHE (5*32+ 10) /* PadLock Hash Engine */
|
||||
#define X86_FEATURE_PHE_EN (5*32+ 11) /* PHE enabled */
|
||||
#define X86_FEATURE_PMM (5*32+ 12) /* PadLock Montgomery Multiplier */
|
||||
#define X86_FEATURE_PMM_EN (5*32+ 13) /* PMM enabled */
|
||||
|
||||
/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
|
||||
#define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */
|
||||
#define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */
|
||||
#define X86_FEATURE_SVME (6*32+ 2) /* Secure Virtual Machine */
|
||||
#define X86_FEATURE_EXTAPICSPACE (6*32+ 3) /* Extended APIC space */
|
||||
#define X86_FEATURE_ALTMOVCR (6*32+ 4) /* LOCK MOV CR accesses CR+8 */
|
||||
#define X86_FEATURE_ABM (6*32+ 5) /* Advanced Bit Manipulation */
|
||||
#define X86_FEATURE_SSE4A (6*32+ 6) /* AMD Streaming SIMD Extensions-4a */
|
||||
#define X86_FEATURE_MISALIGNSSE (6*32+ 7) /* Misaligned SSE Access */
|
||||
#define X86_FEATURE_3DNOWPF (6*32+ 8) /* 3DNow! Prefetch */
|
||||
#define X86_FEATURE_OSVW (6*32+ 9) /* OS Visible Workaround */
|
||||
#define X86_FEATURE_IBS (6*32+ 10) /* Instruction Based Sampling */
|
||||
#define X86_FEATURE_SSE5 (6*32+ 11) /* AMD Streaming SIMD Extensions-5 */
|
||||
#define X86_FEATURE_SKINIT (6*32+ 12) /* SKINIT, STGI/CLGI, DEV */
|
||||
#define X86_FEATURE_WDT (6*32+ 13) /* Watchdog Timer */
|
||||
|
||||
#endif /* __LIBXC_CPUFEATURE_H */
|
||||
@@ -0,0 +1,430 @@
|
||||
/******************************************************************************
|
||||
* xc_cpuid_x86.c
|
||||
*
|
||||
* Compute cpuid of a domain.
|
||||
*
|
||||
* Copyright (c) 2008, Citrix Systems, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307 USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "xc_private.h"
|
||||
#include "xc_cpufeature.h"
|
||||
#include <xen/hvm/params.h>
|
||||
|
||||
#define bitmaskof(idx) (1u << ((idx) & 31))
|
||||
#define clear_bit(idx, dst) ((dst) &= ~(1u << (idx)))
|
||||
#define set_bit(idx, dst) ((dst) |= (1u << (idx)))
|
||||
|
||||
#define DEF_MAX_BASE 0x00000004u
|
||||
#define DEF_MAX_EXT 0x80000008u
|
||||
|
||||
static void amd_xc_cpuid_policy(
|
||||
int xc, domid_t domid, const unsigned int *input, unsigned int *regs)
|
||||
{
|
||||
unsigned long pae = 0;
|
||||
|
||||
xc_get_hvm_param(xc, domid, HVM_PARAM_PAE_ENABLED, &pae);
|
||||
|
||||
switch ( input[0] )
|
||||
{
|
||||
case 0x00000001:
|
||||
/* Mask Intel-only features. */
|
||||
regs[2] &= ~(bitmaskof(X86_FEATURE_SSSE3) |
|
||||
bitmaskof(X86_FEATURE_SSE4_1) |
|
||||
bitmaskof(X86_FEATURE_SSE4_2));
|
||||
break;
|
||||
|
||||
case 0x00000002:
|
||||
case 0x00000004:
|
||||
regs[0] = regs[1] = regs[2] = 0;
|
||||
break;
|
||||
|
||||
case 0x80000001:
|
||||
if ( !pae )
|
||||
clear_bit(X86_FEATURE_PAE & 31, regs[3]);
|
||||
clear_bit(X86_FEATURE_PSE36 & 31, regs[3]);
|
||||
|
||||
/* Filter all other features according to a whitelist. */
|
||||
regs[2] &= (bitmaskof(X86_FEATURE_LAHF_LM) |
|
||||
bitmaskof(X86_FEATURE_ALTMOVCR) |
|
||||
bitmaskof(X86_FEATURE_ABM) |
|
||||
bitmaskof(X86_FEATURE_SSE4A) |
|
||||
bitmaskof(X86_FEATURE_MISALIGNSSE) |
|
||||
bitmaskof(X86_FEATURE_3DNOWPF));
|
||||
regs[3] &= (0x0183f3ff | /* features shared with 0x00000001:EDX */
|
||||
bitmaskof(X86_FEATURE_NX) |
|
||||
bitmaskof(X86_FEATURE_LM) |
|
||||
bitmaskof(X86_FEATURE_SYSCALL) |
|
||||
bitmaskof(X86_FEATURE_MP) |
|
||||
bitmaskof(X86_FEATURE_MMXEXT) |
|
||||
bitmaskof(X86_FEATURE_FFXSR) |
|
||||
bitmaskof(X86_FEATURE_3DNOW) |
|
||||
bitmaskof(X86_FEATURE_3DNOWEXT));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_xc_cpuid_policy(
|
||||
int xc, domid_t domid, const unsigned int *input, unsigned int *regs)
|
||||
{
|
||||
switch ( input[0] )
|
||||
{
|
||||
case 0x00000001:
|
||||
/* Mask AMD-only features. */
|
||||
regs[2] &= ~(bitmaskof(X86_FEATURE_POPCNT));
|
||||
break;
|
||||
|
||||
case 0x00000004:
|
||||
regs[0] &= 0x3FF;
|
||||
regs[3] &= 0x3FF;
|
||||
break;
|
||||
|
||||
case 0x80000001:
|
||||
/* Only a few features are advertised in Intel's 0x80000001. */
|
||||
regs[2] &= (bitmaskof(X86_FEATURE_LAHF_LM));
|
||||
regs[3] &= (bitmaskof(X86_FEATURE_NX) |
|
||||
bitmaskof(X86_FEATURE_LM) |
|
||||
bitmaskof(X86_FEATURE_SYSCALL));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cpuid(const unsigned int *input, unsigned int *regs)
|
||||
{
|
||||
unsigned int count = (input[1] == XEN_CPUID_INPUT_UNUSED) ? 0 : input[1];
|
||||
unsigned int bx_temp;
|
||||
asm ( "mov %%ebx,%4; cpuid; mov %%ebx,%1; mov %4,%%ebx"
|
||||
: "=a" (regs[0]), "=r" (regs[1]),
|
||||
"=c" (regs[2]), "=d" (regs[3]), "=m" (bx_temp)
|
||||
: "0" (input[0]), "2" (count) );
|
||||
}
|
||||
|
||||
/* Get the manufacturer brand name of the host processor. */
|
||||
static void xc_cpuid_brand_get(char *str)
|
||||
{
|
||||
unsigned int input[2] = { 0, 0 };
|
||||
unsigned int regs[4];
|
||||
|
||||
cpuid(input, regs);
|
||||
|
||||
*(uint32_t *)(str + 0) = regs[1];
|
||||
*(uint32_t *)(str + 4) = regs[3];
|
||||
*(uint32_t *)(str + 8) = regs[2];
|
||||
str[12] = '\0';
|
||||
}
|
||||
|
||||
static void xc_cpuid_policy(
|
||||
int xc, domid_t domid, const unsigned int *input, unsigned int *regs)
|
||||
{
|
||||
char brand[13];
|
||||
unsigned long pae;
|
||||
|
||||
xc_get_hvm_param(xc, domid, HVM_PARAM_PAE_ENABLED, &pae);
|
||||
|
||||
switch( input[0] )
|
||||
{
|
||||
case 0x00000000:
|
||||
if ( regs[0] > DEF_MAX_BASE )
|
||||
regs[0] = DEF_MAX_BASE;
|
||||
break;
|
||||
|
||||
case 0x00000001:
|
||||
regs[2] &= (bitmaskof(X86_FEATURE_XMM3) |
|
||||
bitmaskof(X86_FEATURE_SSSE3) |
|
||||
bitmaskof(X86_FEATURE_CX16) |
|
||||
bitmaskof(X86_FEATURE_SSE4_1) |
|
||||
bitmaskof(X86_FEATURE_SSE4_2) |
|
||||
bitmaskof(X86_FEATURE_POPCNT));
|
||||
|
||||
regs[3] &= (bitmaskof(X86_FEATURE_FPU) |
|
||||
bitmaskof(X86_FEATURE_VME) |
|
||||
bitmaskof(X86_FEATURE_DE) |
|
||||
bitmaskof(X86_FEATURE_PSE) |
|
||||
bitmaskof(X86_FEATURE_TSC) |
|
||||
bitmaskof(X86_FEATURE_MSR) |
|
||||
bitmaskof(X86_FEATURE_PAE) |
|
||||
bitmaskof(X86_FEATURE_MCE) |
|
||||
bitmaskof(X86_FEATURE_CX8) |
|
||||
bitmaskof(X86_FEATURE_APIC) |
|
||||
bitmaskof(X86_FEATURE_SEP) |
|
||||
bitmaskof(X86_FEATURE_MTRR) |
|
||||
bitmaskof(X86_FEATURE_PGE) |
|
||||
bitmaskof(X86_FEATURE_MCA) |
|
||||
bitmaskof(X86_FEATURE_CMOV) |
|
||||
bitmaskof(X86_FEATURE_PAT) |
|
||||
bitmaskof(X86_FEATURE_CLFLSH) |
|
||||
bitmaskof(X86_FEATURE_MMX) |
|
||||
bitmaskof(X86_FEATURE_FXSR) |
|
||||
bitmaskof(X86_FEATURE_XMM) |
|
||||
bitmaskof(X86_FEATURE_XMM2));
|
||||
|
||||
/* We always support MTRR MSRs. */
|
||||
regs[3] |= bitmaskof(X86_FEATURE_MTRR);
|
||||
|
||||
if ( !pae )
|
||||
clear_bit(X86_FEATURE_PAE & 31, regs[3]);
|
||||
break;
|
||||
|
||||
case 0x80000000:
|
||||
if ( regs[0] > DEF_MAX_EXT )
|
||||
regs[0] = DEF_MAX_EXT;
|
||||
break;
|
||||
|
||||
case 0x80000001:
|
||||
if ( !pae )
|
||||
clear_bit(X86_FEATURE_NX & 31, regs[3]);
|
||||
break;
|
||||
|
||||
|
||||
case 0x80000008:
|
||||
regs[0] &= 0x0000ffffu;
|
||||
regs[1] = regs[2] = regs[3] = 0;
|
||||
break;
|
||||
|
||||
case 0x00000002:
|
||||
case 0x00000004:
|
||||
case 0x80000002:
|
||||
case 0x80000003:
|
||||
case 0x80000004:
|
||||
case 0x80000006:
|
||||
break;
|
||||
|
||||
default:
|
||||
regs[0] = regs[1] = regs[2] = regs[3] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
xc_cpuid_brand_get(brand);
|
||||
if ( strstr(brand, "AMD") )
|
||||
amd_xc_cpuid_policy(xc, domid, input, regs);
|
||||
else
|
||||
intel_xc_cpuid_policy(xc, domid, input, regs);
|
||||
}
|
||||
|
||||
static int xc_cpuid_do_domctl(
|
||||
int xc, domid_t domid,
|
||||
const unsigned int *input, const unsigned int *regs)
|
||||
{
|
||||
DECLARE_DOMCTL;
|
||||
|
||||
memset(&domctl, 0, sizeof (domctl));
|
||||
domctl.domain = domid;
|
||||
domctl.cmd = XEN_DOMCTL_set_cpuid;
|
||||
domctl.u.cpuid.input[0] = input[0];
|
||||
domctl.u.cpuid.input[1] = input[1];
|
||||
domctl.u.cpuid.eax = regs[0];
|
||||
domctl.u.cpuid.ebx = regs[1];
|
||||
domctl.u.cpuid.ecx = regs[2];
|
||||
domctl.u.cpuid.edx = regs[3];
|
||||
|
||||
return do_domctl(xc, &domctl);
|
||||
}
|
||||
|
||||
static char *alloc_str(void)
|
||||
{
|
||||
char *s = malloc(33);
|
||||
memset(s, 0, 33);
|
||||
return s;
|
||||
}
|
||||
|
||||
void xc_cpuid_to_str(const unsigned int *regs, char **strs)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
strs[i] = alloc_str();
|
||||
for ( j = 0; j < 32; j++ )
|
||||
strs[i][j] = !!((regs[i] & (1U << (31 - j)))) ? '1' : '0';
|
||||
}
|
||||
}
|
||||
|
||||
int xc_cpuid_apply_policy(int xc, domid_t domid)
|
||||
{
|
||||
unsigned int input[2] = { 0, 0 }, regs[4];
|
||||
unsigned int base_max, ext_max;
|
||||
int rc;
|
||||
|
||||
cpuid(input, regs);
|
||||
base_max = (regs[0] <= DEF_MAX_BASE) ? regs[0] : DEF_MAX_BASE;
|
||||
input[0] = 0x80000000;
|
||||
cpuid(input, regs);
|
||||
ext_max = (regs[0] <= DEF_MAX_EXT) ? regs[0] : DEF_MAX_EXT;
|
||||
|
||||
input[0] = 0;
|
||||
input[1] = XEN_CPUID_INPUT_UNUSED;
|
||||
for ( ; ; )
|
||||
{
|
||||
cpuid(input, regs);
|
||||
xc_cpuid_policy(xc, domid, input, regs);
|
||||
|
||||
if ( regs[0] || regs[1] || regs[2] || regs[3] )
|
||||
{
|
||||
rc = xc_cpuid_do_domctl(xc, domid, input, regs);
|
||||
if ( rc )
|
||||
return rc;
|
||||
|
||||
/* Intel cache descriptor leaves. */
|
||||
if ( input[0] == 4 )
|
||||
{
|
||||
input[1]++;
|
||||
/* More to do? Then loop keeping %%eax==0x00000004. */
|
||||
if ( (regs[0] & 0x1f) != 0 )
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
input[0]++;
|
||||
input[1] = (input[0] == 4) ? 0 : XEN_CPUID_INPUT_UNUSED;
|
||||
if ( !(input[0] & 0x80000000u) && (input[0] > base_max ) )
|
||||
input[0] = 0x80000000u;
|
||||
|
||||
if ( (input[0] & 0x80000000u) && (input[0] > ext_max) )
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether a VM is allowed to launch on this host's processor type.
|
||||
*
|
||||
* @config format is similar to that of xc_cpuid_set():
|
||||
* '1' -> the bit must be set to 1
|
||||
* '0' -> must be 0
|
||||
* 'x' -> we don't care
|
||||
* 's' -> (same) must be the same
|
||||
*/
|
||||
int xc_cpuid_check(
|
||||
int xc, const unsigned int *input,
|
||||
const char **config,
|
||||
char **config_transformed)
|
||||
{
|
||||
int i, j;
|
||||
unsigned int regs[4];
|
||||
|
||||
memset(config_transformed, 0, 4 * sizeof(*config_transformed));
|
||||
|
||||
cpuid(input, regs);
|
||||
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
if ( config[i] == NULL )
|
||||
continue;
|
||||
config_transformed[i] = alloc_str();
|
||||
for ( j = 0; j < 32; j++ )
|
||||
{
|
||||
unsigned char val = !!((regs[i] & (1U << (31 - j))));
|
||||
if ( !strchr("10xs", config[i][j]) ||
|
||||
((config[i][j] == '1') && !val) ||
|
||||
((config[i][j] == '0') && val) )
|
||||
goto fail;
|
||||
config_transformed[i][j] = config[i][j];
|
||||
if ( config[i][j] == 's' )
|
||||
config_transformed[i][j] = '0' + val;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
free(config_transformed[i]);
|
||||
config_transformed[i] = NULL;
|
||||
}
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure a single input with the informatiom from config.
|
||||
*
|
||||
* Config is an array of strings:
|
||||
* config[0] = eax
|
||||
* config[1] = ebx
|
||||
* config[2] = ecx
|
||||
* config[3] = edx
|
||||
*
|
||||
* The format of the string is the following:
|
||||
* '1' -> force to 1
|
||||
* '0' -> force to 0
|
||||
* 'x' -> we don't care (use default)
|
||||
* 'k' -> pass through host value
|
||||
* 's' -> pass through the first time and then keep the same value
|
||||
* across save/restore and migration.
|
||||
*
|
||||
* For 's' and 'x' the configuration is overwritten with the value applied.
|
||||
*/
|
||||
int xc_cpuid_set(
|
||||
int xc, domid_t domid, const unsigned int *input,
|
||||
const char **config, char **config_transformed)
|
||||
{
|
||||
int rc;
|
||||
unsigned int i, j, regs[4], polregs[4];
|
||||
|
||||
memset(config_transformed, 0, 4 * sizeof(*config_transformed));
|
||||
|
||||
cpuid(input, regs);
|
||||
|
||||
memcpy(polregs, regs, sizeof(regs));
|
||||
xc_cpuid_policy(xc, domid, input, polregs);
|
||||
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
if ( config[i] == NULL )
|
||||
continue;
|
||||
|
||||
config_transformed[i] = alloc_str();
|
||||
|
||||
for ( j = 0; j < 32; j++ )
|
||||
{
|
||||
unsigned char val = !!((regs[i] & (1U << (31 - j))));
|
||||
unsigned char polval = !!((polregs[i] & (1U << (31 - j))));
|
||||
|
||||
rc = -EINVAL;
|
||||
if ( !strchr("10xks", config[i][j]) )
|
||||
goto fail;
|
||||
|
||||
if ( config[i][j] == '1' )
|
||||
val = 1;
|
||||
else if ( config[i][j] == '0' )
|
||||
val = 0;
|
||||
else if ( config[i][j] == 'x' )
|
||||
val = polval;
|
||||
|
||||
if ( val )
|
||||
set_bit(31 - j, regs[i]);
|
||||
else
|
||||
clear_bit(31 - j, regs[i]);
|
||||
|
||||
config_transformed[i][j] = config[i][j];
|
||||
if ( config[i][j] == 's' )
|
||||
config_transformed[i][j] = '0' + val;
|
||||
}
|
||||
}
|
||||
|
||||
rc = xc_cpuid_do_domctl(xc, domid, input, regs);
|
||||
if ( rc == 0 )
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
free(config_transformed[i]);
|
||||
config_transformed[i] = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -983,4 +983,20 @@ int xc_domain_set_target(int xc_handle,
|
||||
uint32_t domid,
|
||||
uint32_t target);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
int xc_cpuid_check(int xc,
|
||||
const unsigned int *input,
|
||||
const char **config,
|
||||
char **config_transformed);
|
||||
int xc_cpuid_set(int xc,
|
||||
domid_t domid,
|
||||
const unsigned int *input,
|
||||
const char **config,
|
||||
char **config_transformed);
|
||||
int xc_cpuid_apply_policy(int xc,
|
||||
domid_t domid);
|
||||
void xc_cpuid_to_str(const unsigned int *regs,
|
||||
char **strs);
|
||||
#endif
|
||||
|
||||
#endif /* XENCTRL_H */
|
||||
@@ -611,6 +611,110 @@ static PyObject *pyxc_set_os_type(XcObject *self,
|
||||
}
|
||||
#endif /* __ia64__ */
|
||||
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
static void pyxc_dom_extract_cpuid(PyObject *config,
|
||||
char **regs)
|
||||
{
|
||||
const char *regs_extract[4] = { "eax", "ebx", "ecx", "edx" };
|
||||
PyObject *obj;
|
||||
int i;
|
||||
|
||||
memset(regs, 0, 4*sizeof(*regs));
|
||||
|
||||
if ( !PyDict_Check(config) )
|
||||
return;
|
||||
|
||||
for ( i = 0; i < 4; i++ )
|
||||
if ( (obj = PyDict_GetItemString(config, regs_extract[i])) != NULL )
|
||||
regs[i] = PyString_AS_STRING(obj);
|
||||
}
|
||||
|
||||
static PyObject *pyxc_create_cpuid_dict(char **regs)
|
||||
{
|
||||
const char *regs_extract[4] = { "eax", "ebx", "ecx", "edx" };
|
||||
PyObject *dict;
|
||||
int i;
|
||||
|
||||
dict = PyDict_New();
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
if ( regs[i] == NULL )
|
||||
continue;
|
||||
PyDict_SetItemString(dict, regs_extract[i],
|
||||
PyString_FromString(regs[i]));
|
||||
free(regs[i]);
|
||||
regs[i] = NULL;
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
static PyObject *pyxc_dom_check_cpuid(XcObject *self,
|
||||
PyObject *args)
|
||||
{
|
||||
PyObject *sub_input, *config;
|
||||
unsigned int input[2];
|
||||
char *regs[4], *regs_transform[4];
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "iOO", &input[0], &sub_input, &config) )
|
||||
return NULL;
|
||||
|
||||
pyxc_dom_extract_cpuid(config, regs);
|
||||
|
||||
input[1] = XEN_CPUID_INPUT_UNUSED;
|
||||
if ( PyLong_Check(sub_input) )
|
||||
input[1] = PyLong_AsUnsignedLong(sub_input);
|
||||
|
||||
if ( xc_cpuid_check(self->xc_handle, input,
|
||||
(const char **)regs, regs_transform) )
|
||||
return pyxc_error_to_exception();
|
||||
|
||||
return pyxc_create_cpuid_dict(regs_transform);
|
||||
}
|
||||
|
||||
static PyObject *pyxc_dom_set_policy_cpuid(XcObject *self,
|
||||
PyObject *args)
|
||||
{
|
||||
domid_t domid;
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "i", &domid) )
|
||||
return NULL;
|
||||
|
||||
if ( xc_cpuid_apply_policy(self->xc_handle, domid) )
|
||||
return pyxc_error_to_exception();
|
||||
|
||||
Py_INCREF(zero);
|
||||
return zero;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *pyxc_dom_set_cpuid(XcObject *self,
|
||||
PyObject *args)
|
||||
{
|
||||
domid_t domid;
|
||||
PyObject *sub_input, *config;
|
||||
unsigned int input[2];
|
||||
char *regs[4], *regs_transform[4];
|
||||
|
||||
if ( !PyArg_ParseTuple(args, "iiOO", &domid,
|
||||
&input[0], &sub_input, &config) )
|
||||
return NULL;
|
||||
|
||||
pyxc_dom_extract_cpuid(config, regs);
|
||||
|
||||
input[1] = XEN_CPUID_INPUT_UNUSED;
|
||||
if ( PyLong_Check(sub_input) )
|
||||
input[1] = PyLong_AsUnsignedLong(sub_input);
|
||||
|
||||
if ( xc_cpuid_set(self->xc_handle, domid, input, (const char **)regs,
|
||||
regs_transform) )
|
||||
return pyxc_error_to_exception();
|
||||
|
||||
return pyxc_create_cpuid_dict(regs_transform);
|
||||
}
|
||||
|
||||
#endif /* __i386__ || __x86_64__ */
|
||||
|
||||
static PyObject *pyxc_hvm_build(XcObject *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
@@ -1635,6 +1739,37 @@ static PyMethodDef pyxc_methods[] = {
|
||||
" log [int]: Specifies the area's size.\n"
|
||||
"Returns: [int] 0 on success; -1 on error.\n" },
|
||||
#endif /* __powerpc */
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
{ "domain_check_cpuid",
|
||||
(PyCFunction)pyxc_dom_check_cpuid,
|
||||
METH_VARARGS, "\n"
|
||||
"Apply checks to host CPUID.\n"
|
||||
" input [long]: Input for cpuid instruction (eax)\n"
|
||||
" sub_input [long]: Second input (optional, may be None) for cpuid "
|
||||
" instruction (ecx)\n"
|
||||
" config [dict]: Dictionary of register\n"
|
||||
" config [dict]: Dictionary of register, use for checking\n\n"
|
||||
"Returns: [int] 0 on success; exception on error.\n" },
|
||||
|
||||
{ "domain_set_cpuid",
|
||||
(PyCFunction)pyxc_dom_set_cpuid,
|
||||
METH_VARARGS, "\n"
|
||||
"Set cpuid response for an input and a domain.\n"
|
||||
" dom [int]: Identifier of domain.\n"
|
||||
" input [long]: Input for cpuid instruction (eax)\n"
|
||||
" sub_input [long]: Second input (optional, may be None) for cpuid "
|
||||
" instruction (ecx)\n"
|
||||
" config [dict]: Dictionary of register\n\n"
|
||||
"Returns: [int] 0 on success; exception on error.\n" },
|
||||
|
||||
{ "domain_set_policy_cpuid",
|
||||
(PyCFunction)pyxc_dom_set_policy_cpuid,
|
||||
METH_VARARGS, "\n"
|
||||
"Set the default cpuid policy for a domain.\n"
|
||||
" dom [int]: Identifier of domain.\n\n"
|
||||
"Returns: [int] 0 on success; exception on error.\n" },
|
||||
#endif
|
||||
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
@@ -309,6 +309,7 @@ def restore(xd, fd, dominfo = None, paused = False, relocating = False):
|
||||
else:
|
||||
break
|
||||
os.close(qemu_fd)
|
||||
restore_image.setCpuid()
|
||||
|
||||
|
||||
os.read(fd, 1) # Wait for source to close connection
|
||||
|
||||
@@ -203,6 +203,8 @@ XENAPI_CFG_TYPES = {
|
||||
'target': int,
|
||||
'security_label': str,
|
||||
'pci': str,
|
||||
'cpuid' : dict,
|
||||
'cpuid_check' : dict,
|
||||
}
|
||||
|
||||
# List of legacy configuration keys that have no equivalent in the
|
||||
@@ -497,6 +499,32 @@ class XendConfig(dict):
|
||||
if 'handle' in dominfo:
|
||||
self['uuid'] = uuid.toString(dominfo['handle'])
|
||||
|
||||
def parse_cpuid(self, cfg, field):
|
||||
def int2bin(n, count=32):
|
||||
return "".join([str((n >> y) & 1) for y in range(count-1, -1, -1)])
|
||||
|
||||
for input, regs in cfg[field].iteritems():
|
||||
if not regs is dict:
|
||||
cfg[field][input] = dict(regs)
|
||||
|
||||
cpuid = {}
|
||||
for input in cfg[field]:
|
||||
inputs = input.split(',')
|
||||
if inputs[0][0:2] == '0x':
|
||||
inputs[0] = str(int(inputs[0], 16))
|
||||
if len(inputs) == 2:
|
||||
if inputs[1][0:2] == '0x':
|
||||
inputs[1] = str(int(inputs[1], 16))
|
||||
new_input = ','.join(inputs)
|
||||
cpuid[new_input] = {} # new input
|
||||
for reg in cfg[field][input]:
|
||||
val = cfg[field][input][reg]
|
||||
if val[0:2] == '0x':
|
||||
cpuid[new_input][reg] = int2bin(int(val, 16))
|
||||
else:
|
||||
cpuid[new_input][reg] = val
|
||||
cfg[field] = cpuid
|
||||
|
||||
def _parse_sxp(self, sxp_cfg):
|
||||
""" Populate this XendConfig using the parsed SXP.
|
||||
|
||||
@@ -653,6 +681,12 @@ class XendConfig(dict):
|
||||
except ValueError, e:
|
||||
raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
|
||||
|
||||
# Parse cpuid
|
||||
if 'cpuid' in cfg:
|
||||
self.parse_cpuid(cfg, 'cpuid')
|
||||
if 'cpuid_check' in cfg:
|
||||
self.parse_cpuid(cfg, 'cpuid_check')
|
||||
|
||||
import xen.util.xsm.xsm as security
|
||||
if security.on():
|
||||
from xen.util.acmpolicy import ACM_LABEL_UNLABELED
|
||||
@@ -901,6 +935,16 @@ class XendConfig(dict):
|
||||
int(self['vcpus_params'].get('weight', 256))
|
||||
self['vcpus_params']['cap'] = int(self['vcpus_params'].get('cap', 0))
|
||||
|
||||
def cpuid_to_sxp(self, sxpr, field):
|
||||
regs_list = []
|
||||
for input, regs in self[field].iteritems():
|
||||
reg_list = []
|
||||
for reg, val in regs.iteritems():
|
||||
reg_list.append([reg, val])
|
||||
regs_list.append([input, reg_list])
|
||||
sxpr.append([field, regs_list])
|
||||
|
||||
|
||||
def to_sxp(self, domain = None, ignore_devices = False, ignore = [],
|
||||
legacy_only = True):
|
||||
""" Get SXP representation of this config object.
|
||||
@@ -1012,6 +1056,13 @@ class XendConfig(dict):
|
||||
txn.abort()
|
||||
raise
|
||||
|
||||
if 'cpuid' in self:
|
||||
self.cpuid_to_sxp(sxpr, 'cpuid')
|
||||
if 'cpuid_check' in self:
|
||||
self.cpuid_to_sxp(sxpr, 'cpuid_check')
|
||||
|
||||
log.debug(sxpr)
|
||||
|
||||
return sxpr
|
||||
|
||||
def _blkdev_name_to_number(self, dev):
|
||||
|
||||
@@ -551,6 +551,38 @@ class HVMImageHandler(ImageHandler):
|
||||
self.acpi = int(vmConfig['platform'].get('acpi', 0))
|
||||
self.guest_os_type = vmConfig['platform'].get('guest_os_type')
|
||||
|
||||
self.vmConfig = vmConfig
|
||||
|
||||
def setCpuid(self):
|
||||
xc.domain_set_policy_cpuid(self.vm.getDomid())
|
||||
|
||||
if 'cpuid' in self.vmConfig:
|
||||
cpuid = self.vmConfig['cpuid']
|
||||
transformed = {}
|
||||
for sinput, regs in cpuid.iteritems():
|
||||
inputs = sinput.split(',')
|
||||
input = long(inputs[0])
|
||||
sub_input = None
|
||||
if len(inputs) == 2:
|
||||
sub_input = long(inputs[1])
|
||||
t = xc.domain_set_cpuid(self.vm.getDomid(),
|
||||
input, sub_input, regs)
|
||||
transformed[sinput] = t
|
||||
self.vmConfig['cpuid'] = transformed
|
||||
|
||||
if 'cpuid_check' in self.vmConfig:
|
||||
cpuid_check = self.vmConfig['cpuid_check']
|
||||
transformed = {}
|
||||
for sinput, regs_check in cpuid_check.iteritems():
|
||||
inputs = sinput.split(',')
|
||||
input = long(inputs[0])
|
||||
sub_input = None
|
||||
if len(inputs) == 2:
|
||||
sub_input = long(inputs[1])
|
||||
t = xc.domain_check_cpuid(input, sub_input, regs_check)
|
||||
transformed[sinput] = t
|
||||
self.vmConfig['cpuid_check'] = transformed
|
||||
|
||||
# Return a list of cmd line args to the device models based on the
|
||||
# xm config file
|
||||
def parseDeviceModelArgs(self, vmConfig):
|
||||
@@ -718,6 +750,7 @@ class X86_HVM_ImageHandler(HVMImageHandler):
|
||||
|
||||
def buildDomain(self):
|
||||
xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_PAE_ENABLED, self.pae)
|
||||
self.setCpuid()
|
||||
return HVMImageHandler.buildDomain(self)
|
||||
|
||||
def getRequiredAvailableMemory(self, mem_kb):
|
||||
|
||||
@@ -549,6 +549,14 @@ gopts.var('hap', val='HAP',
|
||||
use="""Hap status (0=hap is disabled;
|
||||
1=hap is enabled.""")
|
||||
|
||||
gopts.var('cpuid', val="IN[,SIN]:eax=EAX,ebx=EBX,exc=ECX,edx=EDX",
|
||||
fn=append_value, default=[],
|
||||
use="""Cpuid description.""")
|
||||
|
||||
gopts.var('cpuid_check', val="IN[,SIN]:eax=EAX,ebx=EBX,exc=ECX,edx=EDX",
|
||||
fn=append_value, default=[],
|
||||
use="""Cpuid check description.""")
|
||||
|
||||
def err(msg):
|
||||
"""Print an error to stderr and exit.
|
||||
"""
|
||||
@@ -755,7 +763,7 @@ def configure_hvm(config_image, vals):
|
||||
'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
|
||||
'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
|
||||
'acpi', 'apic', 'usb', 'usbdevice', 'keymap', 'pci', 'hpet',
|
||||
'guest_os_type', 'hap', 'opengl']
|
||||
'guest_os_type', 'hap', 'opengl', 'cpuid', 'cpuid_check']
|
||||
|
||||
for a in args:
|
||||
if a in vals.__dict__ and vals.__dict__[a] is not None:
|
||||
@@ -779,7 +787,8 @@ def make_config(vals):
|
||||
map(add_conf, ['name', 'memory', 'maxmem', 'shadow_memory',
|
||||
'restart', 'on_poweroff',
|
||||
'on_reboot', 'on_crash', 'vcpus', 'vcpu_avail', 'features',
|
||||
'on_xend_start', 'on_xend_stop', 'target'])
|
||||
'on_xend_start', 'on_xend_stop', 'target', 'cpuid',
|
||||
'cpuid_check'])
|
||||
|
||||
if vals.uuid is not None:
|
||||
config.append(['uuid', vals.uuid])
|
||||
@@ -843,6 +852,24 @@ def preprocess_disk(vals):
|
||||
disk.append(d)
|
||||
vals.disk = disk
|
||||
|
||||
def preprocess_cpuid(vals, attr_name):
|
||||
if not vals.cpuid: return
|
||||
cpuid = {}
|
||||
for cpuid_input in getattr(vals, attr_name):
|
||||
cpuid_match = re.match(r"(?P<input>(0x)?[0-9A-Fa-f]+):(?P<regs>.*)", cpuid_input)
|
||||
if cpuid_match != None:
|
||||
res_cpuid = cpuid_match.groupdict()
|
||||
input = res_cpuid['input']
|
||||
regs = res_cpuid['regs'].split(',')
|
||||
cpuid[input]= {} # New input
|
||||
for reg in regs:
|
||||
reg_match = re.match(r"(?P<reg>eax|ebx|ecx|edx)=(?P<val>.*)", reg)
|
||||
if reg_match == None:
|
||||
err("cpuid's syntax is (eax|ebx|ecx|edx)=value")
|
||||
res = reg_match.groupdict()
|
||||
cpuid[input][res['reg']] = res['val'] # new register
|
||||
setattr(vals, attr_name, cpuid)
|
||||
|
||||
def preprocess_pci(vals):
|
||||
if not vals.pci: return
|
||||
pci = []
|
||||
@@ -1047,6 +1074,8 @@ def preprocess(vals):
|
||||
preprocess_vnc(vals)
|
||||
preprocess_vtpm(vals)
|
||||
preprocess_access_control(vals)
|
||||
preprocess_cpuid(vals, 'cpuid')
|
||||
preprocess_cpuid(vals, 'cpuid_check')
|
||||
|
||||
|
||||
def comma_sep_kv_to_dict(c):
|
||||
|
||||
+39
-2
@@ -440,10 +440,9 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags)
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
struct page_info *pg;
|
||||
int i;
|
||||
#endif
|
||||
l1_pgentry_t gdt_l1e;
|
||||
int vcpuid, pdpt_order, paging_initialised = 0;
|
||||
int i, vcpuid, pdpt_order, paging_initialised = 0;
|
||||
int rc = -ENOMEM;
|
||||
|
||||
d->arch.hvm_domain.hap_enabled =
|
||||
@@ -541,6 +540,13 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags)
|
||||
(CONFIG_PAGING_LEVELS != 4);
|
||||
}
|
||||
|
||||
memset(d->arch.cpuids, 0, sizeof(d->arch.cpuids));
|
||||
for ( i = 0; i < MAX_CPUID_INPUT; i++ )
|
||||
{
|
||||
d->arch.cpuids[i].input[0] = XEN_CPUID_INPUT_UNUSED;
|
||||
d->arch.cpuids[i].input[1] = XEN_CPUID_INPUT_UNUSED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@@ -1910,6 +1916,37 @@ void arch_dump_vcpu_info(struct vcpu *v)
|
||||
paging_dump_vcpu_info(v);
|
||||
}
|
||||
|
||||
void domain_cpuid(
|
||||
struct domain *d,
|
||||
unsigned int input,
|
||||
unsigned int sub_input,
|
||||
unsigned int *eax,
|
||||
unsigned int *ebx,
|
||||
unsigned int *ecx,
|
||||
unsigned int *edx)
|
||||
{
|
||||
cpuid_input_t *cpuid;
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < MAX_CPUID_INPUT; i++ )
|
||||
{
|
||||
cpuid = &d->arch.cpuids[i];
|
||||
|
||||
if ( (cpuid->input[0] == input) &&
|
||||
((cpuid->input[1] == XEN_CPUID_INPUT_UNUSED) ||
|
||||
(cpuid->input[1] == sub_input)) )
|
||||
{
|
||||
*eax = cpuid->eax;
|
||||
*ebx = cpuid->ebx;
|
||||
*ecx = cpuid->ecx;
|
||||
*edx = cpuid->edx;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*eax = *ebx = *ecx = *edx = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
||||
@@ -842,6 +842,45 @@ long arch_do_domctl(
|
||||
}
|
||||
break;
|
||||
|
||||
case XEN_DOMCTL_set_cpuid:
|
||||
{
|
||||
struct domain *d;
|
||||
xen_domctl_cpuid_t *ctl = &domctl->u.cpuid;
|
||||
cpuid_input_t *cpuid = NULL;
|
||||
int i;
|
||||
|
||||
ret = -ESRCH;
|
||||
d = rcu_lock_domain_by_id(domctl->domain);
|
||||
if ( d == NULL )
|
||||
break;
|
||||
|
||||
for ( i = 0; i < MAX_CPUID_INPUT; i++ )
|
||||
{
|
||||
cpuid = &d->arch.cpuids[i];
|
||||
|
||||
if ( cpuid->input[0] == XEN_CPUID_INPUT_UNUSED )
|
||||
break;
|
||||
|
||||
if ( (cpuid->input[0] == ctl->input[0]) &&
|
||||
((cpuid->input[1] == XEN_CPUID_INPUT_UNUSED) ||
|
||||
(cpuid->input[1] == ctl->input[1])) )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( i == MAX_CPUID_INPUT )
|
||||
{
|
||||
ret = -ENOENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(cpuid, ctl, sizeof(cpuid_input_t));
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
rcu_unlock_domain(d);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
break;
|
||||
|
||||
+44
-59
@@ -1594,66 +1594,15 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
|
||||
if ( cpuid_hypervisor_leaves(input, eax, ebx, ecx, edx) )
|
||||
return;
|
||||
|
||||
cpuid(input, eax, ebx, ecx, edx);
|
||||
domain_cpuid(v->domain, input, *ecx, eax, ebx, ecx, edx);
|
||||
|
||||
switch ( input )
|
||||
if ( input == 0x00000001 )
|
||||
{
|
||||
case 0x00000001:
|
||||
/* Clear #threads count and poke initial VLAPIC ID. */
|
||||
*ebx &= 0x0000FFFFu;
|
||||
*ebx |= (current->vcpu_id * 2) << 24;
|
||||
|
||||
/* We always support MTRR MSRs. */
|
||||
*edx |= bitmaskof(X86_FEATURE_MTRR);
|
||||
|
||||
*ecx &= (bitmaskof(X86_FEATURE_XMM3) |
|
||||
bitmaskof(X86_FEATURE_SSSE3) |
|
||||
bitmaskof(X86_FEATURE_CX16) |
|
||||
bitmaskof(X86_FEATURE_SSE4_1) |
|
||||
bitmaskof(X86_FEATURE_SSE4_2) |
|
||||
bitmaskof(X86_FEATURE_POPCNT));
|
||||
|
||||
*edx &= (bitmaskof(X86_FEATURE_FPU) |
|
||||
bitmaskof(X86_FEATURE_VME) |
|
||||
bitmaskof(X86_FEATURE_DE) |
|
||||
bitmaskof(X86_FEATURE_PSE) |
|
||||
bitmaskof(X86_FEATURE_TSC) |
|
||||
bitmaskof(X86_FEATURE_MSR) |
|
||||
bitmaskof(X86_FEATURE_PAE) |
|
||||
bitmaskof(X86_FEATURE_MCE) |
|
||||
bitmaskof(X86_FEATURE_CX8) |
|
||||
bitmaskof(X86_FEATURE_APIC) |
|
||||
bitmaskof(X86_FEATURE_SEP) |
|
||||
bitmaskof(X86_FEATURE_MTRR) |
|
||||
bitmaskof(X86_FEATURE_PGE) |
|
||||
bitmaskof(X86_FEATURE_MCA) |
|
||||
bitmaskof(X86_FEATURE_CMOV) |
|
||||
bitmaskof(X86_FEATURE_PAT) |
|
||||
bitmaskof(X86_FEATURE_CLFLSH) |
|
||||
bitmaskof(X86_FEATURE_MMX) |
|
||||
bitmaskof(X86_FEATURE_FXSR) |
|
||||
bitmaskof(X86_FEATURE_XMM) |
|
||||
bitmaskof(X86_FEATURE_XMM2));
|
||||
/* Fix up VLAPIC details. */
|
||||
*ebx &= 0x00FFFFFFu;
|
||||
*ebx |= (v->vcpu_id * 2) << 24;
|
||||
if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
|
||||
__clear_bit(X86_FEATURE_APIC & 31, edx);
|
||||
#if CONFIG_PAGING_LEVELS >= 3
|
||||
if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] )
|
||||
#endif
|
||||
__clear_bit(X86_FEATURE_PAE & 31, edx);
|
||||
break;
|
||||
|
||||
case 0x80000001:
|
||||
#if CONFIG_PAGING_LEVELS >= 3
|
||||
if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] )
|
||||
#endif
|
||||
__clear_bit(X86_FEATURE_NX & 31, edx);
|
||||
#ifdef __i386__
|
||||
/* Mask feature for Intel ia32e or AMD long mode. */
|
||||
__clear_bit(X86_FEATURE_LAHF_LM & 31, ecx);
|
||||
__clear_bit(X86_FEATURE_LM & 31, edx);
|
||||
__clear_bit(X86_FEATURE_SYSCALL & 31, edx);
|
||||
#endif
|
||||
break;
|
||||
__clear_bit(X86_FEATURE_APIC & 31, ebx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1663,11 +1612,15 @@ int hvm_msr_read_intercept(struct cpu_user_regs *regs)
|
||||
uint64_t msr_content = 0;
|
||||
struct vcpu *v = current;
|
||||
uint64_t *var_range_base, *fixed_range_base;
|
||||
int index;
|
||||
int index, mtrr;
|
||||
uint32_t cpuid[4];
|
||||
|
||||
var_range_base = (uint64_t *)v->arch.hvm_vcpu.mtrr.var_ranges;
|
||||
fixed_range_base = (uint64_t *)v->arch.hvm_vcpu.mtrr.fixed_ranges;
|
||||
|
||||
hvm_cpuid(1, &cpuid[0], &cpuid[1], &cpuid[2], &cpuid[3]);
|
||||
mtrr = !!(cpuid[3] & bitmaskof(X86_FEATURE_MTRR));
|
||||
|
||||
switch ( ecx )
|
||||
{
|
||||
case MSR_IA32_TSC:
|
||||
@@ -1695,25 +1648,37 @@ int hvm_msr_read_intercept(struct cpu_user_regs *regs)
|
||||
break;
|
||||
|
||||
case MSR_MTRRcap:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
msr_content = v->arch.hvm_vcpu.mtrr.mtrr_cap;
|
||||
break;
|
||||
case MSR_MTRRdefType:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
msr_content = v->arch.hvm_vcpu.mtrr.def_type
|
||||
| (v->arch.hvm_vcpu.mtrr.enabled << 10);
|
||||
break;
|
||||
case MSR_MTRRfix64K_00000:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
msr_content = fixed_range_base[0];
|
||||
break;
|
||||
case MSR_MTRRfix16K_80000:
|
||||
case MSR_MTRRfix16K_A0000:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
index = regs->ecx - MSR_MTRRfix16K_80000;
|
||||
msr_content = fixed_range_base[index + 1];
|
||||
break;
|
||||
case MSR_MTRRfix4K_C0000...MSR_MTRRfix4K_F8000:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
index = regs->ecx - MSR_MTRRfix4K_C0000;
|
||||
msr_content = fixed_range_base[index + 3];
|
||||
break;
|
||||
case MSR_IA32_MTRR_PHYSBASE0...MSR_IA32_MTRR_PHYSMASK7:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
index = regs->ecx - MSR_IA32_MTRR_PHYSBASE0;
|
||||
msr_content = var_range_base[index];
|
||||
break;
|
||||
@@ -1725,6 +1690,10 @@ int hvm_msr_read_intercept(struct cpu_user_regs *regs)
|
||||
regs->eax = (uint32_t)msr_content;
|
||||
regs->edx = (uint32_t)(msr_content >> 32);
|
||||
return X86EMUL_OKAY;
|
||||
|
||||
gp_fault:
|
||||
hvm_inject_exception(TRAP_gp_fault, 0, 0);
|
||||
return X86EMUL_EXCEPTION;
|
||||
}
|
||||
|
||||
int hvm_msr_write_intercept(struct cpu_user_regs *regs)
|
||||
@@ -1739,7 +1708,11 @@ int hvm_msr_write_intercept(struct cpu_user_regs *regs)
|
||||
uint32_t ecx = regs->ecx;
|
||||
uint64_t msr_content = (uint32_t)regs->eax | ((uint64_t)regs->edx << 32);
|
||||
struct vcpu *v = current;
|
||||
int index;
|
||||
int index, mtrr;
|
||||
uint32_t cpuid[4];
|
||||
|
||||
hvm_cpuid(1, &cpuid[0], &cpuid[1], &cpuid[2], &cpuid[3]);
|
||||
mtrr = !!(cpuid[3] & bitmaskof(X86_FEATURE_MTRR));
|
||||
|
||||
switch ( ecx )
|
||||
{
|
||||
@@ -1758,29 +1731,41 @@ int hvm_msr_write_intercept(struct cpu_user_regs *regs)
|
||||
break;
|
||||
|
||||
case MSR_MTRRcap:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
goto gp_fault;
|
||||
case MSR_MTRRdefType:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
if ( !mtrr_def_type_msr_set(&v->arch.hvm_vcpu.mtrr, msr_content) )
|
||||
goto gp_fault;
|
||||
break;
|
||||
case MSR_MTRRfix64K_00000:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
if ( !mtrr_fix_range_msr_set(&v->arch.hvm_vcpu.mtrr, 0, msr_content) )
|
||||
goto gp_fault;
|
||||
break;
|
||||
case MSR_MTRRfix16K_80000:
|
||||
case MSR_MTRRfix16K_A0000:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
index = regs->ecx - MSR_MTRRfix16K_80000 + 1;
|
||||
if ( !mtrr_fix_range_msr_set(&v->arch.hvm_vcpu.mtrr,
|
||||
index, msr_content) )
|
||||
goto gp_fault;
|
||||
break;
|
||||
case MSR_MTRRfix4K_C0000...MSR_MTRRfix4K_F8000:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
index = regs->ecx - MSR_MTRRfix4K_C0000 + 3;
|
||||
if ( !mtrr_fix_range_msr_set(&v->arch.hvm_vcpu.mtrr,
|
||||
index, msr_content) )
|
||||
goto gp_fault;
|
||||
break;
|
||||
case MSR_IA32_MTRR_PHYSBASE0...MSR_IA32_MTRR_PHYSMASK7:
|
||||
if ( !mtrr )
|
||||
goto gp_fault;
|
||||
if ( !mtrr_var_range_msr_set(&v->arch.hvm_vcpu.mtrr,
|
||||
regs->ecx, msr_content) )
|
||||
goto gp_fault;
|
||||
|
||||
@@ -892,56 +892,11 @@ static void svm_cpuid_intercept(
|
||||
|
||||
hvm_cpuid(input, eax, ebx, ecx, edx);
|
||||
|
||||
switch ( input )
|
||||
if ( input == 0x80000001 )
|
||||
{
|
||||
case 0x00000001:
|
||||
/* Mask Intel-only features. */
|
||||
*ecx &= ~(bitmaskof(X86_FEATURE_SSSE3) |
|
||||
bitmaskof(X86_FEATURE_SSE4_1) |
|
||||
bitmaskof(X86_FEATURE_SSE4_2));
|
||||
break;
|
||||
|
||||
case 0x80000001:
|
||||
/* Filter features which are shared with 0x00000001:EDX. */
|
||||
/* Fix up VLAPIC details. */
|
||||
if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
|
||||
__clear_bit(X86_FEATURE_APIC & 31, edx);
|
||||
#if CONFIG_PAGING_LEVELS >= 3
|
||||
if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] )
|
||||
#endif
|
||||
__clear_bit(X86_FEATURE_PAE & 31, edx);
|
||||
__clear_bit(X86_FEATURE_PSE36 & 31, edx);
|
||||
|
||||
/* We always support MTRR MSRs. */
|
||||
*edx |= bitmaskof(X86_FEATURE_MTRR);
|
||||
|
||||
/* Filter all other features according to a whitelist. */
|
||||
*ecx &= (bitmaskof(X86_FEATURE_LAHF_LM) |
|
||||
bitmaskof(X86_FEATURE_ALTMOVCR) |
|
||||
bitmaskof(X86_FEATURE_ABM) |
|
||||
bitmaskof(X86_FEATURE_SSE4A) |
|
||||
bitmaskof(X86_FEATURE_MISALIGNSSE) |
|
||||
bitmaskof(X86_FEATURE_3DNOWPF));
|
||||
*edx &= (0x0183f3ff | /* features shared with 0x00000001:EDX */
|
||||
bitmaskof(X86_FEATURE_NX) |
|
||||
bitmaskof(X86_FEATURE_LM) |
|
||||
bitmaskof(X86_FEATURE_SYSCALL) |
|
||||
bitmaskof(X86_FEATURE_MP) |
|
||||
bitmaskof(X86_FEATURE_MMXEXT) |
|
||||
bitmaskof(X86_FEATURE_FFXSR) |
|
||||
bitmaskof(X86_FEATURE_3DNOW) |
|
||||
bitmaskof(X86_FEATURE_3DNOWEXT));
|
||||
break;
|
||||
|
||||
case 0x80000007:
|
||||
case 0x8000000A:
|
||||
/* Mask out features of power management and SVM extension. */
|
||||
*eax = *ebx = *ecx = *edx = 0;
|
||||
break;
|
||||
|
||||
case 0x80000008:
|
||||
/* Make sure Number of CPU core is 1 when HTT=0 */
|
||||
*ecx &= 0xFFFFFF00;
|
||||
break;
|
||||
}
|
||||
|
||||
HVMTRACE_3D(CPUID, v, input,
|
||||
|
||||
+10
-23
@@ -1311,34 +1311,21 @@ static void vmx_cpuid_intercept(
|
||||
unsigned int *ecx, unsigned int *edx)
|
||||
{
|
||||
unsigned int input = *eax;
|
||||
unsigned int count = *ecx;
|
||||
struct segment_register cs;
|
||||
struct vcpu *v = current;
|
||||
|
||||
hvm_cpuid(input, eax, ebx, ecx, edx);
|
||||
|
||||
switch ( input )
|
||||
{
|
||||
case 0x00000001:
|
||||
/* Mask AMD-only features. */
|
||||
*ecx &= ~(bitmaskof(X86_FEATURE_POPCNT));
|
||||
break;
|
||||
|
||||
case 0x00000004:
|
||||
cpuid_count(input, count, eax, ebx, ecx, edx);
|
||||
*eax &= 0x3FFF; /* one core */
|
||||
break;
|
||||
|
||||
case 0x00000006:
|
||||
case 0x00000009:
|
||||
*eax = *ebx = *ecx = *edx = 0;
|
||||
break;
|
||||
|
||||
case 0x80000001:
|
||||
/* Only a few features are advertised in Intel's 0x80000001. */
|
||||
*ecx &= (bitmaskof(X86_FEATURE_LAHF_LM));
|
||||
*edx &= (bitmaskof(X86_FEATURE_NX) |
|
||||
bitmaskof(X86_FEATURE_LM) |
|
||||
bitmaskof(X86_FEATURE_SYSCALL));
|
||||
break;
|
||||
case 0x80000001:
|
||||
/* SYSCALL is visible iff running in long mode. */
|
||||
hvm_get_segment_register(v, x86_seg_cs, &cs);
|
||||
if ( cs.attr.fields.l )
|
||||
*edx |= bitmaskof(X86_FEATURE_SYSCALL);
|
||||
else
|
||||
*edx &= ~(bitmaskof(X86_FEATURE_SYSCALL));
|
||||
break;
|
||||
}
|
||||
|
||||
HVMTRACE_3D(CPUID, current, input,
|
||||
|
||||
@@ -187,6 +187,9 @@ struct paging_vcpu {
|
||||
struct shadow_vcpu shadow;
|
||||
};
|
||||
|
||||
#define MAX_CPUID_INPUT 40
|
||||
typedef xen_domctl_cpuid_t cpuid_input_t;
|
||||
|
||||
struct p2m_domain;
|
||||
|
||||
struct arch_domain
|
||||
@@ -243,6 +246,8 @@ struct arch_domain
|
||||
RELMEM_done,
|
||||
} relmem;
|
||||
struct list_head relmem_list;
|
||||
|
||||
cpuid_input_t cpuids[MAX_CPUID_INPUT];
|
||||
} __cacheline_aligned;
|
||||
|
||||
#ifdef CONFIG_X86_PAE
|
||||
@@ -353,6 +358,14 @@ unsigned long pv_guest_cr4_fixup(unsigned long guest_cr4);
|
||||
#define real_cr4_to_pv_guest_cr4(c) \
|
||||
((c) & ~(X86_CR4_PGE | X86_CR4_PSE))
|
||||
|
||||
void domain_cpuid(struct domain *d,
|
||||
unsigned int input,
|
||||
unsigned int sub_input,
|
||||
unsigned int *eax,
|
||||
unsigned int *ebx,
|
||||
unsigned int *ecx,
|
||||
unsigned int *edx);
|
||||
|
||||
#endif /* __ASM_DOMAIN_H__ */
|
||||
|
||||
/*
|
||||
|
||||
@@ -571,6 +571,19 @@ struct xen_domctl_set_target {
|
||||
typedef struct xen_domctl_set_target xen_domctl_set_target_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_target_t);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
# define XEN_CPUID_INPUT_UNUSED 0xFFFFFFFF
|
||||
# define XEN_DOMCTL_set_cpuid 49
|
||||
struct xen_domctl_cpuid {
|
||||
unsigned int input[2];
|
||||
unsigned int eax;
|
||||
unsigned int ebx;
|
||||
unsigned int ecx;
|
||||
unsigned int edx;
|
||||
};
|
||||
typedef struct xen_domctl_cpuid xen_domctl_cpuid_t;
|
||||
DEFINE_XEN_GUEST_HANDLE(xen_domctl_cpuid_t);
|
||||
#endif
|
||||
|
||||
struct xen_domctl {
|
||||
uint32_t cmd;
|
||||
@@ -609,6 +622,9 @@ struct xen_domctl {
|
||||
struct xen_domctl_ext_vcpucontext ext_vcpucontext;
|
||||
struct xen_domctl_set_opt_feature set_opt_feature;
|
||||
struct xen_domctl_set_target set_target;
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
struct xen_domctl_cpuid cpuid;
|
||||
#endif
|
||||
uint8_t pad[128];
|
||||
} u;
|
||||
};
|
||||
|
||||