ia64/xen-unstable

changeset 15276:4f05a587cb6b

hvm vmx: Clean up vmx_io_instruction().

vmx_io_instruction() is too long, so it's hard to understand or change
something. The attached patch splits it into several readable functions,
making it easer to understand and extend.

Signed-off-by: Weidong Han <weidong.han@intel.com>
Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
author kfraser@localhost.localdomain
date Tue Jun 05 10:08:09 2007 +0100 (2007-06-05)
parents 91301122db51
children 0feaf2fc75d3
files xen/arch/x86/hvm/vmx/vmx.c xen/include/asm-x86/hvm/vmx/vmx.h
line diff
     1.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Tue Jun 05 10:00:15 2007 +0100
     1.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Tue Jun 05 10:08:09 2007 +0100
     1.3 @@ -929,7 +929,8 @@ static unsigned long vmx_get_segment_bas
     1.4      ASSERT(v == current);
     1.5  
     1.6  #ifdef __x86_64__
     1.7 -    if ( vmx_long_mode_enabled(v) && (__vmread(GUEST_CS_AR_BYTES) & (1u<<13)) )
     1.8 +    if ( vmx_long_mode_enabled(v) &&
     1.9 +         (__vmread(GUEST_CS_AR_BYTES) & X86_SEG_AR_CS_LM_ACTIVE) )
    1.10          long_mode = 1;
    1.11  #endif
    1.12  
    1.13 @@ -1097,9 +1098,10 @@ static int vmx_guest_x86_mode(struct vcp
    1.14      if ( unlikely(__vmread(GUEST_RFLAGS) & X86_EFLAGS_VM) )
    1.15          return 1;
    1.16      cs_ar_bytes = __vmread(GUEST_CS_AR_BYTES);
    1.17 -    if ( vmx_long_mode_enabled(v) && likely(cs_ar_bytes & (1u<<13)) )
    1.18 +    if ( vmx_long_mode_enabled(v) && likely(cs_ar_bytes &
    1.19 +                                            X86_SEG_AR_CS_LM_ACTIVE) )
    1.20          return 8;
    1.21 -    return (likely(cs_ar_bytes & (1u<<14)) ? 4 : 2);
    1.22 +    return (likely(cs_ar_bytes & X86_SEG_AR_DEF_OP_SIZE) ? 4 : 2);
    1.23  }
    1.24  
    1.25  static int vmx_pae_enabled(struct vcpu *v)
    1.26 @@ -1452,65 +1454,73 @@ static void vmx_do_invlpg(unsigned long 
    1.27      paging_invlpg(v, va);
    1.28  }
    1.29  
    1.30 -
    1.31 -static int vmx_check_descriptor(int long_mode, unsigned long eip, int inst_len,
    1.32 -                                enum x86_segment seg, unsigned long *base,
    1.33 -                                u32 *limit, u32 *ar_bytes)
    1.34 +/*
    1.35 + * get segment for string pio according to guest instruction
    1.36 + */
    1.37 +static void vmx_str_pio_get_segment(int long_mode, unsigned long eip,
    1.38 +                                   int inst_len, enum x86_segment *seg)
    1.39 +{
    1.40 +    unsigned char inst[MAX_INST_LEN];
    1.41 +    int i;
    1.42 +    extern int inst_copy_from_guest(unsigned char *, unsigned long, int);
    1.43 +
    1.44 +    if ( !long_mode )
    1.45 +        eip += __vmread(GUEST_CS_BASE);
    1.46 +
    1.47 +    memset(inst, 0, MAX_INST_LEN);
    1.48 +    if ( inst_copy_from_guest(inst, eip, inst_len) != inst_len )
    1.49 +    {
    1.50 +        gdprintk(XENLOG_ERR, "Get guest instruction failed\n");
    1.51 +        domain_crash(current->domain);
    1.52 +        return;
    1.53 +    }
    1.54 +
    1.55 +    for ( i = 0; i < inst_len; i++ )
    1.56 +    {
    1.57 +        switch ( inst[i] )
    1.58 +        {
    1.59 +        case 0xf3: /* REPZ */
    1.60 +        case 0xf2: /* REPNZ */
    1.61 +        case 0xf0: /* LOCK */
    1.62 +        case 0x66: /* data32 */
    1.63 +        case 0x67: /* addr32 */
    1.64 +#ifdef __x86_64__
    1.65 +        case 0x40 ... 0x4f: /* REX */
    1.66 +#endif
    1.67 +            continue;
    1.68 +        case 0x2e: /* CS */
    1.69 +            *seg = x86_seg_cs;
    1.70 +            continue;
    1.71 +        case 0x36: /* SS */
    1.72 +            *seg = x86_seg_ss;
    1.73 +            continue;
    1.74 +        case 0x26: /* ES */
    1.75 +            *seg = x86_seg_es;
    1.76 +            continue;
    1.77 +        case 0x64: /* FS */
    1.78 +            *seg = x86_seg_fs;
    1.79 +            continue;
    1.80 +        case 0x65: /* GS */
    1.81 +            *seg = x86_seg_gs;
    1.82 +            continue;
    1.83 +        case 0x3e: /* DS */
    1.84 +            *seg = x86_seg_ds;
    1.85 +            continue;
    1.86 +        }
    1.87 +    }
    1.88 +}
    1.89 +
    1.90 +static int vmx_str_pio_check_descriptor(int long_mode, unsigned long eip,
    1.91 +                                        int inst_len, enum x86_segment seg,
    1.92 +                                        unsigned long *base, u32 *limit,
    1.93 +                                        u32 *ar_bytes)
    1.94  {
    1.95      enum vmcs_field ar_field, base_field, limit_field;
    1.96  
    1.97      *base = 0;
    1.98      *limit = 0;
    1.99      if ( seg != x86_seg_es )
   1.100 -    {
   1.101 -        unsigned char inst[MAX_INST_LEN];
   1.102 -        int i;
   1.103 -        extern int inst_copy_from_guest(unsigned char *, unsigned long, int);
   1.104 -
   1.105 -        if ( !long_mode )
   1.106 -            eip += __vmread(GUEST_CS_BASE);
   1.107 -        memset(inst, 0, MAX_INST_LEN);
   1.108 -        if ( inst_copy_from_guest(inst, eip, inst_len) != inst_len )
   1.109 -        {
   1.110 -            gdprintk(XENLOG_ERR, "Get guest instruction failed\n");
   1.111 -            domain_crash(current->domain);
   1.112 -            return 0;
   1.113 -        }
   1.114 -
   1.115 -        for ( i = 0; i < inst_len; i++ )
   1.116 -        {
   1.117 -            switch ( inst[i] )
   1.118 -            {
   1.119 -            case 0xf3: /* REPZ */
   1.120 -            case 0xf2: /* REPNZ */
   1.121 -            case 0xf0: /* LOCK */
   1.122 -            case 0x66: /* data32 */
   1.123 -            case 0x67: /* addr32 */
   1.124 -#ifdef __x86_64__
   1.125 -            case 0x40 ... 0x4f: /* REX */
   1.126 -#endif
   1.127 -                continue;
   1.128 -            case 0x2e: /* CS */
   1.129 -                seg = x86_seg_cs;
   1.130 -                continue;
   1.131 -            case 0x36: /* SS */
   1.132 -                seg = x86_seg_ss;
   1.133 -                continue;
   1.134 -            case 0x26: /* ES */
   1.135 -                seg = x86_seg_es;
   1.136 -                continue;
   1.137 -            case 0x64: /* FS */
   1.138 -                seg = x86_seg_fs;
   1.139 -                continue;
   1.140 -            case 0x65: /* GS */
   1.141 -                seg = x86_seg_gs;
   1.142 -                continue;
   1.143 -            case 0x3e: /* DS */
   1.144 -                seg = x86_seg_ds;
   1.145 -                continue;
   1.146 -            }
   1.147 -        }
   1.148 -    }
   1.149 +        vmx_str_pio_get_segment(long_mode, eip, inst_len, &seg);
   1.150  
   1.151      switch ( seg )
   1.152      {
   1.153 @@ -1559,13 +1569,259 @@ static int vmx_check_descriptor(int long
   1.154      return !(*ar_bytes & 0x10000);
   1.155  }
   1.156  
   1.157 +
   1.158 +static inline void vmx_str_pio_check_limit(u32 limit, unsigned int size,
   1.159 +                                           u32 ar_bytes, unsigned long addr,
   1.160 +                                           unsigned long base, int df,
   1.161 +                                           unsigned long *count)
   1.162 +{
   1.163 +    unsigned long ea = addr - base;
   1.164 +
   1.165 +    /* Offset must be within limits. */
   1.166 +    ASSERT(ea == (u32)ea);
   1.167 +    if ( (u32)(ea + size - 1) < (u32)ea ||
   1.168 +         (ar_bytes & 0xc) != 0x4 ? ea + size - 1 > limit
   1.169 +                                 : ea <= limit )
   1.170 +    {
   1.171 +        vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   1.172 +        return;
   1.173 +    }
   1.174 +
   1.175 +    /* Check the limit for repeated instructions, as above we checked
   1.176 +       only the first instance. Truncate the count if a limit violation
   1.177 +       would occur. Note that the checking is not necessary for page
   1.178 +       granular segments as transfers crossing page boundaries will be
   1.179 +       broken up anyway. */
   1.180 +    if ( !(ar_bytes & X86_SEG_AR_GRANULARITY) && *count > 1 )
   1.181 +    {
   1.182 +        if ( (ar_bytes & 0xc) != 0x4 )
   1.183 +        {
   1.184 +            /* expand-up */
   1.185 +            if ( !df )
   1.186 +            {
   1.187 +                if ( ea + *count * size - 1 < ea ||
   1.188 +                     ea + *count * size - 1 > limit )
   1.189 +                    *count = (limit + 1UL - ea) / size;
   1.190 +            }
   1.191 +            else
   1.192 +            {
   1.193 +                if ( *count - 1 > ea / size )
   1.194 +                    *count = ea / size + 1;
   1.195 +            }
   1.196 +        }
   1.197 +        else
   1.198 +        {
   1.199 +            /* expand-down */
   1.200 +            if ( !df )
   1.201 +            {
   1.202 +                if ( *count - 1 > -(s32)ea / size )
   1.203 +                    *count = -(s32)ea / size + 1UL;
   1.204 +            }
   1.205 +            else
   1.206 +            {
   1.207 +                if ( ea < (*count - 1) * size ||
   1.208 +                     ea - (*count - 1) * size <= limit )
   1.209 +                    *count = (ea - limit - 1) / size + 1;
   1.210 +            }
   1.211 +        }
   1.212 +        ASSERT(*count);
   1.213 +    }
   1.214 +}
   1.215 +
   1.216 +#ifdef __x86_64__
   1.217 +static inline void vmx_str_pio_lm_check_limit(struct cpu_user_regs *regs,
   1.218 +                                              unsigned int size,
   1.219 +                                              unsigned long addr,
   1.220 +                                              unsigned long *count)
   1.221 +{
   1.222 +    if ( !is_canonical_address(addr) ||
   1.223 +         !is_canonical_address(addr + size - 1) )
   1.224 +    {
   1.225 +        vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   1.226 +        return;
   1.227 +    }
   1.228 +    if ( *count > (1UL << 48) / size )
   1.229 +        *count = (1UL << 48) / size;
   1.230 +    if ( !(regs->eflags & EF_DF) )
   1.231 +    {
   1.232 +        if ( addr + *count * size - 1 < addr ||
   1.233 +             !is_canonical_address(addr + *count * size - 1) )
   1.234 +            *count = (addr & ~((1UL << 48) - 1)) / size;
   1.235 +    }
   1.236 +    else
   1.237 +    {
   1.238 +        if ( (*count - 1) * size > addr ||
   1.239 +             !is_canonical_address(addr + (*count - 1) * size) )
   1.240 +            *count = (addr & ~((1UL << 48) - 1)) / size + 1;
   1.241 +    }
   1.242 +    ASSERT(*count);
   1.243 +}
   1.244 +#endif
   1.245 +
   1.246 +static inline void vmx_send_str_pio(struct cpu_user_regs *regs,
   1.247 +                                    struct hvm_io_op *pio_opp,
   1.248 +                                    unsigned long inst_len, unsigned int port,
   1.249 +                                    int sign, unsigned int size, int dir,
   1.250 +                                    int df, unsigned long addr,
   1.251 +                                    unsigned long paddr, unsigned long count)
   1.252 +{
   1.253 +    /*
   1.254 +     * Handle string pio instructions that cross pages or that
   1.255 +     * are unaligned. See the comments in hvm_domain.c/handle_mmio()
   1.256 +     */
   1.257 +    if ( (addr & PAGE_MASK) != ((addr + size - 1) & PAGE_MASK) ) {
   1.258 +        unsigned long value = 0;
   1.259 +
   1.260 +        pio_opp->flags |= OVERLAP;
   1.261 +
   1.262 +        if ( dir == IOREQ_WRITE )   /* OUTS */
   1.263 +        {
   1.264 +            if ( hvm_paging_enabled(current) )
   1.265 +            {
   1.266 +                int rv = hvm_copy_from_guest_virt(&value, addr, size);
   1.267 +                if ( rv != 0 )
   1.268 +                {
   1.269 +                    /* Failed on the page-spanning copy.  Inject PF into
   1.270 +                     * the guest for the address where we failed. */
   1.271 +                    addr += size - rv;
   1.272 +                    gdprintk(XENLOG_DEBUG, "Pagefault reading non-io side "
   1.273 +                             "of a page-spanning PIO: va=%#lx\n", addr);
   1.274 +                    vmx_inject_exception(TRAP_page_fault, 0, addr);
   1.275 +                    return;
   1.276 +                }
   1.277 +            }
   1.278 +            else
   1.279 +                (void) hvm_copy_from_guest_phys(&value, addr, size);
   1.280 +        } else /* dir != IOREQ_WRITE */
   1.281 +            /* Remember where to write the result, as a *VA*.
   1.282 +             * Must be a VA so we can handle the page overlap
   1.283 +             * correctly in hvm_pio_assist() */
   1.284 +            pio_opp->addr = addr;
   1.285 +
   1.286 +        if ( count == 1 )
   1.287 +            regs->eip += inst_len;
   1.288 +
   1.289 +        send_pio_req(port, 1, size, value, dir, df, 0);
   1.290 +    } else {
   1.291 +        unsigned long last_addr = sign > 0 ? addr + count * size - 1
   1.292 +                                           : addr - (count - 1) * size;
   1.293 +
   1.294 +        if ( (addr & PAGE_MASK) != (last_addr & PAGE_MASK) )
   1.295 +        {
   1.296 +            if ( sign > 0 )
   1.297 +                count = (PAGE_SIZE - (addr & ~PAGE_MASK)) / size;
   1.298 +            else
   1.299 +                count = (addr & ~PAGE_MASK) / size + 1;
   1.300 +        } else
   1.301 +            regs->eip += inst_len;
   1.302 +
   1.303 +        send_pio_req(port, count, size, paddr, dir, df, 1);
   1.304 +    }
   1.305 +}
   1.306 +
   1.307 +static void vmx_str_pio_handler(unsigned long exit_qualification,
   1.308 +                                unsigned long inst_len,
   1.309 +                                struct cpu_user_regs *regs,
   1.310 +                                struct hvm_io_op *pio_opp)
   1.311 +{
   1.312 +    unsigned int port, size;
   1.313 +    int dir, df, vm86;
   1.314 +    unsigned long addr, count = 1, base;
   1.315 +    paddr_t paddr;
   1.316 +    unsigned long gfn;
   1.317 +    u32 ar_bytes, limit;
   1.318 +    int sign;
   1.319 +    int long_mode = 0;
   1.320 +
   1.321 +    vm86 = regs->eflags & X86_EFLAGS_VM ? 1 : 0;
   1.322 +    df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;
   1.323 +
   1.324 +    if ( test_bit(6, &exit_qualification) )
   1.325 +        port = (exit_qualification >> 16) & 0xFFFF;
   1.326 +    else
   1.327 +        port = regs->edx & 0xffff;
   1.328 +
   1.329 +    size = (exit_qualification & 7) + 1;
   1.330 +    dir = test_bit(3, &exit_qualification); /* direction */
   1.331 +
   1.332 +    if ( dir == IOREQ_READ )
   1.333 +        HVMTRACE_2D(IO_READ,  current, port, size);
   1.334 +    else
   1.335 +        HVMTRACE_2D(IO_WRITE, current, port, size);
   1.336 +
   1.337 +    sign = regs->eflags & X86_EFLAGS_DF ? -1 : 1;
   1.338 +    ar_bytes = __vmread(GUEST_CS_AR_BYTES);
   1.339 +#ifdef __x86_64__
   1.340 +    if ( vmx_long_mode_enabled(current) &&
   1.341 +         (ar_bytes & X86_SEG_AR_CS_LM_ACTIVE) )
   1.342 +        long_mode = 1;
   1.343 +#endif
   1.344 +    addr = __vmread(GUEST_LINEAR_ADDRESS);
   1.345 +
   1.346 +    if ( test_bit(5, &exit_qualification) ) { /* "rep" prefix */
   1.347 +        pio_opp->flags |= REPZ;
   1.348 +        count = regs->ecx;
   1.349 +        if ( !long_mode &&
   1.350 +            (vm86 || !(ar_bytes & X86_SEG_AR_DEF_OP_SIZE)) )
   1.351 +            count &= 0xFFFF;
   1.352 +    }
   1.353 +
   1.354 +    /*
   1.355 +     * In protected mode, guest linear address is invalid if the
   1.356 +     * selector is null.
   1.357 +     */
   1.358 +    if ( !vmx_str_pio_check_descriptor(long_mode, regs->eip, inst_len,
   1.359 +                                       dir==IOREQ_WRITE ? x86_seg_ds :
   1.360 +                                       x86_seg_es, &base, &limit,
   1.361 +                                       &ar_bytes) ) {
   1.362 +        if ( !long_mode ) {
   1.363 +            vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   1.364 +            return;
   1.365 +        }
   1.366 +        addr = dir == IOREQ_WRITE ? base + regs->esi : regs->edi;
   1.367 +    }
   1.368 +
   1.369 +    if ( !long_mode )
   1.370 +    {
   1.371 +        /* Segment must be readable for outs and writeable for ins. */
   1.372 +        if ( dir == IOREQ_WRITE ? (ar_bytes & 0xa) == 0x8
   1.373 +                                : (ar_bytes & 0xa) != 0x2 ) {
   1.374 +            vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   1.375 +            return;
   1.376 +        }
   1.377 +
   1.378 +        vmx_str_pio_check_limit(limit, size, ar_bytes, addr, base, df, &count);
   1.379 +    }
   1.380 +#ifdef __x86_64__
   1.381 +    else
   1.382 +    {
   1.383 +        vmx_str_pio_lm_check_limit(regs, size, addr, &count);
   1.384 +    }
   1.385 +#endif
   1.386 +
   1.387 +    /* Translate the address to a physical address */
   1.388 +    gfn = paging_gva_to_gfn(current, addr);
   1.389 +    if ( gfn == INVALID_GFN )
   1.390 +    {
   1.391 +        /* The guest does not have the RAM address mapped.
   1.392 +         * Need to send in a page fault */
   1.393 +        int errcode = 0;
   1.394 +        /* IO read --> memory write */
   1.395 +        if ( dir == IOREQ_READ ) errcode |= PFEC_write_access;
   1.396 +        vmx_inject_exception(TRAP_page_fault, errcode, addr);
   1.397 +        return;
   1.398 +    }
   1.399 +    paddr = (paddr_t)gfn << PAGE_SHIFT | (addr & ~PAGE_MASK);
   1.400 +
   1.401 +    vmx_send_str_pio(regs, pio_opp, inst_len, port, sign,
   1.402 +                     size, dir, df, addr, paddr, count);
   1.403 +}
   1.404 +
   1.405  static void vmx_io_instruction(unsigned long exit_qualification,
   1.406                                 unsigned long inst_len)
   1.407  {
   1.408      struct cpu_user_regs *regs;
   1.409      struct hvm_io_op *pio_opp;
   1.410 -    unsigned int port, size;
   1.411 -    int dir, df, vm86;
   1.412  
   1.413      pio_opp = &current->arch.hvm_vcpu.io_op;
   1.414      pio_opp->instr = INSTR_PIO;
   1.415 @@ -1577,216 +1833,33 @@ static void vmx_io_instruction(unsigned 
   1.416      memcpy(regs, guest_cpu_user_regs(), HVM_CONTEXT_STACK_BYTES);
   1.417      hvm_store_cpu_guest_regs(current, regs, NULL);
   1.418  
   1.419 -    vm86 = regs->eflags & X86_EFLAGS_VM ? 1 : 0;
   1.420 -    df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;
   1.421 -
   1.422      HVM_DBG_LOG(DBG_LEVEL_IO, "vm86 %d, eip=%x:%lx, "
   1.423                  "exit_qualification = %lx",
   1.424 -                vm86, regs->cs, (unsigned long)regs->eip, exit_qualification);
   1.425 -
   1.426 -    if ( test_bit(6, &exit_qualification) )
   1.427 -        port = (exit_qualification >> 16) & 0xFFFF;
   1.428 -    else
   1.429 -        port = regs->edx & 0xffff;
   1.430 -
   1.431 -    size = (exit_qualification & 7) + 1;
   1.432 -    dir = test_bit(3, &exit_qualification); /* direction */
   1.433 -
   1.434 -    if (dir==IOREQ_READ)
   1.435 -        HVMTRACE_2D(IO_READ,  current, port, size);
   1.436 +                regs->eflags & X86_EFLAGS_VM ? 1 : 0,
   1.437 +                regs->cs, (unsigned long)regs->eip, exit_qualification);
   1.438 +
   1.439 +    if ( test_bit(4, &exit_qualification) ) /* string instrucation */
   1.440 +        vmx_str_pio_handler(exit_qualification, inst_len, regs, pio_opp);
   1.441      else
   1.442 -        HVMTRACE_2D(IO_WRITE, current, port, size);
   1.443 -
   1.444 -    if ( test_bit(4, &exit_qualification) ) { /* string instruction */
   1.445 -        unsigned long addr, count = 1, base;
   1.446 -        paddr_t paddr;
   1.447 -        unsigned long gfn;
   1.448 -        u32 ar_bytes, limit;
   1.449 -        int sign = regs->eflags & X86_EFLAGS_DF ? -1 : 1;
   1.450 -        int long_mode = 0;
   1.451 -
   1.452 -        ar_bytes = __vmread(GUEST_CS_AR_BYTES);
   1.453 -#ifdef __x86_64__
   1.454 -        if ( vmx_long_mode_enabled(current) && (ar_bytes & (1u<<13)) )
   1.455 -            long_mode = 1;
   1.456 -#endif
   1.457 -        addr = __vmread(GUEST_LINEAR_ADDRESS);
   1.458 -
   1.459 -        if ( test_bit(5, &exit_qualification) ) { /* "rep" prefix */
   1.460 -            pio_opp->flags |= REPZ;
   1.461 -            count = regs->ecx;
   1.462 -            if ( !long_mode && (vm86 || !(ar_bytes & (1u<<14))) )
   1.463 -                count &= 0xFFFF;
   1.464 -        }
   1.465 -
   1.466 -        /*
   1.467 -         * In protected mode, guest linear address is invalid if the
   1.468 -         * selector is null.
   1.469 -         */
   1.470 -        if ( !vmx_check_descriptor(long_mode, regs->eip, inst_len,
   1.471 -                                   dir==IOREQ_WRITE ? x86_seg_ds : x86_seg_es,
   1.472 -                                   &base, &limit, &ar_bytes) ) {
   1.473 -            if ( !long_mode ) {
   1.474 -                vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   1.475 -                return;
   1.476 -            }
   1.477 -            addr = dir == IOREQ_WRITE ? base + regs->esi : regs->edi;
   1.478 -        }
   1.479 -
   1.480 -        if ( !long_mode ) {
   1.481 -            unsigned long ea = addr - base;
   1.482 -
   1.483 -            /* Segment must be readable for outs and writeable for ins. */
   1.484 -            if ( dir == IOREQ_WRITE ? (ar_bytes & 0xa) == 0x8
   1.485 -                                    : (ar_bytes & 0xa) != 0x2 ) {
   1.486 -                vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   1.487 -                return;
   1.488 -            }
   1.489 -
   1.490 -            /* Offset must be within limits. */
   1.491 -            ASSERT(ea == (u32)ea);
   1.492 -            if ( (u32)(ea + size - 1) < (u32)ea ||
   1.493 -                 (ar_bytes & 0xc) != 0x4 ? ea + size - 1 > limit
   1.494 -                                         : ea <= limit )
   1.495 -            {
   1.496 -                vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   1.497 -                return;
   1.498 -            }
   1.499 -
   1.500 -            /* Check the limit for repeated instructions, as above we checked
   1.501 -               only the first instance. Truncate the count if a limit violation
   1.502 -               would occur. Note that the checking is not necessary for page
   1.503 -               granular segments as transfers crossing page boundaries will be
   1.504 -               broken up anyway. */
   1.505 -            if ( !(ar_bytes & (1u<<15)) && count > 1 )
   1.506 -            {
   1.507 -                if ( (ar_bytes & 0xc) != 0x4 )
   1.508 -                {
   1.509 -                    /* expand-up */
   1.510 -                    if ( !df )
   1.511 -                    {
   1.512 -                        if ( ea + count * size - 1 < ea ||
   1.513 -                             ea + count * size - 1 > limit )
   1.514 -                            count = (limit + 1UL - ea) / size;
   1.515 -                    }
   1.516 -                    else
   1.517 -                    {
   1.518 -                        if ( count - 1 > ea / size )
   1.519 -                            count = ea / size + 1;
   1.520 -                    }
   1.521 -                }
   1.522 -                else
   1.523 -                {
   1.524 -                    /* expand-down */
   1.525 -                    if ( !df )
   1.526 -                    {
   1.527 -                        if ( count - 1 > -(s32)ea / size )
   1.528 -                            count = -(s32)ea / size + 1UL;
   1.529 -                    }
   1.530 -                    else
   1.531 -                    {
   1.532 -                        if ( ea < (count - 1) * size ||
   1.533 -                             ea - (count - 1) * size <= limit )
   1.534 -                            count = (ea - limit - 1) / size + 1;
   1.535 -                    }
   1.536 -                }
   1.537 -                ASSERT(count);
   1.538 -            }
   1.539 -        }
   1.540 -#ifdef __x86_64__
   1.541 +    {
   1.542 +        unsigned int port, size;
   1.543 +        int dir, df;
   1.544 +
   1.545 +        df = regs->eflags & X86_EFLAGS_DF ? 1 : 0;
   1.546 +
   1.547 +        if ( test_bit(6, &exit_qualification) )
   1.548 +            port = (exit_qualification >> 16) & 0xFFFF;
   1.549          else
   1.550 -        {
   1.551 -            if ( !is_canonical_address(addr) ||
   1.552 -                 !is_canonical_address(addr + size - 1) )
   1.553 -            {
   1.554 -                vmx_inject_hw_exception(current, TRAP_gp_fault, 0);
   1.555 -                return;
   1.556 -            }
   1.557 -            if ( count > (1UL << 48) / size )
   1.558 -                count = (1UL << 48) / size;
   1.559 -            if ( !(regs->eflags & EF_DF) )
   1.560 -            {
   1.561 -                if ( addr + count * size - 1 < addr ||
   1.562 -                     !is_canonical_address(addr + count * size - 1) )
   1.563 -                    count = (addr & ~((1UL << 48) - 1)) / size;
   1.564 -            }
   1.565 -            else
   1.566 -            {
   1.567 -                if ( (count - 1) * size > addr ||
   1.568 -                     !is_canonical_address(addr + (count - 1) * size) )
   1.569 -                    count = (addr & ~((1UL << 48) - 1)) / size + 1;
   1.570 -            }
   1.571 -            ASSERT(count);
   1.572 -        }
   1.573 -#endif
   1.574 -
   1.575 -        /* Translate the address to a physical address */
   1.576 -        gfn = paging_gva_to_gfn(current, addr);
   1.577 -        if ( gfn == INVALID_GFN ) 
   1.578 -        {
   1.579 -            /* The guest does not have the RAM address mapped. 
   1.580 -             * Need to send in a page fault */
   1.581 -            int errcode = 0;
   1.582 -            /* IO read --> memory write */
   1.583 -            if ( dir == IOREQ_READ ) errcode |= PFEC_write_access;
   1.584 -            vmx_inject_exception(TRAP_page_fault, errcode, addr);
   1.585 -            return;
   1.586 -        }
   1.587 -        paddr = (paddr_t)gfn << PAGE_SHIFT | (addr & ~PAGE_MASK);
   1.588 -
   1.589 -        /*
   1.590 -         * Handle string pio instructions that cross pages or that
   1.591 -         * are unaligned. See the comments in hvm_domain.c/handle_mmio()
   1.592 -         */
   1.593 -        if ( (addr & PAGE_MASK) != ((addr + size - 1) & PAGE_MASK) ) {
   1.594 -            unsigned long value = 0;
   1.595 -
   1.596 -            pio_opp->flags |= OVERLAP;
   1.597 -
   1.598 -            if ( dir == IOREQ_WRITE )   /* OUTS */
   1.599 -            {
   1.600 -                if ( hvm_paging_enabled(current) )
   1.601 -                {
   1.602 -                    int rv = hvm_copy_from_guest_virt(&value, addr, size);
   1.603 -                    if ( rv != 0 ) 
   1.604 -                    {
   1.605 -                        /* Failed on the page-spanning copy.  Inject PF into
   1.606 -                         * the guest for the address where we failed. */ 
   1.607 -                        addr += size - rv;
   1.608 -                        gdprintk(XENLOG_DEBUG, "Pagefault reading non-io side "
   1.609 -                                 "of a page-spanning PIO: va=%#lx\n", addr);
   1.610 -                        vmx_inject_exception(TRAP_page_fault, 0, addr);
   1.611 -                        return;
   1.612 -                    }
   1.613 -                }
   1.614 -                else
   1.615 -                    (void) hvm_copy_from_guest_phys(&value, addr, size);
   1.616 -            } else /* dir != IOREQ_WRITE */
   1.617 -                /* Remember where to write the result, as a *VA*.
   1.618 -                 * Must be a VA so we can handle the page overlap 
   1.619 -                 * correctly in hvm_pio_assist() */
   1.620 -                pio_opp->addr = addr;
   1.621 -
   1.622 -            if ( count == 1 )
   1.623 -                regs->eip += inst_len;
   1.624 -
   1.625 -            send_pio_req(port, 1, size, value, dir, df, 0);
   1.626 -        } else {
   1.627 -            unsigned long last_addr = sign > 0 ? addr + count * size - 1
   1.628 -                                               : addr - (count - 1) * size;
   1.629 -
   1.630 -            if ( (addr & PAGE_MASK) != (last_addr & PAGE_MASK) )
   1.631 -            {
   1.632 -                if ( sign > 0 )
   1.633 -                    count = (PAGE_SIZE - (addr & ~PAGE_MASK)) / size;
   1.634 -                else
   1.635 -                    count = (addr & ~PAGE_MASK) / size + 1;
   1.636 -            } else
   1.637 -                regs->eip += inst_len;
   1.638 -
   1.639 -            send_pio_req(port, count, size, paddr, dir, df, 1);
   1.640 -        }
   1.641 -    } else {
   1.642 +            port = regs->edx & 0xffff;
   1.643 +
   1.644 +        size = (exit_qualification & 7) + 1;
   1.645 +        dir = test_bit(3, &exit_qualification); /* direction */
   1.646 +
   1.647 +        if ( dir == IOREQ_READ )
   1.648 +            HVMTRACE_2D(IO_READ,  current, port, size);
   1.649 +        else
   1.650 +            HVMTRACE_2D(IO_WRITE, current, port, size);
   1.651 +
   1.652          if ( port == 0xe9 && dir == IOREQ_WRITE && size == 1 )
   1.653              hvm_print_line(current, regs->eax); /* guest debug output */
   1.654  
     2.1 --- a/xen/include/asm-x86/hvm/vmx/vmx.h	Tue Jun 05 10:00:15 2007 +0100
     2.2 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h	Tue Jun 05 10:08:09 2007 +0100
     2.3 @@ -130,6 +130,19 @@ void vmx_vlapic_msr_changed(struct vcpu 
     2.4  #define TYPE_MOV_FROM_DR                (1 << 4)
     2.5  #define DEBUG_REG_ACCESS_REG            0xf00   /* 11:8, general purpose register */
     2.6  
     2.7 +/*
     2.8 + * Access Rights
     2.9 + */
    2.10 +#define X86_SEG_AR_SEG_TYPE     0xf        /* 3:0, segment type */
    2.11 +#define X86_SEG_AR_DESC_TYPE    (1u << 4)  /* 4, descriptor type */
    2.12 +#define X86_SEG_AR_DPL          0x60       /* 6:5, descriptor privilege level */
    2.13 +#define X86_SEG_AR_SEG_PRESENT  (1u << 7)  /* 7, segment present */
    2.14 +#define X86_SEG_AR_AVL          (1u << 12) /* 12, available for system software */
    2.15 +#define X86_SEG_AR_CS_LM_ACTIVE (1u << 13) /* 13, long mode active (CS only) */
    2.16 +#define X86_SEG_AR_DEF_OP_SIZE  (1u << 14) /* 14, default operation size */
    2.17 +#define X86_SEG_AR_GRANULARITY  (1u << 15) /* 15, granularity */
    2.18 +#define X86_SEG_AR_SEG_UNUSABLE (1u << 16) /* 16, segment unusable */
    2.19 +
    2.20  /* These bits in the CR4 are owned by the host */
    2.21  #if CONFIG_PAGING_LEVELS >= 3
    2.22  #define VMX_CR4_HOST_MASK (X86_CR4_VMXE | X86_CR4_PAE)