2021-04-07 07:37:03

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 0/4] KVM: SVM: A fix and cleanups for vmcb tracking

Belated code review for the vmcb changes that are queued for 5.13.

Sean Christopherson (4):
KVM: SVM: Don't set current_vmcb->cpu when switching vmcb
KVM: SVM: Drop vcpu_svm.vmcb_pa
KVM: SVM: Add a comment to clarify what vcpu_svm.vmcb points at
KVM: SVM: Enhance and clean up the vmcb tracking comment in
pre_svm_run()

arch/x86/kvm/svm/svm.c | 29 +++++++++++++----------------
arch/x86/kvm/svm/svm.h | 2 +-
2 files changed, 14 insertions(+), 17 deletions(-)

--
2.31.0.208.g409f899ff0-goog


2021-04-07 07:37:12

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 2/4] KVM: SVM: Drop vcpu_svm.vmcb_pa

Remove vmcb_pa from vcpu_svm and simply read current_vmcb->pa directly in
the one path where it is consumed. Unlike svm->vmcb, use of the current
vmcb's address is very limited, as evidenced by the fact that its use
can be trimmed to a single dereference.

Opportunistically add a comment about using vmcb01 for VMLOAD/VMSAVE, at
first glance using vmcb01 instead of vmcb_pa looks wrong.

No functional change intended.

Cc: Maxim Levitsky <[email protected]>
Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/svm/svm.c | 12 +++++++++---
arch/x86/kvm/svm/svm.h | 1 -
2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 89619cc52cf4..f62c56adf7c9 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1310,7 +1310,6 @@ void svm_switch_vmcb(struct vcpu_svm *svm, struct kvm_vmcb_info *target_vmcb)
{
svm->current_vmcb = target_vmcb;
svm->vmcb = target_vmcb->ptr;
- svm->vmcb_pa = target_vmcb->pa;
}

static int svm_create_vcpu(struct kvm_vcpu *vcpu)
@@ -3704,6 +3703,7 @@ static fastpath_t svm_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ unsigned long vmcb_pa = svm->current_vmcb->pa;

/*
* VMENTER enables interrupts (host state), but the kernel state is
@@ -3726,12 +3726,18 @@ static noinstr void svm_vcpu_enter_exit(struct kvm_vcpu *vcpu)
lockdep_hardirqs_on(CALLER_ADDR0);

if (sev_es_guest(vcpu->kvm)) {
- __svm_sev_es_vcpu_run(svm->vmcb_pa);
+ __svm_sev_es_vcpu_run(vmcb_pa);
} else {
struct svm_cpu_data *sd = per_cpu(svm_data, vcpu->cpu);

+ /*
+ * Use a single vmcb (vmcb01 because it's always valid) for
+ * context switching guest state via VMLOAD/VMSAVE, that way
+ * the state doesn't need to be copied between vmcb01 and
+ * vmcb02 when switching vmcbs for nested virtualization.
+ */
vmload(svm->vmcb01.pa);
- __svm_vcpu_run(svm->vmcb_pa, (unsigned long *)&vcpu->arch.regs);
+ __svm_vcpu_run(vmcb_pa, (unsigned long *)&vcpu->arch.regs);
vmsave(svm->vmcb01.pa);

