ia64/xen-unstable

changeset 16455:51082cf273d4

vmx: Initial framework for real-mode emulation (disabled by default).
Still plenty to do:
- i/o emulation
- more instructions
- interrupt/exception delivery
- vm86 fast path
At this stage we can get three instructions into the rombios.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Sat Nov 24 21:46:14 2007 +0000 (2007-11-24)
parents d5c396128897
children ad632e4f26d4
files xen/arch/x86/hvm/vmx/Makefile xen/arch/x86/hvm/vmx/realmode.c 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/Makefile	Sat Nov 24 21:40:19 2007 +0000
     1.2 +++ b/xen/arch/x86/hvm/vmx/Makefile	Sat Nov 24 21:46:14 2007 +0000
     1.3 @@ -4,5 +4,8 @@ subdir-$(x86_32) += x86_32
     1.4  subdir-$(x86_64) += x86_64
     1.5  
     1.6  obj-y += intr.o
     1.7 +ifneq ($(vmxassist),y)
     1.8 +obj-y += realmode.o
     1.9 +endif
    1.10  obj-y += vmcs.o
    1.11  obj-y += vmx.o
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/xen/arch/x86/hvm/vmx/realmode.c	Sat Nov 24 21:46:14 2007 +0000
     2.3 @@ -0,0 +1,274 @@
     2.4 +/******************************************************************************
     2.5 + * arch/x86/hvm/vmx/realmode.c
     2.6 + * 
     2.7 + * Real-mode emulation for VMX.
     2.8 + * 
     2.9 + * Copyright (c) 2007 Citrix Systems, Inc.
    2.10 + * 
    2.11 + * Authors:
    2.12 + *    Keir Fraser <keir.fraser@citrix.com>
    2.13 + */
    2.14 +
    2.15 +#include <xen/config.h>
    2.16 +#include <xen/init.h>
    2.17 +#include <xen/lib.h>
    2.18 +#include <xen/sched.h>
    2.19 +#include <asm/hvm/hvm.h>
    2.20 +#include <asm/hvm/support.h>
    2.21 +#include <asm/hvm/vmx/vmx.h>
    2.22 +#include <asm/hvm/vmx/vmcs.h>
    2.23 +#include <asm/hvm/vmx/cpu.h>
    2.24 +#include <asm/x86_emulate.h>
    2.25 +
    2.26 +struct realmode_emulate_ctxt {
    2.27 +    struct x86_emulate_ctxt ctxt;
    2.28 +
    2.29 +    /* Cache of up to 31 bytes of instruction. */
    2.30 +    uint8_t insn_buf[31];
    2.31 +    uint8_t insn_buf_bytes;
    2.32 +    unsigned long insn_buf_eip;
    2.33 +
    2.34 +    struct segment_register seg_reg[10];
    2.35 +};
    2.36 +
    2.37 +static int realmode_translate_linear_addr(
    2.38 +    enum x86_segment seg,
    2.39 +    unsigned long offset,
    2.40 +    unsigned int bytes,
    2.41 +    enum hvm_access_type access_type,
    2.42 +    struct realmode_emulate_ctxt *rm_ctxt,
    2.43 +    unsigned long *paddr)
    2.44 +{
    2.45 +    struct segment_register *reg = &rm_ctxt->seg_reg[seg];
    2.46 +    int okay;
    2.47 +
    2.48 +    okay = hvm_virtual_to_linear_addr(
    2.49 +        seg, reg, offset, bytes, access_type, rm_ctxt->ctxt.addr_size, paddr);
    2.50 +
    2.51 +    if ( !okay )
    2.52 +    {
    2.53 +        hvm_inject_exception(TRAP_gp_fault, 0, 0);
    2.54 +        return X86EMUL_EXCEPTION;
    2.55 +    }
    2.56 +
    2.57 +    return 0;
    2.58 +}
    2.59 +
    2.60 +static int
    2.61 +realmode_read(
    2.62 +    enum x86_segment seg,
    2.63 +    unsigned long offset,
    2.64 +    unsigned long *val,
    2.65 +    unsigned int bytes,
    2.66 +    enum hvm_access_type access_type,
    2.67 +    struct realmode_emulate_ctxt *rm_ctxt)
    2.68 +{
    2.69 +    unsigned long addr;
    2.70 +    int rc;
    2.71 +
    2.72 +    rc = realmode_translate_linear_addr(
    2.73 +        seg, offset, bytes, access_type, rm_ctxt, &addr);
    2.74 +    if ( rc )
    2.75 +        return rc;
    2.76 +
    2.77 +    *val = 0;
    2.78 +    (void)hvm_copy_from_guest_phys(val, addr, bytes);
    2.79 +    return X86EMUL_OKAY;
    2.80 +}
    2.81 +
    2.82 +static int
    2.83 +realmode_emulate_read(
    2.84 +    enum x86_segment seg,
    2.85 +    unsigned long offset,
    2.86 +    unsigned long *val,
    2.87 +    unsigned int bytes,
    2.88 +    struct x86_emulate_ctxt *ctxt)
    2.89 +{
    2.90 +    return realmode_read(
    2.91 +        seg, offset, val, bytes, hvm_access_read,
    2.92 +        container_of(ctxt, struct realmode_emulate_ctxt, ctxt));
    2.93 +}
    2.94 +
    2.95 +static int
    2.96 +realmode_emulate_insn_fetch(
    2.97 +    enum x86_segment seg,
    2.98 +    unsigned long offset,
    2.99 +    unsigned long *val,
   2.100 +    unsigned int bytes,
   2.101 +    struct x86_emulate_ctxt *ctxt)
   2.102 +{
   2.103 +    struct realmode_emulate_ctxt *rm_ctxt =
   2.104 +        container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
   2.105 +    unsigned int insn_off = offset - rm_ctxt->insn_buf_eip;
   2.106 +
   2.107 +    /* Fall back if requested bytes are not in the prefetch cache. */
   2.108 +    if ( unlikely((insn_off + bytes) > rm_ctxt->insn_buf_bytes) )
   2.109 +        return realmode_read(
   2.110 +            seg, offset, val, bytes,
   2.111 +            hvm_access_insn_fetch, rm_ctxt);
   2.112 +
   2.113 +    /* Hit the cache. Simple memcpy. */
   2.114 +    *val = 0;
   2.115 +    memcpy(val, &rm_ctxt->insn_buf[insn_off], bytes);
   2.116 +    return X86EMUL_OKAY;
   2.117 +}
   2.118 +
   2.119 +static int
   2.120 +realmode_emulate_write(
   2.121 +    enum x86_segment seg,
   2.122 +    unsigned long offset,
   2.123 +    unsigned long val,
   2.124 +    unsigned int bytes,
   2.125 +    struct x86_emulate_ctxt *ctxt)
   2.126 +{
   2.127 +    struct realmode_emulate_ctxt *rm_ctxt =
   2.128 +        container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
   2.129 +    unsigned long addr;
   2.130 +    int rc;
   2.131 +
   2.132 +    rc = realmode_translate_linear_addr(
   2.133 +        seg, offset, bytes, hvm_access_write, rm_ctxt, &addr);
   2.134 +    if ( rc )
   2.135 +        return rc;
   2.136 +
   2.137 +    (void)hvm_copy_to_guest_phys(addr, &val, bytes);
   2.138 +    return X86EMUL_OKAY;
   2.139 +}
   2.140 +
   2.141 +static int 
   2.142 +realmode_emulate_cmpxchg(
   2.143 +    enum x86_segment seg,
   2.144 +    unsigned long offset,
   2.145 +    unsigned long old,
   2.146 +    unsigned long new,
   2.147 +    unsigned int bytes,
   2.148 +    struct x86_emulate_ctxt *ctxt)
   2.149 +{
   2.150 +    return X86EMUL_UNHANDLEABLE;
   2.151 +}
   2.152 +
   2.153 +static int
   2.154 +realmode_read_segment(
   2.155 +    enum x86_segment seg,
   2.156 +    struct segment_register *reg,
   2.157 +    struct x86_emulate_ctxt *ctxt)
   2.158 +{
   2.159 +    struct realmode_emulate_ctxt *rm_ctxt =
   2.160 +        container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
   2.161 +    memcpy(reg, &rm_ctxt->seg_reg[seg], sizeof(struct segment_register));
   2.162 +    return X86EMUL_OKAY;
   2.163 +}
   2.164 +
   2.165 +static int
   2.166 +realmode_write_segment(
   2.167 +    enum x86_segment seg,
   2.168 +    struct segment_register *reg,
   2.169 +    struct x86_emulate_ctxt *ctxt)
   2.170 +{
   2.171 +    struct realmode_emulate_ctxt *rm_ctxt =
   2.172 +        container_of(ctxt, struct realmode_emulate_ctxt, ctxt);
   2.173 +    memcpy(&rm_ctxt->seg_reg[seg], reg, sizeof(struct segment_register));
   2.174 +    return X86EMUL_OKAY;
   2.175 +}
   2.176 +
   2.177 +static int
   2.178 +realmode_read_io(
   2.179 +    unsigned int port,
   2.180 +    unsigned int bytes,
   2.181 +    unsigned long *val,
   2.182 +    struct x86_emulate_ctxt *ctxt)
   2.183 +{
   2.184 +    return X86EMUL_UNHANDLEABLE;
   2.185 +}
   2.186 +
   2.187 +static int realmode_write_io(
   2.188 +    unsigned int port,
   2.189 +    unsigned int bytes,
   2.190 +    unsigned long val,
   2.191 +    struct x86_emulate_ctxt *ctxt)
   2.192 +{
   2.193 +    return X86EMUL_UNHANDLEABLE;
   2.194 +}
   2.195 +
   2.196 +static int
   2.197 +realmode_read_cr(
   2.198 +    unsigned int reg,
   2.199 +    unsigned long *val,
   2.200 +    struct x86_emulate_ctxt *ctxt)
   2.201 +{
   2.202 +    switch ( reg )
   2.203 +    {
   2.204 +    case 0:
   2.205 +    case 2:
   2.206 +    case 3:
   2.207 +    case 4:
   2.208 +        *val = current->arch.hvm_vcpu.guest_cr[reg];
   2.209 +        break;
   2.210 +    default:
   2.211 +        return X86EMUL_UNHANDLEABLE;
   2.212 +    }
   2.213 +
   2.214 +    return X86EMUL_OKAY;
   2.215 +}
   2.216 +
   2.217 +static struct x86_emulate_ops realmode_emulator_ops = {
   2.218 +    .read          = realmode_emulate_read,
   2.219 +    .insn_fetch    = realmode_emulate_insn_fetch,
   2.220 +    .write         = realmode_emulate_write,
   2.221 +    .cmpxchg       = realmode_emulate_cmpxchg,
   2.222 +    .read_segment  = realmode_read_segment,
   2.223 +    .write_segment = realmode_write_segment,
   2.224 +    .read_io       = realmode_read_io,
   2.225 +    .write_io      = realmode_write_io,
   2.226 +    .read_cr       = realmode_read_cr
   2.227 +};
   2.228 +
   2.229 +int vmx_realmode(struct cpu_user_regs *regs)
   2.230 +{
   2.231 +    struct vcpu *curr = current;
   2.232 +    struct realmode_emulate_ctxt rm_ctxt;
   2.233 +    unsigned long addr;
   2.234 +    int i, rc = 0;
   2.235 +
   2.236 +    for ( i = 0; i < 10; i++ )
   2.237 +        hvm_get_segment_register(curr, i, &rm_ctxt.seg_reg[i]);
   2.238 +
   2.239 +    while ( !(curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE) &&
   2.240 +            !softirq_pending(smp_processor_id()) )
   2.241 +    {
   2.242 +        rm_ctxt.ctxt.regs = regs;
   2.243 +        rm_ctxt.ctxt.addr_size =
   2.244 +            rm_ctxt.seg_reg[x86_seg_cs].attr.fields.db ? 32 : 16;
   2.245 +        rm_ctxt.ctxt.sp_size =
   2.246 +            rm_ctxt.seg_reg[x86_seg_ss].attr.fields.db ? 32 : 16;
   2.247 +
   2.248 +        rm_ctxt.insn_buf_eip = regs->eip;
   2.249 +        rm_ctxt.insn_buf_bytes =
   2.250 +            (hvm_virtual_to_linear_addr(
   2.251 +                x86_seg_cs, &rm_ctxt.seg_reg[x86_seg_cs],
   2.252 +                regs->eip, sizeof(rm_ctxt.insn_buf),
   2.253 +                hvm_access_insn_fetch, rm_ctxt.ctxt.addr_size, &addr) &&
   2.254 +             !hvm_copy_from_guest_virt(
   2.255 +                 rm_ctxt.insn_buf, addr, sizeof(rm_ctxt.insn_buf)))
   2.256 +            ? sizeof(rm_ctxt.insn_buf) : 0;
   2.257 +
   2.258 +        gdprintk(XENLOG_DEBUG,
   2.259 +                 "RM %04x:%08lx: %02x %02x %02x %02x %02x %02x\n",
   2.260 +                 rm_ctxt.seg_reg[x86_seg_cs].sel, regs->eip,
   2.261 +                 rm_ctxt.insn_buf[0], rm_ctxt.insn_buf[1],
   2.262 +                 rm_ctxt.insn_buf[2], rm_ctxt.insn_buf[3],
   2.263 +                 rm_ctxt.insn_buf[4], rm_ctxt.insn_buf[5]);
   2.264 +
   2.265 +        if ( x86_emulate(&rm_ctxt.ctxt, &realmode_emulator_ops) )
   2.266 +        {            
   2.267 +            gdprintk(XENLOG_ERR, "Emulation failed\n");
   2.268 +            rc = -EINVAL;
   2.269 +            break;
   2.270 +        }
   2.271 +    }
   2.272 +
   2.273 +    for ( i = 0; i < 10; i++ )
   2.274 +        hvm_set_segment_register(curr, i, &rm_ctxt.seg_reg[i]);
   2.275 +
   2.276 +    return rc;
   2.277 +}
     3.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Sat Nov 24 21:40:19 2007 +0000
     3.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Sat Nov 24 21:46:14 2007 +0000
     3.3 @@ -2078,13 +2078,6 @@ static int vmx_set_cr0(unsigned long val
     3.4  
     3.5  #define vmx_set_cr0(v) hvm_set_cr0(v)
     3.6  
     3.7 -static int vmx_realmode(struct cpu_user_regs *regs)
     3.8 -{
     3.9 -    gdprintk(XENLOG_ERR, "Attempt to enter real mode on VCPU %d\n",
    3.10 -             current->vcpu_id);
    3.11 -    return -EINVAL;
    3.12 -}
    3.13 -
    3.14  #endif
    3.15  
    3.16  #define CASE_SET_REG(REG, reg)      \
     4.1 --- a/xen/include/asm-x86/hvm/vmx/vmx.h	Sat Nov 24 21:40:19 2007 +0000
     4.2 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h	Sat Nov 24 21:46:14 2007 +0000
     4.3 @@ -33,6 +33,7 @@ void vmx_intr_assist(void);
     4.4  void vmx_do_resume(struct vcpu *);
     4.5  void set_guest_time(struct vcpu *v, u64 gtime);
     4.6  void vmx_vlapic_msr_changed(struct vcpu *v);
     4.7 +int vmx_realmode(struct cpu_user_regs *regs);
     4.8  
     4.9  /*
    4.10   * Exit Reasons