[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20200512181157.GD6859@zn.tnic>
Date: Tue, 12 May 2020 20:11:57 +0200
From: Borislav Petkov <bp@...en8.de>
To: Joerg Roedel <joro@...tes.org>
Cc: x86@...nel.org, hpa@...or.com, Andy Lutomirski <luto@...nel.org>,
Dave Hansen <dave.hansen@...ux.intel.com>,
Peter Zijlstra <peterz@...radead.org>,
Thomas Hellstrom <thellstrom@...are.com>,
Jiri Slaby <jslaby@...e.cz>,
Dan Williams <dan.j.williams@...el.com>,
Tom Lendacky <thomas.lendacky@....com>,
Juergen Gross <jgross@...e.com>,
Kees Cook <keescook@...omium.org>,
David Rientjes <rientjes@...gle.com>,
Cfir Cohen <cfir@...gle.com>,
Erdem Aktas <erdemaktas@...gle.com>,
Masami Hiramatsu <mhiramat@...nel.org>,
Mike Stunes <mstunes@...are.com>,
Joerg Roedel <jroedel@...e.de>, linux-kernel@...r.kernel.org,
kvm@...r.kernel.org, virtualization@...ts.linux-foundation.org
Subject: Re: [PATCH v3 23/75] x86/boot/compressed/64: Setup GHCB Based VC
Exception handler
On Tue, Apr 28, 2020 at 05:16:33PM +0200, Joerg Roedel wrote:
> From: Joerg Roedel <jroedel@...e.de>
>
> Install an exception handler for #VC exception that uses a GHCB. Also
> add the infrastructure for handling different exit-codes by decoding
> the instruction that caused the exception and error handling.
>
> Signed-off-by: Joerg Roedel <jroedel@...e.de>
> ---
> arch/x86/Kconfig | 1 +
> arch/x86/boot/compressed/Makefile | 3 +
> arch/x86/boot/compressed/idt_64.c | 4 +
> arch/x86/boot/compressed/idt_handlers_64.S | 3 +-
> arch/x86/boot/compressed/misc.c | 7 +
> arch/x86/boot/compressed/misc.h | 7 +
> arch/x86/boot/compressed/sev-es.c | 110 +++++++++++++++
> arch/x86/include/asm/sev-es.h | 39 ++++++
> arch/x86/include/uapi/asm/svm.h | 1 +
> arch/x86/kernel/sev-es-shared.c | 154 +++++++++++++++++++++
> 10 files changed, 328 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 1197b5596d5a..2ba5f74f186d 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -1523,6 +1523,7 @@ config AMD_MEM_ENCRYPT
> select DYNAMIC_PHYSICAL_MASK
> select ARCH_USE_MEMREMAP_PROT
> select ARCH_HAS_FORCE_DMA_UNENCRYPTED
> + select INSTRUCTION_DECODER
> ---help---
> Say yes to enable support for the encryption of system memory.
> This requires an AMD processor that supports Secure Memory
> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> index a7847a1ef63a..8372b85c9c0e 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -41,6 +41,9 @@ KBUILD_CFLAGS += -Wno-pointer-sign
> KBUILD_CFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
> KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
>
> +# sev-es.c inludes generated $(objtree)/arch/x86/lib/inat-tables.c
"includes"
> +CFLAGS_sev-es.o += -I$(objtree)/arch/x86/lib/
Does it?
I see
#include "../../lib/inat.c"
#include "../../lib/insn.c"
only and with the above CFLAGS-line removed, it builds still.
Leftover from earlier?
> +
> KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
> GCOV_PROFILE := n
> UBSAN_SANITIZE :=n
> diff --git a/arch/x86/boot/compressed/idt_64.c b/arch/x86/boot/compressed/idt_64.c
> index f8295d68b3e1..44d20c4f47c9 100644
> --- a/arch/x86/boot/compressed/idt_64.c
> +++ b/arch/x86/boot/compressed/idt_64.c
> @@ -45,5 +45,9 @@ void load_stage2_idt(void)
>
> set_idt_entry(X86_TRAP_PF, boot_page_fault);
>
> +#ifdef CONFIG_AMD_MEM_ENCRYPT
> + set_idt_entry(X86_TRAP_VC, boot_stage2_vc);
> +#endif
if IS_ENABLED()...
...
> +static enum es_result vc_decode_insn(struct es_em_ctxt *ctxt)
> +{
> + char buffer[MAX_INSN_SIZE];
> + enum es_result ret;
> +
> + memcpy(buffer, (unsigned char *)ctxt->regs->ip, MAX_INSN_SIZE);
> +
> + insn_init(&ctxt->insn, buffer, MAX_INSN_SIZE, 1);
> + insn_get_length(&ctxt->insn);
> +
> + ret = ctxt->insn.immediate.got ? ES_OK : ES_DECODE_FAILED;
Why are we checking whether the immediate? insn_get_length() sets
insn->length unconditionally while insn_get_immediate() can error out
and not set ->got... ?
> +
> + return ret;
> +}
...
> +static bool sev_es_setup_ghcb(void)
> +{
> + if (!sev_es_negotiate_protocol())
> + sev_es_terminate(GHCB_SEV_ES_REASON_PROTOCOL_UNSUPPORTED);
> +
> + if (set_page_decrypted((unsigned long)&boot_ghcb_page))
> + return false;
> +
> + /* Page is now mapped decrypted, clear it */
> + memset(&boot_ghcb_page, 0, sizeof(boot_ghcb_page));
> +
> + boot_ghcb = &boot_ghcb_page;
> +
> + /* Initialize lookup tables for the instruction decoder */
> + inat_init_tables();
Yeah, that call doesn't logically belong in this function AFAICT as this
function should setup the GHCB only. You can move it to the caller.
> +
> + return true;
> +}
> +
> +void sev_es_shutdown_ghcb(void)
> +{
> + if (!boot_ghcb)
> + return;
> +
> + /*
> + * GHCB Page must be flushed from the cache and mapped encrypted again.
> + * Otherwise the running kernel will see strange cache effects when
> + * trying to use that page.
> + */
> + if (set_page_encrypted((unsigned long)&boot_ghcb_page))
> + error("Can't map GHCB page encrypted");
Is that error() call enough?
Shouldn't we BUG_ON() here or mark that page Reserved or so, so that
nothing uses it during the system lifetime and thus avoid the strange
cache effects?
...
> +static enum es_result sev_es_ghcb_hv_call(struct ghcb *ghcb,
> + struct es_em_ctxt *ctxt,
> + u64 exit_code, u64 exit_info_1,
> + u64 exit_info_2)
> +{
> + enum es_result ret;
> +
> + /* Fill in protocol and format specifiers */
> + ghcb->protocol_version = GHCB_PROTOCOL_MAX;
> + ghcb->ghcb_usage = GHCB_DEFAULT_USAGE;
> +
> + ghcb_set_sw_exit_code(ghcb, exit_code);
> + ghcb_set_sw_exit_info_1(ghcb, exit_info_1);
> + ghcb_set_sw_exit_info_2(ghcb, exit_info_2);
> +
> + sev_es_wr_ghcb_msr(__pa(ghcb));
> + VMGEXIT();
> +
> + if ((ghcb->save.sw_exit_info_1 & 0xffffffff) == 1) {
^^^^^^^^^^^
(1UL << 32) - 1
I guess.
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
Powered by blists - more mailing lists