vmload(__sme_page_pa(sd->save_area));
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 02f8ece8c741..2173fe985104 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -112,7 +112,6 @@ struct svm_nested_state {
struct vcpu_svm {
struct kvm_vcpu vcpu;
struct vmcb *vmcb;
- unsigned long vmcb_pa;
struct kvm_vmcb_info vmcb01;
struct kvm_vmcb_info *current_vmcb;
struct svm_cpu_data *svm_data;
--
2.31.0.208.g409f899ff0-goog

2021-04-07 10:06:12

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 4/4] KVM: SVM: Enhance and clean up the vmcb tracking comment in pre_svm_run()

Explicitly document why a vmcb must be marked dirty and assigned a new
asid when it will be run on a different cpu. The "what" is relatively
obvious, whereas the "why" requires reading the APM and/or KVM code.

Opportunistically remove a spurious period and several unnecessary
newlines in the comment.

No functional change intended.

Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/svm/svm.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index f62c56adf7c9..afc275ba5d59 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3336,11 +3336,10 @@ static void pre_svm_run(struct kvm_vcpu *vcpu)
struct vcpu_svm *svm = to_svm(vcpu);

/*
- * If the previous vmrun of the vmcb occurred on
- * a different physical cpu then we must mark the vmcb dirty.
- * and assign a new asid.
- */
-
+ * If the previous vmrun of the vmcb occurred on a different physical
+ * cpu, then mark the vmcb dirty and assign a new asid. Hardware's
+ * vmcb clean bits are per logical CPU, as are KVM's asid assignments.
+ */
if (unlikely(svm->current_vmcb->cpu != vcpu->cpu)) {
svm->current_vmcb->asid_generation = 0;
vmcb_mark_all_dirty(svm->vmcb);
--
2.31.0.208.g409f899ff0-goog

2021-04-07 10:26:06

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 3/4] KVM: SVM: Add a comment to clarify what vcpu_svm.vmcb points at

Add a comment above the declaration of vcpu_svm.vmcb to call out that it
is simply a shorthand for current_vmcb->ptr. The myriad accesses to
svm->vmcb are quite confusing without this crucial detail.

No functional change intended.

Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/svm/svm.h | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 2173fe985104..b230950c1aa6 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -111,6 +111,7 @@ struct svm_nested_state {

struct vcpu_svm {
struct kvm_vcpu vcpu;
+ /* vmcb always points at current_vmcb->ptr, it's purely a shorthand. */
struct vmcb *vmcb;
struct kvm_vmcb_info vmcb01;
struct kvm_vmcb_info *current_vmcb;
--
2.31.0.208.g409f899ff0-goog

2021-04-07 10:26:23

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 1/4] KVM: SVM: Don't set current_vmcb->cpu when switching vmcb

Do not update the new vmcb's last-run cpu when switching to a different
vmcb. If the vCPU is migrated between its last run and a vmcb switch,
e.g. for nested VM-Exit, then setting the cpu without marking the vmcb
dirty will lead to KVM running the vCPU on a different physical cpu with
stale clean bit settings.

vcpu->cpu current_vmcb->cpu hardware
pre_svm_run() cpu0 cpu0 cpu0,clean
kvm_arch_vcpu_load() cpu1 cpu0 cpu0,clean
svm_switch_vmcb() cpu1 cpu1 cpu0,clean
pre_svm_run() cpu1 cpu1 kaboom

Simply delete the offending code; unlike VMX, which needs to update the
cpu at switch time due to the need to do VMPTRLD, SVM only cares about
which cpu last ran the vCPU.

Fixes: af18fa775d07 ("KVM: nSVM: Track the physical cpu of the vmcb vmrun through the vmcb")
Cc: Cathy Avery <[email protected]>
Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/svm/svm.c | 8 --------
1 file changed, 8 deletions(-)

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 48b396f33bee..89619cc52cf4 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1311,14 +1311,6 @@ void svm_switch_vmcb(struct vcpu_svm *svm, struct kvm_vmcb_info *target_vmcb)
svm->current_vmcb = target_vmcb;
svm->vmcb = target_vmcb->ptr;
svm->vmcb_pa = target_vmcb->pa;
-
- /*
- * Track the physical CPU the target_vmcb is running on
- * in order to mark the VMCB dirty if the cpu changes at
- * its next vmrun.
- */
-
- svm->current_vmcb->cpu = svm->vcpu.cpu;
}

static int svm_create_vcpu(struct kvm_vcpu *vcpu)
--
2.31.0.208.g409f899ff0-goog

2021-04-17 12:51:14

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH 0/4] KVM: SVM: A fix and cleanups for vmcb tracking

On 06/04/21 19:18, Sean Christopherson wrote:
> Belated code review for the vmcb changes that are queued for 5.13.
>
> Sean Christopherson (4):
> KVM: SVM: Don't set current_vmcb->cpu when switching vmcb
> KVM: SVM: Drop vcpu_svm.vmcb_pa
> KVM: SVM: Add a comment to clarify what vcpu_svm.vmcb points at
> KVM: SVM: Enhance and clean up the vmcb tracking comment in
> pre_svm_run()
>
> arch/x86/kvm/svm/svm.c | 29 +++++++++++++----------------
> arch/x86/kvm/svm/svm.h | 2 +-
> 2 files changed, 14 insertions(+), 17 deletions(-)
>

Queued, thanks -- especially for the bug in patch 1, which avoided review.

Paolo