aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest/x86
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2011-07-22 01:09:51 -0400
committerRusty Russell <rusty@rustcorp.com.au>2011-07-22 01:09:51 -0400
commit996ba96a97f7406052486682846d68935a60e986 (patch)
treef02f603742129314a497d3406b02a7f929893d9c /drivers/lguest/x86
parent8d431f41603acff8a20cf5df99bc8958c91879c1 (diff)
lguest: Fix in/out emulation
We were blatting too much of the register. Linux didn't care, but in theory it might. Reported-by: Jonas Maebe <jonas.maebe@elis.ugent.be> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/lguest/x86')
-rw-r--r--drivers/lguest/x86/core.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index 3b9b810cbf28..65af42f2d593 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -269,7 +269,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
269static int emulate_insn(struct lg_cpu *cpu) 269static int emulate_insn(struct lg_cpu *cpu)
270{ 270{
271 u8 insn; 271 u8 insn;
272 unsigned int insnlen = 0, in = 0, shift = 0; 272 unsigned int insnlen = 0, in = 0, small_operand = 0;
273 /* 273 /*
274 * The eip contains the *virtual* address of the Guest's instruction: 274 * The eip contains the *virtual* address of the Guest's instruction:
275 * walk the Guest's page tables to find the "physical" address. 275 * walk the Guest's page tables to find the "physical" address.
@@ -300,11 +300,10 @@ static int emulate_insn(struct lg_cpu *cpu)
300 } 300 }
301 301
302 /* 302 /*
303 * 0x66 is an "operand prefix". It means it's using the upper 16 bits 303 * 0x66 is an "operand prefix". It means a 16, not 32 bit in/out.
304 * of the eax register.
305 */ 304 */
306 if (insn == 0x66) { 305 if (insn == 0x66) {
307 shift = 16; 306 small_operand = 1;
308 /* The instruction is 1 byte so far, read the next byte. */ 307 /* The instruction is 1 byte so far, read the next byte. */
309 insnlen = 1; 308 insnlen = 1;
310 insn = lgread(cpu, physaddr + insnlen, u8); 309 insn = lgread(cpu, physaddr + insnlen, u8);
@@ -340,11 +339,14 @@ static int emulate_insn(struct lg_cpu *cpu)
340 * traditionally means "there's nothing there". 339 * traditionally means "there's nothing there".
341 */ 340 */
342 if (in) { 341 if (in) {
343 /* Lower bit tells is whether it's a 16 or 32 bit access */ 342 /* Lower bit tells means it's a 32/16 bit access */
344 if (insn & 0x1) 343 if (insn & 0x1) {
345 cpu->regs->eax = 0xFFFFFFFF; 344 if (small_operand)
346 else 345 cpu->regs->eax |= 0xFFFF;
347 cpu->regs->eax |= (0xFFFF << shift); 346 else
347 cpu->regs->eax = 0xFFFFFFFF;
348 } else
349 cpu->regs->eax |= 0xFF;
348 } 350 }
349 /* Finally, we've "done" the instruction, so move past it. */ 351 /* Finally, we've "done" the instruction, so move past it. */
350 cpu->regs->eip += insnlen; 352 cpu->regs->eip += insnlen;