74 lines
3.2 KiB
Diff
74 lines
3.2 KiB
Diff
|
|
From 92b95a2982e192b90b45a988afe81e253862690f Mon Sep 17 00:00:00 2001
|
||
|
|
From: tangzhongrui <tangzhongrui@cmss.chinamobile.com>
|
||
|
|
Date: Thu, 7 Dec 2023 20:06:08 +0800
|
||
|
|
Subject: [PATCH] i386/sev: Avoid SEV-ES crash due to missing MSR_EFER_LMA
|
||
|
|
bit
|
||
|
|
MIME-Version: 1.0
|
||
|
|
Content-Type: text/plain; charset=UTF-8
|
||
|
|
Content-Transfer-Encoding: 8bit
|
||
|
|
|
||
|
|
Commit 7191f24c7fcf ("accel/kvm/kvm-all: Handle register access errors")
|
||
|
|
added error checking for KVM_SET_SREGS/KVM_SET_SREGS2. In doing so, it
|
||
|
|
exposed a long-running bug in current KVM support for SEV-ES where the
|
||
|
|
kernel assumes that MSR_EFER_LMA will be set explicitly by the guest
|
||
|
|
kernel, in which case EFER write traps would result in KVM eventually
|
||
|
|
seeing MSR_EFER_LMA get set and recording it in such a way that it would
|
||
|
|
be subsequently visible when accessing it via KVM_GET_SREGS/etc.
|
||
|
|
|
||
|
|
However, guest kernels currently rely on MSR_EFER_LMA getting set
|
||
|
|
automatically when MSR_EFER_LME is set and paging is enabled via
|
||
|
|
CR0_PG_MASK. As a result, the EFER write traps don't actually expose the
|
||
|
|
MSR_EFER_LMA bit, even though it is set internally, and when QEMU
|
||
|
|
subsequently tries to pass this EFER value back to KVM via
|
||
|
|
KVM_SET_SREGS* it will fail various sanity checks and return -EINVAL,
|
||
|
|
which is now considered fatal due to the aforementioned QEMU commit.
|
||
|
|
|
||
|
|
This can be addressed by inferring the MSR_EFER_LMA bit being set when
|
||
|
|
paging is enabled and MSR_EFER_LME is set, and synthesizing it to ensure
|
||
|
|
the expected bits are all present in subsequent handling on the host
|
||
|
|
side.
|
||
|
|
|
||
|
|
Ultimately, this handling will be implemented in the host kernel, but to
|
||
|
|
avoid breaking QEMU's SEV-ES support when using older host kernels, the
|
||
|
|
same handling can be done in QEMU just after fetching the register
|
||
|
|
values via KVM_GET_SREGS*. Implement that here.
|
||
|
|
|
||
|
|
Cc: Paolo Bonzini <pbonzini@redhat.com>
|
||
|
|
Cc: Marcelo Tosatti <mtosatti@redhat.com>
|
||
|
|
Cc: Tom Lendacky <thomas.lendacky@amd.com>
|
||
|
|
Cc: Akihiko Odaki <akihiko.odaki@daynix.com>
|
||
|
|
Cc: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||
|
|
Cc: Lara Lazier <laramglazier@gmail.com>
|
||
|
|
Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
|
||
|
|
Cc: Maxim Levitsky <mlevitsk@redhat.com>
|
||
|
|
Cc: <kvm@vger.kernel.org>
|
||
|
|
Fixes: 7191f24c7fcf ("accel/kvm/kvm-all: Handle register access errors")
|
||
|
|
Signed-off-by: Michael Roth <michael.roth@amd.com>
|
||
|
|
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
||
|
|
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
|
||
|
|
Message-ID: <20231206155821.1194551-1-michael.roth@amd.com>
|
||
|
|
|
||
|
|
Signed-off-by: Zhongrui Tang <tangzhongrui@cmss.chinamobile.com>
|
||
|
|
---
|
||
|
|
target/i386/kvm/kvm.c | 4 ++++
|
||
|
|
1 file changed, 4 insertions(+)
|
||
|
|
|
||
|
|
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
|
||
|
|
index 55ee75e844..54e48530ad 100644
|
||
|
|
--- a/target/i386/kvm/kvm.c
|
||
|
|
+++ b/target/i386/kvm/kvm.c
|
||
|
|
@@ -3420,6 +3420,10 @@ static int kvm_get_sregs(X86CPU *cpu)
|
||
|
|
env->cr[4] = sregs.cr4;
|
||
|
|
|
||
|
|
env->efer = sregs.efer;
|
||
|
|
+ if (sev_es_enabled() && env->efer & MSR_EFER_LME &&
|
||
|
|
+ env->cr[0] & CR0_PG_MASK) {
|
||
|
|
+ env->efer |= MSR_EFER_LMA;
|
||
|
|
+ }
|
||
|
|
|
||
|
|
/* changes to apic base and cr8/tpr are read back via kvm_arch_post_run */
|
||
|
|
x86_update_hflags(env);
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|