diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-06-11 11:35:35 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-06-11 11:35:35 +0100 |
commit | 923ca284ebdcaf3636d028b151166271ff313f29 (patch) | |
tree | 4adb9c9ea1bfb22bdc8bca7053319e367fae14fa /tools/libxc/xc_cpuid_x86.c | |
parent | cd6d8982db8f673e7399000e37c827e02eee4ff6 (diff) | |
download | xen-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.c | 175 |
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( |