ia64/xen-unstable
changeset 16238:b100412f621c
hvm,x86: Add more vmxassist opcodes for Ubuntu 7.0.4 support
Signed-off-by: Ben Guthro <bguthro@virtualron.com>
Signed-off-by: Gary Grebus <ggrebus@virtualiron.com>
Signed-off-by: Ben Guthro <bguthro@virtualron.com>
Signed-off-by: Gary Grebus <ggrebus@virtualiron.com>
author | Keir Fraser <keir@xensource.com> |
---|---|
date | Thu Oct 25 14:55:37 2007 +0100 (2007-10-25) |
parents | a4df9c0c33fd |
children | b4060976cf5e |
files | tools/firmware/vmxassist/machine.h tools/firmware/vmxassist/vm86.c |
line diff
1.1 --- a/tools/firmware/vmxassist/machine.h Thu Oct 25 14:45:47 2007 +0100 1.2 +++ b/tools/firmware/vmxassist/machine.h Thu Oct 25 14:55:37 2007 +0100 1.3 @@ -38,10 +38,15 @@ 1.4 #define CR4_PSE (1 << 4) 1.5 #define CR4_PAE (1 << 5) 1.6 1.7 +#define EFLAGS_CF (1 << 0) 1.8 +#define EFLAGS_PF (1 << 2) 1.9 +#define EFLAGS_AF (1 << 4) 1.10 #define EFLAGS_ZF (1 << 6) 1.11 +#define EFLAGS_SF (1 << 7) 1.12 #define EFLAGS_TF (1 << 8) 1.13 #define EFLAGS_IF (1 << 9) 1.14 #define EFLAGS_DF (1 << 10) 1.15 +#define EFLAGS_OF (1 << 11) 1.16 #define EFLAGS_IOPL (3 << 12) 1.17 #define EFLAGS_VM ((1 << 17) | EFLAGS_IOPL) 1.18 #define EFLAGS_VIF (1 << 19)
2.1 --- a/tools/firmware/vmxassist/vm86.c Thu Oct 25 14:45:47 2007 +0100 2.2 +++ b/tools/firmware/vmxassist/vm86.c Thu Oct 25 14:55:37 2007 +0100 2.3 @@ -33,6 +33,7 @@ 2.4 #define SEG_SS 0x0020 2.5 #define SEG_FS 0x0040 2.6 #define SEG_GS 0x0080 2.7 +#define REP 0x0100 2.8 2.9 static unsigned prev_eip = 0; 2.10 enum vm86_mode mode = 0; 2.11 @@ -656,6 +657,108 @@ movr(struct regs *regs, unsigned prefix, 2.12 } 2.13 2.14 /* 2.15 + * We need to handle string moves that address memory beyond the 64KB segment 2.16 + * limit that VM8086 mode enforces. 2.17 + */ 2.18 +static inline int 2.19 +movs(struct regs *regs, unsigned prefix, unsigned opc) 2.20 +{ 2.21 + unsigned eip = regs->eip - 1; 2.22 + unsigned sseg = segment(prefix, regs, regs->vds); 2.23 + unsigned dseg = regs->ves; 2.24 + unsigned saddr, daddr; 2.25 + unsigned count = 1; 2.26 + int incr = ((regs->eflags & EFLAGS_DF) == 0) ? 1 : -1; 2.27 + 2.28 + saddr = address(regs, sseg, regs->esi); 2.29 + daddr = address(regs, dseg, regs->edi); 2.30 + 2.31 + if ((prefix & REP) != 0) { 2.32 + count = regs->ecx; 2.33 + regs->ecx = 0; 2.34 + } 2.35 + 2.36 + switch (opc) { 2.37 + case 0xA4: /* movsb */ 2.38 + regs->esi += (incr * count); 2.39 + regs->edi += (incr * count); 2.40 + 2.41 + while (count-- != 0) { 2.42 + write8(daddr, read8(saddr)); 2.43 + daddr += incr; 2.44 + saddr += incr; 2.45 + } 2.46 + TRACE((regs, regs->eip - eip, "movsb (%%esi),%%es:(%%edi)")); 2.47 + break; 2.48 + 2.49 + case 0xA5: /* movsw */ 2.50 + if ((prefix & DATA32) == 0) { 2.51 + incr = 2 * incr; 2.52 + regs->esi += (incr * count); 2.53 + regs->edi += (incr * count); 2.54 + 2.55 + while (count-- != 0) { 2.56 + write16(daddr, read16(saddr)); 2.57 + daddr += incr; 2.58 + saddr += incr; 2.59 + } 2.60 + } else { 2.61 + incr = 4 * incr; 2.62 + regs->esi += (incr * count); 2.63 + regs->edi += (incr * count); 2.64 + 2.65 + while (count-- != 0) { 2.66 + write32(daddr, read32(saddr)); 2.67 + daddr += incr; 2.68 + saddr += incr; 2.69 + } 2.70 + } 2.71 + TRACE((regs, regs->eip - eip, "movsw %s(%%esi),%%es:(%%edi)")); 2.72 + break; 2.73 + } 2.74 + 2.75 + return 1; 2.76 +} 2.77 + 2.78 +static inline int 2.79 +lods(struct regs *regs, unsigned prefix, unsigned opc) 2.80 +{ 2.81 + unsigned eip = regs->eip - 1; 2.82 + unsigned seg = segment(prefix, regs, regs->vds); 2.83 + unsigned addr = address(regs, seg, regs->esi); 2.84 + unsigned count = 1; 2.85 + int incr = ((regs->eflags & EFLAGS_DF) == 0) ? 1 : -1; 2.86 + 2.87 + if ((prefix & REP) != 0) { 2.88 + count = regs->ecx; 2.89 + regs->ecx = 0; 2.90 + } 2.91 + 2.92 + switch (opc) { 2.93 + case 0xAD: /* lodsw */ 2.94 + if ((prefix & DATA32) == 0) { 2.95 + incr = 2 * incr; 2.96 + regs->esi += (incr * count); 2.97 + while (count-- != 0) { 2.98 + setreg16(regs, 0, read16(addr)); 2.99 + addr += incr; 2.100 + } 2.101 + 2.102 + TRACE((regs, regs->eip - eip, "lodsw (%%esi),%%ax")); 2.103 + } else { 2.104 + incr = 4 * incr; 2.105 + regs->esi += (incr * count); 2.106 + while (count-- != 0) { 2.107 + setreg32(regs, 0, read32(addr)); 2.108 + addr += incr; 2.109 + } 2.110 + TRACE((regs, regs->eip - eip, "lodsw (%%esi),%%eax")); 2.111 + } 2.112 + break; 2.113 + } 2.114 + return 1; 2.115 +} 2.116 +/* 2.117 * Move to and from a control register. 2.118 */ 2.119 static int 2.120 @@ -718,6 +821,55 @@ static inline void set_eflags_ZF(unsigne 2.121 regs->eflags &= ~EFLAGS_ZF; 2.122 } 2.123 2.124 +static void set_eflags_add(unsigned hi_bit_mask, unsigned v1, unsigned v2, 2.125 + unsigned result, struct regs *regs) 2.126 +{ 2.127 + int bit_count; 2.128 + unsigned tmp; 2.129 + unsigned full_mask; 2.130 + unsigned nonsign_mask; 2.131 + 2.132 + /* Carry out of high order bit? */ 2.133 + if ( v1 & v2 & hi_bit_mask ) 2.134 + regs->eflags |= EFLAGS_CF; 2.135 + else 2.136 + regs->eflags &= ~EFLAGS_CF; 2.137 + 2.138 + /* Even parity in least significant byte? */ 2.139 + tmp = result & 0xff; 2.140 + for (bit_count = 0; tmp != 0; bit_count++) 2.141 + tmp &= (tmp - 1); 2.142 + 2.143 + if (bit_count & 1) 2.144 + regs->eflags &= ~EFLAGS_PF; 2.145 + else 2.146 + regs->eflags |= EFLAGS_PF; 2.147 + 2.148 + /* Carry out of least significant BCD digit? */ 2.149 + if ( v1 & v2 & (1<<3) ) 2.150 + regs->eflags |= EFLAGS_AF; 2.151 + else 2.152 + regs->eflags &= ~EFLAGS_AF; 2.153 + 2.154 + /* Result is zero? */ 2.155 + full_mask = (hi_bit_mask - 1) | hi_bit_mask; 2.156 + set_eflags_ZF(full_mask, result, regs); 2.157 + 2.158 + /* Sign of result? */ 2.159 + if ( result & hi_bit_mask ) 2.160 + regs->eflags |= EFLAGS_SF; 2.161 + else 2.162 + regs->eflags &= ~EFLAGS_SF; 2.163 + 2.164 + /* Carry out of highest non-sign bit? */ 2.165 + nonsign_mask = (hi_bit_mask >> 1) & ~hi_bit_mask; 2.166 + if ( v1 & v2 & hi_bit_mask ) 2.167 + regs->eflags |= EFLAGS_OF; 2.168 + else 2.169 + regs->eflags &= ~EFLAGS_OF; 2.170 + 2.171 +} 2.172 + 2.173 /* 2.174 * We need to handle cmp opcodes that address memory beyond the 64KB 2.175 * segment limit that VM8086 mode enforces. 2.176 @@ -792,6 +944,82 @@ test(struct regs *regs, unsigned prefix, 2.177 } 2.178 2.179 /* 2.180 + * We need to handle add opcodes that address memory beyond the 64KB 2.181 + * segment limit that VM8086 mode enforces. 2.182 + */ 2.183 +static int 2.184 +add(struct regs *regs, unsigned prefix, unsigned opc) 2.185 +{ 2.186 + unsigned eip = regs->eip - 1; 2.187 + unsigned modrm = fetch8(regs); 2.188 + unsigned addr = operand(prefix, regs, modrm); 2.189 + unsigned r = (modrm >> 3) & 7; 2.190 + 2.191 + unsigned val1 = 0; 2.192 + unsigned val2 = 0; 2.193 + unsigned result = 0; 2.194 + unsigned hi_bit; 2.195 + 2.196 + if ((modrm & 0xC0) == 0xC0) /* no registers */ 2.197 + return 0; 2.198 + 2.199 + switch (opc) { 2.200 + case 0x00: /* addr32 add r8, r/m8 */ 2.201 + val1 = getreg8(regs, r); 2.202 + val2 = read8(addr); 2.203 + result = val1 + val2; 2.204 + write8(addr, result); 2.205 + TRACE((regs, regs->eip - eip, 2.206 + "addb %%e%s, *0x%x", rnames[r], addr)); 2.207 + break; 2.208 + 2.209 + case 0x01: /* addr32 add r16, r/m16 */ 2.210 + if (prefix & DATA32) { 2.211 + val1 = getreg32(regs, r); 2.212 + val2 = read32(addr); 2.213 + result = val1 + val2; 2.214 + write32(addr, result); 2.215 + TRACE((regs, regs->eip - eip, 2.216 + "addl %%e%s, *0x%x", rnames[r], addr)); 2.217 + } else { 2.218 + val1 = getreg16(regs, r); 2.219 + val2 = read16(addr); 2.220 + result = val1 + val2; 2.221 + write16(addr, result); 2.222 + TRACE((regs, regs->eip - eip, 2.223 + "addw %%e%s, *0x%x", rnames[r], addr)); 2.224 + } 2.225 + break; 2.226 + 2.227 + case 0x03: /* addr32 add r/m16, r16 */ 2.228 + if (prefix & DATA32) { 2.229 + val1 = getreg32(regs, r); 2.230 + val2 = read32(addr); 2.231 + result = val1 + val2; 2.232 + setreg32(regs, r, result); 2.233 + TRACE((regs, regs->eip - eip, 2.234 + "addl *0x%x, %%e%s", addr, rnames[r])); 2.235 + } else { 2.236 + val1 = getreg16(regs, r); 2.237 + val2 = read16(addr); 2.238 + result = val1 + val2; 2.239 + setreg16(regs, r, result); 2.240 + TRACE((regs, regs->eip - eip, 2.241 + "addw *0x%x, %%%s", addr, rnames[r])); 2.242 + } 2.243 + break; 2.244 + } 2.245 + 2.246 + if (opc == 0x00) 2.247 + hi_bit = (1<<7); 2.248 + else 2.249 + hi_bit = (prefix & DATA32) ? (1<<31) : (1<<15); 2.250 + set_eflags_add(hi_bit, val1, val2, result, regs); 2.251 + 2.252 + return 1; 2.253 +} 2.254 + 2.255 +/* 2.256 * We need to handle pop opcodes that address memory beyond the 64KB 2.257 * segment limit that VM8086 mode enforces. 2.258 */ 2.259 @@ -1314,6 +1542,18 @@ opcode(struct regs *regs) 2.260 2.261 for (;;) { 2.262 switch ((opc = fetch8(regs))) { 2.263 + 2.264 + case 0x00: /* addr32 add r8, r/m8 */ 2.265 + case 0x01: /* addr32 add r16, r/m16 */ 2.266 + case 0x03: /* addr32 add r/m16, r16 */ 2.267 + if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) 2.268 + goto invalid; 2.269 + if ((prefix & ADDR32) == 0) 2.270 + goto invalid; 2.271 + if (!add(regs, prefix, opc)) 2.272 + goto invalid; 2.273 + return OPC_EMULATED; 2.274 + 2.275 case 0x07: /* pop %es */ 2.276 regs->ves = (prefix & DATA32) ? 2.277 pop32(regs) : pop16(regs); 2.278 @@ -1510,6 +1750,21 @@ opcode(struct regs *regs) 2.279 return OPC_EMULATED; 2.280 } 2.281 2.282 + case 0xA4: /* movsb */ 2.283 + case 0xA5: /* movsw */ 2.284 + if ((prefix & ADDR32) == 0) 2.285 + goto invalid; 2.286 + if (!movs(regs, prefix, opc)) 2.287 + goto invalid; 2.288 + return OPC_EMULATED; 2.289 + 2.290 + case 0xAD: /* lodsw */ 2.291 + if ((prefix & ADDR32) == 0) 2.292 + goto invalid; 2.293 + if (!lods(regs, prefix, opc)) 2.294 + goto invalid; 2.295 + return OPC_EMULATED; 2.296 + 2.297 case 0xBB: /* mov bx, imm16 */ 2.298 { 2.299 int data; 2.300 @@ -1627,6 +1882,11 @@ opcode(struct regs *regs) 2.301 /* Do something power-saving here! */ 2.302 return OPC_EMULATED; 2.303 2.304 + case 0xF3: /* rep/repe/repz */ 2.305 + TRACE((regs, regs->eip - eip, "rep")); 2.306 + prefix |= REP; 2.307 + continue; 2.308 + 2.309 case 0xF6: /* addr32 testb $imm, r/m8 */ 2.310 if (!(prefix & ADDR32)) 2.311 goto invalid; 2.312 @@ -1660,6 +1920,7 @@ emulate(struct regs *regs) 2.313 { 2.314 unsigned flteip; 2.315 int nemul = 0; 2.316 + unsigned ip; 2.317 2.318 /* emulate as many instructions as possible */ 2.319 while (opcode(regs) != OPC_INVALID) 2.320 @@ -1668,6 +1929,12 @@ emulate(struct regs *regs) 2.321 /* detect the case where we are not making progress */ 2.322 if (nemul == 0 && prev_eip == regs->eip) { 2.323 flteip = address(regs, MASK16(regs->cs), regs->eip); 2.324 + 2.325 + printf("Undecoded sequence: \n"); 2.326 + for (ip=flteip; ip < flteip+16; ip++) 2.327 + printf("0x%02x ", read8(ip)); 2.328 + printf("\n"); 2.329 + 2.330 panic("Unknown opcode at %04x:%04x=0x%x", 2.331 MASK16(regs->cs), regs->eip, flteip); 2.332 } else