ia64/xen-unstable

diff xen/arch/x86/traps.c @ 10892:0d2ba35c0cf2

[XEN] Add hypercall support for HVM guests. This is
fairly useless at the moment, since all of the hypercalls
fail, since copy_from_user doesn't work correctly in HVM
domains.

Signed-off-by: Steven Smith <ssmith@xensource.com>

Add a CPUID hypervisor platform interface at leaf
0x40000000. Allow hypercall transfer page to be filled
in via MSR 0x40000000.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Tue Aug 01 17:18:05 2006 +0100 (2006-08-01)
parents 2d2ed4d9b1c1
children 16aa4b417c6b
line diff
     1.1 --- a/xen/arch/x86/traps.c	Tue Aug 01 15:48:48 2006 +0100
     1.2 +++ b/xen/arch/x86/traps.c	Tue Aug 01 17:18:05 2006 +0100
     1.3 @@ -44,6 +44,7 @@
     1.4  #include <xen/symbols.h>
     1.5  #include <xen/iocap.h>
     1.6  #include <xen/nmi.h>
     1.7 +#include <xen/version.h>
     1.8  #include <asm/shadow.h>
     1.9  #include <asm/system.h>
    1.10  #include <asm/io.h>
    1.11 @@ -429,18 +430,95 @@ DO_ERROR_NOCODE(16, "fpu error", coproce
    1.12  DO_ERROR(17, "alignment check", alignment_check)
    1.13  DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error)
    1.14  
    1.15 +int rdmsr_hypervisor_regs(
    1.16 +    uint32_t idx, uint32_t *eax, uint32_t *edx)
    1.17 +{
    1.18 +    idx -= 0x40000000;
    1.19 +    if ( idx > 0 )
    1.20 +        return 0;
    1.21 +
    1.22 +    *eax = *edx = 0;
    1.23 +    return 1;
    1.24 +}
    1.25 +
    1.26 +int wrmsr_hypervisor_regs(
    1.27 +    uint32_t idx, uint32_t eax, uint32_t edx)
    1.28 +{
    1.29 +    struct domain *d = current->domain;
    1.30 +
    1.31 +    idx -= 0x40000000;
    1.32 +    if ( idx > 0 )
    1.33 +        return 0;
    1.34 +
    1.35 +    switch ( idx )
    1.36 +    {
    1.37 +    case 0:
    1.38 +    {
    1.39 +        void         *hypercall_page;
    1.40 +        unsigned long mfn;
    1.41 +        unsigned long gmfn = ((unsigned long)edx << 20) | (eax >> 12);
    1.42 +        unsigned int  idx  = eax & 0xfff;
    1.43 +
    1.44 +        if ( idx > 0 )
    1.45 +        {
    1.46 +            DPRINTK("Dom%d: Out of range index %u to MSR %08x\n",
    1.47 +                    d->domain_id, idx, 0x40000000);
    1.48 +            return 0;
    1.49 +        }
    1.50 +
    1.51 +        mfn = gmfn_to_mfn(d, gmfn);
    1.52 +
    1.53 +        if ( !mfn_valid(mfn) ||
    1.54 +             !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
    1.55 +        {
    1.56 +            DPRINTK("Dom%d: Bad GMFN %lx (MFN %lx) to MSR %08x\n",
    1.57 +                    d->domain_id, gmfn, mfn, 0x40000000);
    1.58 +            return 0;
    1.59 +        }
    1.60 +
    1.61 +        hypercall_page = map_domain_page(mfn);
    1.62 +        hypercall_page_initialise(d, hypercall_page);
    1.63 +        unmap_domain_page(hypercall_page);
    1.64 +
    1.65 +        put_page_and_type(mfn_to_page(mfn));
    1.66 +        break;
    1.67 +    }
    1.68 +
    1.69 +    default:
    1.70 +        BUG();
    1.71 +    }
    1.72 +
    1.73 +    return 1;
    1.74 +}
    1.75 +
    1.76  int cpuid_hypervisor_leaves(
    1.77      uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
    1.78  {
    1.79 -    if ( (idx < 0x40000000) || (idx > 0x40000000) )
    1.80 +    idx -= 0x40000000;
    1.81 +    if ( idx > 2 )
    1.82          return 0;
    1.83  
    1.84 -    switch ( idx - 0x40000000 )
    1.85 +    switch ( idx )
    1.86      {
    1.87      case 0:
    1.88 -        *eax = 0x40000000;
    1.89 -        *ebx = 0x006e6558; /* "Xen\0" */
    1.90 -        *ecx = *edx = 0;
    1.91 +        *eax = 0x40000002; /* Largest leaf        */
    1.92 +        *ebx = 0x566e6558; /* Signature 1: "XenV" */
    1.93 +        *ecx = 0x65584d4d; /* Signature 2: "MMXe" */
    1.94 +        *edx = 0x4d4d566e; /* Signature 3: "nVMM" */
    1.95 +        break;
    1.96 +
    1.97 +    case 1:
    1.98 +        *eax = (xen_major_version() << 16) | xen_minor_version();
    1.99 +        *ebx = 0;          /* Reserved */
   1.100 +        *ecx = 0;          /* Reserved */
   1.101 +        *edx = 0;          /* Reserved */
   1.102 +        break;
   1.103 +
   1.104 +    case 2:
   1.105 +        *eax = 1;          /* Number of hypercall-transfer pages */
   1.106 +        *ebx = 0x40000000; /* MSR base address */
   1.107 +        *ecx = 0;          /* Features 1 */
   1.108 +        *edx = 0;          /* Features 2 */
   1.109          break;
   1.110  
   1.111      default:
   1.112 @@ -1297,6 +1375,9 @@ static int emulate_privileged_op(struct 
   1.113              break;
   1.114  #endif
   1.115          default:
   1.116 +            if ( wrmsr_hypervisor_regs(regs->ecx, regs->eax, regs->edx) )
   1.117 +                break;
   1.118 +
   1.119              if ( (rdmsr_safe(regs->ecx, l, h) != 0) ||
   1.120                   (regs->eax != l) || (regs->edx != h) )
   1.121                  DPRINTK("Domain attempted WRMSR %p from "
   1.122 @@ -1328,6 +1409,12 @@ static int emulate_privileged_op(struct 
   1.123                  goto fail;
   1.124              break;
   1.125          default:
   1.126 +            if ( rdmsr_hypervisor_regs(regs->ecx, &l, &h) )
   1.127 +            {
   1.128 +                regs->eax = l;
   1.129 +                regs->edx = h;
   1.130 +                break;
   1.131 +            }
   1.132              /* Everyone can read the MSR space. */
   1.133              /*DPRINTK("Domain attempted RDMSR %p.\n", _p(regs->ecx));*/
   1.134              if ( rdmsr_safe(regs->ecx, regs->eax, regs->edx) )