diff options
| author | Rusty Russell <rusty@rustcorp.com.au> | 2011-07-22 14:39:51 +0930 | 
|---|---|---|
| committer | Rusty Russell <rusty@rustcorp.com.au> | 2011-07-22 14:39:51 +0930 | 
| commit | 996ba96a97f7406052486682846d68935a60e986 (patch) | |
| tree | f02f603742129314a497d3406b02a7f929893d9c /drivers/lguest | |
| 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')
| -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)  static int emulate_insn(struct lg_cpu *cpu)  {  	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:  	 * walk the Guest's page tables to find the "physical" address. @@ -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 -	 * of the eax register. +	 * 0x66 is an "operand prefix".  It means a 16, not 32 bit in/out.  	 */  	if (insn == 0x66) { -		shift = 16; +		small_operand = 1;  		/* The instruction is 1 byte so far, read the next byte. */  		insnlen = 1;  		insn = lgread(cpu, physaddr + insnlen, u8); @@ -340,11 +339,14 @@ static int emulate_insn(struct lg_cpu *cpu)  	 * traditionally means "there's nothing there".  	 */  	if (in) { -		/* Lower bit tells is whether it's a 16 or 32 bit access */ -		if (insn & 0x1) -			cpu->regs->eax = 0xFFFFFFFF; -		else -			cpu->regs->eax |= (0xFFFF << shift); +		/* Lower bit tells means it's a 32/16 bit access */ +		if (insn & 0x1) { +			if (small_operand) +				cpu->regs->eax |= 0xFFFF; +			else +				cpu->regs->eax = 0xFFFFFFFF; +		} else +			cpu->regs->eax |= 0xFF;  	}  	/* Finally, we've "done" the instruction, so move past it. */  	cpu->regs->eip += insnlen; | 
