Commit 996ba96a authored by Rusty Russell's avatar Rusty Russell

lguest: Fix in/out emulation

We were blatting too much of the register.  Linux didn't care, but in
theory it might.
Reported-by: default avatarJonas Maebe <jonas.maebe@elis.ugent.be>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 8d431f41
...@@ -269,7 +269,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu) ...@@ -269,7 +269,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
static int emulate_insn(struct lg_cpu *cpu) static int emulate_insn(struct lg_cpu *cpu)
{ {
u8 insn; u8 insn;
unsigned int insnlen = 0, in = 0, shift = 0; unsigned int insnlen = 0, in = 0, small_operand = 0;
/* /*
* The eip contains the *virtual* address of the Guest's instruction: * The eip contains the *virtual* address of the Guest's instruction:
* walk the Guest's page tables to find the "physical" address. * walk the Guest's page tables to find the "physical" address.
...@@ -300,11 +300,10 @@ static int emulate_insn(struct lg_cpu *cpu) ...@@ -300,11 +300,10 @@ static int emulate_insn(struct lg_cpu *cpu)
} }
/* /*
* 0x66 is an "operand prefix". It means it's using the upper 16 bits * 0x66 is an "operand prefix". It means a 16, not 32 bit in/out.
* of the eax register.
*/ */
if (insn == 0x66) { if (insn == 0x66) {
shift = 16; small_operand = 1;
/* The instruction is 1 byte so far, read the next byte. */ /* The instruction is 1 byte so far, read the next byte. */
insnlen = 1; insnlen = 1;
insn = lgread(cpu, physaddr + insnlen, u8); insn = lgread(cpu, physaddr + insnlen, u8);
...@@ -340,11 +339,14 @@ static int emulate_insn(struct lg_cpu *cpu) ...@@ -340,11 +339,14 @@ static int emulate_insn(struct lg_cpu *cpu)
* traditionally means "there's nothing there". * traditionally means "there's nothing there".
*/ */
if (in) { if (in) {
/* Lower bit tells is whether it's a 16 or 32 bit access */ /* Lower bit tells means it's a 32/16 bit access */
if (insn & 0x1) if (insn & 0x1) {
cpu->regs->eax = 0xFFFFFFFF; if (small_operand)
else cpu->regs->eax |= 0xFFFF;
cpu->regs->eax |= (0xFFFF << shift); else
cpu->regs->eax = 0xFFFFFFFF;
} else
cpu->regs->eax |= 0xFF;
} }
/* Finally, we've "done" the instruction, so move past it. */ /* Finally, we've "done" the instruction, so move past it. */
cpu->regs->eip += insnlen; cpu->regs->eip += insnlen;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment