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>
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