linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* RFC: Task switch emulation fails for VM86 mode
@ 2017-07-09  7:30 Wanpeng Li
  2017-07-10 10:50 ` Wanpeng Li
  0 siblings, 1 reply; 5+ messages in thread
From: Wanpeng Li @ 2017-07-09  7:30 UTC (permalink / raw)
  To: Paolo Bonzini, Radim Krcmar; +Cc: kvm, linux-kernel

Hi all,

I found that task switch emulation fails to work for VM86 mode if
guest state is invalid. It can be reproduced by running
kvm-unit-tests/taskswitch2.flat, EPT = 0 or EPT=1,
unrestricted_guest=N, emulate_invalid_guest_state=Y.

When EPT=1, unrestricted_guest=Y, emulate_invalid_state=Y, the trace
of kvm-unit-tests/taskswitch2.flat is like below:

kvm_entry: vcpu 0
kvm_exit: reason TASK_SWITCH rip 0x4008d0 info 40000058 0
kvm_entry: vcpu 0
kvm_exit: reason EXCEPTION_NMI rip 0x0 info 0 80000306
kvm_emulate_insn: 42000:0:0f 0b (0x2)
kvm_inj_exception: #UD (0x0)
kvm_entry: vcpu 0
kvm_exit: reason TASK_SWITCH rip 0x0 info c0000050 0
kvm_entry: vcpu 0

When EPT=1, unrestricted_guest=Y, emulate_invalid_state=Y, the trace
of kvm-unit-tests/taskswitch2.flat is like below, when emulating "0f
0b(#UD)" fails, it injects another #UD and triggers a task switch in
the kvm-unit-tests/taskswitch2.flat again.

kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
kvm_emulate_insn: 42000:0:0f 0b (0x2)
kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
kvm_inj_exception: #UD (0x0)
kvm_entry: vcpu 0
kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
kvm_emulate_insn: 42000:0:0f 0b (0x2)
kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
kvm_inj_exception: #UD (0x0)
kvm_entry: vcpu 0
kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
kvm_emulate_insn: 42000:0:0f 0b (0x2)
kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
kvm_inj_exception: #UD (0x0)
.....................

Then I try to add the task switch emulation in the
handle_invalid_guest_state() path, however, I will get TRIPLE FAULT.

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index f76efad..758f728 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -6312,11 +6312,15 @@ static int handle_invalid_guest_state(struct
kvm_vcpu *vcpu)
     u32 cpu_exec_ctrl;
     bool intr_window_requested;
     unsigned count = 130;
+    u32 exit_reason = vmx->exit_reason;

     cpu_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
     intr_window_requested = cpu_exec_ctrl & CPU_BASED_VIRTUAL_INTR_PENDING;

     while (vmx->emulation_required && count-- != 0) {
+        if (exit_reason == EXIT_REASON_TASK_SWITCH)
+            return handle_task_switch(vcpu);
+
         if (intr_window_requested && vmx_interrupt_allowed(vcpu))
             return handle_interrupt_window(&vmx->vcpu);


kvm_exit: reason TASK_SWITCH rip 0x4008d0 info 40000058 0
kvm_entry: vcpu 0
kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
kvm_entry: vcpu 0
kvm_exit: reason TRIPLE_FAULT rip 0xffff info 0 0
kvm_userspace_exit: reason KVM_EXIT_SHUTDOWN (8)

Any proposal is a great appreciated. :)

Regards,
Wanpeng Li

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: RFC: Task switch emulation fails for VM86 mode
  2017-07-09  7:30 RFC: Task switch emulation fails for VM86 mode Wanpeng Li
@ 2017-07-10 10:50 ` Wanpeng Li
  2017-07-10 15:48   ` Nadav Amit
  0 siblings, 1 reply; 5+ messages in thread
From: Wanpeng Li @ 2017-07-10 10:50 UTC (permalink / raw)
  To: Paolo Bonzini, Radim Krcmar; +Cc: kvm, linux-kernel, Jan Kiszka, Nadav Amit

Cc Nadav, Jan,
2017-07-09 15:30 GMT+08:00 Wanpeng Li <kernellwp@gmail.com>:
> Hi all,
>
> I found that task switch emulation fails to work for VM86 mode if
> guest state is invalid. It can be reproduced by running
> kvm-unit-tests/taskswitch2.flat, EPT = 0 or EPT=1,
> unrestricted_guest=N, emulate_invalid_guest_state=Y.
>
> When EPT=1, unrestricted_guest=Y, emulate_invalid_state=Y, the trace
> of kvm-unit-tests/taskswitch2.flat is like below:
>
> kvm_entry: vcpu 0
> kvm_exit: reason TASK_SWITCH rip 0x4008d0 info 40000058 0
> kvm_entry: vcpu 0
> kvm_exit: reason EXCEPTION_NMI rip 0x0 info 0 80000306
> kvm_emulate_insn: 42000:0:0f 0b (0x2)
> kvm_inj_exception: #UD (0x0)
> kvm_entry: vcpu 0
> kvm_exit: reason TASK_SWITCH rip 0x0 info c0000050 0
> kvm_entry: vcpu 0
>
> When EPT=1, unrestricted_guest=Y, emulate_invalid_state=Y, the trace
> of kvm-unit-tests/taskswitch2.flat is like below, when emulating "0f
> 0b(#UD)" fails, it injects another #UD and triggers a task switch in
> the kvm-unit-tests/taskswitch2.flat again.
>
> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
> kvm_emulate_insn: 42000:0:0f 0b (0x2)
> kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
> kvm_inj_exception: #UD (0x0)
> kvm_entry: vcpu 0
> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
> kvm_emulate_insn: 42000:0:0f 0b (0x2)
> kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
> kvm_inj_exception: #UD (0x0)
> kvm_entry: vcpu 0
> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
> kvm_emulate_insn: 42000:0:0f 0b (0x2)
> kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
> kvm_inj_exception: #UD (0x0)
> .....................
>
> Then I try to add the task switch emulation in the
> handle_invalid_guest_state() path, however, I will get TRIPLE FAULT.
>
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index f76efad..758f728 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -6312,11 +6312,15 @@ static int handle_invalid_guest_state(struct
> kvm_vcpu *vcpu)
>      u32 cpu_exec_ctrl;
>      bool intr_window_requested;
>      unsigned count = 130;
> +    u32 exit_reason = vmx->exit_reason;
>
>      cpu_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
>      intr_window_requested = cpu_exec_ctrl & CPU_BASED_VIRTUAL_INTR_PENDING;
>
>      while (vmx->emulation_required && count-- != 0) {
> +        if (exit_reason == EXIT_REASON_TASK_SWITCH)
> +            return handle_task_switch(vcpu);
> +
>          if (intr_window_requested && vmx_interrupt_allowed(vcpu))
>              return handle_interrupt_window(&vmx->vcpu);
>
>
> kvm_exit: reason TASK_SWITCH rip 0x4008d0 info 40000058 0
> kvm_entry: vcpu 0
> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
> kvm_entry: vcpu 0
> kvm_exit: reason TRIPLE_FAULT rip 0xffff info 0 0
> kvm_userspace_exit: reason KVM_EXIT_SHUTDOWN (8)
>
> Any proposal is a great appreciated. :)
>
> Regards,
> Wanpeng Li

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Task switch emulation fails for VM86 mode
  2017-07-10 10:50 ` Wanpeng Li
