ia64/xen-unstable

changeset 17102:8338290757c5

x86 hvm: More emulation simplifications.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Feb 22 10:52:27 2008 +0000 (2008-02-22)
parents b21b434b3b1a
children 3d6e463d08a2 757cd7bb5e35
files xen/arch/x86/hvm/Makefile xen/arch/x86/hvm/emulate.c xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/intercept.c xen/arch/x86/hvm/io.c xen/arch/x86/hvm/platform.c xen/arch/x86/hvm/svm/emulate.c xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/vmx/realmode.c xen/include/asm-x86/hvm/io.h xen/include/asm-x86/hvm/vcpu.h
line diff
     1.1 --- a/xen/arch/x86/hvm/Makefile	Fri Feb 22 10:07:35 2008 +0000
     1.2 +++ b/xen/arch/x86/hvm/Makefile	Fri Feb 22 10:52:27 2008 +0000
     1.3 @@ -9,7 +9,6 @@ obj-y += io.o
     1.4  obj-y += iommu.o
     1.5  obj-y += irq.o
     1.6  obj-y += mtrr.o
     1.7 -obj-y += platform.o
     1.8  obj-y += pmtimer.o
     1.9  obj-y += rtc.o
    1.10  obj-y += hpet.o
     2.1 --- a/xen/arch/x86/hvm/emulate.c	Fri Feb 22 10:07:35 2008 +0000
     2.2 +++ b/xen/arch/x86/hvm/emulate.c	Fri Feb 22 10:52:27 2008 +0000
     2.3 @@ -3,7 +3,7 @@
     2.4   * 
     2.5   * HVM instruction emulation. Used for MMIO and VMX real mode.
     2.6   * 
     2.7 - * Copyright (c) 2008 Citrix Systems, Inc.
     2.8 + * Copyright (c) 2008, Citrix Systems, Inc.
     2.9   * 
    2.10   * Authors:
    2.11   *    Keir Fraser <keir.fraser@citrix.com>
    2.12 @@ -310,18 +310,9 @@ static int hvmemul_rep_ins(
    2.13      if ( curr->arch.hvm_vcpu.io_in_progress )
    2.14          return X86EMUL_UNHANDLEABLE;
    2.15  
    2.16 -    if ( !curr->arch.hvm_vcpu.io_completed )
    2.17 -    {
    2.18 -        curr->arch.hvm_vcpu.io_in_progress = 1;
    2.19 -        send_pio_req(src_port, *reps, bytes_per_rep,
    2.20 -                     gpa, IOREQ_READ,
    2.21 -                     !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1);
    2.22 -    }
    2.23 -
    2.24 -    if ( !curr->arch.hvm_vcpu.io_completed )
    2.25 -        return X86EMUL_RETRY;
    2.26 -
    2.27 -    curr->arch.hvm_vcpu.io_completed = 0;
    2.28 +    curr->arch.hvm_vcpu.io_in_progress = 1;
    2.29 +    send_pio_req(src_port, *reps, bytes_per_rep, gpa, IOREQ_READ,
    2.30 +                 !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1);
    2.31  
    2.32      return X86EMUL_OKAY;
    2.33  }
    2.34 @@ -408,18 +399,10 @@ static int hvmemul_rep_movs(
    2.35      (void)gfn_to_mfn_current(sgpa >> PAGE_SHIFT, &p2mt);
    2.36      if ( !p2m_is_ram(p2mt) )
    2.37      {
    2.38 -        if ( !curr->arch.hvm_vcpu.io_completed )
    2.39 -        {
    2.40 -            curr->arch.hvm_vcpu.io_in_progress = 1;
    2.41 -            send_mmio_req(IOREQ_TYPE_COPY, sgpa, *reps, bytes_per_rep,
    2.42 +        curr->arch.hvm_vcpu.io_in_progress = 1;
    2.43 +        send_mmio_req(IOREQ_TYPE_COPY, sgpa, *reps, bytes_per_rep,
    2.44                        dgpa, IOREQ_READ,
    2.45                        !!(ctxt->regs->eflags & X86_EFLAGS_DF), 1);
    2.46 -        }
    2.47 -
    2.48 -        if ( !curr->arch.hvm_vcpu.io_completed )
    2.49 -            return X86EMUL_RETRY;
    2.50 -
    2.51 -        curr->arch.hvm_vcpu.io_completed = 0;
    2.52      }
    2.53      else
    2.54      {
     3.1 --- a/xen/arch/x86/hvm/hvm.c	Fri Feb 22 10:07:35 2008 +0000
     3.2 +++ b/xen/arch/x86/hvm/hvm.c	Fri Feb 22 10:52:27 2008 +0000
     3.3 @@ -3,7 +3,8 @@
     3.4   *
     3.5   * Copyright (c) 2004, Intel Corporation.
     3.6   * Copyright (c) 2005, International Business Machines Corporation.
     3.7 - *
     3.8 + * Copyright (c) 2008, Citrix Systems, Inc.
     3.9 + * 
    3.10   * This program is free software; you can redistribute it and/or modify it
    3.11   * under the terms and conditions of the GNU General Public License,
    3.12   * version 2, as published by the Free Software Foundation.
    3.13 @@ -1517,6 +1518,38 @@ enum hvm_copy_result hvm_fetch_from_gues
    3.14      return __hvm_copy(buf, vaddr, size, 0, 1, hvm_nx_enabled(current));
    3.15  }
    3.16  
    3.17 +DEFINE_PER_CPU(int, guest_handles_in_xen_space);
    3.18 +
    3.19 +/* Note that copy_{to,from}_user_hvm require the PTE to be writable even
    3.20 +   when they're only trying to read from it.  The guest is expected to
    3.21 +   deal with this. */
    3.22 +unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len)
    3.23 +{
    3.24 +    int rc;
    3.25 +
    3.26 +    if ( this_cpu(guest_handles_in_xen_space) )
    3.27 +    {
    3.28 +        memcpy(to, from, len);
    3.29 +        return 0;
    3.30 +    }
    3.31 +
    3.32 +    rc = hvm_copy_to_guest_virt_nofault((unsigned long)to, (void *)from, len);
    3.33 +    return rc ? len : 0; /* fake a copy_to_user() return code */
    3.34 +}
    3.35 +
    3.36 +unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len)
    3.37 +{
    3.38 +    int rc;
    3.39 +
    3.40 +    if ( this_cpu(guest_handles_in_xen_space) )
    3.41 +    {
    3.42 +        memcpy(to, from, len);
    3.43 +        return 0;
    3.44 +    }
    3.45 +
    3.46 +    rc = hvm_copy_from_guest_virt_nofault(to, (unsigned long)from, len);
    3.47 +    return rc ? len : 0; /* fake a copy_from_user() return code */
    3.48 +}
    3.49  
    3.50  /* HVM specific printbuf. Mostly used for hvmloader chit-chat. */
    3.51  void hvm_print_line(struct vcpu *v, const char c)
     4.1 --- a/xen/arch/x86/hvm/intercept.c	Fri Feb 22 10:07:35 2008 +0000
     4.2 +++ b/xen/arch/x86/hvm/intercept.c	Fri Feb 22 10:52:27 2008 +0000
     4.3 @@ -2,6 +2,7 @@
     4.4   * intercept.c: Handle performance critical I/O packets in hypervisor space
     4.5   *
     4.6   * Copyright (c) 2004, Intel Corporation.
     4.7 + * Copyright (c) 2008, Citrix Systems, Inc.
     4.8   *
     4.9   * This program is free software; you can redistribute it and/or modify it
    4.10   * under the terms and conditions of the GNU General Public License,
    4.11 @@ -93,83 +94,6 @@ static inline void hvm_mmio_access(struc
    4.12      }
    4.13  }
    4.14  
    4.15 -int hvm_buffered_io_send(ioreq_t *p)
    4.16 -{
    4.17 -    struct vcpu *v = current;
    4.18 -    struct hvm_ioreq_page *iorp = &v->domain->arch.hvm_domain.buf_ioreq;
    4.19 -    buffered_iopage_t *pg = iorp->va;
    4.20 -    buf_ioreq_t bp;
    4.21 -    /* Timeoffset sends 64b data, but no address. Use two consecutive slots. */
    4.22 -    int qw = 0;
    4.23 -
    4.24 -    /* Ensure buffered_iopage fits in a page */
    4.25 -    BUILD_BUG_ON(sizeof(buffered_iopage_t) > PAGE_SIZE);
    4.26 -
    4.27 -    /*
    4.28 -     * Return 0 for the cases we can't deal with:
    4.29 -     *  - 'addr' is only a 20-bit field, so we cannot address beyond 1MB
    4.30 -     *  - we cannot buffer accesses to guest memory buffers, as the guest
    4.31 -     *    may expect the memory buffer to be synchronously accessed
    4.32 -     *  - the count field is usually used with data_is_ptr and since we don't
    4.33 -     *    support data_is_ptr we do not waste space for the count field either
    4.34 -     */
    4.35 -    if ( (p->addr > 0xffffful) || p->data_is_ptr || (p->count != 1) )
    4.36 -        return 0;
    4.37 -
    4.38 -    bp.type = p->type;
    4.39 -    bp.dir  = p->dir;
    4.40 -    switch ( p->size )
    4.41 -    {
    4.42 -    case 1:
    4.43 -        bp.size = 0;
    4.44 -        break;
    4.45 -    case 2:
    4.46 -        bp.size = 1;
    4.47 -        break;
    4.48 -    case 4:
    4.49 -        bp.size = 2;
    4.50 -        break;
    4.51 -    case 8:
    4.52 -        bp.size = 3;
    4.53 -        qw = 1;
    4.54 -        break;
    4.55 -    default:
    4.56 -        gdprintk(XENLOG_WARNING, "unexpected ioreq size:%"PRId64"\n", p->size);
    4.57 -        return 0;
    4.58 -    }
    4.59 -    
    4.60 -    bp.data = p->data;
    4.61 -    bp.addr = p->addr;
    4.62 -    
    4.63 -    spin_lock(&iorp->lock);
    4.64 -
    4.65 -    if ( (pg->write_pointer - pg->read_pointer) >=
    4.66 -         (IOREQ_BUFFER_SLOT_NUM - qw) )
    4.67 -    {
    4.68 -        /* The queue is full: send the iopacket through the normal path. */
    4.69 -        spin_unlock(&iorp->lock);
    4.70 -        return 0;
    4.71 -    }
    4.72 -    
    4.73 -    memcpy(&pg->buf_ioreq[pg->write_pointer % IOREQ_BUFFER_SLOT_NUM],
    4.74 -           &bp, sizeof(bp));
    4.75 -    
    4.76 -    if ( qw )
    4.77 -    {
    4.78 -        bp.data = p->data >> 32;
    4.79 -        memcpy(&pg->buf_ioreq[(pg->write_pointer+1) % IOREQ_BUFFER_SLOT_NUM],
    4.80 -               &bp, sizeof(bp));
    4.81 -    }
    4.82 -
    4.83 -    /* Make the ioreq_t visible /before/ write_pointer. */
    4.84 -    wmb();
    4.85 -    pg->write_pointer += qw ? 2 : 1;
    4.86 -
    4.87 -    spin_unlock(&iorp->lock);
    4.88 -    
    4.89 -    return 1;
    4.90 -}
    4.91 -
    4.92  int hvm_mmio_intercept(ioreq_t *p)
    4.93  {
    4.94      struct vcpu *v = current;
     5.1 --- a/xen/arch/x86/hvm/io.c	Fri Feb 22 10:07:35 2008 +0000
     5.2 +++ b/xen/arch/x86/hvm/io.c	Fri Feb 22 10:52:27 2008 +0000
     5.3 @@ -3,6 +3,7 @@
     5.4   *
     5.5   * Copyright (c) 2004, Intel Corporation.
     5.6   * Copyright (c) 2005, International Business Machines Corporation.
     5.7 + * Copyright (c) 2008, Citrix Systems, Inc.
     5.8   *
     5.9   * This program is free software; you can redistribute it and/or modify it
    5.10   * under the terms and conditions of the GNU General Public License,
    5.11 @@ -25,7 +26,6 @@
    5.12  #include <xen/errno.h>
    5.13  #include <xen/trace.h>
    5.14  #include <xen/event.h>
    5.15 -
    5.16  #include <xen/hypercall.h>
    5.17  #include <asm/current.h>
    5.18  #include <asm/cpufeature.h>
    5.19 @@ -41,79 +41,246 @@
    5.20  #include <asm/hvm/vpic.h>
    5.21  #include <asm/hvm/vlapic.h>
    5.22  #include <asm/hvm/trace.h>
    5.23 -
    5.24 +#include <asm/hvm/emulate.h>
    5.25  #include <public/sched.h>
    5.26  #include <xen/iocap.h>
    5.27  #include <public/hvm/ioreq.h>
    5.28  
    5.29 -static void hvm_pio_assist(
    5.30 -    struct cpu_user_regs *regs, ioreq_t *p, struct hvm_io_op *pio_opp)
    5.31 +int hvm_buffered_io_send(ioreq_t *p)
    5.32  {
    5.33 -    if ( p->data_is_ptr || (pio_opp->flags & OVERLAP) )
    5.34 -    {
    5.35 -        int sign = p->df ? -1 : 1;
    5.36 -
    5.37 -        if ( pio_opp->flags & REPZ )
    5.38 -            regs->ecx -= p->count;
    5.39 +    struct vcpu *v = current;
    5.40 +    struct hvm_ioreq_page *iorp = &v->domain->arch.hvm_domain.buf_ioreq;
    5.41 +    buffered_iopage_t *pg = iorp->va;
    5.42 +    buf_ioreq_t bp;
    5.43 +    /* Timeoffset sends 64b data, but no address. Use two consecutive slots. */
    5.44 +    int qw = 0;
    5.45  
    5.46 -        if ( p->dir == IOREQ_READ )
    5.47 -        {
    5.48 -            if ( pio_opp->flags & OVERLAP )
    5.49 -            {
    5.50 -                unsigned long addr = pio_opp->addr;
    5.51 -                if ( hvm_paging_enabled(current) )
    5.52 -                {
    5.53 -                    int rv = hvm_copy_to_guest_virt(addr, &p->data, p->size);
    5.54 -                    if ( rv == HVMCOPY_bad_gva_to_gfn )
    5.55 -                        return; /* exception already injected */
    5.56 -                }
    5.57 -                else
    5.58 -                    (void)hvm_copy_to_guest_phys(addr, &p->data, p->size);
    5.59 -            }
    5.60 -            regs->edi += sign * p->count * p->size;
    5.61 -        }
    5.62 -        else /* p->dir == IOREQ_WRITE */
    5.63 -        {
    5.64 -            ASSERT(p->dir == IOREQ_WRITE);
    5.65 -            regs->esi += sign * p->count * p->size;
    5.66 -        }
    5.67 +    /* Ensure buffered_iopage fits in a page */
    5.68 +    BUILD_BUG_ON(sizeof(buffered_iopage_t) > PAGE_SIZE);
    5.69 +
    5.70 +    /*
    5.71 +     * Return 0 for the cases we can't deal with:
    5.72 +     *  - 'addr' is only a 20-bit field, so we cannot address beyond 1MB
    5.73 +     *  - we cannot buffer accesses to guest memory buffers, as the guest
    5.74 +     *    may expect the memory buffer to be synchronously accessed
    5.75 +     *  - the count field is usually used with data_is_ptr and since we don't
    5.76 +     *    support data_is_ptr we do not waste space for the count field either
    5.77 +     */
    5.78 +    if ( (p->addr > 0xffffful) || p->data_is_ptr || (p->count != 1) )
    5.79 +        return 0;
    5.80 +
    5.81 +    bp.type = p->type;
    5.82 +    bp.dir  = p->dir;
    5.83 +    switch ( p->size )
    5.84 +    {
    5.85 +    case 1:
    5.86 +        bp.size = 0;
    5.87 +        break;
    5.88 +    case 2:
    5.89 +        bp.size = 1;
    5.90 +        break;
    5.91 +    case 4:
    5.92 +        bp.size = 2;
    5.93 +        break;
    5.94 +    case 8:
    5.95 +        bp.size = 3;
    5.96 +        qw = 1;
    5.97 +        break;
    5.98 +    default:
    5.99 +        gdprintk(XENLOG_WARNING, "unexpected ioreq size:%"PRId64"\n", p->size);
   5.100 +        return 0;
   5.101      }
   5.102 -    else if ( p->dir == IOREQ_READ )
   5.103 -    {
   5.104 -        unsigned long old_eax = regs->eax;
   5.105 +    
   5.106 +    bp.data = p->data;
   5.107 +    bp.addr = p->addr;
   5.108 +    
   5.109 +    spin_lock(&iorp->lock);
   5.110  
   5.111 -        switch ( p->size )
   5.112 -        {
   5.113 -        case 1:
   5.114 -            regs->eax = (old_eax & ~0xff) | (p->data & 0xff);
   5.115 -            break;
   5.116 -        case 2:
   5.117 -            regs->eax = (old_eax & ~0xffff) | (p->data & 0xffff);
   5.118 -            break;
   5.119 -        case 4:
   5.120 -            regs->eax = (p->data & 0xffffffff);
   5.121 -            break;
   5.122 -        default:
   5.123 -            printk("Error: %s unknown port size\n", __FUNCTION__);
   5.124 -            domain_crash_synchronous();
   5.125 -        }
   5.126 -        HVMTRACE_1D(IO_ASSIST, current, p->data);
   5.127 +    if ( (pg->write_pointer - pg->read_pointer) >=
   5.128 +         (IOREQ_BUFFER_SLOT_NUM - qw) )
   5.129 +    {
   5.130 +        /* The queue is full: send the iopacket through the normal path. */
   5.131 +        spin_unlock(&iorp->lock);
   5.132 +        return 0;
   5.133      }
   5.134 +    
   5.135 +    memcpy(&pg->buf_ioreq[pg->write_pointer % IOREQ_BUFFER_SLOT_NUM],
   5.136 +           &bp, sizeof(bp));
   5.137 +    
   5.138 +    if ( qw )
   5.139 +    {
   5.140 +        bp.data = p->data >> 32;
   5.141 +        memcpy(&pg->buf_ioreq[(pg->write_pointer+1) % IOREQ_BUFFER_SLOT_NUM],
   5.142 +               &bp, sizeof(bp));
   5.143 +    }
   5.144 +
   5.145 +    /* Make the ioreq_t visible /before/ write_pointer. */
   5.146 +    wmb();
   5.147 +    pg->write_pointer += qw ? 2 : 1;
   5.148 +
   5.149 +    spin_unlock(&iorp->lock);
   5.150 +    
   5.151 +    return 1;
   5.152 +}
   5.153 +
   5.154 +void send_pio_req(unsigned long port, unsigned long count, int size,
   5.155 +                  paddr_t value, int dir, int df, int value_is_ptr)
   5.156 +{
   5.157 +    struct vcpu *v = current;
   5.158 +    vcpu_iodata_t *vio = get_ioreq(v);
   5.159 +    ioreq_t *p = &vio->vp_ioreq;
   5.160 +
   5.161 +    if ( p->state != STATE_IOREQ_NONE )
   5.162 +        gdprintk(XENLOG_WARNING,
   5.163 +                 "WARNING: send pio with something already pending (%d)?\n",
   5.164 +                 p->state);
   5.165 +
   5.166 +    p->dir = dir;
   5.167 +    p->data_is_ptr = value_is_ptr;
   5.168 +    p->type = IOREQ_TYPE_PIO;
   5.169 +    p->size = size;
   5.170 +    p->addr = port;
   5.171 +    p->count = count;
   5.172 +    p->df = df;
   5.173 +    p->data = value;
   5.174 +    p->io_count++;
   5.175 +
   5.176 +    if ( hvm_portio_intercept(p) )
   5.177 +    {
   5.178 +        p->state = STATE_IORESP_READY;
   5.179 +        hvm_io_assist();
   5.180 +    }
   5.181 +    else
   5.182 +    {
   5.183 +        hvm_send_assist_req(v);
   5.184 +    }
   5.185 +}
   5.186 +
   5.187 +void send_mmio_req(unsigned char type, paddr_t gpa,
   5.188 +                   unsigned long count, int size, paddr_t value,
   5.189 +                   int dir, int df, int value_is_ptr)
   5.190 +{
   5.191 +    struct vcpu *v = current;
   5.192 +    vcpu_iodata_t *vio = get_ioreq(v);
   5.193 +    ioreq_t *p = &vio->vp_ioreq;
   5.194 +
   5.195 +    if ( p->state != STATE_IOREQ_NONE )
   5.196 +        gdprintk(XENLOG_WARNING,
   5.197 +                 "WARNING: send mmio with something already pending (%d)?\n",
   5.198 +                 p->state);
   5.199 +
   5.200 +    p->dir = dir;
   5.201 +    p->data_is_ptr = value_is_ptr;
   5.202 +    p->type = type;
   5.203 +    p->size = size;
   5.204 +    p->addr = gpa;
   5.205 +    p->count = count;
   5.206 +    p->df = df;
   5.207 +    p->data = value;
   5.208 +    p->io_count++;
   5.209 +
   5.210 +    if ( hvm_mmio_intercept(p) || hvm_buffered_io_intercept(p) )
   5.211 +    {
   5.212 +        p->state = STATE_IORESP_READY;
   5.213 +        hvm_io_assist();
   5.214 +    }
   5.215 +    else
   5.216 +    {
   5.217 +        hvm_send_assist_req(v);
   5.218 +    }
   5.219 +}
   5.220 +
   5.221 +void send_timeoffset_req(unsigned long timeoff)
   5.222 +{
   5.223 +    ioreq_t p[1];
   5.224 +
   5.225 +    if ( timeoff == 0 )
   5.226 +        return;
   5.227 +
   5.228 +    memset(p, 0, sizeof(*p));
   5.229 +
   5.230 +    p->type = IOREQ_TYPE_TIMEOFFSET;
   5.231 +    p->size = 8;
   5.232 +    p->count = 1;
   5.233 +    p->dir = IOREQ_WRITE;
   5.234 +    p->data = timeoff;
   5.235 +
   5.236 +    p->state = STATE_IOREQ_READY;
   5.237 +
   5.238 +    if ( !hvm_buffered_io_send(p) )
   5.239 +        printk("Unsuccessful timeoffset update\n");
   5.240 +}
   5.241 +
   5.242 +/* Ask ioemu mapcache to invalidate mappings. */
   5.243 +void send_invalidate_req(void)
   5.244 +{
   5.245 +    struct vcpu *v = current;
   5.246 +    vcpu_iodata_t *vio;
   5.247 +    ioreq_t *p;
   5.248 +
   5.249 +    vio = get_ioreq(v);
   5.250 +    if ( vio == NULL )
   5.251 +    {
   5.252 +        printk("bad shared page: %lx\n", (unsigned long) vio);
   5.253 +        domain_crash_synchronous();
   5.254 +    }
   5.255 +
   5.256 +    p = &vio->vp_ioreq;
   5.257 +    if ( p->state != STATE_IOREQ_NONE )
   5.258 +        printk("WARNING: send invalidate req with something "
   5.259 +               "already pending (%d)?\n", p->state);
   5.260 +
   5.261 +    p->type = IOREQ_TYPE_INVALIDATE;
   5.262 +    p->size = 4;
   5.263 +    p->dir = IOREQ_WRITE;
   5.264 +    p->data = ~0UL; /* flush all */
   5.265 +    p->io_count++;
   5.266 +
   5.267 +    hvm_send_assist_req(v);
   5.268 +}
   5.269 +
   5.270 +int handle_mmio(void)
   5.271 +{
   5.272 +    struct hvm_emulate_ctxt ctxt;
   5.273 +    struct vcpu *curr = current;
   5.274 +    int rc;
   5.275 +
   5.276 +    hvm_emulate_prepare(&ctxt, guest_cpu_user_regs());
   5.277 +
   5.278 +    rc = hvm_emulate_one(&ctxt);
   5.279 +
   5.280 +    switch ( rc )
   5.281 +    {
   5.282 +    case X86EMUL_UNHANDLEABLE:
   5.283 +        gdprintk(XENLOG_WARNING,
   5.284 +                 "MMIO emulation failed @ %04x:%lx: "
   5.285 +                 "%02x %02x %02x %02x %02x %02x\n",
   5.286 +                 hvmemul_get_seg_reg(x86_seg_cs, &ctxt)->sel,
   5.287 +                 ctxt.insn_buf_eip,
   5.288 +                 ctxt.insn_buf[0], ctxt.insn_buf[1],
   5.289 +                 ctxt.insn_buf[2], ctxt.insn_buf[3],
   5.290 +                 ctxt.insn_buf[4], ctxt.insn_buf[5]);
   5.291 +        return 0;
   5.292 +    case X86EMUL_EXCEPTION:
   5.293 +        if ( ctxt.flags.exn_pending )
   5.294 +            hvm_inject_exception(ctxt.exn_vector, 0, 0);
   5.295 +        break;
   5.296 +    default:
   5.297 +        break;
   5.298 +    }
   5.299 +
   5.300 +    hvm_emulate_writeback(&ctxt);
   5.301 +
   5.302 +    curr->arch.hvm_vcpu.mmio_in_progress = curr->arch.hvm_vcpu.io_in_progress;
   5.303 +
   5.304 +    return 1;
   5.305  }
   5.306  
   5.307  void hvm_io_assist(void)
   5.308  {
   5.309 -    vcpu_iodata_t *vio;
   5.310 -    ioreq_t *p;
   5.311 -    struct cpu_user_regs *regs;
   5.312 -    struct hvm_io_op *io_opp;
   5.313      struct vcpu *v = current;
   5.314 +    ioreq_t *p = &get_ioreq(v)->vp_ioreq;
   5.315  
   5.316 -    io_opp = &v->arch.hvm_vcpu.io_op;
   5.317 -    regs   = &io_opp->io_context;
   5.318 -    vio    = get_ioreq(v);
   5.319 -
   5.320 -    p = &vio->vp_ioreq;
   5.321      if ( p->state != STATE_IORESP_READY )
   5.322      {
   5.323          gdprintk(XENLOG_ERR, "Unexpected HVM iorequest state %d.\n", p->state);
   5.324 @@ -128,35 +295,15 @@ void hvm_io_assist(void)
   5.325      if ( v->arch.hvm_vcpu.io_in_progress )
   5.326      {
   5.327          v->arch.hvm_vcpu.io_in_progress = 0;
   5.328 -        if ( p->dir == IOREQ_READ )
   5.329 +        if ( (p->dir == IOREQ_READ) && !p->data_is_ptr )
   5.330          {
   5.331              v->arch.hvm_vcpu.io_completed = 1;
   5.332              v->arch.hvm_vcpu.io_data = p->data;
   5.333 +            if ( v->arch.hvm_vcpu.mmio_in_progress )
   5.334 +                (void)handle_mmio();
   5.335          }
   5.336 -        if ( v->arch.hvm_vcpu.mmio_in_progress )
   5.337 -            (void)handle_mmio();
   5.338 -        goto out;
   5.339      }
   5.340  
   5.341 -    switch ( p->type )
   5.342 -    {
   5.343 -    case IOREQ_TYPE_INVALIDATE:
   5.344 -        goto out;
   5.345 -    case IOREQ_TYPE_PIO:
   5.346 -        hvm_pio_assist(regs, p, io_opp);
   5.347 -        break;
   5.348 -    default:
   5.349 -        gdprintk(XENLOG_ERR, "Unexpected HVM iorequest state %d.\n", p->state);
   5.350 -        domain_crash(v->domain);
   5.351 -        goto out;
   5.352 -    }
   5.353 -
   5.354 -    /* Copy register changes back into current guest state. */
   5.355 -    regs->eflags &= ~X86_EFLAGS_RF;
   5.356 -    memcpy(guest_cpu_user_regs(), regs, HVM_CONTEXT_STACK_BYTES);
   5.357 -    if ( regs->eflags & X86_EFLAGS_TF )
   5.358 -        hvm_inject_exception(TRAP_debug, HVM_DELIVER_NO_ERROR_CODE, 0);
   5.359 -
   5.360   out:
   5.361      vcpu_end_shutdown_deferral(v);
   5.362  }
   5.363 @@ -173,13 +320,13 @@ void dpci_ioport_read(uint32_t mport, io
   5.364          
   5.365          switch ( p->size )
   5.366          {
   5.367 -        case BYTE:
   5.368 +        case 1:
   5.369              z_data = (uint64_t)inb(mport);
   5.370              break;
   5.371 -        case WORD:
   5.372 +        case 2:
   5.373              z_data = (uint64_t)inw(mport);
   5.374              break;
   5.375 -        case LONG:
   5.376 +        case 4:
   5.377              z_data = (uint64_t)inl(mport);
   5.378              break;
   5.379          default:
   5.380 @@ -218,13 +365,13 @@ void dpci_ioport_write(uint32_t mport, i
   5.381  
   5.382          switch ( p->size )
   5.383          {
   5.384 -        case BYTE:
   5.385 +        case 1:
   5.386              outb((uint8_t) z_data, mport);
   5.387              break;
   5.388 -        case WORD:
   5.389 +        case 2:
   5.390              outw((uint16_t) z_data, mport);
   5.391              break;
   5.392 -        case LONG:
   5.393 +        case 4:
   5.394              outl((uint32_t) z_data, mport);
   5.395              break;
   5.396          default:
     6.1 --- a/xen/arch/x86/hvm/platform.c	Fri Feb 22 10:07:35 2008 +0000
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,273 +0,0 @@
     6.4 -/*
     6.5 - * platform.c: handling x86 platform related MMIO instructions
     6.6 - *
     6.7 - * Copyright (c) 2004, Intel Corporation.
     6.8 - * Copyright (c) 2005, International Business Machines Corporation.
     6.9 - *
    6.10 - * This program is free software; you can redistribute it and/or modify it
    6.11 - * under the terms and conditions of the GNU General Public License,
    6.12 - * version 2, as published by the Free Software Foundation.
    6.13 - *
    6.14 - * This program is distributed in the hope it will be useful, but WITHOUT
    6.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    6.16 - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
    6.17 - * more details.
    6.18 - *
    6.19 - * You should have received a copy of the GNU General Public License along with
    6.20 - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
    6.21 - * Place - Suite 330, Boston, MA 02111-1307 USA.
    6.22 - */
    6.23 -
    6.24 -#include <xen/config.h>
    6.25 -#include <xen/types.h>
    6.26 -#include <xen/mm.h>
    6.27 -#include <xen/domain_page.h>
    6.28 -#include <asm/page.h>
    6.29 -#include <xen/event.h>
    6.30 -#include <xen/trace.h>
    6.31 -#include <xen/sched.h>
    6.32 -#include <asm/regs.h>
    6.33 -#include <asm/x86_emulate.h>
    6.34 -#include <asm/paging.h>
    6.35 -#include <asm/hvm/hvm.h>
    6.36 -#include <asm/hvm/support.h>
    6.37 -#include <asm/hvm/io.h>
    6.38 -#include <public/hvm/ioreq.h>
    6.39 -#include <xen/lib.h>
    6.40 -#include <xen/sched.h>
    6.41 -#include <asm/hvm/emulate.h>
    6.42 -
    6.43 -int inst_copy_from_guest(
    6.44 -    unsigned char *buf, unsigned long guest_eip, int inst_len)
    6.45 -{
    6.46 -    if ( inst_len > MAX_INST_LEN || inst_len <= 0 )
    6.47 -        return 0;
    6.48 -    if ( hvm_fetch_from_guest_virt_nofault(buf, guest_eip, inst_len) )
    6.49 -        return 0;
    6.50 -    return inst_len;
    6.51 -}
    6.52 -
    6.53 -void send_pio_req(unsigned long port, unsigned long count, int size,
    6.54 -                  paddr_t value, int dir, int df, int value_is_ptr)
    6.55 -{
    6.56 -    struct vcpu *v = current;
    6.57 -    vcpu_iodata_t *vio;
    6.58 -    ioreq_t *p;
    6.59 -
    6.60 -    if ( size == 0 || count == 0 ) {
    6.61 -        printk("null pio request? port %lx, count %lx, "
    6.62 -               "size %d, value %"PRIpaddr", dir %d, value_is_ptr %d.\n",
    6.63 -               port, count, size, value, dir, value_is_ptr);
    6.64 -    }
    6.65 -
    6.66 -    vio = get_ioreq(v);
    6.67 -    if ( vio == NULL ) {
    6.68 -        printk("bad shared page: %lx\n", (unsigned long) vio);
    6.69 -        domain_crash_synchronous();
    6.70 -    }
    6.71 -
    6.72 -    p = &vio->vp_ioreq;
    6.73 -    if ( p->state != STATE_IOREQ_NONE )
    6.74 -        printk("WARNING: send pio with something already pending (%d)?\n",
    6.75 -               p->state);
    6.76 -
    6.77 -    p->dir = dir;
    6.78 -    p->data_is_ptr = value_is_ptr;
    6.79 -
    6.80 -    p->type = IOREQ_TYPE_PIO;
    6.81 -    p->size = size;
    6.82 -    p->addr = port;
    6.83 -    p->count = count;
    6.84 -    p->df = df;
    6.85 -
    6.86 -    p->io_count++;
    6.87 -
    6.88 -    p->data = value;
    6.89 -
    6.90 -    if ( hvm_portio_intercept(p) )
    6.91 -    {
    6.92 -        p->state = STATE_IORESP_READY;
    6.93 -        hvm_io_assist();
    6.94 -        return;
    6.95 -    }
    6.96 -
    6.97 -    hvm_send_assist_req(v);
    6.98 -}
    6.99 -
   6.100 -void send_mmio_req(unsigned char type, paddr_t gpa,
   6.101 -                   unsigned long count, int size, paddr_t value,
   6.102 -                   int dir, int df, int value_is_ptr)
   6.103 -{
   6.104 -    struct vcpu *v = current;
   6.105 -    vcpu_iodata_t *vio;
   6.106 -    ioreq_t *p;
   6.107 -
   6.108 -    if ( size == 0 || count == 0 ) {
   6.109 -        printk("null mmio request? type %d, gpa %"PRIpaddr", "
   6.110 -               "count %lx, size %d, value %"PRIpaddr", dir %d, "
   6.111 -               "value_is_ptr %d.\n",
   6.112 -               type, gpa, count, size, value, dir, value_is_ptr);
   6.113 -    }
   6.114 -
   6.115 -    vio = get_ioreq(v);
   6.116 -    if (vio == NULL) {
   6.117 -        printk("bad shared page\n");
   6.118 -        domain_crash_synchronous();
   6.119 -    }
   6.120 -
   6.121 -    p = &vio->vp_ioreq;
   6.122 -
   6.123 -    if ( p->state != STATE_IOREQ_NONE )
   6.124 -        printk("WARNING: send mmio with something already pending (%d)?\n",
   6.125 -               p->state);
   6.126 -    p->dir = dir;
   6.127 -    p->data_is_ptr = value_is_ptr;
   6.128 -
   6.129 -    p->type = type;
   6.130 -    p->size = size;
   6.131 -    p->addr = gpa;
   6.132 -    p->count = count;
   6.133 -    p->df = df;
   6.134 -
   6.135 -    p->io_count++;
   6.136 -
   6.137 -    p->data = value;
   6.138 -
   6.139 -    if ( hvm_mmio_intercept(p) || hvm_buffered_io_intercept(p) )
   6.140 -    {
   6.141 -        p->state = STATE_IORESP_READY;
   6.142 -        hvm_io_assist();
   6.143 -        return;
   6.144 -    }
   6.145 -
   6.146 -    hvm_send_assist_req(v);
   6.147 -}
   6.148 -
   6.149 -void send_timeoffset_req(unsigned long timeoff)
   6.150 -{
   6.151 -    ioreq_t p[1];
   6.152 -
   6.153 -    if ( timeoff == 0 )
   6.154 -        return;
   6.155 -
   6.156 -    memset(p, 0, sizeof(*p));
   6.157 -
   6.158 -    p->type = IOREQ_TYPE_TIMEOFFSET;
   6.159 -    p->size = 8;
   6.160 -    p->count = 1;
   6.161 -    p->dir = IOREQ_WRITE;
   6.162 -    p->data = timeoff;
   6.163 -
   6.164 -    p->state = STATE_IOREQ_READY;
   6.165 -
   6.166 -    if ( !hvm_buffered_io_send(p) )
   6.167 -        printk("Unsuccessful timeoffset update\n");
   6.168 -}
   6.169 -
   6.170 -/* Ask ioemu mapcache to invalidate mappings. */
   6.171 -void send_invalidate_req(void)
   6.172 -{
   6.173 -    struct vcpu *v = current;
   6.174 -    vcpu_iodata_t *vio;
   6.175 -    ioreq_t *p;
   6.176 -
   6.177 -    vio = get_ioreq(v);
   6.178 -    if ( vio == NULL )
   6.179 -    {
   6.180 -        printk("bad shared page: %lx\n", (unsigned long) vio);
   6.181 -        domain_crash_synchronous();
   6.182 -    }
   6.183 -
   6.184 -    p = &vio->vp_ioreq;
   6.185 -    if ( p->state != STATE_IOREQ_NONE )
   6.186 -        printk("WARNING: send invalidate req with something "
   6.187 -               "already pending (%d)?\n", p->state);
   6.188 -
   6.189 -    p->type = IOREQ_TYPE_INVALIDATE;
   6.190 -    p->size = 4;
   6.191 -    p->dir = IOREQ_WRITE;
   6.192 -    p->data = ~0UL; /* flush all */
   6.193 -    p->io_count++;
   6.194 -
   6.195 -    hvm_send_assist_req(v);
   6.196 -}
   6.197 -
   6.198 -int handle_mmio(void)
   6.199 -{
   6.200 -    struct hvm_emulate_ctxt ctxt;
   6.201 -    struct vcpu *curr = current;
   6.202 -    int rc;
   6.203 -
   6.204 -    hvm_emulate_prepare(&ctxt, guest_cpu_user_regs());
   6.205 -
   6.206 -    rc = hvm_emulate_one(&ctxt);
   6.207 -
   6.208 -    switch ( rc )
   6.209 -    {
   6.210 -    case X86EMUL_UNHANDLEABLE:
   6.211 -        gdprintk(XENLOG_WARNING,
   6.212 -                 "MMIO emulation failed @ %04x:%lx: "
   6.213 -                 "%02x %02x %02x %02x %02x %02x\n",
   6.214 -                 hvmemul_get_seg_reg(x86_seg_cs, &ctxt)->sel,
   6.215 -                 ctxt.insn_buf_eip,
   6.216 -                 ctxt.insn_buf[0], ctxt.insn_buf[1],
   6.217 -                 ctxt.insn_buf[2], ctxt.insn_buf[3],
   6.218 -                 ctxt.insn_buf[4], ctxt.insn_buf[5]);
   6.219 -        return 0;
   6.220 -    case X86EMUL_EXCEPTION:
   6.221 -        if ( ctxt.flags.exn_pending )
   6.222 -            hvm_inject_exception(ctxt.exn_vector, 0, 0);
   6.223 -        break;
   6.224 -    default:
   6.225 -        break;
   6.226 -    }
   6.227 -
   6.228 -    hvm_emulate_writeback(&ctxt);
   6.229 -
   6.230 -    curr->arch.hvm_vcpu.mmio_in_progress = curr->arch.hvm_vcpu.io_in_progress;
   6.231 -
   6.232 -    return 1;
   6.233 -}
   6.234 -
   6.235 -DEFINE_PER_CPU(int, guest_handles_in_xen_space);
   6.236 -
   6.237 -/* Note that copy_{to,from}_user_hvm require the PTE to be writable even
   6.238 -   when they're only trying to read from it.  The guest is expected to
   6.239 -   deal with this. */
   6.240 -unsigned long copy_to_user_hvm(void *to, const void *from, unsigned len)
   6.241 -{
   6.242 -    int rc;
   6.243 -
   6.244 -    if ( this_cpu(guest_handles_in_xen_space) )
   6.245 -    {
   6.246 -        memcpy(to, from, len);
   6.247 -        return 0;
   6.248 -    }
   6.249 -
   6.250 -    rc = hvm_copy_to_guest_virt_nofault((unsigned long)to, (void *)from, len);
   6.251 -    return rc ? len : 0; /* fake a copy_to_user() return code */
   6.252 -}
   6.253 -
   6.254 -unsigned long copy_from_user_hvm(void *to, const void *from, unsigned len)
   6.255 -{
   6.256 -    int rc;
   6.257 -
   6.258 -    if ( this_cpu(guest_handles_in_xen_space) )
   6.259 -    {
   6.260 -        memcpy(to, from, len);
   6.261 -        return 0;
   6.262 -    }
   6.263 -
   6.264 -    rc = hvm_copy_from_guest_virt_nofault(to, (unsigned long)from, len);
   6.265 -    return rc ? len : 0; /* fake a copy_from_user() return code */
   6.266 -}
   6.267 -
   6.268 -/*
   6.269 - * Local variables:
   6.270 - * mode: C
   6.271 - * c-set-style: "BSD"
   6.272 - * c-basic-offset: 4
   6.273 - * tab-width: 4
   6.274 - * indent-tabs-mode: nil
   6.275 - * End:
   6.276 - */
     7.1 --- a/xen/arch/x86/hvm/svm/emulate.c	Fri Feb 22 10:07:35 2008 +0000
     7.2 +++ b/xen/arch/x86/hvm/svm/emulate.c	Fri Feb 22 10:52:27 2008 +0000
     7.3 @@ -27,8 +27,17 @@
     7.4  #include <asm/hvm/svm/vmcb.h>
     7.5  #include <asm/hvm/svm/emulate.h>
     7.6  
     7.7 -int inst_copy_from_guest(
     7.8 -    unsigned char *buf, unsigned long guest_eip, int inst_len);
     7.9 +#define MAX_INST_LEN 15
    7.10 +
    7.11 +static int inst_copy_from_guest(
    7.12 +    unsigned char *buf, unsigned long guest_eip, int inst_len)
    7.13 +{
    7.14 +    if ( (inst_len > MAX_INST_LEN) || (inst_len <= 0) )
    7.15 +        return 0;
    7.16 +    if ( hvm_fetch_from_guest_virt_nofault(buf, guest_eip, inst_len) )
    7.17 +        return 0;
    7.18 +    return inst_len;
    7.19 +}
    7.20  
    7.21  static unsigned int is_prefix(u8 opc)
    7.22  {
     8.1 --- a/xen/arch/x86/hvm/svm/svm.c	Fri Feb 22 10:07:35 2008 +0000
     8.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Fri Feb 22 10:52:27 2008 +0000
     8.3 @@ -58,8 +58,6 @@ u32 svm_feature_flags;
     8.4  
     8.5  enum handler_return { HNDL_done, HNDL_unhandled, HNDL_exception_raised };
     8.6  
     8.7 -int inst_copy_from_guest(unsigned char *buf, unsigned long guest_eip,
     8.8 -                         int inst_len);
     8.9  asmlinkage void do_IRQ(struct cpu_user_regs *);
    8.10  
    8.11  static void svm_update_guest_cr(struct vcpu *v, unsigned int cr);
     9.1 --- a/xen/arch/x86/hvm/vmx/realmode.c	Fri Feb 22 10:07:35 2008 +0000
     9.2 +++ b/xen/arch/x86/hvm/vmx/realmode.c	Fri Feb 22 10:52:27 2008 +0000
     9.3 @@ -221,8 +221,7 @@ void vmx_realmode(struct cpu_user_regs *
     9.4      hvm_emulate_prepare(&rm_ctxt.hvm, regs);
     9.5      rm_ctxt.intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
     9.6  
     9.7 -    if ( curr->arch.hvm_vcpu.io_in_progress ||
     9.8 -         curr->arch.hvm_vcpu.io_completed )
     9.9 +    if ( curr->arch.hvm_vcpu.io_completed )
    9.10          realmode_emulate_one(&rm_ctxt);
    9.11  
    9.12      /* Only deliver interrupts into emulated real mode. */
    10.1 --- a/xen/include/asm-x86/hvm/io.h	Fri Feb 22 10:07:35 2008 +0000
    10.2 +++ b/xen/include/asm-x86/hvm/io.h	Fri Feb 22 10:52:27 2008 +0000
    10.3 @@ -25,61 +25,6 @@
    10.4  #include <public/hvm/ioreq.h>
    10.5  #include <public/event_channel.h>
    10.6  
    10.7 -#define operand_size(operand)   \
    10.8 -    ((operand >> 24) & 0xFF)
    10.9 -
   10.10 -#define operand_index(operand)  \
   10.11 -    ((operand >> 16) & 0xFF)
   10.12 -
   10.13 -/* for instruction.operand[].size */
   10.14 -#define BYTE       1
   10.15 -#define WORD       2
   10.16 -#define LONG       4
   10.17 -#define QUAD       8
   10.18 -#define BYTE_64    16
   10.19 -
   10.20 -/* for instruction.operand[].flag */
   10.21 -#define REGISTER   0x1
   10.22 -#define MEMORY     0x2
   10.23 -#define IMMEDIATE  0x4
   10.24 -
   10.25 -/* for instruction.flags */
   10.26 -#define REPZ       0x1
   10.27 -#define REPNZ      0x2
   10.28 -#define OVERLAP    0x4
   10.29 -
   10.30 -/* instruction type */
   10.31 -#define INSTR_PIO   1
   10.32 -#define INSTR_OR    2
   10.33 -#define INSTR_AND   3
   10.34 -#define INSTR_XOR   4
   10.35 -#define INSTR_CMP   5
   10.36 -#define INSTR_MOV   6
   10.37 -#define INSTR_MOVS  7
   10.38 -#define INSTR_MOVZX 8
   10.39 -#define INSTR_MOVSX 9
   10.40 -#define INSTR_STOS  10
   10.41 -#define INSTR_LODS  11
   10.42 -#define INSTR_TEST  12
   10.43 -#define INSTR_BT    13
   10.44 -#define INSTR_XCHG  14
   10.45 -#define INSTR_SUB   15
   10.46 -#define INSTR_ADD   16
   10.47 -#define INSTR_PUSH  17
   10.48 -
   10.49 -#define MAX_INST_LEN      15 /* Maximum instruction length = 15 bytes */
   10.50 -
   10.51 -struct hvm_io_op {
   10.52 -    unsigned int            instr;      /* instruction */
   10.53 -    unsigned int            flags;
   10.54 -    unsigned long           addr;       /* virt addr for overlap PIO/MMIO */
   10.55 -    struct {
   10.56 -        unsigned int        operand[2]; /* operands */
   10.57 -        unsigned long       immediate;  /* immediate portion */
   10.58 -    };
   10.59 -    struct cpu_user_regs    io_context; /* current context */
   10.60 -};
   10.61 -
   10.62  #define MAX_IO_HANDLER             12
   10.63  
   10.64  #define HVM_PORTIO                  0
   10.65 @@ -119,7 +64,6 @@ struct hvm_mmio_handler {
   10.66      hvm_mmio_write_t write_handler;
   10.67  };
   10.68  
   10.69 -/* global io interception point in HV */
   10.70  int hvm_io_intercept(ioreq_t *p, int type);
   10.71  int register_io_handler(
   10.72      struct domain *d, unsigned long addr, unsigned long size,
    11.1 --- a/xen/include/asm-x86/hvm/vcpu.h	Fri Feb 22 10:07:35 2008 +0000
    11.2 +++ b/xen/include/asm-x86/hvm/vcpu.h	Fri Feb 22 10:52:27 2008 +0000
    11.3 @@ -42,7 +42,6 @@ struct hvm_vcpu {
    11.4       */
    11.5      unsigned long       hw_cr[5];
    11.6  
    11.7 -    struct hvm_io_op    io_op;
    11.8      struct vlapic       vlapic;
    11.9      s64                 cache_tsc_offset;
   11.10      u64                 guest_time;
   11.11 @@ -77,9 +76,5 @@ struct hvm_vcpu {
   11.12      unsigned long       io_data;
   11.13  };
   11.14  
   11.15 -#define ARCH_HVM_IO_WAIT         1   /* Waiting for I/O completion */
   11.16 -
   11.17 -#define HVM_CONTEXT_STACK_BYTES  (offsetof(struct cpu_user_regs, ss))
   11.18 -
   11.19  #endif /* __ASM_X86_HVM_VCPU_H__ */
   11.20