diff mbox

[9/9] KVM: x86: smsw emulation is incorrect in 64-bit mode

Message ID 1401723251-8034-10-git-send-email-namit@cs.technion.ac.il (mailing list archive)
State New, archived
Headers show

Commit Message

Nadav Amit June 2, 2014, 3:34 p.m. UTC
In 64-bit mode, when the destination is a register, the assignment is done
according to the operand size. Otherwise (memory operand or no 64-bit mode), a
16-bit assignment is performed.

Currently, 16-bit assignment is always done to the destination.

Signed-off-by: Nadav Amit <namit@cs.technion.ac.il>
---
 arch/x86/kvm/emulate.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Paolo Bonzini June 5, 2014, 2:53 p.m. UTC | #1
Il 02/06/2014 17:34, Nadav Amit ha scritto:
> In 64-bit mode, when the destination is a register, the assignment is done
> according to the operand size. Otherwise (memory operand or no 64-bit mode), a
> 16-bit assignment is performed.

I'm sorry, I'm missing the place where 64-bit mode is taken into account?

Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Nadav Amit June 5, 2014, 3:02 p.m. UTC | #2
On Jun 5, 2014, at 5:53 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:

> Il 02/06/2014 17:34, Nadav Amit ha scritto:
>> In 64-bit mode, when the destination is a register, the assignment is done
>> according to the operand size. Otherwise (memory operand or no 64-bit mode), a
>> 16-bit assignment is performed.
> 
> I'm sorry, I'm missing the place where 64-bit mode is taken into account?
It is not, since on 32-bit mode the high-order 16 bits of a register destination are undefined. 
If I recall correctly, in this case the high-order 16-bits on native system actually reflect the high-order 16-bits of CR0.

Therefore, regardless to the mode of operation:
1. If the target is memory - the destination is 16-bit
2. If the target is a register - the register is written according to the operand size.

Nadav--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
H. Peter Anvin June 5, 2014, 3:04 p.m. UTC | #3
On 06/05/2014 08:02 AM, Nadav Amit wrote:
>> I'm sorry, I'm missing the place where 64-bit mode is taken into account?
> It is not, since on 32-bit mode the high-order 16 bits of a register destination are undefined. 
> If I recall correctly, in this case the high-order 16-bits on native
system actually reflect the high-order 16-bits of CR0.

This sounds like something that really should be verified
experimentally.  The above claim seems... odd.

	-hpa


--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Paolo Bonzini June 5, 2014, 3:27 p.m. UTC | #4
Il 05/06/2014 17:04, H. Peter Anvin ha scritto:
> On 06/05/2014 08:02 AM, Nadav Amit wrote:
>>> I'm sorry, I'm missing the place where 64-bit mode is taken into account?
>> It is not, since on 32-bit mode the high-order 16 bits of a register destination are undefined.
>> If I recall correctly, in this case the high-order 16-bits on native
> system actually reflect the high-order 16-bits of CR0.
>
> This sounds like something that really should be verified
> experimentally.  The above claim seems... odd.

Here is a test program:

#if __SIZEOF_LONG__ == 4
#define V "12345678"
#define R "e"
#else
#define V "1234567812345678"
#define R "r"
#endif

#include <stdio.h>
int main()
{
	register volatile unsigned long ecx asm("ecx");

#if __SIZEOF_LONG__ > 4
	asm volatile("mov $0x" V ", %%" R "cx; smswq %%rcx": : :"ecx");
	printf("smswq: %lx\n", ecx);
#endif

	asm volatile("mov $0x" V ", %%" R "cx; smswl %%ecx": : :"ecx");
	printf("smswl: %lx\n", ecx);

	asm volatile("mov $0x" V ", %%" R "cx; smsww %%cx": : :"ecx");
	printf("smsww: %lx\n", ecx);
}

Output in 32-bit mode:
smswq: 80050033
smswl: 12340033

Output in 64-bit mode:
smswq: 80050033
smswl: 80050033
smsww: 1234567812340033

Can you please make a test case for kvm-unit-tests (x86/emulator.c), in 
order to check the validity of the patch?

Paolo
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Nadav Amit June 5, 2014, 11:56 p.m. UTC | #5
This patch set adds two tests for smsw. The first one is intended to add
coverage of smsw. It covers the case smsw is executed with memory operand in a
page which is write-protected by the hypervisor. Note that the existing smsw
tests are not supposed to be trapped by the hypervisor. This test was added
just for additional coverage.

The realmode smsw test covers the recent patch that saves the high 16-bits to
32-bit register operand. Implementing a long-mode test is difficult since we
need to cause an "invalid guest state" in long-mode.

Nadav Amit (2):
  x86: emulator: additional smsw test-case
  x86: realmode: test smsw behavior with register operand

 x86/emulator.c | 10 ++++++++--
 x86/realmode.c | 15 +++++++++++++++
 2 files changed, 23 insertions(+), 2 deletions(-)
Paolo Bonzini June 6, 2014, 8:04 a.m. UTC | #6
Il 06/06/2014 01:56, Nadav Amit ha scritto:
> This patch set adds two tests for smsw. The first one is intended to add
> coverage of smsw. It covers the case smsw is executed with memory operand in a
> page which is write-protected by the hypervisor. Note that the existing smsw
> tests are not supposed to be trapped by the hypervisor. This test was added
> just for additional coverage.
>
> The realmode smsw test covers the recent patch that saves the high 16-bits to
> 32-bit register operand. Implementing a long-mode test is difficult since we
> need to cause an "invalid guest state" in long-mode.

You can use emulator.flat to test the emulator in long mode.

See test_movabs for an example.

Paolo

> Nadav Amit (2):
>   x86: emulator: additional smsw test-case
>   x86: realmode: test smsw behavior with register operand
>
>  x86/emulator.c | 10 ++++++++--
>  x86/realmode.c | 15 +++++++++++++++
>  2 files changed, 23 insertions(+), 2 deletions(-)
>

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index a151f8d..9b5d97d 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -3235,7 +3235,8 @@  static int em_lidt(struct x86_emulate_ctxt *ctxt)
 
 static int em_smsw(struct x86_emulate_ctxt *ctxt)
 {
-	ctxt->dst.bytes = 2;
+	if (ctxt->dst.type == OP_MEM)
+		ctxt->dst.bytes = 2;
 	ctxt->dst.val = ctxt->ops->get_cr(ctxt, 0);
 	return X86EMUL_CONTINUE;
 }