Merge branch 'x86-kdump-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 9 Jul 2019 18:52:34 +0000 (11:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 9 Jul 2019 18:52:34 +0000 (11:52 -0700)
Pull x865 kdump updates from Thomas Gleixner:
 "Yet more kexec/kdump updates:

   - Properly support kexec when AMD's memory encryption (SME) is
     enabled

   - Pass reserved e820 ranges to the kexec kernel so both PCI and SME
     can work"

* 'x86-kdump-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  fs/proc/vmcore: Enable dumping of encrypted memory when SEV was active
  x86/kexec: Set the C-bit in the identity map page table when SEV is active
  x86/kexec: Do not map kexec area as decrypted when SEV is active
  x86/crash: Add e820 reserved ranges to kdump kernel's e820 table
  x86/mm: Rework ioremap resource mapping determination
  x86/e820, ioport: Add a new I/O resource descriptor IORES_DESC_RESERVED
  x86/mm: Create a workarea in the kernel for SME early encryption
  x86/mm: Identify the end of the kernel area to be reserved

1  2 
arch/x86/kernel/crash.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/setup.c
arch/x86/mm/mem_encrypt_identity.c

diff --combined arch/x86/kernel/crash.c
index a55094b5f452d462c0dc1130178f0398195cb68f,32c956705b8e427e3a4cf7123bf5155d518bda7a..2bf70a2fed905975f943e5a89df2fafb3f0bc0c8
@@@ -56,6 -56,7 +56,6 @@@ struct crash_memmap_data 
   */
  crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss = NULL;
  EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss);
 -unsigned long crash_zero_bytes;
  
  static inline void cpu_crash_vmclear_loaded_vmcss(void)
  {
  
  static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
  {
 -#ifdef CONFIG_X86_32
 -      struct pt_regs fixed_regs;
 -
 -      if (!user_mode(regs)) {
 -              crash_fixup_ss_esp(&fixed_regs, regs);
 -              regs = &fixed_regs;
 -      }
 -#endif
        crash_save_cpu(regs, cpu);
  
        /*
@@@ -172,9 -181,6 +172,9 @@@ void native_machine_crash_shutdown(stru
  }
  
  #ifdef CONFIG_KEXEC_FILE
 +
 +static unsigned long crash_zero_bytes;
 +
  static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
  {
        unsigned int *nr_ranges = arg;
@@@ -375,6 -381,12 +375,12 @@@ int crash_setup_memmap_entries(struct k
        walk_iomem_res_desc(IORES_DESC_ACPI_NV_STORAGE, flags, 0, -1, &cmd,
                        memmap_entry_callback);
  
+       /* Add e820 reserved ranges */
+       cmd.type = E820_TYPE_RESERVED;
+       flags = IORESOURCE_MEM;
+       walk_iomem_res_desc(IORES_DESC_RESERVED, flags, 0, -1, &cmd,
+                          memmap_entry_callback);
        /* Add crashk_low_res region */
        if (crashk_low_res.end) {
                ei.addr = crashk_low_res.start;
index 9184037aec62f92e8bb147ef7a083c65ce6fec86,16c37fe489bc2047fb69a334d4ce936072e3f1c7..5dcd438ad8f25f85869f7a25ff34928594f4abf4
@@@ -1,7 -1,9 +1,7 @@@
 +// SPDX-License-Identifier: GPL-2.0-only
  /*
   * handle transition of Linux booting another kernel
   * Copyright (C) 2002-2005 Eric Biederman  <ebiederm@xmission.com>
 - *
 - * This source code is licensed under the GNU General Public License,
 - * Version 2.  See the file COPYING for more details.
   */
  
  #define pr_fmt(fmt)   "kexec: " fmt
@@@ -16,7 -18,6 +16,7 @@@
  #include <linux/io.h>
  #include <linux/suspend.h>
  #include <linux/vmalloc.h>
 +#include <linux/efi.h>
  
  #include <asm/init.h>
  #include <asm/pgtable.h>
  #include <asm/setup.h>
  #include <asm/set_memory.h>
  
 +#ifdef CONFIG_ACPI
 +/*
 + * Used while adding mapping for ACPI tables.
 + * Can be reused when other iomem regions need be mapped
 + */
 +struct init_pgtable_data {
 +      struct x86_mapping_info *info;
 +      pgd_t *level4p;
 +};
 +
 +static int mem_region_callback(struct resource *res, void *arg)
 +{
 +      struct init_pgtable_data *data = arg;
 +      unsigned long mstart, mend;
 +
 +      mstart = res->start;
 +      mend = mstart + resource_size(res) - 1;
 +
 +      return kernel_ident_mapping_init(data->info, data->level4p, mstart, mend);
 +}
 +
 +static int
 +map_acpi_tables(struct x86_mapping_info *info, pgd_t *level4p)
 +{
 +      struct init_pgtable_data data;
 +      unsigned long flags;
 +      int ret;
 +
 +      data.info = info;
 +      data.level4p = level4p;
 +      flags = IORESOURCE_MEM | IORESOURCE_BUSY;
 +
 +      ret = walk_iomem_res_desc(IORES_DESC_ACPI_TABLES, flags, 0, -1,
 +                                &data, mem_region_callback);
 +      if (ret && ret != -EINVAL)
 +              return ret;
 +
 +      /* ACPI tables could be located in ACPI Non-volatile Storage region */
 +      ret = walk_iomem_res_desc(IORES_DESC_ACPI_NV_STORAGE, flags, 0, -1,
 +                                &data, mem_region_callback);
 +      if (ret && ret != -EINVAL)
 +              return ret;
 +
 +      return 0;
 +}
 +#else
 +static int map_acpi_tables(struct x86_mapping_info *info, pgd_t *level4p) { return 0; }
 +#endif
 +
  #ifdef CONFIG_KEXEC_FILE
  const struct kexec_file_ops * const kexec_file_loaders[] = {
                &kexec_bzImage64_ops,
  };
  #endif
  
 +static int
 +map_efi_systab(struct x86_mapping_info *info, pgd_t *level4p)
 +{
 +#ifdef CONFIG_EFI
 +      unsigned long mstart, mend;
 +
 +      if (!efi_enabled(EFI_BOOT))
 +              return 0;
 +
 +      mstart = (boot_params.efi_info.efi_systab |
 +                      ((u64)boot_params.efi_info.efi_systab_hi<<32));
 +
 +      if (efi_enabled(EFI_64BIT))
 +              mend = mstart + sizeof(efi_system_table_64_t);
 +      else
 +              mend = mstart + sizeof(efi_system_table_32_t);
 +
 +      if (!mstart)
 +              return 0;
 +
 +      return kernel_ident_mapping_init(info, level4p, mstart, mend);
 +#endif
 +      return 0;
 +}
 +
  static void free_transition_pgtable(struct kimage *image)
  {
        free_page((unsigned long)image->arch.p4d);
  
  static int init_transition_pgtable(struct kimage *image, pgd_t *pgd)
  {
+       pgprot_t prot = PAGE_KERNEL_EXEC_NOENC;
+       unsigned long vaddr, paddr;
+       int result = -ENOMEM;
        p4d_t *p4d;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
-       unsigned long vaddr, paddr;
-       int result = -ENOMEM;
  
        vaddr = (unsigned long)relocate_kernel;
        paddr = __pa(page_address(image->control_code_page)+PAGE_SIZE);
                set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE));
        }
        pte = pte_offset_kernel(pmd, vaddr);
-       set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL_EXEC_NOENC));
+       if (sev_active())
+               prot = PAGE_KERNEL_EXEC;
+       set_pte(pte, pfn_pte(paddr >> PAGE_SHIFT, prot));
        return 0;
  err:
        return result;