@ 2017-07-10 15:48   ` Nadav Amit
  2017-07-10 16:21     ` Paolo Bonzini
  0 siblings, 1 reply; 5+ messages in thread
From: Nadav Amit @ 2017-07-10 15:48 UTC (permalink / raw)
  To: Wanpeng Li; +Cc: Paolo Bonzini, Radim Krcmar, kvm, linux-kernel, Jan Kiszka

Wanpeng Li <kernellwp@gmail.com> wrote:

> Cc Nadav, Jan,
> 2017-07-09 15:30 GMT+08:00 Wanpeng Li <kernellwp@gmail.com>:
>> Hi all,
>> 
>> I found that task switch emulation fails to work for VM86 mode if
>> guest state is invalid. It can be reproduced by running
>> kvm-unit-tests/taskswitch2.flat, EPT = 0 or EPT=1,
>> unrestricted_guest=N, emulate_invalid_guest_state=Y.
>> 
>> When EPT=1, unrestricted_guest=Y, emulate_invalid_state=Y, the trace
>> of kvm-unit-tests/taskswitch2.flat is like below:
>> 
>> kvm_entry: vcpu 0
>> kvm_exit: reason TASK_SWITCH rip 0x4008d0 info 40000058 0
>> kvm_entry: vcpu 0
>> kvm_exit: reason EXCEPTION_NMI rip 0x0 info 0 80000306
>> kvm_emulate_insn: 42000:0:0f 0b (0x2)
>> kvm_inj_exception: #UD (0x0)
>> kvm_entry: vcpu 0
>> kvm_exit: reason TASK_SWITCH rip 0x0 info c0000050 0
>> kvm_entry: vcpu 0
>> 
>> When EPT=1, unrestricted_guest=Y, emulate_invalid_state=Y, the trace
>> of kvm-unit-tests/taskswitch2.flat is like below, when emulating "0f
>> 0b(#UD)" fails, it injects another #UD and triggers a task switch in
>> the kvm-unit-tests/taskswitch2.flat again.
>> 
>> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
>> kvm_emulate_insn: 42000:0:0f 0b (0x2)
>> kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
>> kvm_inj_exception: #UD (0x0)
>> kvm_entry: vcpu 0
>> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
>> kvm_emulate_insn: 42000:0:0f 0b (0x2)
>> kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
>> kvm_inj_exception: #UD (0x0)
>> kvm_entry: vcpu 0
>> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
>> kvm_emulate_insn: 42000:0:0f 0b (0x2)
>> kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
>> kvm_inj_exception: #UD (0x0)
>> .....................
>> 
>> Then I try to add the task switch emulation in the
>> handle_invalid_guest_state() path, however, I will get TRIPLE FAULT.
>> 
>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>> index f76efad..758f728 100644
>> --- a/arch/x86/kvm/vmx.c
>> +++ b/arch/x86/kvm/vmx.c
>> @@ -6312,11 +6312,15 @@ static int handle_invalid_guest_state(struct
>> kvm_vcpu *vcpu)
>>     u32 cpu_exec_ctrl;
>>     bool intr_window_requested;
>>     unsigned count = 130;
>> +    u32 exit_reason = vmx->exit_reason;
>> 
>>     cpu_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
>>     intr_window_requested = cpu_exec_ctrl & CPU_BASED_VIRTUAL_INTR_PENDING;
>> 
>>     while (vmx->emulation_required && count-- != 0) {
>> +        if (exit_reason == EXIT_REASON_TASK_SWITCH)
>> +            return handle_task_switch(vcpu);
>> +
>>         if (intr_window_requested && vmx_interrupt_allowed(vcpu))
>>             return handle_interrupt_window(&vmx->vcpu);
>> 
>> 
>> kvm_exit: reason TASK_SWITCH rip 0x4008d0 info 40000058 0
>> kvm_entry: vcpu 0
>> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
>> kvm_entry: vcpu 0
>> kvm_exit: reason TRIPLE_FAULT rip 0xffff info 0 0
>> kvm_userspace_exit: reason KVM_EXIT_SHUTDOWN (8)
>> 
>> Any proposal is a great appreciated. :)

I don’t see a (very) easy solution. The code was (apparently) never built to
deal with a task switch during an instruction emulation.

AFAIU kvm_task_switch() expects information about the task-switch from the
CPU “task-switch assist” mechanisms, and this information (or even the fact
that a task-switch is needed due to an exception) are unavailable from the
instruction emulator. The instruction emulator itself does not know to
emulate task-switches, e.g., during far CALL and JMP.

A complete solution is therefore complicated and requires some work. Your
specific problem may be addressed by detecting the injection of an exception
while having invalid guest state in vm86 in vmx_queue_exception() or in
handle_invalid_guest_state(), and emulating the “task-switch assist”
mechanism.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Task switch emulation fails for VM86 mode
  2017-07-10 15:48   ` Nadav Amit
@ 2017-07-10 16:21     ` Paolo Bonzini
  2017-07-10 19:26       ` Nadav Amit
  0 siblings, 1 reply; 5+ messages in thread
From: Paolo Bonzini @ 2017-07-10 16:21 UTC (permalink / raw)
  To: Nadav Amit, Wanpeng Li; +Cc: Radim Krcmar, kvm, linux-kernel, Jan Kiszka

On 10/07/2017 17:48, Nadav Amit wrote:
>>>
>>> Any proposal is a great appreciated. :)
> I don’t see a (very) easy solution. The code was (apparently) never built to
> deal with a task switch during an instruction emulation.
> 
> AFAIU kvm_task_switch() expects information about the task-switch from the
> CPU “task-switch assist” mechanisms, and this information (or even the fact
> that a task-switch is needed due to an exception) are unavailable from the
> instruction emulator. The instruction emulator itself does not know to
> emulate task-switches, e.g., during far CALL and JMP.
> 
> A complete solution is therefore complicated and requires some work. Your
> specific problem may be addressed by detecting the injection of an exception
> while having invalid guest state in vm86 in vmx_queue_exception() or in
> handle_invalid_guest_state(), and emulating the “task-switch assist”
> mechanism.

I agree, the right solution would be to read the IDT in
vmx_queue_exception if vmx->emulation_required, and inject the exception
manually.  It would be an extension of what
kvm_inject_realmode_interrupt already does.

Paolo

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: RFC: Task switch emulation fails for VM86 mode
  2017-07-10 16:21     ` Paolo Bonzini
@ 2017-07-10 19:26       ` Nadav Amit
  0 siblings, 0 replies; 5+ messages in thread
From: Nadav Amit @ 2017-07-10 19:26 UTC (permalink / raw)
  To: Paolo Bonzini, Wanpeng Li; +Cc: Radim Krcmar, kvm, linux-kernel, Jan Kiszka

Paolo Bonzini <pbonzini@redhat.com> wrote:

> On 10/07/2017 17:48, Nadav Amit wrote:
>>>> Any proposal is a great appreciated. :)
>> I don’t see a (very) easy solution. The code was (apparently) never built to
>> deal with a task switch during an instruction emulation.
>> 
>> AFAIU kvm_task_switch() expects information about the task-switch from the
>> CPU “task-switch assist” mechanisms, and this information (or even the fact
>> that a task-switch is needed due to an exception) are unavailable from the
>> instruction emulator. The instruction emulator itself does not know to
>> emulate task-switches, e.g., during far CALL and JMP.
>> 
>> A complete solution is therefore complicated and requires some work. Your
>> specific problem may be addressed by detecting the injection of an exception
>> while having invalid guest state in vm86 in vmx_queue_exception() or in
>> handle_invalid_guest_state(), and emulating the “task-switch assist”
>> mechanism.
> 
> I agree, the right solution would be to read the IDT in
> vmx_queue_exception if vmx->emulation_required, and inject the exception
> manually.  It would be an extension of what
> kvm_inject_realmode_interrupt already does.

I take it back. While everything I said is true, there is no reason for the
guest state to be invalid in vm86, at least in the unit-test. It appears
that the task-switch emulation updates rflags (and vm86 flag) only after the
segments are loaded, causing vmx->emulation_required to be set, when in fact
emulation is not needed.

And indeed adding in the end of handle_task_switch():

	vmx->emulation_required = emulation_required(vcpu); 

solves the problem for me.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-07-10 19:26 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-09  7:30 RFC: Task switch emulation fails for VM86 mode Wanpeng Li
2017-07-10 10:50 ` Wanpeng Li
2017-07-10 15:48   ` Nadav Amit
2017-07-10 16:21     ` Paolo Bonzini
2017-07-10 19:26       ` Nadav Amit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).