kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: Sean Christopherson <sean.j.christopherson@intel.com>
Cc: Vivek Goyal <vgoyal@redhat.com>,
	Vitaly Kuznetsov <vkuznets@redhat.com>,
	kvm@vger.kernel.org, x86@kernel.org,
	Andy Lutomirski <luto@kernel.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	Borislav Petkov <bp@alien8.de>, "H. Peter Anvin" <hpa@zytor.com>,
	Wanpeng Li <wanpengli@tencent.com>,
	Jim Mattson <jmattson@google.com>, Gavin Shan <gshan@redhat.com>,
	Peter Zijlstra <peterz@infradead.org>,
	linux-kernel@vger.kernel.org,
	Andrew Cooper <andrew.cooper3@citrix.com>
Subject: Re: [PATCH 2/8] KVM: x86: extend struct kvm_vcpu_pv_apf_data with token info
Date: Sat, 16 May 2020 00:23:31 +0200	[thread overview]
Message-ID: <943cfc2f-5b18-e00a-f5a2-4577472a1ff5@redhat.com> (raw)
In-Reply-To: <20200515204341.GF17572@linux.intel.com>

On 15/05/20 22:43, Sean Christopherson wrote:
> On Fri, May 15, 2020 at 09:18:07PM +0200, Paolo Bonzini wrote:
>> On 15/05/20 20:46, Sean Christopherson wrote:
>>> Why even bother using 'struct kvm_vcpu_pv_apf_data' for the #PF case?  VMX
>>> only requires error_code[31:16]==0 and SVM doesn't vet it at all, i.e. we
>>> can (ab)use the error code to indicate an async #PF by setting it to an
>>> impossible value, e.g. 0xaaaa (a is for async!).  That partciular error code
>>> is even enforced by the SDM, which states:
>>
>> Possibly, but it's water under the bridge now.
> 
> Why is that?  I thought we were redoing the entire thing because the current
> ABI is unfixably broken?  In other words, since the guest needs to change,
> why are we keeping any of the current async #PF pieces?  E.g. why keep using
> #PF instead of usurping something like #NP?

Because that would be 3 ABIs to support instead of 2.  The #PF solution
is only broken as long as you allow async PF from ring 0 (which wasn't
even true except for preemptable kernels) _and_ have NMIs that can
generate page faults.  We also have the #PF vmexit part for nested
virtualization.  This adds up and makes a quick fix for 'page not ready'
notifications not that quick.

However, interrupts for 'page ready' do have a bunch of advantages (more
control on what can be preempted by the notification, a saner check for
new page faults which is effectively a bug fix) so it makes sense to get
them in more quickly (probably 5.9 at this point due to the massive
cleanups that are being done around interrupt vectors).

>> And the #PF mechanism also has the problem with NMIs that happen before the
>> error code is read and page faults happening in the handler.
> 
> Hrm, I think there's no unfixable problem except for a pathological
> #PF->NMI->#DB->#PF scenario.  But it is a problem :-(

Yeah, that made no sense.  But still I'm not sure the x86 maintainers
would like it.

The only possible isue with #VE is the re-entrancy at the end.  Andy
proposed re-enabling it from an interrupt, but here is one solution that
can be done almost entirely from C.  The idea is to split the IST in two
halves, and flip between them in the TSS with an XOR operation on entry
to the interrupt handler.  This is possible because there won't ever be
more than two handlers active at the same time.  Unlike if you used
SUB/ADD, with XOR you don't have to restore the IST on exit: the two
halves will take turns as the current IST and there's no problematic
window between the ADD and the IRET.

The pseudocode would be:

- on #VE entry
   xor 512 with the IST address in the TSS
   check if saved RSP comes from the IST
   if so:
     overwrite the saved flags/CS/SS in the "other" IST half with the
       current value of the registers
     overwrite the saved RSP in the "other" IST half with the address
       of the top of the IST itself
     overwrite the saved RIP in the "other" IST half with the address
       of a trampoline (see below)
   else:
     save the top 5 words of the IST somewhere
     do normal stuff

- the trampoline restores the 5 words at the top of the IST with five
  push instructions, and jumps back to the first instruction of the
  handler

Everything except the first step can even be done in C.

Here is an example.

Assuming that on entry to the outer #VE the IST is the "even" half, the
outer #VE moves the IST to the "odd" half and the return
flags/CS/SS/RSP/RIP are saved.

After the reentrancy flag has been cleared, a nested #VE arrives and
runs within the "odd" half of the IST.  The IST is moved back to the
"even" half and the return flags/CS/SS/RSP/RIP in the "even" half are
patched to point to the trampoline.

When we get back to the outer handler the reentrancy flag not zero, so
even though the IST points to the current stack, reentrancy is
impossible and we go just fine through the few final instructions of the
handler.

