On Tue, Apr 28, 2020 at 05:16:33PM +0200, Joerg Roedel wrote:
> From: Joerg Roedel <[email protected]>
> 
> 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 <[email protected]>
> ---
>  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

Reply via email to