Merge tag 'dma-mapping-5.19-2022-05-25' of git://git.infradead.org/users/hch/dma...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 May 2022 02:18:36 +0000 (19:18 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 26 May 2022 02:18:36 +0000 (19:18 -0700)
Pull dma-mapping updates from Christoph Hellwig:

 - don't over-decrypt memory (Robin Murphy)

 - takes min align mask into account for the swiotlb max mapping size
   (Tianyu Lan)

 - use GFP_ATOMIC in dma-debug (Mikulas Patocka)

 - fix DMA_ATTR_NO_KERNEL_MAPPING on xen/arm (me)

 - don't fail on highmem CMA pages in dma_direct_alloc_pages (me)

 - cleanup swiotlb initialization and share more code with swiotlb-xen
   (me, Stefano Stabellini)

* tag 'dma-mapping-5.19-2022-05-25' of git://git.infradead.org/users/hch/dma-mapping: (23 commits)
  dma-direct: don't over-decrypt memory
  swiotlb: max mapping size takes min align mask into account
  swiotlb: use the right nslabs-derived sizes in swiotlb_init_late
  swiotlb: use the right nslabs value in swiotlb_init_remap
  swiotlb: don't panic when the swiotlb buffer can't be allocated
  dma-debug: change allocation mode from GFP_NOWAIT to GFP_ATIOMIC
  dma-direct: don't fail on highmem CMA pages in dma_direct_alloc_pages
  swiotlb-xen: fix DMA_ATTR_NO_KERNEL_MAPPING on arm
  x86: remove cruft from <asm/dma-mapping.h>
  swiotlb: remove swiotlb_init_with_tbl and swiotlb_init_late_with_tbl
  swiotlb: merge swiotlb-xen initialization into swiotlb
  swiotlb: provide swiotlb_init variants that remap the buffer
  swiotlb: pass a gfp_mask argument to swiotlb_init_late
  swiotlb: add a SWIOTLB_ANY flag to lift the low memory restriction
  swiotlb: make the swiotlb_init interface more useful
  x86: centralize setting SWIOTLB_FORCE when guest memory encryption is enabled
  x86: remove the IOMMU table infrastructure
  MIPS/octeon: use swiotlb_init instead of open coding it
  arm/xen: don't check for xen_initial_domain() in xen_create_contiguous_region
  swiotlb: rename swiotlb_late_init_with_default_size
  ...

1  2 
arch/arm64/mm/init.c
arch/riscv/mm/init.c
arch/x86/kernel/Makefile
arch/x86/mm/mem_encrypt_amd.c