On outer #VE exit, the IRET instruction jumps to the trampoline, with
RSP pointing at the top of the "even" half.  The return
flags/CS/SS/RSP/RIP are restored, and everything restarts from the
beginning: the outer #VE moves the IST to the "odd" half, the return
flags/CS/SS/RSP/RIP are saved, the data for the nested #VE is fished out
of the virtualization exception area and so on.

Paolo


  reply	other threads:[~2020-05-15 22:23 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-11 16:47 [PATCH 0/8] KVM: x86: Interrupt-based mechanism for async_pf 'page present' notifications Vitaly Kuznetsov
2020-05-11 16:47 ` [PATCH 1/8] Revert "KVM: async_pf: Fix #DF due to inject "Page not Present" and "Page Ready" exceptions simultaneously" Vitaly Kuznetsov
2020-05-11 16:47 ` [PATCH 2/8] KVM: x86: extend struct kvm_vcpu_pv_apf_data with token info Vitaly Kuznetsov
2020-05-12 15:27   ` Vivek Goyal
2020-05-12 15:40     ` Vitaly Kuznetsov
2020-05-12 15:53       ` Vivek Goyal
2020-05-12 17:50         ` Sean Christopherson
2020-05-13  9:09           ` Vitaly Kuznetsov
2020-05-13 12:52           ` Vivek Goyal
2020-05-15 15:59             ` Paolo Bonzini
2020-05-15 18:46               ` Sean Christopherson
2020-05-15 19:18                 ` Paolo Bonzini
2020-05-15 20:33                   ` Vivek Goyal
2020-05-15 20:53                     ` Sean Christopherson
2020-05-15 20:43                   ` Sean Christopherson
2020-05-15 22:23                     ` Paolo Bonzini [this message]
2020-05-15 23:16                       ` Sean Christopherson
2020-05-21 14:59                       ` Vitaly Kuznetsov
2020-05-22  7:33                         ` Paolo Bonzini
2020-05-12 21:15       ` Vivek Goyal
2020-05-21 18:38   ` Vivek Goyal
2020-05-23 16:34     ` Vitaly Kuznetsov
2020-05-26 12:50       ` Vivek Goyal
2020-05-11 16:47 ` [PATCH 3/8] KVM: introduce kvm_read_guest_offset_cached() Vitaly Kuznetsov
2020-05-11 16:47 ` [PATCH 4/8] KVM: x86: interrupt based APF page-ready event delivery Vitaly Kuznetsov
2020-05-12 14:24   ` Vivek Goyal
2020-05-12 15:50     ` Vitaly Kuznetsov
2020-05-12 18:07       ` Vivek Goyal
2020-05-13  9:03         ` Vitaly Kuznetsov
2020-05-13 13:53           ` Vivek Goyal
2020-05-13 14:03             ` Vivek Goyal
2020-05-13 14:23             ` Vitaly Kuznetsov
2020-05-13 18:46               ` Vivek Goyal
2020-05-14  8:08                 ` Vitaly Kuznetsov
2020-05-14 13:31                   ` Vivek Goyal
2020-05-11 16:47 ` [PATCH 5/8] KVM: x86: acknowledgment mechanism for async pf page ready notifications Vitaly Kuznetsov
2020-05-11 16:47 ` [PATCH 6/8] KVM: x86: announce KVM_FEATURE_ASYNC_PF_INT Vitaly Kuznetsov
2020-05-11 16:47 ` [PATCH 7/8] KVM: x86: Switch KVM guest to using interrupts for page ready APF delivery Vitaly Kuznetsov
2020-05-13  1:44   ` [kbuild-all] " kbuild test robot
2020-05-11 16:47 ` [PATCH 8/8] KVM: x86: drop KVM_PV_REASON_PAGE_READY case from kvm_handle_page_fault() Vitaly Kuznetsov
2020-05-12 15:32 ` [PATCH 0/8] KVM: x86: Interrupt-based mechanism for async_pf 'page present' notifications Vivek Goyal
2020-05-12 16:12   ` Vitaly Kuznetsov
2020-05-13 14:16 ` Vivek Goyal
2020-05-14 18:14   ` Vitaly Kuznetsov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=943cfc2f-5b18-e00a-f5a2-4577472a1ff5@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=bp@alien8.de \
    --cc=gshan@redhat.com \
    --cc=hpa@zytor.com \
    --cc=jmattson@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=peterz@infradead.org \
    --cc=sean.j.christopherson@intel.com \
    --cc=tglx@linutronix.de \
    --cc=vgoyal@redhat.com \
    --cc=vkuznets@redhat.com \
    --cc=wanpengli@tencent.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).