]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 Jan 2018 15:38:32 +0000 (16:38 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 Jan 2018 15:38:32 +0000 (16:38 +0100)
added patches:
x86-mm-centralize-pmd-flags-in-sme_encrypt_kernel.patch
x86-mm-clean-up-register-saving-in-the-__enc_copy-assembly-code.patch
x86-mm-prepare-sme_encrypt_kernel-for-page-aligned-encryption.patch
x86-mm-use-a-struct-to-reduce-parameters-for-sme-pgd-mapping.patch

queue-4.14/series
queue-4.14/x86-mm-centralize-pmd-flags-in-sme_encrypt_kernel.patch [new file with mode: 0644]
queue-4.14/x86-mm-clean-up-register-saving-in-the-__enc_copy-assembly-code.patch [new file with mode: 0644]
queue-4.14/x86-mm-prepare-sme_encrypt_kernel-for-page-aligned-encryption.patch [new file with mode: 0644]
queue-4.14/x86-mm-use-a-struct-to-reduce-parameters-for-sme-pgd-mapping.patch [new file with mode: 0644]

index 05e68d89310252bb12cef3a3da125013cd68ee07..01c2155502dacc1663da38c4764cadab3beeb4d3 100644 (file)
@@ -41,3 +41,7 @@ x86-tsc-future-proof-native_calibrate_tsc.patch
 x86-tsc-fix-erroneous-tsc-rate-on-skylake-xeon.patch
 pipe-avoid-round_pipe_size-nr_pages-overflow-on-32-bit.patch
 x86-apic-vector-fix-off-by-one-in-error-path.patch
+x86-mm-clean-up-register-saving-in-the-__enc_copy-assembly-code.patch
+x86-mm-use-a-struct-to-reduce-parameters-for-sme-pgd-mapping.patch
+x86-mm-centralize-pmd-flags-in-sme_encrypt_kernel.patch
+x86-mm-prepare-sme_encrypt_kernel-for-page-aligned-encryption.patch
diff --git a/queue-4.14/x86-mm-centralize-pmd-flags-in-sme_encrypt_kernel.patch b/queue-4.14/x86-mm-centralize-pmd-flags-in-sme_encrypt_kernel.patch
new file mode 100644 (file)
index 0000000..ed51dc1
--- /dev/null
@@ -0,0 +1,235 @@
+From 2b5d00b6c2cdd94f6d6a494a6f6c0c0fc7b8e711 Mon Sep 17 00:00:00 2001
+From: Tom Lendacky <thomas.lendacky@amd.com>
+Date: Wed, 10 Jan 2018 13:26:16 -0600
+Subject: x86/mm: Centralize PMD flags in sme_encrypt_kernel()
+
+From: Tom Lendacky <thomas.lendacky@amd.com>
+
+commit 2b5d00b6c2cdd94f6d6a494a6f6c0c0fc7b8e711 upstream.
+
+In preparation for encrypting more than just the kernel during early
+boot processing, centralize the use of the PMD flag settings based
+on the type of mapping desired.  When 4KB aligned encryption is added,
+this will allow either PTE flags or large page PMD flags to be used
+without requiring the caller to adjust.
+
+Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com>
+Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
+Reviewed-by: Borislav Petkov <bp@suse.de>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Brijesh Singh <brijesh.singh@amd.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/20180110192615.6026.14767.stgit@tlendack-t1.amdoffice.net
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/mm/mem_encrypt.c |  137 ++++++++++++++++++++++++++--------------------
+ 1 file changed, 79 insertions(+), 58 deletions(-)
+
+--- a/arch/x86/mm/mem_encrypt.c
++++ b/arch/x86/mm/mem_encrypt.c
+@@ -217,31 +217,39 @@ struct sme_populate_pgd_data {
+       void    *pgtable_area;
+       pgd_t   *pgd;
+-      pmdval_t pmd_val;
++      pmdval_t pmd_flags;
++      unsigned long paddr;
++
+       unsigned long vaddr;
++      unsigned long vaddr_end;
+ };
+-static void __init sme_clear_pgd(pgd_t *pgd_base, unsigned long start,
+-                               unsigned long end)
++static void __init sme_clear_pgd(struct sme_populate_pgd_data *ppd)
+ {
+       unsigned long pgd_start, pgd_end, pgd_size;
+       pgd_t *pgd_p;
+-      pgd_start = start & PGDIR_MASK;
+-      pgd_end = end & PGDIR_MASK;
++      pgd_start = ppd->vaddr & PGDIR_MASK;
++      pgd_end = ppd->vaddr_end & PGDIR_MASK;
+-      pgd_size = (((pgd_end - pgd_start) / PGDIR_SIZE) + 1);
+-      pgd_size *= sizeof(pgd_t);
++      pgd_size = (((pgd_end - pgd_start) / PGDIR_SIZE) + 1) * sizeof(pgd_t);
+-      pgd_p = pgd_base + pgd_index(start);
++      pgd_p = ppd->pgd + pgd_index(ppd->vaddr);
+       memset(pgd_p, 0, pgd_size);
+ }
+-#define PGD_FLAGS     _KERNPG_TABLE_NOENC
+-#define P4D_FLAGS     _KERNPG_TABLE_NOENC
+-#define PUD_FLAGS     _KERNPG_TABLE_NOENC
+-#define PMD_FLAGS     (__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL)
++#define PGD_FLAGS             _KERNPG_TABLE_NOENC
++#define P4D_FLAGS             _KERNPG_TABLE_NOENC
++#define PUD_FLAGS             _KERNPG_TABLE_NOENC
++
++#define PMD_FLAGS_LARGE               (__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL)
++
++#define PMD_FLAGS_DEC         PMD_FLAGS_LARGE
++#define PMD_FLAGS_DEC_WP      ((PMD_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
++                               (_PAGE_PAT | _PAGE_PWT))
++
++#define PMD_FLAGS_ENC         (PMD_FLAGS_LARGE | _PAGE_ENC)
+ static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
+ {
+@@ -310,7 +318,35 @@ static void __init sme_populate_pgd_larg
+       pmd_p += pmd_index(ppd->vaddr);
+       if (!native_pmd_val(*pmd_p) || !(native_pmd_val(*pmd_p) & _PAGE_PSE))
+-              native_set_pmd(pmd_p, native_make_pmd(ppd->pmd_val));
++              native_set_pmd(pmd_p, native_make_pmd(ppd->paddr | ppd->pmd_flags));
++}
++
++static void __init __sme_map_range(struct sme_populate_pgd_data *ppd,
++                                 pmdval_t pmd_flags)
++{
++      ppd->pmd_flags = pmd_flags;
++
++      while (ppd->vaddr < ppd->vaddr_end) {
++              sme_populate_pgd_large(ppd);
++
++              ppd->vaddr += PMD_PAGE_SIZE;
++              ppd->paddr += PMD_PAGE_SIZE;
++      }
++}
++
++static void __init sme_map_range_encrypted(struct sme_populate_pgd_data *ppd)
++{
++      __sme_map_range(ppd, PMD_FLAGS_ENC);
++}
++
++static void __init sme_map_range_decrypted(struct sme_populate_pgd_data *ppd)
++{
++      __sme_map_range(ppd, PMD_FLAGS_DEC);
++}
++
++static void __init sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd)
++{
++      __sme_map_range(ppd, PMD_FLAGS_DEC_WP);
+ }
+ static unsigned long __init sme_pgtable_calc(unsigned long len)
+@@ -370,7 +406,6 @@ void __init sme_encrypt_kernel(void)
+       unsigned long kernel_start, kernel_end, kernel_len;
+       struct sme_populate_pgd_data ppd;
+       unsigned long pgtable_area_len;
+-      unsigned long paddr, pmd_flags;
+       unsigned long decrypted_base;
+       if (!sme_active())
+@@ -442,14 +477,10 @@ void __init sme_encrypt_kernel(void)
+        * addressing the workarea.
+        */
+       ppd.pgd = (pgd_t *)native_read_cr3_pa();
+-      paddr = workarea_start;
+-      while (paddr < workarea_end) {
+-              ppd.pmd_val = paddr + PMD_FLAGS;
+-              ppd.vaddr = paddr;
+-              sme_populate_pgd_large(&ppd);
+-
+-              paddr += PMD_PAGE_SIZE;
+-      }
++      ppd.paddr = workarea_start;
++      ppd.vaddr = workarea_start;
++      ppd.vaddr_end = workarea_end;
++      sme_map_range_decrypted(&ppd);
+       /* Flush the TLB - no globals so cr3 is enough */
+       native_write_cr3(__native_read_cr3());
+@@ -464,17 +495,6 @@ void __init sme_encrypt_kernel(void)
+       memset(ppd.pgd, 0, sizeof(pgd_t) * PTRS_PER_PGD);
+       ppd.pgtable_area += sizeof(pgd_t) * PTRS_PER_PGD;
+-      /* Add encrypted kernel (identity) mappings */
+-      pmd_flags = PMD_FLAGS | _PAGE_ENC;
+-      paddr = kernel_start;
+-      while (paddr < kernel_end) {
+-              ppd.pmd_val = paddr + pmd_flags;
+-              ppd.vaddr = paddr;
+-              sme_populate_pgd_large(&ppd);
+-
+-              paddr += PMD_PAGE_SIZE;
+-      }
+-
+       /*
+        * A different PGD index/entry must be used to get different
+        * pagetable entries for the decrypted mapping. Choose the next
+@@ -484,29 +504,28 @@ void __init sme_encrypt_kernel(void)
+       decrypted_base = (pgd_index(workarea_end) + 1) & (PTRS_PER_PGD - 1);
+       decrypted_base <<= PGDIR_SHIFT;
+-      /* Add decrypted, write-protected kernel (non-identity) mappings */
+-      pmd_flags = (PMD_FLAGS & ~_PAGE_CACHE_MASK) | (_PAGE_PAT | _PAGE_PWT);
+-      paddr = kernel_start;
+-      while (paddr < kernel_end) {
+-              ppd.pmd_val = paddr + pmd_flags;
+-              ppd.vaddr = paddr + decrypted_base;
+-              sme_populate_pgd_large(&ppd);
++      /* Add encrypted kernel (identity) mappings */
++      ppd.paddr = kernel_start;
++      ppd.vaddr = kernel_start;
++      ppd.vaddr_end = kernel_end;
++      sme_map_range_encrypted(&ppd);
+-              paddr += PMD_PAGE_SIZE;
+-      }
++      /* Add decrypted, write-protected kernel (non-identity) mappings */
++      ppd.paddr = kernel_start;
++      ppd.vaddr = kernel_start + decrypted_base;
++      ppd.vaddr_end = kernel_end + decrypted_base;
++      sme_map_range_decrypted_wp(&ppd);
+       /* Add decrypted workarea mappings to both kernel mappings */
+-      paddr = workarea_start;
+-      while (paddr < workarea_end) {
+-              ppd.pmd_val = paddr + PMD_FLAGS;
+-              ppd.vaddr = paddr;
+-              sme_populate_pgd_large(&ppd);
+-
+-              ppd.vaddr = paddr + decrypted_base;
+-              sme_populate_pgd_large(&ppd);
+-
+-              paddr += PMD_PAGE_SIZE;
+-      }
++      ppd.paddr = workarea_start;
++      ppd.vaddr = workarea_start;
++      ppd.vaddr_end = workarea_end;
++      sme_map_range_decrypted(&ppd);
++
++      ppd.paddr = workarea_start;
++      ppd.vaddr = workarea_start + decrypted_base;
++      ppd.vaddr_end = workarea_end + decrypted_base;
++      sme_map_range_decrypted(&ppd);
+       /* Perform the encryption */
+       sme_encrypt_execute(kernel_start, kernel_start + decrypted_base,
+@@ -517,11 +536,13 @@ void __init sme_encrypt_kernel(void)
+        * the decrypted areas - all that is needed for this is to remove
+        * the PGD entry/entries.
+        */
+-      sme_clear_pgd(ppd.pgd, kernel_start + decrypted_base,
+-                    kernel_end + decrypted_base);
+-
+-      sme_clear_pgd(ppd.pgd, workarea_start + decrypted_base,
+-                    workarea_end + decrypted_base);
++      ppd.vaddr = kernel_start + decrypted_base;
++      ppd.vaddr_end = kernel_end + decrypted_base;
++      sme_clear_pgd(&ppd);
++
++      ppd.vaddr = workarea_start + decrypted_base;
++      ppd.vaddr_end = workarea_end + decrypted_base;
++      sme_clear_pgd(&ppd);
+       /* Flush the TLB - no globals so cr3 is enough */
+       native_write_cr3(__native_read_cr3());
diff --git a/queue-4.14/x86-mm-clean-up-register-saving-in-the-__enc_copy-assembly-code.patch b/queue-4.14/x86-mm-clean-up-register-saving-in-the-__enc_copy-assembly-code.patch
new file mode 100644 (file)
index 0000000..9b540e2
--- /dev/null
@@ -0,0 +1,80 @@
+From 1303880179e67c59e801429b7e5d0f6b21137d99 Mon Sep 17 00:00:00 2001
+From: Tom Lendacky <thomas.lendacky@amd.com>
+Date: Wed, 10 Jan 2018 13:25:56 -0600
+Subject: x86/mm: Clean up register saving in the __enc_copy() assembly code
+
+From: Tom Lendacky <thomas.lendacky@amd.com>
+
+commit 1303880179e67c59e801429b7e5d0f6b21137d99 upstream.
+
+Clean up the use of PUSH and POP and when registers are saved in the
+__enc_copy() assembly function in order to improve the readability of the code.
+
+Move parameter register saving into general purpose registers earlier
+in the code and move all the pushes to the beginning of the function
+with corresponding pops at the end.
+
+We do this to prepare fixes.
+
+Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com>
+Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
+Reviewed-by: Borislav Petkov <bp@suse.de>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Brijesh Singh <brijesh.singh@amd.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/20180110192556.6026.74187.stgit@tlendack-t1.amdoffice.net
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/mm/mem_encrypt_boot.S |   20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/arch/x86/mm/mem_encrypt_boot.S
++++ b/arch/x86/mm/mem_encrypt_boot.S
+@@ -103,20 +103,19 @@ ENTRY(__enc_copy)
+       orq     $X86_CR4_PGE, %rdx
+       mov     %rdx, %cr4
++      push    %r15
++
++      movq    %rcx, %r9               /* Save kernel length */
++      movq    %rdi, %r10              /* Save encrypted kernel address */
++      movq    %rsi, %r11              /* Save decrypted kernel address */
++
+       /* Set the PAT register PA5 entry to write-protect */
+-      push    %rcx
+       movl    $MSR_IA32_CR_PAT, %ecx
+       rdmsr
+-      push    %rdx                    /* Save original PAT value */
++      mov     %rdx, %r15              /* Save original PAT value */
+       andl    $0xffff00ff, %edx       /* Clear PA5 */
+       orl     $0x00000500, %edx       /* Set PA5 to WP */
+       wrmsr
+-      pop     %rdx                    /* RDX contains original PAT value */
+-      pop     %rcx
+-
+-      movq    %rcx, %r9               /* Save kernel length */
+-      movq    %rdi, %r10              /* Save encrypted kernel address */
+-      movq    %rsi, %r11              /* Save decrypted kernel address */
+       wbinvd                          /* Invalidate any cache entries */
+@@ -138,12 +137,13 @@ ENTRY(__enc_copy)
+       jnz     1b                      /* Kernel length not zero? */
+       /* Restore PAT register */
+-      push    %rdx                    /* Save original PAT value */
+       movl    $MSR_IA32_CR_PAT, %ecx
+       rdmsr
+-      pop     %rdx                    /* Restore original PAT value */
++      mov     %r15, %rdx              /* Restore original PAT value */
+       wrmsr
++      pop     %r15
++
+       ret
+ .L__enc_copy_end:
+ ENDPROC(__enc_copy)
diff --git a/queue-4.14/x86-mm-prepare-sme_encrypt_kernel-for-page-aligned-encryption.patch b/queue-4.14/x86-mm-prepare-sme_encrypt_kernel-for-page-aligned-encryption.patch
new file mode 100644 (file)
index 0000000..eabd072
--- /dev/null
@@ -0,0 +1,298 @@
+From cc5f01e28d6c60f274fd1e33b245f679f79f543c Mon Sep 17 00:00:00 2001
+From: Tom Lendacky <thomas.lendacky@amd.com>
+Date: Wed, 10 Jan 2018 13:26:26 -0600
+Subject: x86/mm: Prepare sme_encrypt_kernel() for PAGE aligned encryption
+
+From: Tom Lendacky <thomas.lendacky@amd.com>
+
+commit cc5f01e28d6c60f274fd1e33b245f679f79f543c upstream.
+
+In preparation for encrypting more than just the kernel, the encryption
+support in sme_encrypt_kernel() needs to support 4KB page aligned
+encryption instead of just 2MB large page aligned encryption.
+
+Update the routines that populate the PGD to support non-2MB aligned
+addresses.  This is done by creating PTE page tables for the start
+and end portion of the address range that fall outside of the 2MB
+alignment.  This results in, at most, two extra pages to hold the
+PTE entries for each mapping of a range.
+
+Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com>
+Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
+Reviewed-by: Borislav Petkov <bp@suse.de>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Brijesh Singh <brijesh.singh@amd.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/20180110192626.6026.75387.stgit@tlendack-t1.amdoffice.net
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/mm/mem_encrypt.c      |  123 +++++++++++++++++++++++++++++++++++------
+ arch/x86/mm/mem_encrypt_boot.S |   20 ++++--
+ 2 files changed, 121 insertions(+), 22 deletions(-)
+
+--- a/arch/x86/mm/mem_encrypt.c
++++ b/arch/x86/mm/mem_encrypt.c
+@@ -218,6 +218,7 @@ struct sme_populate_pgd_data {
+       pgd_t   *pgd;
+       pmdval_t pmd_flags;
++      pteval_t pte_flags;
+       unsigned long paddr;
+       unsigned long vaddr;
+@@ -242,6 +243,7 @@ static void __init sme_clear_pgd(struct
+ #define PGD_FLAGS             _KERNPG_TABLE_NOENC
+ #define P4D_FLAGS             _KERNPG_TABLE_NOENC
+ #define PUD_FLAGS             _KERNPG_TABLE_NOENC
++#define PMD_FLAGS             _KERNPG_TABLE_NOENC
+ #define PMD_FLAGS_LARGE               (__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL)
+@@ -251,7 +253,15 @@ static void __init sme_clear_pgd(struct
+ #define PMD_FLAGS_ENC         (PMD_FLAGS_LARGE | _PAGE_ENC)
+-static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
++#define PTE_FLAGS             (__PAGE_KERNEL_EXEC & ~_PAGE_GLOBAL)
++
++#define PTE_FLAGS_DEC         PTE_FLAGS
++#define PTE_FLAGS_DEC_WP      ((PTE_FLAGS_DEC & ~_PAGE_CACHE_MASK) | \
++                               (_PAGE_PAT | _PAGE_PWT))
++
++#define PTE_FLAGS_ENC         (PTE_FLAGS | _PAGE_ENC)
++
++static pmd_t __init *sme_prepare_pgd(struct sme_populate_pgd_data *ppd)
+ {
+       pgd_t *pgd_p;
+       p4d_t *p4d_p;
+@@ -302,7 +312,7 @@ static void __init sme_populate_pgd_larg
+       pud_p += pud_index(ppd->vaddr);
+       if (native_pud_val(*pud_p)) {
+               if (native_pud_val(*pud_p) & _PAGE_PSE)
+-                      return;
++                      return NULL;
+               pmd_p = (pmd_t *)(native_pud_val(*pud_p) & ~PTE_FLAGS_MASK);
+       } else {
+@@ -316,16 +326,55 @@ static void __init sme_populate_pgd_larg
+               native_set_pud(pud_p, pud);
+       }
++      return pmd_p;
++}
++
++static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
++{
++      pmd_t *pmd_p;
++
++      pmd_p = sme_prepare_pgd(ppd);
++      if (!pmd_p)
++              return;
++
+       pmd_p += pmd_index(ppd->vaddr);
+       if (!native_pmd_val(*pmd_p) || !(native_pmd_val(*pmd_p) & _PAGE_PSE))
+               native_set_pmd(pmd_p, native_make_pmd(ppd->paddr | ppd->pmd_flags));
+ }
+-static void __init __sme_map_range(struct sme_populate_pgd_data *ppd,
+-                                 pmdval_t pmd_flags)
++static void __init sme_populate_pgd(struct sme_populate_pgd_data *ppd)
+ {
+-      ppd->pmd_flags = pmd_flags;
++      pmd_t *pmd_p;
++      pte_t *pte_p;
++      pmd_p = sme_prepare_pgd(ppd);
++      if (!pmd_p)
++              return;
++
++      pmd_p += pmd_index(ppd->vaddr);
++      if (native_pmd_val(*pmd_p)) {
++              if (native_pmd_val(*pmd_p) & _PAGE_PSE)
++                      return;
++
++              pte_p = (pte_t *)(native_pmd_val(*pmd_p) & ~PTE_FLAGS_MASK);
++      } else {
++              pmd_t pmd;
++
++              pte_p = ppd->pgtable_area;
++              memset(pte_p, 0, sizeof(*pte_p) * PTRS_PER_PTE);
++              ppd->pgtable_area += sizeof(*pte_p) * PTRS_PER_PTE;
++
++              pmd = native_make_pmd((pteval_t)pte_p + PMD_FLAGS);
++              native_set_pmd(pmd_p, pmd);
++      }
++
++      pte_p += pte_index(ppd->vaddr);
++      if (!native_pte_val(*pte_p))
++              native_set_pte(pte_p, native_make_pte(ppd->paddr | ppd->pte_flags));
++}
++
++static void __init __sme_map_range_pmd(struct sme_populate_pgd_data *ppd)
++{
+       while (ppd->vaddr < ppd->vaddr_end) {
+               sme_populate_pgd_large(ppd);
+@@ -334,33 +383,71 @@ static void __init __sme_map_range(struc
+       }
+ }
++static void __init __sme_map_range_pte(struct sme_populate_pgd_data *ppd)
++{
++      while (ppd->vaddr < ppd->vaddr_end) {
++              sme_populate_pgd(ppd);
++
++              ppd->vaddr += PAGE_SIZE;
++              ppd->paddr += PAGE_SIZE;
++      }
++}
++
++static void __init __sme_map_range(struct sme_populate_pgd_data *ppd,
++                                 pmdval_t pmd_flags, pteval_t pte_flags)
++{
++      unsigned long vaddr_end;
++
++      ppd->pmd_flags = pmd_flags;
++      ppd->pte_flags = pte_flags;
++
++      /* Save original end value since we modify the struct value */
++      vaddr_end = ppd->vaddr_end;
++
++      /* If start is not 2MB aligned, create PTE entries */
++      ppd->vaddr_end = ALIGN(ppd->vaddr, PMD_PAGE_SIZE);
++      __sme_map_range_pte(ppd);
++
++      /* Create PMD entries */
++      ppd->vaddr_end = vaddr_end & PMD_PAGE_MASK;
++      __sme_map_range_pmd(ppd);
++
++      /* If end is not 2MB aligned, create PTE entries */
++      ppd->vaddr_end = vaddr_end;
++      __sme_map_range_pte(ppd);
++}
++
+ static void __init sme_map_range_encrypted(struct sme_populate_pgd_data *ppd)
+ {
+-      __sme_map_range(ppd, PMD_FLAGS_ENC);
++      __sme_map_range(ppd, PMD_FLAGS_ENC, PTE_FLAGS_ENC);
+ }
+ static void __init sme_map_range_decrypted(struct sme_populate_pgd_data *ppd)
+ {
+-      __sme_map_range(ppd, PMD_FLAGS_DEC);
++      __sme_map_range(ppd, PMD_FLAGS_DEC, PTE_FLAGS_DEC);
+ }
+ static void __init sme_map_range_decrypted_wp(struct sme_populate_pgd_data *ppd)
+ {
+-      __sme_map_range(ppd, PMD_FLAGS_DEC_WP);
++      __sme_map_range(ppd, PMD_FLAGS_DEC_WP, PTE_FLAGS_DEC_WP);
+ }
+ static unsigned long __init sme_pgtable_calc(unsigned long len)
+ {
+-      unsigned long p4d_size, pud_size, pmd_size;
++      unsigned long p4d_size, pud_size, pmd_size, pte_size;
+       unsigned long total;
+       /*
+        * Perform a relatively simplistic calculation of the pagetable
+-       * entries that are needed. That mappings will be covered by 2MB
+-       * PMD entries so we can conservatively calculate the required
++       * entries that are needed. Those mappings will be covered mostly
++       * by 2MB PMD entries so we can conservatively calculate the required
+        * number of P4D, PUD and PMD structures needed to perform the
+-       * mappings. Incrementing the count for each covers the case where
+-       * the addresses cross entries.
++       * mappings.  For mappings that are not 2MB aligned, PTE mappings
++       * would be needed for the start and end portion of the address range
++       * that fall outside of the 2MB alignment.  This results in, at most,
++       * two extra pages to hold PTE entries for each range that is mapped.
++       * Incrementing the count for each covers the case where the addresses
++       * cross entries.
+        */
+       if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
+               p4d_size = (ALIGN(len, PGDIR_SIZE) / PGDIR_SIZE) + 1;
+@@ -374,8 +461,9 @@ static unsigned long __init sme_pgtable_
+       }
+       pmd_size = (ALIGN(len, PUD_SIZE) / PUD_SIZE) + 1;
+       pmd_size *= sizeof(pmd_t) * PTRS_PER_PMD;
++      pte_size = 2 * sizeof(pte_t) * PTRS_PER_PTE;
+-      total = p4d_size + pud_size + pmd_size;
++      total = p4d_size + pud_size + pmd_size + pte_size;
+       /*
+        * Now calculate the added pagetable structures needed to populate
+@@ -458,10 +546,13 @@ void __init sme_encrypt_kernel(void)
+       /*
+        * The total workarea includes the executable encryption area and
+-       * the pagetable area.
++       * the pagetable area. The start of the workarea is already 2MB
++       * aligned, align the end of the workarea on a 2MB boundary so that
++       * we don't try to create/allocate PTE entries from the workarea
++       * before it is mapped.
+        */
+       workarea_len = execute_len + pgtable_area_len;
+-      workarea_end = workarea_start + workarea_len;
++      workarea_end = ALIGN(workarea_start + workarea_len, PMD_PAGE_SIZE);
+       /*
+        * Set the address to the start of where newly created pagetable
+--- a/arch/x86/mm/mem_encrypt_boot.S
++++ b/arch/x86/mm/mem_encrypt_boot.S
+@@ -104,6 +104,7 @@ ENTRY(__enc_copy)
+       mov     %rdx, %cr4
+       push    %r15
++      push    %r12
+       movq    %rcx, %r9               /* Save kernel length */
+       movq    %rdi, %r10              /* Save encrypted kernel address */
+@@ -119,21 +120,27 @@ ENTRY(__enc_copy)
+       wbinvd                          /* Invalidate any cache entries */
+-      /* Copy/encrypt 2MB at a time */
++      /* Copy/encrypt up to 2MB at a time */
++      movq    $PMD_PAGE_SIZE, %r12
+ 1:
++      cmpq    %r12, %r9
++      jnb     2f
++      movq    %r9, %r12
++
++2:
+       movq    %r11, %rsi              /* Source - decrypted kernel */
+       movq    %r8, %rdi               /* Dest   - intermediate copy buffer */
+-      movq    $PMD_PAGE_SIZE, %rcx    /* 2MB length */
++      movq    %r12, %rcx
+       rep     movsb
+       movq    %r8, %rsi               /* Source - intermediate copy buffer */
+       movq    %r10, %rdi              /* Dest   - encrypted kernel */
+-      movq    $PMD_PAGE_SIZE, %rcx    /* 2MB length */
++      movq    %r12, %rcx
+       rep     movsb
+-      addq    $PMD_PAGE_SIZE, %r11
+-      addq    $PMD_PAGE_SIZE, %r10
+-      subq    $PMD_PAGE_SIZE, %r9     /* Kernel length decrement */
++      addq    %r12, %r11
++      addq    %r12, %r10
++      subq    %r12, %r9               /* Kernel length decrement */
+       jnz     1b                      /* Kernel length not zero? */
+       /* Restore PAT register */
+@@ -142,6 +149,7 @@ ENTRY(__enc_copy)
+       mov     %r15, %rdx              /* Restore original PAT value */
+       wrmsr
++      pop     %r12
+       pop     %r15
+       ret
diff --git a/queue-4.14/x86-mm-use-a-struct-to-reduce-parameters-for-sme-pgd-mapping.patch b/queue-4.14/x86-mm-use-a-struct-to-reduce-parameters-for-sme-pgd-mapping.patch
new file mode 100644 (file)
index 0000000..b898c70
--- /dev/null
@@ -0,0 +1,252 @@
+From bacf6b499e11760aef73a3bb5ce4e5eea74a3fd4 Mon Sep 17 00:00:00 2001
+From: Tom Lendacky <thomas.lendacky@amd.com>
+Date: Wed, 10 Jan 2018 13:26:05 -0600
+Subject: x86/mm: Use a struct to reduce parameters for SME PGD mapping
+
+From: Tom Lendacky <thomas.lendacky@amd.com>
+
+commit bacf6b499e11760aef73a3bb5ce4e5eea74a3fd4 upstream.
+
+In preparation for follow-on patches, combine the PGD mapping parameters
+into a struct to reduce the number of function arguments and allow for
+direct updating of the next pagetable mapping area pointer.
+
+Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com>
+Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com>
+Reviewed-by: Borislav Petkov <bp@suse.de>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Brijesh Singh <brijesh.singh@amd.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/20180110192605.6026.96206.stgit@tlendack-t1.amdoffice.net
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/mm/mem_encrypt.c |   92 +++++++++++++++++++++++-----------------------
+ 1 file changed, 47 insertions(+), 45 deletions(-)
+
+--- a/arch/x86/mm/mem_encrypt.c
++++ b/arch/x86/mm/mem_encrypt.c
+@@ -213,6 +213,14 @@ void swiotlb_set_mem_attributes(void *va
+       set_memory_decrypted((unsigned long)vaddr, size >> PAGE_SHIFT);
+ }
++struct sme_populate_pgd_data {
++      void    *pgtable_area;
++      pgd_t   *pgd;
++
++      pmdval_t pmd_val;
++      unsigned long vaddr;
++};
++
+ static void __init sme_clear_pgd(pgd_t *pgd_base, unsigned long start,
+                                unsigned long end)
+ {
+@@ -235,15 +243,14 @@ static void __init sme_clear_pgd(pgd_t *
+ #define PUD_FLAGS     _KERNPG_TABLE_NOENC
+ #define PMD_FLAGS     (__PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL)
+-static void __init *sme_populate_pgd(pgd_t *pgd_base, void *pgtable_area,
+-                                   unsigned long vaddr, pmdval_t pmd_val)
++static void __init sme_populate_pgd_large(struct sme_populate_pgd_data *ppd)
+ {
+       pgd_t *pgd_p;
+       p4d_t *p4d_p;
+       pud_t *pud_p;
+       pmd_t *pmd_p;
+-      pgd_p = pgd_base + pgd_index(vaddr);
++      pgd_p = ppd->pgd + pgd_index(ppd->vaddr);
+       if (native_pgd_val(*pgd_p)) {
+               if (IS_ENABLED(CONFIG_X86_5LEVEL))
+                       p4d_p = (p4d_t *)(native_pgd_val(*pgd_p) & ~PTE_FLAGS_MASK);
+@@ -253,15 +260,15 @@ static void __init *sme_populate_pgd(pgd
+               pgd_t pgd;
+               if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
+-                      p4d_p = pgtable_area;
++                      p4d_p = ppd->pgtable_area;
+                       memset(p4d_p, 0, sizeof(*p4d_p) * PTRS_PER_P4D);
+-                      pgtable_area += sizeof(*p4d_p) * PTRS_PER_P4D;
++                      ppd->pgtable_area += sizeof(*p4d_p) * PTRS_PER_P4D;
+                       pgd = native_make_pgd((pgdval_t)p4d_p + PGD_FLAGS);
+               } else {
+-                      pud_p = pgtable_area;
++                      pud_p = ppd->pgtable_area;
+                       memset(pud_p, 0, sizeof(*pud_p) * PTRS_PER_PUD);
+-                      pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD;
++                      ppd->pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD;
+                       pgd = native_make_pgd((pgdval_t)pud_p + PGD_FLAGS);
+               }
+@@ -269,44 +276,41 @@ static void __init *sme_populate_pgd(pgd
+       }
+       if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
+-              p4d_p += p4d_index(vaddr);
++              p4d_p += p4d_index(ppd->vaddr);
+               if (native_p4d_val(*p4d_p)) {
+                       pud_p = (pud_t *)(native_p4d_val(*p4d_p) & ~PTE_FLAGS_MASK);
+               } else {
+                       p4d_t p4d;
+-                      pud_p = pgtable_area;
++                      pud_p = ppd->pgtable_area;
+                       memset(pud_p, 0, sizeof(*pud_p) * PTRS_PER_PUD);
+-                      pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD;
++                      ppd->pgtable_area += sizeof(*pud_p) * PTRS_PER_PUD;
+                       p4d = native_make_p4d((pudval_t)pud_p + P4D_FLAGS);
+                       native_set_p4d(p4d_p, p4d);
+               }
+       }
+-      pud_p += pud_index(vaddr);
++      pud_p += pud_index(ppd->vaddr);
+       if (native_pud_val(*pud_p)) {
+               if (native_pud_val(*pud_p) & _PAGE_PSE)
+-                      goto out;
++                      return;
+               pmd_p = (pmd_t *)(native_pud_val(*pud_p) & ~PTE_FLAGS_MASK);
+       } else {
+               pud_t pud;
+-              pmd_p = pgtable_area;
++              pmd_p = ppd->pgtable_area;
+               memset(pmd_p, 0, sizeof(*pmd_p) * PTRS_PER_PMD);
+-              pgtable_area += sizeof(*pmd_p) * PTRS_PER_PMD;
++              ppd->pgtable_area += sizeof(*pmd_p) * PTRS_PER_PMD;
+               pud = native_make_pud((pmdval_t)pmd_p + PUD_FLAGS);
+               native_set_pud(pud_p, pud);
+       }
+-      pmd_p += pmd_index(vaddr);
++      pmd_p += pmd_index(ppd->vaddr);
+       if (!native_pmd_val(*pmd_p) || !(native_pmd_val(*pmd_p) & _PAGE_PSE))
+-              native_set_pmd(pmd_p, native_make_pmd(pmd_val));
+-
+-out:
+-      return pgtable_area;
++              native_set_pmd(pmd_p, native_make_pmd(ppd->pmd_val));
+ }
+ static unsigned long __init sme_pgtable_calc(unsigned long len)
+@@ -364,11 +368,10 @@ void __init sme_encrypt_kernel(void)
+       unsigned long workarea_start, workarea_end, workarea_len;
+       unsigned long execute_start, execute_end, execute_len;
+       unsigned long kernel_start, kernel_end, kernel_len;
++      struct sme_populate_pgd_data ppd;
+       unsigned long pgtable_area_len;
+       unsigned long paddr, pmd_flags;
+       unsigned long decrypted_base;
+-      void *pgtable_area;
+-      pgd_t *pgd;
+       if (!sme_active())
+               return;
+@@ -432,18 +435,18 @@ void __init sme_encrypt_kernel(void)
+        * pagetables and when the new encrypted and decrypted kernel
+        * mappings are populated.
+        */
+-      pgtable_area = (void *)execute_end;
++      ppd.pgtable_area = (void *)execute_end;
+       /*
+        * Make sure the current pagetable structure has entries for
+        * addressing the workarea.
+        */
+-      pgd = (pgd_t *)native_read_cr3_pa();
++      ppd.pgd = (pgd_t *)native_read_cr3_pa();
+       paddr = workarea_start;
+       while (paddr < workarea_end) {
+-              pgtable_area = sme_populate_pgd(pgd, pgtable_area,
+-                                              paddr,
+-                                              paddr + PMD_FLAGS);
++              ppd.pmd_val = paddr + PMD_FLAGS;
++              ppd.vaddr = paddr;
++              sme_populate_pgd_large(&ppd);
+               paddr += PMD_PAGE_SIZE;
+       }
+@@ -457,17 +460,17 @@ void __init sme_encrypt_kernel(void)
+        * populated with new PUDs and PMDs as the encrypted and decrypted
+        * kernel mappings are created.
+        */
+-      pgd = pgtable_area;
+-      memset(pgd, 0, sizeof(*pgd) * PTRS_PER_PGD);
+-      pgtable_area += sizeof(*pgd) * PTRS_PER_PGD;
++      ppd.pgd = ppd.pgtable_area;
++      memset(ppd.pgd, 0, sizeof(pgd_t) * PTRS_PER_PGD);
++      ppd.pgtable_area += sizeof(pgd_t) * PTRS_PER_PGD;
+       /* Add encrypted kernel (identity) mappings */
+       pmd_flags = PMD_FLAGS | _PAGE_ENC;
+       paddr = kernel_start;
+       while (paddr < kernel_end) {
+-              pgtable_area = sme_populate_pgd(pgd, pgtable_area,
+-                                              paddr,
+-                                              paddr + pmd_flags);
++              ppd.pmd_val = paddr + pmd_flags;
++              ppd.vaddr = paddr;
++              sme_populate_pgd_large(&ppd);
+               paddr += PMD_PAGE_SIZE;
+       }
+@@ -485,9 +488,9 @@ void __init sme_encrypt_kernel(void)
+       pmd_flags = (PMD_FLAGS & ~_PAGE_CACHE_MASK) | (_PAGE_PAT | _PAGE_PWT);
+       paddr = kernel_start;
+       while (paddr < kernel_end) {
+-              pgtable_area = sme_populate_pgd(pgd, pgtable_area,
+-                                              paddr + decrypted_base,
+-                                              paddr + pmd_flags);
++              ppd.pmd_val = paddr + pmd_flags;
++              ppd.vaddr = paddr + decrypted_base;
++              sme_populate_pgd_large(&ppd);
+               paddr += PMD_PAGE_SIZE;
+       }
+@@ -495,30 +498,29 @@ void __init sme_encrypt_kernel(void)
+       /* Add decrypted workarea mappings to both kernel mappings */
+       paddr = workarea_start;
+       while (paddr < workarea_end) {
+-              pgtable_area = sme_populate_pgd(pgd, pgtable_area,
+-                                              paddr,
+-                                              paddr + PMD_FLAGS);
+-
+-              pgtable_area = sme_populate_pgd(pgd, pgtable_area,
+-                                              paddr + decrypted_base,
+-                                              paddr + PMD_FLAGS);
++              ppd.pmd_val = paddr + PMD_FLAGS;
++              ppd.vaddr = paddr;
++              sme_populate_pgd_large(&ppd);
++
++              ppd.vaddr = paddr + decrypted_base;
++              sme_populate_pgd_large(&ppd);
+               paddr += PMD_PAGE_SIZE;
+       }
+       /* Perform the encryption */
+       sme_encrypt_execute(kernel_start, kernel_start + decrypted_base,
+-                          kernel_len, workarea_start, (unsigned long)pgd);
++                          kernel_len, workarea_start, (unsigned long)ppd.pgd);
+       /*
+        * At this point we are running encrypted.  Remove the mappings for
+        * the decrypted areas - all that is needed for this is to remove
+        * the PGD entry/entries.
+        */
+-      sme_clear_pgd(pgd, kernel_start + decrypted_base,
++      sme_clear_pgd(ppd.pgd, kernel_start + decrypted_base,
+                     kernel_end + decrypted_base);
+-      sme_clear_pgd(pgd, workarea_start + decrypted_base,
++      sme_clear_pgd(ppd.pgd, workarea_start + decrypted_base,
+                     workarea_end + decrypted_base);
+       /* Flush the TLB - no globals so cr3 is enough */