[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v2 1/4] xen/libxc: Allow changes to hypervisor CPUID leaf from config file



On 11/03/14 03:54, Boris Ostrovsky wrote:
> Currently only "real" cpuid leaves can be overwritten by users via
> 'cpuid' option in the configuration file. This patch provides ability to
> do the same for hypervisor leaves (those in the 0x40000000 range).
>
> Signed-off-by: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>

How?  There is nothing stopping leaves in 0x40000000 being set in the
policy with XEN_DOMCTL_set_cpuid, but I dont see anything which plumbs
this together at the Xen level.

> ---
>  tools/libxc/xc_cpuid_x86.c   |   23 ++++++++++++++++++++++-
>  tools/libxc/xc_misc.c        |   18 ++++++++++++++++++
>  tools/libxc/xenctrl.h        |    2 ++
>  xen/arch/x86/domain.c        |   19 ++++++++++++++++---
>  xen/arch/x86/sysctl.c        |   17 +++++++++++++++++
>  xen/arch/x86/traps.c         |    3 +++
>  xen/include/asm-x86/domain.h |    7 +++++++
>  xen/include/public/sysctl.h  |   18 ++++++++++++++++++
>  8 files changed, 103 insertions(+), 4 deletions(-)
>
> diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c
> index bbbf9b8..544a0fd 100644
> --- a/tools/libxc/xc_cpuid_x86.c
> +++ b/tools/libxc/xc_cpuid_x86.c
> @@ -33,6 +33,8 @@
>  #define DEF_MAX_INTELEXT  0x80000008u
>  #define DEF_MAX_AMDEXT    0x8000001cu
>  
> +#define HYPERVISOR_LEAF(idx) (((idx) & 0x40000000) == 0x40000000)
> +

This check is wrong.

