From: Mathias Krause <minipli@grsecurity.net>
To: Sean Christopherson <seanjc@google.com>
Cc: Mathias Krause <minipli@grsecurity.net>,
kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
Paolo Bonzini <pbonzini@redhat.com>
Subject: Re: [PATCH v3 2/6] KVM: VMX: Avoid retpoline call for control register caused exits
Date: Mon, 20 Mar 2023 21:43:44 +0100 [thread overview]
Message-ID: <20230320204344.24109-1-minipli@grsecurity.net> (raw)
In-Reply-To: <ZBI62RUnMB3ppRqO@google.com>
On Wed, Mar 15, 2023 at 02:38:33PM -0700, Sean Christopherson wrote:
> On Wed, Feb 01, 2023, Mathias Krause wrote:
> > Complement commit 4289d2728664 ("KVM: retpolines: x86: eliminate
> > retpoline from vmx.c exit handlers") and avoid a retpoline call for
> > control register accesses as well.
> >
> > This speeds up guests that make heavy use of it, like grsecurity
> > kernels toggling CR0.WP to implement kernel W^X.
>
> I would rather drop this patch for VMX and instead unconditionally make CR0.WP
> guest owned when TDP (EPT) is enabled, i.e. drop the module param from patch 6.
That's fine with me. As EPT usually implies TDP (if neither of both was
explicitly disabled) that should be no limitation and as the non-EPT
case only saw a very small gain from this change anyways (less than 1%)
we can drop it.
>
> > Signed-off-by: Mathias Krause <minipli@grsecurity.net>
> > ---
> >
> > Meanwhile I got my hands on a AMD system and while doing a similar change
> > for SVM gives a small measurable win (1.1% faster for grsecurity guests),
>
> Mostly out of curiosity...
>
> Is the 1.1% roughly aligned with the gains for VMX? If VMX sees a significantly
> larger improvement, any idea why SVM doesn't benefit as much? E.g. did you double
> check that the kernel was actually using RETPOLINE?
I measured the runtime of the ssdd test I used before and got 3.98s for
a kernel with the whole series applied and 3.94s with the below change
on top:
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index d13cf53e7390..2a471eae11c6 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3369,6 +3369,10 @@ int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)
return intr_interception(vcpu);
else if (exit_code == SVM_EXIT_HLT)
return kvm_emulate_halt(vcpu);
+ else if (exit_code == SVM_EXIT_READ_CR0 ||
+ exit_code == SVM_EXIT_WRITE_CR0 ||
+ exit_code == SVM_EXIT_CR0_SEL_WRITE)
+ return cr_interception(vcpu);
else if (exit_code == SVM_EXIT_NPF)
return npf_interception(vcpu);
#endif
Inspecting svm_invoke_exit_handler() on the host with perf confirmed it
could use the direct call of cr_interception() most of the time, thereby
could avoid the retpoline for it:
(My version of perf is, apparently, unable to detect tail calls properly
and therefore lacks symbol information for the jump targets in the below
assembly dump. I therefore added these manually.)
Percent│
│
│ ffffffffc194c410 <load0>: # svm_invoke_exit_handler
5.00 │ nop
7.44 │ push %rbp
10.43 │ cmp $0x403,%rsi
5.86 │ mov %rdi,%rbp
1.23 │ push %rbx
2.11 │ mov %rsi,%rbx
4.60 │ jbe 7a
│ 16: [svm_handle_invalid_exit() path removed]
4.59 │ 7a: mov -0x3e6a5b00(,%rsi,8),%rax
4.52 │ test %rax,%rax
│ je 16
6.25 │ cmp $0x7c,%rsi
│ je dd
4.18 │ cmp $0x64,%rsi
│ je f2
3.26 │ cmp $0x60,%rsi
│ je ca
4.57 │ cmp $0x78,%rsi
│ je f9
1.27 │ test $0xffffffffffffffef,%rsi
│ je c3
1.67 │ cmp $0x65,%rsi
│ je c3
│ cmp $0x400,%rsi
│ je 13d
│ pop %rbx
│ pop %rbp
│ jmp 0xffffffffa0487d80 # __x86_indirect_thunk_rax
│ int3
11.68 │ c3: pop %rbx
10.01 │ pop %rbp
10.47 │ jmp 0xffffffffc19482a0 # cr_interception
│ ca: incq 0x1940(%rdi)
│ mov $0x1,%eax
│ pop %rbx
0.42 │ pop %rbp
│ ret
│ int3
│ int3
│ int3
│ int3
│ dd: mov 0x1a20(%rdi),%rax
│ cmpq $0x0,0x78(%rax)
│ je 100
│ pop %rbx
│ pop %rbp
│ jmp 0xffffffffc185af20 # kvm_emulate_wrmsr
│ f2: pop %rbx
│ pop %rbp
0.42 │ jmp 0xffffffffc19472b0 # interrupt_window_interception
│ f9: pop %rbx
│ pop %rbp
│ jmp 0xffffffffc185a6a0 # kvm_emulate_halt
│100: pop %rbx
│ pop %rbp
│ jmp 0xffffffffc18602a0 # kvm_emulate_rdmsr
│107: mov %rbp,%rdi
│ mov $0x10,%esi
│ call kvm_register_read_raw
│ mov 0x24(%rbp),%edx
│ mov %rax,%rcx
│ mov %rbx,%r8
│ mov %gs:0x2ac00,%rax
│ mov 0x95c(%rax),%esi
│ mov $0xffffffffc195dc28,%rdi
│ call _printk
│ jmp 31
│13d: pop %rbx
│ pop %rbp
│ jmp 0xffffffffc1946b90 # npf_interception
What's clear from above (or so I hope!), cr_interception() is *the* reason to
cause a VM exit for my test run and by taking the shortcut via a direct call,
it doesn't have to do the retpoline dance which might be the explanation for
the ~1.1% performance gain (even in the face of three additional compare
instructions). However! As I realized that these three more instructions
probably "hurt" all other workloads (that don't toggle CR0.WP as often as a
grsecurity kernel would do), I didn't include the above change as a patch of
the series. If you think it's worth it nonetheless, as VM exits shouldn't
happen often anyways, I can do a proper patch.
>
> > it would provide nothing for other guests, as the change I was testing was
> > specifically targeting CR0 caused exits.
> >
> > A more general approach would instead cover CR3 and, maybe, CR4 as well.
> > However, that would require a lot more exit code compares, likely
> > vanishing the gains in the general case. So this tweak is VMX only.
>
> I don't think targeting on CR0 exits is a reason to not do this for SVM. With
> NPT enabled, CR3 isn't intercepted, and CR4 exits should be very rare. If the
> performance benefits are marginal (I don't have a good frame of reference for the
> 1.1%), then _that's_ a good reason to leave SVM alone. But not giving CR3 and CR4
> priority is a non-issue.
Ok. But yeah, the win isn't all the big either, less so in real
workloads that won't exercise this code path so often.
>
> > arch/x86/kvm/vmx/vmx.c | 2 ++
> > 1 file changed, 2 insertions(+)
> >
> > diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> > index c788aa382611..c8198c8a9b55 100644
> > --- a/arch/x86/kvm/vmx/vmx.c
> > +++ b/arch/x86/kvm/vmx/vmx.c
> > @@ -6538,6 +6538,8 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
> > return handle_external_interrupt(vcpu);
> > else if (exit_reason.basic == EXIT_REASON_HLT)
> > return kvm_emulate_halt(vcpu);
> > + else if (exit_reason.basic == EXIT_REASON_CR_ACCESS)
> > + return handle_cr(vcpu);
> > else if (exit_reason.basic == EXIT_REASON_EPT_MISCONFIG)
> > return handle_ept_misconfig(vcpu);
> > #endif
> > --
> > 2.39.1
> >
next prev parent reply other threads:[~2023-03-20 20:41 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-02-01 19:45 [PATCH v3 0/6] KVM: MMU: performance tweaks for heavy CR0.WP users Mathias Krause
2023-02-01 19:45 ` [PATCH v3 1/6] KVM: x86/mmu: Avoid indirect call for get_cr3 Mathias Krause
2023-02-01 19:46 ` [PATCH v3 2/6] KVM: VMX: Avoid retpoline call for control register caused exits Mathias Krause
2023-03-15 21:38 ` Sean Christopherson
2023-03-20 20:43 ` Mathias Krause [this message]
2023-02-01 19:46 ` [PATCH v3 3/6] KVM: x86: Do not unload MMU roots when only toggling CR0.WP Mathias Krause
2023-02-07 13:36 ` Zhi Wang
2023-02-08 9:52 ` Mathias Krause
2023-03-15 21:22 ` Sean Christopherson
2023-03-15 22:11 ` Sean Christopherson
2023-03-20 21:13 ` Mathias Krause
2023-02-01 19:46 ` [PATCH v3 4/6] KVM: x86: Make use of kvm_read_cr*_bits() when testing bits Mathias Krause
2023-02-07 13:05 ` Zhi Wang
2023-02-08 9:11 ` Mathias Krause
2023-02-14 11:08 ` Zhi Wang
2023-03-15 22:18 ` Sean Christopherson
2023-03-20 21:34 ` Mathias Krause
2023-03-21 15:57 ` Sean Christopherson
2023-02-01 19:46 ` [PATCH v3 5/6] KVM: x86/mmu: Fix comment typo Mathias Krause
2023-02-01 19:46 ` [PATCH v3 6/6] KVM: VMX: Make CR0.WP a guest owned bit Mathias Krause
2023-03-15 22:30 ` Sean Christopherson
2023-03-20 21:31 ` Mathias Krause
2023-03-06 6:34 ` [PATCH v3 0/6] KVM: MMU: performance tweaks for heavy CR0.WP users Mathias Krause
2023-03-06 18:07 ` Sean Christopherson
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=20230320204344.24109-1-minipli@grsecurity.net \
--to=minipli@grsecurity.net \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
/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
all inboxes | Powered by JetHome®