diff --combined arch/arm64/mm/init.c
@@@ -90,32 -90,6 +90,32 @@@ phys_addr_t __ro_after_init arm64_dma_p
  phys_addr_t __ro_after_init arm64_dma_phys_limit = PHYS_MASK + 1;
  #endif
  
 +/* Current arm64 boot protocol requires 2MB alignment */
 +#define CRASH_ALIGN                   SZ_2M
 +
 +#define CRASH_ADDR_LOW_MAX            arm64_dma_phys_limit
 +#define CRASH_ADDR_HIGH_MAX           (PHYS_MASK + 1)
 +
 +static int __init reserve_crashkernel_low(unsigned long long low_size)
 +{
 +      unsigned long long low_base;
 +
 +      low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX);
 +      if (!low_base) {
 +              pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
 +              return -ENOMEM;
 +      }
 +
 +      pr_info("crashkernel low memory reserved: 0x%08llx - 0x%08llx (%lld MB)\n",
 +              low_base, low_base + low_size, low_size >> 20);
 +
 +      crashk_low_res.start = low_base;
 +      crashk_low_res.end   = low_base + low_size - 1;
 +      insert_resource(&iomem_resource, &crashk_low_res);
 +
 +      return 0;
 +}
 +
  /*
   * reserve_crashkernel() - reserves memory for crash kernel
   *
  static void __init reserve_crashkernel(void)
  {
        unsigned long long crash_base, crash_size;
 -      unsigned long long crash_max = arm64_dma_phys_limit;
 +      unsigned long long crash_low_size = 0;
 +      unsigned long long crash_max = CRASH_ADDR_LOW_MAX;
 +      char *cmdline = boot_command_line;
        int ret;
  
        if (!IS_ENABLED(CONFIG_KEXEC_CORE))
                return;
  
 -      ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
 +      /* crashkernel=X[@offset] */
 +      ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
                                &crash_size, &crash_base);
 -      /* no crashkernel= or invalid value specified */
 -      if (ret || !crash_size)
 +      if (ret == -ENOENT) {
 +              ret = parse_crashkernel_high(cmdline, 0, &crash_size, &crash_base);
 +              if (ret || !crash_size)
 +                      return;
 +
 +              /*
 +               * crashkernel=Y,low can be specified or not, but invalid value
 +               * is not allowed.
 +               */
 +              ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base);
 +              if (ret && (ret != -ENOENT))
 +                      return;
 +
 +              crash_max = CRASH_ADDR_HIGH_MAX;
 +      } else if (ret || !crash_size) {
 +              /* The specified value is invalid */
                return;
 +      }
  
        crash_size = PAGE_ALIGN(crash_size);
  
        if (crash_base)
                crash_max = crash_base + crash_size;
  
 -      /* Current arm64 boot protocol requires 2MB alignment */
 -      crash_base = memblock_phys_alloc_range(crash_size, SZ_2M,
 +      crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
                                               crash_base, crash_max);
        if (!crash_base) {
                pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
                return;
        }
  
 +      if ((crash_base >= CRASH_ADDR_LOW_MAX) &&
 +           crash_low_size && reserve_crashkernel_low(crash_low_size)) {
 +              memblock_phys_free(crash_base, crash_size);
 +              return;
 +      }
 +
        pr_info("crashkernel reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
                crash_base, crash_base + crash_size, crash_size >> 20);
  
         * map. Inform kmemleak so that it won't try to access it.
         */
        kmemleak_ignore_phys(crash_base);
 +      if (crashk_low_res.end)
 +              kmemleak_ignore_phys(crashk_low_res.start);
 +
        crashk_res.start = crash_base;
        crashk_res.end = crash_base + crash_size - 1;
 +      insert_resource(&iomem_resource, &crashk_res);
  }
  
  /*
@@@ -210,7 -157,7 +210,7 @@@ static phys_addr_t __init max_zone_phys
        return min(zone_mask, memblock_end_of_DRAM() - 1) + 1;
  }
  
 -static void __init zone_sizes_init(unsigned long min, unsigned long max)
 +static void __init zone_sizes_init(void)
  {
        unsigned long max_zone_pfns[MAX_NR_ZONES]  = {0};
        unsigned int __maybe_unused acpi_zone_dma_bits;
        if (!arm64_dma_phys_limit)
                arm64_dma_phys_limit = dma32_phys_limit;
  #endif
 -      max_zone_pfns[ZONE_NORMAL] = max;
 +      max_zone_pfns[ZONE_NORMAL] = max_pfn;
  
        free_area_init(max_zone_pfns);
  }
@@@ -427,7 -374,7 +427,7 @@@ void __init bootmem_init(void
         * done after the fixed reservations
         */
        sparse_init();
 -      zone_sizes_init(min, max);
 +      zone_sizes_init();
  
        /*
         * Reserve the CMA area after arm64_dma_phys_limit was initialised.
   */
  void __init mem_init(void)
  {
-       if (swiotlb_force == SWIOTLB_FORCE ||
-           max_pfn > PFN_DOWN(arm64_dma_phys_limit))
-               swiotlb_init(1);
-       else if (!xen_swiotlb_detect())
-               swiotlb_force = SWIOTLB_NO_FORCE;
+       swiotlb_init(max_pfn > PFN_DOWN(arm64_dma_phys_limit), SWIOTLB_VERBOSE);
  
        /* this will put all unused low memory onto the freelists */
        memblock_free_all();
diff --combined arch/riscv/mm/init.c
@@@ -120,13 -120,7 +120,7 @@@ void __init mem_init(void
        BUG_ON(!mem_map);
  #endif /* CONFIG_FLATMEM */
  
- #ifdef CONFIG_SWIOTLB
-       if (swiotlb_force == SWIOTLB_FORCE ||
-           max_pfn > PFN_DOWN(dma32_phys_limit))
-               swiotlb_init(1);
-       else
-               swiotlb_force = SWIOTLB_NO_FORCE;
- #endif
+       swiotlb_init(max_pfn > PFN_DOWN(dma32_phys_limit), SWIOTLB_VERBOSE);
        memblock_free_all();
  
        print_vm_layout();
@@@ -208,25 -202,8 +202,25 @@@ static void __init setup_bootmem(void
         * early_init_fdt_reserve_self() since __pa() does
         * not work for DTB pointers that are fixmap addresses
         */
 -      if (!IS_ENABLED(CONFIG_BUILTIN_DTB))
 -              memblock_reserve(dtb_early_pa, fdt_totalsize(dtb_early_va));
 +      if (!IS_ENABLED(CONFIG_BUILTIN_DTB)) {
 +              /*
 +               * In case the DTB is not located in a memory region we won't
 +               * be able to locate it later on via the linear mapping and
 +               * get a segfault when accessing it via __va(dtb_early_pa).
 +               * To avoid this situation copy DTB to a memory region.
 +               * Note that memblock_phys_alloc will also reserve DTB region.
 +               */
 +              if (!memblock_is_memory(dtb_early_pa)) {
 +                      size_t fdt_size = fdt_totalsize(dtb_early_va);
 +                      phys_addr_t new_dtb_early_pa = memblock_phys_alloc(fdt_size, PAGE_SIZE);
 +                      void *new_dtb_early_va = early_memremap(new_dtb_early_pa, fdt_size);
 +
 +                      memcpy(new_dtb_early_va, dtb_early_va, fdt_size);
 +                      early_memunmap(new_dtb_early_va, fdt_size);
 +                      _dtb_early_pa = new_dtb_early_pa;
 +              } else
 +                      memblock_reserve(dtb_early_pa, fdt_totalsize(dtb_early_va));
 +      }
  
        early_init_fdt_scan_reserved_mem();
        dma_contiguous_reserve(dma32_phys_limit);
@@@ -735,7 -712,6 +729,7 @@@ retry
                if (!check_l4) {
                        disable_pgtable_l5();
                        check_l4 = true;
 +                      memset(early_pg_dir, 0, PAGE_SIZE);
                        goto retry;
                }
                disable_pgtable_l4();
diff --combined arch/x86/kernel/Makefile
@@@ -46,6 -46,8 +46,6 @@@ endi
  # non-deterministic coverage.
  KCOV_INSTRUMENT               := n
  
 -CFLAGS_head$(BITS).o  += -fno-stack-protector
 -
  CFLAGS_irq.o := -I $(srctree)/$(src)/../include/asm/trace
  
  obj-y                 := process_$(BITS).o signal.o
@@@ -66,7 -68,6 +66,6 @@@ obj-y                 += bootflag.o e820.
  obj-y                 += pci-dma.o quirks.o topology.o kdebugfs.o
  obj-y                 += alternative.o i8253.o hw_breakpoint.o
  obj-y                 += tsc.o tsc_msr.o io_delay.o rtc.o
- obj-y                 += pci-iommu_table.o
  obj-y                 += resource.o
  obj-y                 += irqflags.o
  obj-y                 += static_call.o
@@@ -132,7 -133,6 +131,6 @@@ obj-$(CONFIG_PCSPKR_PLATFORM)      += pcspea
  
  obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
  
- obj-$(CONFIG_SWIOTLB)                 += pci-swiotlb.o
  obj-$(CONFIG_OF)                      += devicetree.o
  obj-$(CONFIG_UPROBES)                 += uprobes.o
  
@@@ -31,7 -31,6 +31,7 @@@
  #include <asm/processor-flags.h>
  #include <asm/msr.h>
  #include <asm/cmdline.h>
 +#include <asm/sev.h>
  
  #include "mm_internal.h"
  
@@@ -48,36 -47,6 +48,36 @@@ EXPORT_SYMBOL(sme_me_mask)
  /* Buffer used for early in-place encryption by BSP, no locking needed */
  static char sme_early_buffer[PAGE_SIZE] __initdata __aligned(PAGE_SIZE);
  
 +/*
 + * SNP-specific routine which needs to additionally change the page state from
 + * private to shared before copying the data from the source to destination and
 + * restore after the copy.
 + */
 +static inline void __init snp_memcpy(void *dst, void *src, size_t sz,
 +                                   unsigned long paddr, bool decrypt)
 +{
 +      unsigned long npages = PAGE_ALIGN(sz) >> PAGE_SHIFT;
 +
 +      if (decrypt) {
 +              /*
 +               * @paddr needs to be accessed decrypted, mark the page shared in
 +               * the RMP table before copying it.
 +               */
 +              early_snp_set_memory_shared((unsigned long)__va(paddr), paddr, npages);
 +
 +              memcpy(dst, src, sz);
 +
 +              /* Restore the page state after the memcpy. */
 +              early_snp_set_memory_private((unsigned long)__va(paddr), paddr, npages);
 +      } else {
 +              /*
 +               * @paddr need to be accessed encrypted, no need for the page state
 +               * change.
 +               */
 +              memcpy(dst, src, sz);
 +      }
 +}
 +
  /*
   * This routine does not change the underlying encryption setting of the
   * page(s) that map this memory. It assumes that eventually the memory is
@@@ -126,13 -95,8 +126,13 @@@ static void __init __sme_early_enc_dec(
                 * Use a temporary buffer, of cache-line multiple size, to
                 * avoid data corruption as documented in the APM.
                 */
 -              memcpy(sme_early_buffer, src, len);
 -              memcpy(dst, sme_early_buffer, len);
 +              if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP)) {
 +                      snp_memcpy(sme_early_buffer, src, len, paddr, enc);
 +                      snp_memcpy(dst, sme_early_buffer, len, paddr, !enc);
 +              } else {
 +                      memcpy(sme_early_buffer, src, len);
 +                      memcpy(dst, sme_early_buffer, len);
 +              }
  
                early_memunmap(dst, len);
                early_memunmap(src, len);
@@@ -316,24 -280,11 +316,24 @@@ static void enc_dec_hypercall(unsigned 
  
  static void amd_enc_status_change_prepare(unsigned long vaddr, int npages, bool enc)
  {
 +      /*
 +       * To maintain the security guarantees of SEV-SNP guests, make sure
 +       * to invalidate the memory before encryption attribute is cleared.
 +       */
 +      if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP) && !enc)
 +              snp_set_memory_shared(vaddr, npages);
  }
  
  /* Return true unconditionally: return value doesn't matter for the SEV side */
  static bool amd_enc_status_change_finish(unsigned long vaddr, int npages, bool enc)
  {
 +      /*
 +       * After memory is mapped encrypted in the page table, validate it
 +       * so that it is consistent with the page table updates.
 +       */
 +      if (cc_platform_has(CC_ATTR_GUEST_SEV_SNP) && enc)
 +              snp_set_memory_private(vaddr, npages);
 +
        if (!cc_platform_has(CC_ATTR_HOST_MEM_ENCRYPT))
                enc_dec_hypercall(vaddr, npages, enc);
  
@@@ -371,28 -322,14 +371,28 @@@ static void __init __set_clr_pte_enc(pt
        clflush_cache_range(__va(pa), size);
  
        /* Encrypt/decrypt the contents in-place */
 -      if (enc)
 +      if (enc) {
                sme_early_encrypt(pa, size);
 -      else
 +      } else {
                sme_early_decrypt(pa, size);
  
 +              /*
 +               * ON SNP, the page state in the RMP table must happen
 +               * before the page table updates.
 +               */
 +              early_snp_set_memory_shared((unsigned long)__va(pa), pa, 1);
 +      }
 +
        /* Change the page encryption mask. */
        new_pte = pfn_pte(pfn, new_prot);
        set_pte_atomic(kpte, new_pte);
 +
 +      /*
 +       * If page is set encrypted in the page table, then update the RMP table to
 +       * add this page as private.
 +       */
 +      if (enc)
 +              early_snp_set_memory_private((unsigned long)__va(pa), pa, 1);
  }
  
  static int __init early_set_memory_enc_dec(unsigned long vaddr,
@@@ -495,9 -432,6 +495,6 @@@ void __init sme_early_init(void
        for (i = 0; i < ARRAY_SIZE(protection_map); i++)
                protection_map[i] = pgprot_encrypted(protection_map[i]);
  
-       if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
-               swiotlb_force = SWIOTLB_FORCE;
        x86_platform.guest.enc_status_change_prepare = amd_enc_status_change_prepare;
        x86_platform.guest.enc_status_change_finish  = amd_enc_status_change_finish;
        x86_platform.guest.enc_tlb_flush_required    = amd_enc_tlb_flush_required;