@@@ -202,6 -134,11 +207,11 @@@ static int init_pgtable(struct kimage *
        level4p = (pgd_t *)__va(start_pgtable);
        clear_page(level4p);
  
+       if (sev_active()) {
+               info.page_flag   |= _PAGE_ENC;
+               info.kernpg_flag |= _PAGE_ENC;
+       }
        if (direct_gbpages)
                info.direct_gbpages = true;
  
                        return result;
        }
  
 +      /*
 +       * Prepare EFI systab and ACPI tables for kexec kernel since they are
 +       * not covered by pfn_mapped.
 +       */
 +      result = map_efi_systab(&info, level4p);
 +      if (result)
 +              return result;
 +
 +      result = map_acpi_tables(&info, level4p);
 +      if (result)
 +              return result;
 +
        return init_transition_pgtable(image, level4p);
  }
  
@@@ -644,8 -569,20 +654,20 @@@ void arch_kexec_unprotect_crashkres(voi
        kexec_mark_crashkres(false);
  }
  
+ /*
+  * During a traditional boot under SME, SME will encrypt the kernel,
+  * so the SME kexec kernel also needs to be un-encrypted in order to
+  * replicate a normal SME boot.
+  *
+  * During a traditional boot under SEV, the kernel has already been
+  * loaded encrypted, so the SEV kexec kernel needs to be encrypted in
+  * order to replicate a normal SEV boot.
+  */
  int arch_kexec_post_alloc_pages(void *vaddr, unsigned int pages, gfp_t gfp)
  {
+       if (sev_active())
+               return 0;
        /*
         * If SME is active we need to be sure that kexec pages are
         * not encrypted because when we boot to the new kernel the
  
  void arch_kexec_pre_free_pages(void *vaddr, unsigned int pages)
  {
+       if (sev_active())
+               return;
        /*
         * If SME is active we need to reset the pages back to being
         * an encrypted mapping before freeing them.
diff --combined arch/x86/kernel/setup.c
index dcbdf54fb5c107c3bbcc7d397dee0abe655de55b,dac60ad37e5e2c4fcd63be312618a93060676403..bbe35bf879f57e1af06a9105ce7d3f31cbc3f895
@@@ -453,24 -453,15 +453,24 @@@ static void __init memblock_x86_reserve
  #define CRASH_ALIGN           SZ_16M
  
  /*
 - * Keep the crash kernel below this limit.  On 32 bits earlier kernels
 - * would limit the kernel to the low 512 MiB due to mapping restrictions.
 + * Keep the crash kernel below this limit.
 + *
 + * On 32 bits earlier kernels would limit the kernel to the low 512 MiB
 + * due to mapping restrictions.
 + *
 + * On 64bit, kdump kernel need be restricted to be under 64TB, which is
 + * the upper limit of system RAM in 4-level paing mode. Since the kdump
 + * jumping could be from 5-level to 4-level, the jumping will fail if
 + * kernel is put above 64TB, and there's no way to detect the paging mode
 + * of the kernel which will be loaded for dumping during the 1st kernel
 + * bootup.
   */
  #ifdef CONFIG_X86_32
  # define CRASH_ADDR_LOW_MAX   SZ_512M
  # define CRASH_ADDR_HIGH_MAX  SZ_512M
  #else
  # define CRASH_ADDR_LOW_MAX   SZ_4G
 -# define CRASH_ADDR_HIGH_MAX  MAXMEM
 +# define CRASH_ADDR_HIGH_MAX  SZ_64T
  #endif
  
  static int __init reserve_crashkernel_low(void)
@@@ -836,8 -827,14 +836,14 @@@ dump_kernel_offset(struct notifier_bloc
  
  void __init setup_arch(char **cmdline_p)
  {
+       /*
+        * Reserve the memory occupied by the kernel between _text and
+        * __end_of_kernel_reserve symbols. Any kernel sections after the
+        * __end_of_kernel_reserve symbol must be explicitly reserved with a
+        * separate memblock_reserve() or they will be discarded.
+        */
        memblock_reserve(__pa_symbol(_text),
-                        (unsigned long)__bss_stop - (unsigned long)_text);
+                        (unsigned long)__end_of_kernel_reserve - (unsigned long)_text);
  
        /*
         * Make sure page 0 is always reserved because on systems with
index dddcd2a1afdb3b348bb624578b37303f26efdbd4,6a8dd483f7d9e84d8008fe5218ccee4e63769228..e2b0e2ac07bb6366a61c3f86cf3cb315ca092ccf
@@@ -1,10 -1,13 +1,10 @@@
 +// SPDX-License-Identifier: GPL-2.0-only
  /*
   * AMD Memory Encryption Support
   *
   * Copyright (C) 2016 Advanced Micro Devices, Inc.
   *
   * Author: Tom Lendacky <thomas.lendacky@amd.com>
 - *
 - * This program is free software; you can redistribute it and/or modify
 - * it under the terms of the GNU General Public License version 2 as
 - * published by the Free Software Foundation.
   */
  
  #define DISABLE_BRANCH_PROFILING
@@@ -70,6 -73,19 +70,19 @@@ struct sme_populate_pgd_data 
        unsigned long vaddr_end;
  };
  
+ /*
+  * This work area lives in the .init.scratch section, which lives outside of
+  * the kernel proper. It is sized to hold the intermediate copy buffer and
+  * more than enough pagetable pages.
+  *
+  * By using this section, the kernel can be encrypted in place and it
+  * avoids any possibility of boot parameters or initramfs images being
+  * placed such that the in-place encryption logic overwrites them.  This
+  * section is 2MB aligned to allow for simple pagetable setup using only
+  * PMD entries (see vmlinux.lds.S).
+  */
+ static char sme_workarea[2 * PMD_PAGE_SIZE] __section(.init.scratch);
  static char sme_cmdline_arg[] __initdata = "mem_encrypt";
  static char sme_cmdline_on[]  __initdata = "on";
  static char sme_cmdline_off[] __initdata = "off";
@@@ -311,8 -327,13 +324,13 @@@ void __init sme_encrypt_kernel(struct b
        }
  #endif
  
-       /* Set the encryption workarea to be immediately after the kernel */
-       workarea_start = kernel_end;
+       /*
+        * We're running identity mapped, so we must obtain the address to the
+        * SME encryption workarea using rip-relative addressing.
+        */
+       asm ("lea sme_workarea(%%rip), %0"
+            : "=r" (workarea_start)
+            : "p" (sme_workarea));
  
        /*
         * Calculate required number of workarea bytes needed: