FAILED: patch "[PATCH] x86/sev: Unroll string mmio with" failed to apply to 5.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 4009a4ac82dd95b8cd2b62bd30019476983f0aff Mon Sep 17 00:00:00 2001
From: Joerg Roedel <[email protected]>
Date: Mon, 21 Mar 2022 10:33:51 +0100
Subject: [PATCH] x86/sev: Unroll string mmio with
CC_ATTR_GUEST_UNROLL_STRING_IO
The io-specific memcpy/memset functions use string mmio accesses to do their work. Under SEV, the hypervisor can't emulate these instructions because they read/write directly from/to encrypted memory.
KVM will inject a page fault exception into the guest when it is asked to emulate string mmio instructions for an SEV guest:
BUG: unable to handle page fault for address: ffffc90000065068 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 8000100000067 P4D 8000100000067 PUD 80001000fb067 PMD 80001000fc067 PTE 80000000fed40173 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.17.0-rc7 #3
As string mmio for an SEV guest can not be supported by the hypervisor, unroll the instructions for CC_ATTR_GUEST_UNROLL_STRING_IO enabled kernels.
This issue appears when kernels are launched in recent libvirt-managed SEV virtual machines, because virt-install started to add a tpm-crb device to the guest by default and proactively because, raisins:
https://github.com/virt-manager/virt-manager/commit/eb58c09f488b0633ed1eea012cd311e48864401e
and as that commit says, the default adding of a TPM can be disabled with "virt-install ... --tpm none".
The kernel driver for tpm-crb uses memcpy_to/from_io() functions to access MMIO memory, resulting in a page-fault injected by KVM and crashing the kernel at boot.
[ bp: Massage and extend commit message. ]
arch/x86/lib/iomem.c +57 -8
@@ -22,7 +22,7 @@ static __always_inline void rep_movs(void *to, const void *from, size_t n) : "memory"); } -void memcpy_fromio (void *to,const volatile void __iomem *from,size_t n) +static void string_memcpy_fromio (void *to,const volatile void __iomem *from,size_t n) {if (unlikely (!n))return ;
@@ -38,9 +38,8 @@ void memcpy_fromio(void *to, const volatile void __iomem *from, size_t n) }rep_movs (to, (const void *)from, n); } -EXPORT_SYMBOL (memcpy_fromio); -void memcpy_toio (volatile void __iomem *to,const void *from,size_t n) +static void string_memcpy_toio (volatile void __iomem *to,const void *from,size_t n) {if (unlikely (!n))return ;
@@ -56,14 +55,64 @@ void memcpy_toio(volatile void __iomem *to, const void *from, size_t n) }rep_movs ((void *)to, (const void *) from, n); } + +static void unrolled_memcpy_fromio (void *to,const volatile void __iomem *from,size_t n) +{ +const volatile char __iomem *in = from; +char *out = to; +int i; + +for (i =0 ; i < n; ++i) + out[i] =readb (&in[i]); +} + +static void unrolled_memcpy_toio (volatile void __iomem *to,const void *from,size_t n) +{ +volatile char __iomem *out = to; +const char *in = from; +int i; + +for (i =0 ; i < n; ++i) +writeb (in[i], &out[i]); +} + +static void unrolled_memset_io (volatile void __iomem *a,int b,size_t c) +{ +volatile char __iomem *mem = a; +int i; + +for (i =0 ; i < c; ++i) +writeb (b, &mem[i]); +} + +void memcpy_fromio (void *to,const volatile void __iomem *from,size_t n) +{ +if (cc_platform_has (CC_ATTR_GUEST_UNROLL_STRING_IO )) +unrolled_memcpy_fromio (to, from, n); +else +string_memcpy_fromio (to, from, n); +} +EXPORT_SYMBOL (memcpy_fromio); + +void memcpy_toio (volatile void __iomem *to,const void *from,size_t n) +{ +if (cc_platform_has (CC_ATTR_GUEST_UNROLL_STRING_IO )) +unrolled_memcpy_toio (to, from, n); +else +string_memcpy_toio (to, from, n); +}EXPORT_SYMBOL (memcpy_toio);void memset_io (volatile void __iomem *a,int b,size_t c) { -/* -* TODO: memset can mangle the IO patterns quite a bit. -* perhaps it would be better to use a dumb one: -*/ -memset ((void *)a, b, c); +if (cc_platform_has (CC_ATTR_GUEST_UNROLL_STRING_IO )) { +unrolled_memset_io (a, b, c); + }else { +/* +* TODO: memset can mangle the IO patterns quite a bit. +* perhaps it would be better to use a dumb one: +*/ +memset ((void *)a, b, c); + } }EXPORT_SYMBOL (memset_io);