>  static int hypervisor_is_64bit(xc_interface *xch)
>  {
>      xen_capabilities_info_t xen_caps = "";
> @@ -555,6 +557,9 @@ static int xc_cpuid_policy(
>  {
>      xc_dominfo_t        info;
>  
> +    if ( HYPERVISOR_LEAF(input[0]) )
> +        return 0;
> +
>      if ( xc_domain_getinfo(xch, domid, 1, &info) == 0 )
>          return -EINVAL;
>  
> @@ -754,7 +759,23 @@ int xc_cpuid_set(
>  
>      memset(config_transformed, 0, 4 * sizeof(*config_transformed));
>  
> -    cpuid(input, regs);
> +    if ( HYPERVISOR_LEAF(input[0]) )
> +    {
> +        xc_cpuid_t cpuid;
> +
> +        cpuid.input[0] = input[0];
> +        cpuid.input[1] = input[1];
> +
> +        if (xc_cpuid(xch, &cpuid))
> +            regs[0] = regs[1] = regs[2] = regs[3] = 0;
> +        else {
> +            regs[0] = cpuid.eax;
> +            regs[1] = cpuid.ebx;
> +            regs[2] = cpuid.ecx;
> +            regs[3] = cpuid.edx;
> +        }
> +     } else
> +        cpuid(input, regs);
>  
>      memcpy(polregs, regs, sizeof(regs));
>      xc_cpuid_policy(xch, domid, input, polregs);
> diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c
> index 3303454..4e8669b 100644
> --- a/tools/libxc/xc_misc.c
> +++ b/tools/libxc/xc_misc.c
> @@ -159,6 +159,24 @@ int xc_send_debug_keys(xc_interface *xch, char *keys)
>      return ret;
>  }
>  
> +int xc_cpuid(xc_interface *xch,
> +             xc_cpuid_t *cpuid)
> +{
> +    int ret;
> +    DECLARE_SYSCTL;
> +
> +    sysctl.cmd = XEN_SYSCTL_cpuid_op;
> +
> +    memcpy(&sysctl.u.cpuid, cpuid, sizeof(*cpuid));
> +
> +    if ( (ret = do_sysctl(xch, &sysctl)) != 0 )
> +        return ret;
> +
> +    memcpy(cpuid, &sysctl.u.cpuid, sizeof(*cpuid));
> +
> +    return 0;
> +}
> +
>  int xc_physinfo(xc_interface *xch,
>                  xc_physinfo_t *put_info)
>  {
> diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
> index 13f816b..6c709f5 100644
> --- a/tools/libxc/xenctrl.h
> +++ b/tools/libxc/xenctrl.h
> @@ -1135,6 +1135,7 @@ int xc_send_debug_keys(xc_interface *xch, char *keys);
>  typedef xen_sysctl_physinfo_t xc_physinfo_t;
>  typedef xen_sysctl_topologyinfo_t xc_topologyinfo_t;
>  typedef xen_sysctl_numainfo_t xc_numainfo_t;
> +typedef xen_sysctl_cpuid_t xc_cpuid_t;
>  
>  typedef uint32_t xc_cpu_to_node_t;
>  typedef uint32_t xc_cpu_to_socket_t;
> @@ -1146,6 +1147,7 @@ typedef uint32_t xc_node_to_node_dist_t;
>  int xc_physinfo(xc_interface *xch, xc_physinfo_t *info);
>  int xc_topologyinfo(xc_interface *xch, xc_topologyinfo_t *info);
>  int xc_numainfo(xc_interface *xch, xc_numainfo_t *info);
> +int xc_cpuid(xc_interface *xch, xc_cpuid_t *cpuid);
>  
>  int xc_sched_id(xc_interface *xch,
>                  int *sched_id);
> diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
> index c42a079..98e2b5f 100644
> --- a/xen/arch/x86/domain.c
> +++ b/xen/arch/x86/domain.c
> @@ -1997,7 +1997,7 @@ void arch_dump_vcpu_info(struct vcpu *v)
>          vpmu_dump(v);
>  }
>  
> -void domain_cpuid(
> +bool_t domain_cpuid_exists(
>      struct domain *d,
>      unsigned int  input,
>      unsigned int  sub_input,
> @@ -2030,11 +2030,24 @@ void domain_cpuid(
>                   !d->disable_migrate && !d->arch.vtsc )
>                  *edx &= ~(1u<<8); /* TSC Invariant */
>  
> -            return;
> +            return 1;
>          }
>      }
>  
> -    *eax = *ebx = *ecx = *edx = 0;
> +    return 0;
> +}
> +
> +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)
> +{
> +    if ( !domain_cpuid_exists(d, input, sub_input, eax, ebx, ecx, edx) )
> +        *eax = *ebx = *ecx = *edx = 0;
>  }
>  
>  void vcpu_kick(struct vcpu *v)
> diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
> index 15d4b91..08f8038 100644
> --- a/xen/arch/x86/sysctl.c
> +++ b/xen/arch/x86/sysctl.c
> @@ -101,6 +101,23 @@ long arch_do_sysctl(
>      }
>      break;
>  
> +    case XEN_SYSCTL_cpuid_op:

This would appear to be a cpuid instruction in the context of a domain,
which should be a domctl, not a sysctl.  I have a different
implementation of sysctl cpuid posted, which takes a pcpu parameter.

> +    {
> +        struct xen_sysctl_cpuid *cpuid = &sysctl->u.cpuid;
> +
> +        if ( !cpuid_hypervisor_leaves(cpuid->input[0], cpuid->input[1],
> +                                      &cpuid->eax,&cpuid->ebx,
> +                                      &cpuid->ecx, &cpuid->edx) )
> +            asm ( "cpuid"
> +                 :"=a" (cpuid->eax), "=b" (cpuid->ebx),
> +                  "=c" (cpuid->ecx), "=d" (cpuid->edx)
> +                 : "0" (cpuid->input[0]), "1" (cpuid->input[1]) );

This will likely bypass masking/levelling for a domain.  As suggested,
the hypervisor leaves should be plumbed properly through to be usable
from domain_cpuid().

~Andrew

> +
> +        if ( __copy_to_guest(u_sysctl, sysctl, 1) )
> +            ret = -EFAULT;
> +    }
> +    break;
> +
>      default:
>          ret = -ENOSYS;
>          break;
> diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
> index c462317..e1f39d9 100644
> --- a/xen/arch/x86/traps.c
> +++ b/xen/arch/x86/traps.c
> @@ -690,6 +690,9 @@ int cpuid_hypervisor_leaves( uint32_t idx, uint32_t 
> sub_idx,
>      if ( idx > limit ) 
>          return 0;
>  
> +    if ( domain_cpuid_exists(d, base + idx, sub_idx, eax, ebx, ecx, edx) )
> +        return 1;
> +
>      switch ( idx )
>      {
>      case 0:
> diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
> index 49f7c0c..5fd47de 100644
> --- a/xen/include/asm-x86/domain.h
> +++ b/xen/include/asm-x86/domain.h
> @@ -471,6 +471,13 @@ unsigned long pv_guest_cr4_fixup(const struct vcpu *, 
> unsigned long guest_cr4);
>      ((c) & ~(X86_CR4_PGE | X86_CR4_PSE | X86_CR4_TSD |      \
>               X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE))
>  
> +bool_t domain_cpuid_exists(struct domain *d,
> +                           unsigned int  input,
> +                           unsigned int  sub_input,
> +                           unsigned int  *eax,
> +                           unsigned int  *ebx,
> +                           unsigned int  *ecx,
> +                           unsigned int  *edx);
>  void domain_cpuid(struct domain *d,
>                    unsigned int  input,
>                    unsigned int  sub_input,
> diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
> index 8437d31..7c1c662 100644
> --- a/xen/include/public/sysctl.h
> +++ b/xen/include/public/sysctl.h
> @@ -632,6 +632,20 @@ struct xen_sysctl_coverage_op {
>  typedef struct xen_sysctl_coverage_op xen_sysctl_coverage_op_t;
>  DEFINE_XEN_GUEST_HANDLE(xen_sysctl_coverage_op_t);
>  
> +#if defined(__i386__) || defined(__x86_64__)
> +/* XEN_SYSCTL_cpuid_op */
> +/* Get CPUID of a particular leaf */
> +
> +struct xen_sysctl_cpuid {
> +     uint32_t input[2];
> +     uint32_t eax;
> +     uint32_t ebx;
> +     uint32_t ecx;
> +     uint32_t edx;
> +};
> +typedef struct xen_sysctl_cpuid xen_sysctl_cpuid_t;
> +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cpuid_t);
> +#endif
>  
>  struct xen_sysctl {
>      uint32_t cmd;
> @@ -654,6 +668,7 @@ struct xen_sysctl {
>  #define XEN_SYSCTL_cpupool_op                    18
>  #define XEN_SYSCTL_scheduler_op                  19
>  #define XEN_SYSCTL_coverage_op                   20
> +#define XEN_SYSCTL_cpuid_op                      21
>      uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
>      union {
>          struct xen_sysctl_readconsole       readconsole;
> @@ -675,6 +690,9 @@ struct xen_sysctl {
>          struct xen_sysctl_cpupool_op        cpupool_op;
>          struct xen_sysctl_scheduler_op      scheduler_op;
>          struct xen_sysctl_coverage_op       coverage_op;
> +#if defined(__i386__) || defined(__x86_64__)
> +        struct xen_sysctl_cpuid             cpuid;
> +#endif
>          uint8_t                             pad[128];
>      } u;
>  };


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.