# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1213180535 -3600
# Node ID 7c771f0a24f37cbb3ab56db79f3a82106b42f4d8
# Parent f292689f48ba62050f1e019dfad1da0bb6444034
x86: cpuid configuration for PV guest
Add pv guest support for the cpuid configuration and checking. That
feature only works for cpuid request which are coming from the guest's
kernel, a process could still call the cpuid directly.
A new policy for pv guest has been created in libxc. dom0 cpuid
emulation is left hardcoded in Xen.
Signed-off-by: Jean Guyader <jean.guyader@xxxxxxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
tools/libxc/xc_cpuid_x86.c | 177 +++++++++++++++++++++++++++++++----------
tools/python/xen/xend/image.py | 78 ++++++++++--------
xen/arch/x86/traps.c | 69 +++++++++------
3 files changed, 222 insertions(+), 102 deletions(-)
diff -r f292689f48ba -r 7c771f0a24f3 tools/libxc/xc_cpuid_x86.c
--- a/tools/libxc/xc_cpuid_x86.c Wed Jun 11 09:44:42 2008 +0100
+++ b/tools/libxc/xc_cpuid_x86.c Wed Jun 11 11:35:35 2008 +0100
@@ -25,8 +25,8 @@
#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 clear_bit(idx, dst) ((dst) &= ~(1u << ((idx) & 31)))
+#define set_bit(idx, dst) ((dst) |= (1u << ((idx) & 31)))
#define DEF_MAX_BASE 0x00000004u
#define DEF_MAX_EXT 0x80000008u
@@ -36,6 +36,33 @@ static int hypervisor_is_64bit(int xc)
xen_capabilities_info_t xen_caps = "";
return ((xc_version(xc, XENVER_capabilities, &xen_caps) == 0) &&
(strstr(xen_caps, "x86_64") != NULL));
+}
+
+static void cpuid(const unsigned int *input, unsigned int *regs)
+{
+ unsigned int count = (input[1] == XEN_CPUID_INPUT_UNUSED) ? 0 : input[1];
+ asm (
+#ifdef __i386__
+ "push %%ebx; cpuid; mov %%ebx,%1; pop %%ebx"
+#else
+ "push %%rbx; cpuid; mov %%ebx,%1; pop %%rbx"
+#endif
+ : "=a" (regs[0]), "=r" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
+ : "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 amd_xc_cpuid_policy(
@@ -60,8 +87,8 @@ static void amd_xc_cpuid_policy(
int is_64bit = hypervisor_is_64bit(xc) && is_pae;
if ( !is_pae )
- clear_bit(X86_FEATURE_PAE & 31, regs[3]);
- clear_bit(X86_FEATURE_PSE36 & 31, regs[3]);
+ clear_bit(X86_FEATURE_PAE, regs[3]);
+ clear_bit(X86_FEATURE_PSE36, regs[3]);
/* Filter all other features according to a whitelist. */
regs[2] &= ((is_64bit ? bitmaskof(X86_FEATURE_LAHF_LM) : 0) |
@@ -113,42 +140,17 @@ static void intel_xc_cpuid_policy(
}
}
-static void cpuid(const unsigned int *input, unsigned int *regs)
-{
- unsigned int count = (input[1] == XEN_CPUID_INPUT_UNUSED) ? 0 : input[1];
- asm (
-#ifdef __i386__
- "push %%ebx; cpuid; mov %%ebx,%1; pop %%ebx"
-#else
- "push %%rbx; cpuid; mov %%ebx,%1; pop %%rbx"
-#endif
- : "=a" (regs[0]), "=r" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
- : "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(
+static void xc_cpuid_hvm_policy(
int xc, domid_t domid, const unsigned int *input, unsigned int *regs)
{
char brand[13];
unsigned long pae;
+ int is_pae;
xc_get_hvm_param(xc, domid, HVM_PARAM_PAE_ENABLED, &pae);
-
- switch( input[0] )
+ is_pae = !!pae;
+
+ switch ( input[0] )
{
case 0x00000000:
if ( regs[0] > DEF_MAX_BASE )
@@ -188,8 +190,8 @@ static void xc_cpuid_policy(
/* We always support MTRR MSRs. */
regs[3] |= bitmaskof(X86_FEATURE_MTRR);
- if ( !pae )
- clear_bit(X86_FEATURE_PAE & 31, regs[3]);
+ if ( !is_pae )
+ clear_bit(X86_FEATURE_PAE, regs[3]);
break;
case 0x80000000:
@@ -198,8 +200,8 @@ static void xc_cpuid_policy(
break;
case 0x80000001:
- if ( !pae )
- clear_bit(X86_FEATURE_NX & 31, regs[3]);
+ if ( !is_pae )
+ clear_bit(X86_FEATURE_NX, regs[3]);
break;
@@ -223,9 +225,104 @@ static void xc_cpuid_policy(
xc_cpuid_brand_get(brand);
if ( strstr(brand, "AMD") )
- amd_xc_cpuid_policy(xc, domid, input, regs, !!pae);
+ amd_xc_cpuid_policy(xc, domid, input, regs, is_pae);
else
- intel_xc_cpuid_policy(xc, domid, input, regs, !!pae);
+ intel_xc_cpuid_policy(xc, domid, input, regs, is_pae);
+
+}
+
+static void xc_cpuid_pv_policy(
+ int xc, domid_t domid, const unsigned int *input, unsigned int *regs)
+{
+ DECLARE_DOMCTL;
+ int guest_64bit, xen_64bit = hypervisor_is_64bit(xc);
+ char brand[13];
+
+ xc_cpuid_brand_get(brand);
+
+ memset(&domctl, 0, sizeof(domctl));
+ domctl.domain = domid;
+ domctl.cmd = XEN_DOMCTL_get_address_size;
+ do_domctl(xc, &domctl);
+ guest_64bit = (domctl.u.address_size.size == 64);
+
+ if ( (input[0] & 0x7fffffff) == 1 )
+ {
+ clear_bit(X86_FEATURE_VME, regs[3]);
+ clear_bit(X86_FEATURE_PSE, regs[3]);
+ clear_bit(X86_FEATURE_PGE, regs[3]);
+ clear_bit(X86_FEATURE_MCE, regs[3]);
+ clear_bit(X86_FEATURE_MCA, regs[3]);
+ clear_bit(X86_FEATURE_MTRR, regs[3]);
+ clear_bit(X86_FEATURE_PSE36, regs[3]);
+ }
+
+ switch ( input[0] )
+ {
+ case 1:
+ if ( !xen_64bit || strstr(brand, "AMD") )
+ clear_bit(X86_FEATURE_SEP, regs[3]);
+ clear_bit(X86_FEATURE_DS, regs[3]);
+ clear_bit(X86_FEATURE_ACC, regs[3]);
+ clear_bit(X86_FEATURE_PBE, regs[3]);
+
+ clear_bit(X86_FEATURE_DTES64, regs[2]);
+ clear_bit(X86_FEATURE_MWAIT, regs[2]);
+ clear_bit(X86_FEATURE_DSCPL, regs[2]);
+ clear_bit(X86_FEATURE_VMXE, regs[2]);
+ clear_bit(X86_FEATURE_SMXE, regs[2]);
+ clear_bit(X86_FEATURE_EST, regs[2]);
+ clear_bit(X86_FEATURE_TM2, regs[2]);
+ if ( !guest_64bit )
+ clear_bit(X86_FEATURE_CX16, regs[2]);
+ clear_bit(X86_FEATURE_XTPR, regs[2]);
+ clear_bit(X86_FEATURE_PDCM, regs[2]);
+ clear_bit(X86_FEATURE_DCA, regs[2]);
+ break;
+ case 0x80000001:
+ if ( !guest_64bit )
+ {
+ clear_bit(X86_FEATURE_LM, regs[3]);
+ clear_bit(X86_FEATURE_LAHF_LM, regs[2]);
+ if ( !strstr(brand, "AMD") )
+ clear_bit(X86_FEATURE_SYSCALL, regs[3]);
+ }
+ else
+ {
+ set_bit(X86_FEATURE_SYSCALL, regs[3]);
+ }
+ clear_bit(X86_FEATURE_PAGE1GB, regs[3]);
+ clear_bit(X86_FEATURE_RDTSCP, regs[3]);
+
+ clear_bit(X86_FEATURE_SVME, regs[2]);
+ clear_bit(X86_FEATURE_OSVW, regs[2]);
+ clear_bit(X86_FEATURE_IBS, regs[2]);
+ clear_bit(X86_FEATURE_SKINIT, regs[2]);
+ clear_bit(X86_FEATURE_WDT, regs[2]);
+ break;
+ case 5: /* MONITOR/MWAIT */
+ case 0xa: /* Architectural Performance Monitor Features */
+ case 0x8000000a: /* SVM revision and features */
+ case 0x8000001b: /* Instruction Based Sampling */
+ regs[0] = regs[1] = regs[2] = regs[3] = 0;
+ break;
+ }
+}
+
+static int xc_cpuid_policy(
+ int xc, domid_t domid, const unsigned int *input, unsigned int *regs)
+{
+ xc_dominfo_t info;
+
+ if ( xc_domain_getinfo(xc, domid, 1, &info) == 0 )
+ return -EINVAL;
+
+ if ( info.hvm )
+ xc_cpuid_hvm_policy(xc, domid, input, regs);
+ else
+ xc_cpuid_pv_policy(xc, domid, input, regs);
+
+ return 0;
}
static int xc_cpuid_do_domctl(
diff -r f292689f48ba -r 7c771f0a24f3 tools/python/xen/xend/image.py
--- a/tools/python/xen/xend/image.py Wed Jun 11 09:44:42 2008 +0100
+++ b/tools/python/xen/xend/image.py Wed Jun 11 11:35:35 2008 +0100
@@ -103,6 +103,12 @@ class ImageHandler:
if rtc_timeoffset is not None:
xc.domain_set_time_offset(self.vm.getDomid(), int(rtc_timeoffset))
+ self.cpuid = None
+ self.cpuid_check = None
+ if 'cpuid' in vmConfig:
+ self.cpuid = vmConfig['cpuid'];
+ if 'cpuid_check' in vmConfig:
+ self.cpuid_check = vmConfig['cpuid_check']
def cleanupBootloading(self):
if self.bootloader:
@@ -454,6 +460,37 @@ class ImageHandler:
except:
pass
+ def setCpuid(self):
+ xc.domain_set_policy_cpuid(self.vm.getDomid())
+
+ if self.cpuid is not None:
+ cpuid = self.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.cpuid = transformed
+
+ if self.cpuid_check is not None:
+ cpuid_check = self.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.cpuid_check = transformed
+
+
class LinuxImageHandler(ImageHandler):
@@ -536,38 +573,7 @@ class HVMImageHandler(ImageHandler):
self.apic = int(vmConfig['platform'].get('apic', 0))
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
@@ -730,6 +736,9 @@ class IA64_Linux_ImageHandler(LinuxImage
LinuxImageHandler.configure(self, vmConfig)
self.vhpt = int(vmConfig['platform'].get('vhpt', 0))
+ def setCpuid(self):
+ # Guest CPUID configuration is not implemented yet.
+ return
class X86_HVM_ImageHandler(HVMImageHandler):
@@ -739,8 +748,9 @@ class X86_HVM_ImageHandler(HVMImageHandl
def buildDomain(self):
xc.hvm_set_param(self.vm.getDomid(), HVM_PARAM_PAE_ENABLED, self.pae)
+ rc = HVMImageHandler.buildDomain(self)
self.setCpuid()
- return HVMImageHandler.buildDomain(self)
+ return rc
def getRequiredAvailableMemory(self, mem_kb):
# Add 8 MiB overhead for QEMU's video RAM.
@@ -769,7 +779,9 @@ class X86_Linux_ImageHandler(LinuxImageH
# add an 8MB slack to balance backend allocations.
mem_kb = self.getRequiredMaximumReservation() + (8 * 1024)
xc.domain_set_memmap_limit(self.vm.getDomid(), mem_kb)
- return LinuxImageHandler.buildDomain(self)
+ rc = LinuxImageHandler.buildDomain(self)
+ self.setCpuid()
+ return rc
_handlers = {
"ia64": {
diff -r f292689f48ba -r 7c771f0a24f3 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c Wed Jun 11 09:44:42 2008 +0100
+++ b/xen/arch/x86/traps.c Wed Jun 11 11:35:35 2008 +0100
@@ -649,37 +649,21 @@ int cpuid_hypervisor_leaves(
return 1;
}
-static int emulate_forced_invalid_op(struct cpu_user_regs *regs)
-{
- char sig[5], instr[2];
+static void pv_cpuid(struct cpu_user_regs *regs)
+{
uint32_t a, b, c, d;
- unsigned long eip, rc;
a = regs->eax;
b = regs->ebx;
c = regs->ecx;
d = regs->edx;
- eip = regs->eip;
-
- /* Check for forced emulation signature: ud2 ; .ascii "xen". */
- if ( (rc = copy_from_user(sig, (char *)eip, sizeof(sig))) != 0 )
- {
- propagate_page_fault(eip + sizeof(sig) - rc, 0);
- return EXCRET_fault_fixed;
- }
- if ( memcmp(sig, "\xf\xbxen", sizeof(sig)) )
- return 0;
- eip += sizeof(sig);
-
- /* We only emulate CPUID. */
- if ( ( rc = copy_from_user(instr, (char *)eip, sizeof(instr))) != 0 )
- {
- propagate_page_fault(eip + sizeof(instr) - rc, 0);
- return EXCRET_fault_fixed;
- }
- if ( memcmp(instr, "\xf\xa2", sizeof(instr)) )
- return 0;
- eip += sizeof(instr);
+
+ if ( current->domain->domain_id != 0 )
+ {
+ if ( !cpuid_hypervisor_leaves(a, &a, &b, &c, &d) )
+ domain_cpuid(current->domain, a, b, &a, &b, &c, &d);
+ goto out;
+ }
asm (
"cpuid"
@@ -694,8 +678,6 @@ static int emulate_forced_invalid_op(str
__clear_bit(X86_FEATURE_PGE, &d);
__clear_bit(X86_FEATURE_MCE, &d);
__clear_bit(X86_FEATURE_MCA, &d);
- if ( !IS_PRIV(current->domain) )
- __clear_bit(X86_FEATURE_MTRR, &d);
__clear_bit(X86_FEATURE_PSE36, &d);
}
switch ( (uint32_t)regs->eax )
@@ -717,8 +699,6 @@ static int emulate_forced_invalid_op(str
__clear_bit(X86_FEATURE_DSCPL % 32, &c);
__clear_bit(X86_FEATURE_VMXE % 32, &c);
__clear_bit(X86_FEATURE_SMXE % 32, &c);
- if ( !IS_PRIV(current->domain) )
- __clear_bit(X86_FEATURE_EST % 32, &c);
__clear_bit(X86_FEATURE_TM2 % 32, &c);
if ( is_pv_32bit_vcpu(current) )
__clear_bit(X86_FEATURE_CX16 % 32, &c);
@@ -758,10 +738,41 @@ static int emulate_forced_invalid_op(str
break;
}
+ out:
regs->eax = a;
regs->ebx = b;
regs->ecx = c;
regs->edx = d;
+}
+
+static int emulate_forced_invalid_op(struct cpu_user_regs *regs)
+{
+ char sig[5], instr[2];
+ unsigned long eip, rc;
+
+ eip = regs->eip;
+
+ /* Check for forced emulation signature: ud2 ; .ascii "xen". */
+ if ( (rc = copy_from_user(sig, (char *)eip, sizeof(sig))) != 0 )
+ {
+ propagate_page_fault(eip + sizeof(sig) - rc, 0);
+ return EXCRET_fault_fixed;
+ }
+ if ( memcmp(sig, "\xf\xbxen", sizeof(sig)) )
+ return 0;
+ eip += sizeof(sig);
+
+ /* We only emulate CPUID. */
+ if ( ( rc = copy_from_user(instr, (char *)eip, sizeof(instr))) != 0 )
+ {
+ propagate_page_fault(eip + sizeof(instr) - rc, 0);
+ return EXCRET_fault_fixed;
+ }
+ if ( memcmp(instr, "\xf\xa2", sizeof(instr)) )
+ return 0;
+ eip += sizeof(instr);
+
+ pv_cpuid(regs);
instruction_done(regs, eip, 0);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|