lkml.org 
[lkml]   [2020]   [May]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [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@suse.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@suse.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

    \
     
     \ /
      Last update: 2020-05-12 20:13    [W:4.110 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site