ia64/xen-unstable
changeset 10080:632ad28f2fd7
SVM patch to cleanup IOIO handling, do not use "real" mode but rather
the correct "bitness".
Signed-off-by: Tom Woller <thomas.woller@amd.com>
Signed-off-by: Mats Petersson <mats.petersson@amd.com>
the correct "bitness".
Signed-off-by: Tom Woller <thomas.woller@amd.com>
Signed-off-by: Mats Petersson <mats.petersson@amd.com>
author | kaf24@firebug.cl.cam.ac.uk |
---|---|
date | Wed May 17 23:50:23 2006 +0100 (2006-05-17) |
parents | 81ab21f76a6f |
children | 3d85f350a66a |
files | xen/arch/x86/hvm/svm/svm.c |
line diff
1.1 --- a/xen/arch/x86/hvm/svm/svm.c Wed May 17 23:47:19 2006 +0100 1.2 +++ b/xen/arch/x86/hvm/svm/svm.c Wed May 17 23:50:23 2006 +0100 1.3 @@ -1118,19 +1118,17 @@ static void svm_dr_access (struct vcpu * 1.4 } 1.5 1.6 1.7 -static unsigned int check_for_null_selector(struct vmcb_struct *vmcb, 1.8 - unsigned int dir, unsigned long *base, unsigned int real) 1.9 - 1.10 +static void svm_get_prefix_info(struct vmcb_struct *vmcb, 1.11 + unsigned int dir, segment_selector_t **seg, unsigned int *asize) 1.12 { 1.13 unsigned char inst[MAX_INST_LEN]; 1.14 - segment_selector_t seg; 1.15 int i; 1.16 1.17 memset(inst, 0, MAX_INST_LEN); 1.18 if (inst_copy_from_guest(inst, svm_rip2pointer(vmcb), sizeof(inst)) 1.19 != MAX_INST_LEN) 1.20 { 1.21 - printk("check_for_null_selector: get guest instruction failed\n"); 1.22 + printk("%s: get guest instruction failed\n", __func__); 1.23 domain_crash_synchronous(); 1.24 } 1.25 1.26 @@ -1142,7 +1140,6 @@ static unsigned int check_for_null_selec 1.27 case 0xf2: /* REPNZ */ 1.28 case 0xf0: /* LOCK */ 1.29 case 0x66: /* data32 */ 1.30 - case 0x67: /* addr32 */ 1.31 #if __x86_64__ 1.32 /* REX prefixes */ 1.33 case 0x40: 1.34 @@ -1164,79 +1161,127 @@ static unsigned int check_for_null_selec 1.35 case 0x4f: 1.36 #endif 1.37 continue; 1.38 + case 0x67: /* addr32 */ 1.39 + *asize ^= 48; /* Switch 16/32 bits */ 1.40 + continue; 1.41 case 0x2e: /* CS */ 1.42 - seg = vmcb->cs; 1.43 - break; 1.44 + *seg = &vmcb->cs; 1.45 + continue; 1.46 case 0x36: /* SS */ 1.47 - seg = vmcb->ss; 1.48 - break; 1.49 + *seg = &vmcb->ss; 1.50 + continue; 1.51 case 0x26: /* ES */ 1.52 - seg = vmcb->es; 1.53 - break; 1.54 + *seg = &vmcb->es; 1.55 + continue; 1.56 case 0x64: /* FS */ 1.57 - seg = vmcb->fs; 1.58 - break; 1.59 + *seg = &vmcb->fs; 1.60 + continue; 1.61 case 0x65: /* GS */ 1.62 - seg = vmcb->gs; 1.63 - break; 1.64 + *seg = &vmcb->gs; 1.65 + continue; 1.66 case 0x3e: /* DS */ 1.67 - /* FALLTHROUGH */ 1.68 - seg = vmcb->ds; 1.69 - break; 1.70 + *seg = &vmcb->ds; 1.71 + continue; 1.72 default: 1.73 - if (dir == IOREQ_READ) /* IN/INS instruction? */ 1.74 - seg = vmcb->es; 1.75 - else 1.76 - seg = vmcb->ds; 1.77 + break; 1.78 } 1.79 - 1.80 - if (base) 1.81 - *base = seg.base; 1.82 - 1.83 - return seg.attributes.fields.p; 1.84 + return; 1.85 } 1.86 - 1.87 - ASSERT(0); 1.88 - return 0; 1.89 } 1.90 1.91 1.92 /* Get the address of INS/OUTS instruction */ 1.93 -static inline unsigned long svm_get_io_address(struct vmcb_struct *vmcb, 1.94 - struct cpu_user_regs *regs, unsigned int dir, unsigned int real) 1.95 +static inline int svm_get_io_address(struct vmcb_struct *vmcb, 1.96 + struct cpu_user_regs *regs, unsigned int dir, 1.97 + unsigned long *count, unsigned long *addr) 1.98 { 1.99 - unsigned long addr = 0; 1.100 - unsigned long base = 0; 1.101 - 1.102 - check_for_null_selector(vmcb, dir, &base, real); 1.103 + unsigned long reg; 1.104 + unsigned int asize = 0; 1.105 + unsigned int isize; 1.106 + int long_mode; 1.107 + ioio_info_t info; 1.108 + segment_selector_t *seg = NULL; 1.109 + 1.110 + info.bytes = vmcb->exitinfo1; 1.111 + 1.112 + /* If we're in long mode, we shouldn't check the segment presence and limit */ 1.113 + long_mode = vmcb->cs.attributes.fields.l && vmcb->efer & EFER_LMA; 1.114 + 1.115 + /* d field of cs.attributes is 1 for 32-bit, 0 for 16 or 64 bit. 1.116 + * l field combined with EFER_LMA -> longmode says whether it's 16 or 64 bit. 1.117 + */ 1.118 + asize = (long_mode)?64:((vmcb->cs.attributes.fields.db)?32:16); 1.119 + 1.120 + 1.121 + /* The ins/outs instructions are single byte, so if we have got more 1.122 + * than one byte (+ maybe rep-prefix), we have some prefix so we need 1.123 + * to figure out what it is... 1.124 + */ 1.125 + isize = vmcb->exitinfo2 - vmcb->rip; 1.126 + 1.127 + if (info.fields.rep) 1.128 + isize --; 1.129 + 1.130 + if (isize > 1) 1.131 + { 1.132 + svm_get_prefix_info(vmcb, dir, &seg, &asize); 1.133 + } 1.134 + 1.135 + ASSERT(dir == IOREQ_READ || dir == IOREQ_WRITE); 1.136 1.137 if (dir == IOREQ_WRITE) 1.138 { 1.139 - if (real) 1.140 - addr = (regs->esi & 0xFFFF) + base; 1.141 - else 1.142 - addr = regs->esi + base; 1.143 + reg = regs->esi; 1.144 + if (!seg) /* If no prefix, used DS. */ 1.145 + seg = &vmcb->ds; 1.146 } 1.147 else 1.148 { 1.149 - if (real) 1.150 - addr = (regs->edi & 0xFFFF) + base; 1.151 - else 1.152 - addr = regs->edi + base; 1.153 + reg = regs->edi; 1.154 + seg = &vmcb->es; /* Note: This is ALWAYS ES. */ 1.155 + } 1.156 + 1.157 + /* If the segment isn't present, give GP fault! */ 1.158 + if (!long_mode && !seg->attributes.fields.p) 1.159 + { 1.160 + svm_inject_exception(vmcb, TRAP_gp_fault, 1, seg->sel); 1.161 + return 0; 1.162 + } 1.163 + 1.164 + if (asize == 16) 1.165 + { 1.166 + *addr = (reg & 0xFFFF); 1.167 + *count = regs->ecx & 0xffff; 1.168 } 1.169 - 1.170 - return addr; 1.171 + else 1.172 + { 1.173 + *addr = reg; 1.174 + *count = regs->ecx; 1.175 + } 1.176 + 1.177 + if (!long_mode) { 1.178 + if (*addr > seg->limit) 1.179 + { 1.180 + svm_inject_exception(vmcb, TRAP_gp_fault, 1, seg->sel); 1.181 + return 0; 1.182 + } 1.183 + else 1.184 + { 1.185 + *addr += seg->base; 1.186 + } 1.187 + } 1.188 + 1.189 + 1.190 + return 1; 1.191 } 1.192 1.193 1.194 static void svm_io_instruction(struct vcpu *v, struct cpu_user_regs *regs) 1.195 { 1.196 struct mmio_op *mmio_opp; 1.197 - unsigned long eip, cs, eflags, cr0; 1.198 - unsigned long port; 1.199 - unsigned int real, size, dir; 1.200 + unsigned int port; 1.201 + unsigned int size, dir; 1.202 ioio_info_t info; 1.203 - 1.204 struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; 1.205 1.206 ASSERT(vmcb); 1.207 @@ -1244,10 +1289,6 @@ static void svm_io_instruction(struct vc 1.208 mmio_opp->instr = INSTR_PIO; 1.209 mmio_opp->flags = 0; 1.210 1.211 - eip = vmcb->rip; 1.212 - cs = vmcb->cs.sel; 1.213 - eflags = vmcb->rflags; 1.214 - 1.215 info.bytes = vmcb->exitinfo1; 1.216 1.217 port = info.fields.port; /* port used to be addr */ 1.218 @@ -1259,27 +1300,33 @@ static void svm_io_instruction(struct vc 1.219 else 1.220 size = 1; 1.221 1.222 - cr0 = vmcb->cr0; 1.223 - real = (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE); 1.224 - 1.225 HVM_DBG_LOG(DBG_LEVEL_IO, 1.226 - "svm_io_instruction: port 0x%lx real %d, eip=%lx:%lx, " 1.227 + "svm_io_instruction: port 0x%x eip=%lx:%lx, " 1.228 "exit_qualification = %lx", 1.229 - (unsigned long) port, real, cs, eip, (unsigned long)info.bytes); 1.230 + port, vmcb->cs.sel, vmcb->rip, (unsigned long)info.bytes); 1.231 /* string instruction */ 1.232 if (info.fields.str) 1.233 { 1.234 - unsigned long addr, count = 1; 1.235 + unsigned long addr, count; 1.236 int sign = regs->eflags & EF_DF ? -1 : 1; 1.237 1.238 - /* Need the original rip, here. */ 1.239 - addr = svm_get_io_address(vmcb, regs, dir, real); 1.240 + if (!svm_get_io_address(vmcb, regs, dir, &count, &addr)) 1.241 + { 1.242 + /* We failed to get a valid address, so don't do the IO operation - 1.243 + * it would just get worse if we do! Hopefully the guest is handing 1.244 + * gp-faults... 1.245 + */ 1.246 + return; 1.247 + } 1.248 1.249 /* "rep" prefix */ 1.250 if (info.fields.rep) 1.251 { 1.252 mmio_opp->flags |= REPZ; 1.253 - count = real ? regs->ecx & 0xFFFF : regs->ecx; 1.254 + } 1.255 + else 1.256 + { 1.257 + count = 1; 1.258 } 1.259 1.260 /*