diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2011-07-22 01:09:51 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2011-07-22 01:09:51 -0400 |
commit | 996ba96a97f7406052486682846d68935a60e986 (patch) | |
tree | f02f603742129314a497d3406b02a7f929893d9c /drivers/lguest/x86 | |
parent | 8d431f41603acff8a20cf5df99bc8958c91879c1 (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.c | 20 |
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) | |||
269 | static int emulate_insn(struct lg_cpu *cpu) | 269 | static 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; |