aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxc/xc_cpuid_x86.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-06-11 11:35:35 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-06-11 11:35:35 +0100
commit923ca284ebdcaf3636d028b151166271ff313f29 (patch)
tree4adb9c9ea1bfb22bdc8bca7053319e367fae14fa /tools/libxc/xc_cpuid_x86.c
parentcd6d8982db8f673e7399000e37c827e02eee4ff6 (diff)
downloadxen-923ca284ebdcaf3636d028b151166271ff313f29.tar.gz
xen-923ca284ebdcaf3636d028b151166271ff313f29.tar.bz2
xen-923ca284ebdcaf3636d028b151166271ff313f29.zip
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@eu.citrix.com> Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'tools/libxc/xc_cpuid_x86.c')
-rw-r--r--tools/libxc/xc_cpuid_x86.c175
1 files changed, 136 insertions, 39 deletions
diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c
index 7aa3256a35..2f08182bfd 100644
--- a/tools/libxc/xc_cpuid_x86.c
+++ b/tools/libxc/xc_cpuid_x86.c
@@ -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
@@ -38,6 +38,33 @@ static int hypervisor_is_64bit(int xc)
(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(
int xc, domid_t domid, const unsigned int *input, unsigned int *regs,
int is_pae)
@@ -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);
+ is_pae = !!pae;
- switch( input[0] )
+ 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, 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
- intel_xc_cpuid_policy(xc, domid, input, regs, !!pae);
+ xc_cpuid_pv_policy(xc, domid, input, regs);
+
+ return 0;
}
static int xc_cpuid_do_domctl(