]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
fixes for 5.4
authorSasha Levin <sashal@kernel.org>
Tue, 10 Mar 2020 00:30:47 +0000 (20:30 -0400)
committerSasha Levin <sashal@kernel.org>
Tue, 10 Mar 2020 00:32:04 +0000 (20:32 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.4/powerpc-convert-flush_icache_range-friends-to-c.patch [new file with mode: 0644]
queue-5.4/powerpc-define-helpers-to-get-l1-icache-sizes.patch [new file with mode: 0644]
queue-5.4/powerpc-mm-fix-missing-kuap-disable-in-flush_coheren.patch [new file with mode: 0644]
queue-5.4/series

diff --git a/queue-5.4/powerpc-convert-flush_icache_range-friends-to-c.patch b/queue-5.4/powerpc-convert-flush_icache_range-friends-to-c.patch
new file mode 100644 (file)
index 0000000..3ff2c21
--- /dev/null
@@ -0,0 +1,545 @@
+From bfbf8bd13508c31fb7591ab0483b4d657e0b084a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Nov 2019 13:32:56 +1100
+Subject: powerpc: Convert flush_icache_range & friends to C
+
+From: Alastair D'Silva <alastair@d-silva.org>
+
+[ Upstream commit 23eb7f560a2a6a1b0dbaaaae8685da75314347e4 ]
+
+Similar to commit 22e9c88d486a
+("powerpc/64: reuse PPC32 static inline flush_dcache_range()")
+this patch converts the following ASM symbols to C:
+    flush_icache_range()
+    __flush_dcache_icache()
+    __flush_dcache_icache_phys()
+
+This was done as we discovered a long-standing bug where the length of the
+range was truncated due to using a 32 bit shift instead of a 64 bit one.
+
+By converting these functions to C, it becomes easier to maintain.
+
+flush_dcache_icache_phys() retains a critical assembler section as we must
+ensure there are no memory accesses while the data MMU is disabled
+(authored by Christophe Leroy). Since this has no external callers, it has
+also been made static, allowing the compiler to inline it within
+flush_dcache_icache_page().
+
+Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
+Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+[mpe: Minor fixups, don't export __flush_dcache_icache()]
+Link: https://lore.kernel.org/r/20191104023305.9581-5-alastair@au1.ibm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/include/asm/cache.h      |  26 ++---
+ arch/powerpc/include/asm/cacheflush.h |  24 ++---
+ arch/powerpc/kernel/misc_32.S         | 120 ---------------------
+ arch/powerpc/kernel/misc_64.S         | 102 ------------------
+ arch/powerpc/mm/mem.c                 | 150 +++++++++++++++++++++++++-
+ 5 files changed, 170 insertions(+), 252 deletions(-)
+
+diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
+index afb88754e0e07..72b81015cebe9 100644
+--- a/arch/powerpc/include/asm/cache.h
++++ b/arch/powerpc/include/asm/cache.h
+@@ -96,22 +96,7 @@ static inline u32 l1_icache_bytes(void)
+ }
+ #endif
+-#endif /* ! __ASSEMBLY__ */
+-
+-#if defined(__ASSEMBLY__)
+-/*
+- * For a snooping icache, we still need a dummy icbi to purge all the
+- * prefetched instructions from the ifetch buffers. We also need a sync
+- * before the icbi to order the the actual stores to memory that might
+- * have modified instructions with the icbi.
+- */
+-#define PURGE_PREFETCHED_INS  \
+-      sync;                   \
+-      icbi    0,r3;           \
+-      sync;                   \
+-      isync
+-#else
+ #define __read_mostly __attribute__((__section__(".data..read_mostly")))
+ #ifdef CONFIG_PPC_BOOK3S_32
+@@ -145,6 +130,17 @@ static inline void dcbst(void *addr)
+ {
+       __asm__ __volatile__ ("dcbst 0, %0" : : "r"(addr) : "memory");
+ }
++
++static inline void icbi(void *addr)
++{
++      asm volatile ("icbi 0, %0" : : "r"(addr) : "memory");
++}
++
++static inline void iccci(void *addr)
++{
++      asm volatile ("iccci 0, %0" : : "r"(addr) : "memory");
++}
++
+ #endif /* !__ASSEMBLY__ */
+ #endif /* __KERNEL__ */
+ #endif /* _ASM_POWERPC_CACHE_H */
+diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
+index ed57843ef4524..4a1c9f0200e1b 100644
+--- a/arch/powerpc/include/asm/cacheflush.h
++++ b/arch/powerpc/include/asm/cacheflush.h
+@@ -42,24 +42,20 @@ extern void flush_dcache_page(struct page *page);
+ #define flush_dcache_mmap_lock(mapping)               do { } while (0)
+ #define flush_dcache_mmap_unlock(mapping)     do { } while (0)
+-extern void flush_icache_range(unsigned long, unsigned long);
++void flush_icache_range(unsigned long start, unsigned long stop);
+ extern void flush_icache_user_range(struct vm_area_struct *vma,
+                                   struct page *page, unsigned long addr,
+                                   int len);
+-extern void __flush_dcache_icache(void *page_va);
+ extern void flush_dcache_icache_page(struct page *page);
+-#if defined(CONFIG_PPC32) && !defined(CONFIG_BOOKE)
+-extern void __flush_dcache_icache_phys(unsigned long physaddr);
+-#else
+-static inline void __flush_dcache_icache_phys(unsigned long physaddr)
+-{
+-      BUG();
+-}
+-#endif
+-
+-/*
+- * Write any modified data cache blocks out to memory and invalidate them.
+- * Does not invalidate the corresponding instruction cache blocks.
++void __flush_dcache_icache(void *page);
++
++/**
++ * flush_dcache_range(): Write any modified data cache blocks out to memory and
++ * invalidate them. Does not invalidate the corresponding instruction cache
++ * blocks.
++ *
++ * @start: the start address
++ * @stop: the stop address (exclusive)
+  */
+ static inline void flush_dcache_range(unsigned long start, unsigned long stop)
+ {
+diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
+index 82df4b09e79f4..f4e4a1926a7a5 100644
+--- a/arch/powerpc/kernel/misc_32.S
++++ b/arch/powerpc/kernel/misc_32.S
+@@ -316,126 +316,6 @@ _GLOBAL(flush_instruction_cache)
+ EXPORT_SYMBOL(flush_instruction_cache)
+ #endif /* CONFIG_PPC_8xx */
+-/*
+- * Write any modified data cache blocks out to memory
+- * and invalidate the corresponding instruction cache blocks.
+- * This is a no-op on the 601.
+- *
+- * flush_icache_range(unsigned long start, unsigned long stop)
+- */
+-_GLOBAL(flush_icache_range)
+-#if defined(CONFIG_PPC_BOOK3S_601) || defined(CONFIG_E200)
+-      PURGE_PREFETCHED_INS
+-      blr                             /* for 601 and e200, do nothing */
+-#else
+-      rlwinm  r3,r3,0,0,31 - L1_CACHE_SHIFT
+-      subf    r4,r3,r4
+-      addi    r4,r4,L1_CACHE_BYTES - 1
+-      srwi.   r4,r4,L1_CACHE_SHIFT
+-      beqlr
+-      mtctr   r4
+-      mr      r6,r3
+-1:    dcbst   0,r3
+-      addi    r3,r3,L1_CACHE_BYTES
+-      bdnz    1b
+-      sync                            /* wait for dcbst's to get to ram */
+-#ifndef CONFIG_44x
+-      mtctr   r4
+-2:    icbi    0,r6
+-      addi    r6,r6,L1_CACHE_BYTES
+-      bdnz    2b
+-#else
+-      /* Flash invalidate on 44x because we are passed kmapped addresses and
+-         this doesn't work for userspace pages due to the virtually tagged
+-         icache.  Sigh. */
+-      iccci   0, r0
+-#endif
+-      sync                            /* additional sync needed on g4 */
+-      isync
+-      blr
+-#endif
+-_ASM_NOKPROBE_SYMBOL(flush_icache_range)
+-EXPORT_SYMBOL(flush_icache_range)
+-
+-/*
+- * Flush a particular page from the data cache to RAM.
+- * Note: this is necessary because the instruction cache does *not*
+- * snoop from the data cache.
+- * This is a no-op on the 601 and e200 which have a unified cache.
+- *
+- *    void __flush_dcache_icache(void *page)
+- */
+-_GLOBAL(__flush_dcache_icache)
+-#if defined(CONFIG_PPC_BOOK3S_601) || defined(CONFIG_E200)
+-      PURGE_PREFETCHED_INS
+-      blr
+-#else
+-      rlwinm  r3,r3,0,0,31-PAGE_SHIFT         /* Get page base address */
+-      li      r4,PAGE_SIZE/L1_CACHE_BYTES     /* Number of lines in a page */
+-      mtctr   r4
+-      mr      r6,r3
+-0:    dcbst   0,r3                            /* Write line to ram */
+-      addi    r3,r3,L1_CACHE_BYTES
+-      bdnz    0b
+-      sync
+-#ifdef CONFIG_44x
+-      /* We don't flush the icache on 44x. Those have a virtual icache
+-       * and we don't have access to the virtual address here (it's
+-       * not the page vaddr but where it's mapped in user space). The
+-       * flushing of the icache on these is handled elsewhere, when
+-       * a change in the address space occurs, before returning to
+-       * user space
+-       */
+-BEGIN_MMU_FTR_SECTION
+-      blr
+-END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_44x)
+-#endif /* CONFIG_44x */
+-      mtctr   r4
+-1:    icbi    0,r6
+-      addi    r6,r6,L1_CACHE_BYTES
+-      bdnz    1b
+-      sync
+-      isync
+-      blr
+-#endif
+-
+-#ifndef CONFIG_BOOKE
+-/*
+- * Flush a particular page from the data cache to RAM, identified
+- * by its physical address.  We turn off the MMU so we can just use
+- * the physical address (this may be a highmem page without a kernel
+- * mapping).
+- *
+- *    void __flush_dcache_icache_phys(unsigned long physaddr)
+- */
+-_GLOBAL(__flush_dcache_icache_phys)
+-#if defined(CONFIG_PPC_BOOK3S_601) || defined(CONFIG_E200)
+-      PURGE_PREFETCHED_INS
+-      blr                                     /* for 601 and e200, do nothing */
+-#else
+-      mfmsr   r10
+-      rlwinm  r0,r10,0,28,26                  /* clear DR */
+-      mtmsr   r0
+-      isync
+-      rlwinm  r3,r3,0,0,31-PAGE_SHIFT         /* Get page base address */
+-      li      r4,PAGE_SIZE/L1_CACHE_BYTES     /* Number of lines in a page */
+-      mtctr   r4
+-      mr      r6,r3
+-0:    dcbst   0,r3                            /* Write line to ram */
+-      addi    r3,r3,L1_CACHE_BYTES
+-      bdnz    0b
+-      sync
+-      mtctr   r4
+-1:    icbi    0,r6
+-      addi    r6,r6,L1_CACHE_BYTES
+-      bdnz    1b
+-      sync
+-      mtmsr   r10                             /* restore DR */
+-      isync
+-      blr
+-#endif
+-#endif /* CONFIG_BOOKE */
+-
+ /*
+  * Copy a whole page.  We use the dcbz instruction on the destination
+  * to reduce memory traffic (it eliminates the unnecessary reads of
+diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
+index 9bc0aa9aeb654..ff20c253f2737 100644
+--- a/arch/powerpc/kernel/misc_64.S
++++ b/arch/powerpc/kernel/misc_64.S
+@@ -49,108 +49,6 @@ _GLOBAL(call_do_irq)
+       mtlr    r0
+       blr
+-      .section        ".toc","aw"
+-PPC64_CACHES:
+-      .tc             ppc64_caches[TC],ppc64_caches
+-      .section        ".text"
+-
+-/*
+- * Write any modified data cache blocks out to memory
+- * and invalidate the corresponding instruction cache blocks.
+- *
+- * flush_icache_range(unsigned long start, unsigned long stop)
+- *
+- *   flush all bytes from start through stop-1 inclusive
+- */
+-
+-_GLOBAL_TOC(flush_icache_range)
+-BEGIN_FTR_SECTION
+-      PURGE_PREFETCHED_INS
+-      blr
+-END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
+-/*
+- * Flush the data cache to memory 
+- * 
+- * Different systems have different cache line sizes
+- * and in some cases i-cache and d-cache line sizes differ from
+- * each other.
+- */
+-      ld      r10,PPC64_CACHES@toc(r2)
+-      lwz     r7,DCACHEL1BLOCKSIZE(r10)/* Get cache block size */
+-      addi    r5,r7,-1
+-      andc    r6,r3,r5                /* round low to line bdy */
+-      subf    r8,r6,r4                /* compute length */
+-      add     r8,r8,r5                /* ensure we get enough */
+-      lwz     r9,DCACHEL1LOGBLOCKSIZE(r10)    /* Get log-2 of cache block size */
+-      srd.    r8,r8,r9                /* compute line count */
+-      beqlr                           /* nothing to do? */
+-      mtctr   r8
+-1:    dcbst   0,r6
+-      add     r6,r6,r7
+-      bdnz    1b
+-      sync
+-
+-/* Now invalidate the instruction cache */
+-      
+-      lwz     r7,ICACHEL1BLOCKSIZE(r10)       /* Get Icache block size */
+-      addi    r5,r7,-1
+-      andc    r6,r3,r5                /* round low to line bdy */
+-      subf    r8,r6,r4                /* compute length */
+-      add     r8,r8,r5
+-      lwz     r9,ICACHEL1LOGBLOCKSIZE(r10)    /* Get log-2 of Icache block size */
+-      srd.    r8,r8,r9                /* compute line count */
+-      beqlr                           /* nothing to do? */
+-      mtctr   r8
+-2:    icbi    0,r6
+-      add     r6,r6,r7
+-      bdnz    2b
+-      isync
+-      blr
+-_ASM_NOKPROBE_SYMBOL(flush_icache_range)
+-EXPORT_SYMBOL(flush_icache_range)
+-
+-/*
+- * Flush a particular page from the data cache to RAM.
+- * Note: this is necessary because the instruction cache does *not*
+- * snoop from the data cache.
+- *
+- *    void __flush_dcache_icache(void *page)
+- */
+-_GLOBAL(__flush_dcache_icache)
+-/*
+- * Flush the data cache to memory 
+- * 
+- * Different systems have different cache line sizes
+- */
+-
+-BEGIN_FTR_SECTION
+-      PURGE_PREFETCHED_INS
+-      blr
+-END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
+-
+-/* Flush the dcache */
+-      ld      r7,PPC64_CACHES@toc(r2)
+-      clrrdi  r3,r3,PAGE_SHIFT                    /* Page align */
+-      lwz     r4,DCACHEL1BLOCKSPERPAGE(r7)    /* Get # dcache blocks per page */
+-      lwz     r5,DCACHEL1BLOCKSIZE(r7)        /* Get dcache block size */
+-      mr      r6,r3
+-      mtctr   r4
+-0:    dcbst   0,r6
+-      add     r6,r6,r5
+-      bdnz    0b
+-      sync
+-
+-/* Now invalidate the icache */       
+-
+-      lwz     r4,ICACHEL1BLOCKSPERPAGE(r7)    /* Get # icache blocks per page */
+-      lwz     r5,ICACHEL1BLOCKSIZE(r7)        /* Get icache block size */
+-      mtctr   r4
+-1:    icbi    0,r3
+-      add     r3,r3,r5
+-      bdnz    1b
+-      isync
+-      blr
+-
+ _GLOBAL(__bswapdi2)
+ EXPORT_SYMBOL(__bswapdi2)
+       srdi    r8,r3,32
+diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
+index 9f5b32163bda3..6612796ea69c2 100644
+--- a/arch/powerpc/mm/mem.c
++++ b/arch/powerpc/mm/mem.c
+@@ -348,6 +348,120 @@ void free_initmem(void)
+       free_initmem_default(POISON_FREE_INITMEM);
+ }
++/**
++ * flush_coherent_icache() - if a CPU has a coherent icache, flush it
++ * @addr: The base address to use (can be any valid address, the whole cache will be flushed)
++ * Return true if the cache was flushed, false otherwise
++ */
++static inline bool flush_coherent_icache(unsigned long addr)
++{
++      /*
++       * For a snooping icache, we still need a dummy icbi to purge all the
++       * prefetched instructions from the ifetch buffers. We also need a sync
++       * before the icbi to order the the actual stores to memory that might
++       * have modified instructions with the icbi.
++       */
++      if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
++              mb(); /* sync */
++              icbi((void *)addr);
++              mb(); /* sync */
++              isync();
++              return true;
++      }
++
++      return false;
++}
++
++/**
++ * invalidate_icache_range() - Flush the icache by issuing icbi across an address range
++ * @start: the start address
++ * @stop: the stop address (exclusive)
++ */
++static void invalidate_icache_range(unsigned long start, unsigned long stop)
++{
++      unsigned long shift = l1_icache_shift();
++      unsigned long bytes = l1_icache_bytes();
++      char *addr = (char *)(start & ~(bytes - 1));
++      unsigned long size = stop - (unsigned long)addr + (bytes - 1);
++      unsigned long i;
++
++      for (i = 0; i < size >> shift; i++, addr += bytes)
++              icbi(addr);
++
++      mb(); /* sync */
++      isync();
++}
++
++/**
++ * flush_icache_range: Write any modified data cache blocks out to memory
++ * and invalidate the corresponding blocks in the instruction cache
++ *
++ * Generic code will call this after writing memory, before executing from it.
++ *
++ * @start: the start address
++ * @stop: the stop address (exclusive)
++ */
++void flush_icache_range(unsigned long start, unsigned long stop)
++{
++      if (flush_coherent_icache(start))
++              return;
++
++      clean_dcache_range(start, stop);
++
++      if (IS_ENABLED(CONFIG_44x)) {
++              /*
++               * Flash invalidate on 44x because we are passed kmapped
++               * addresses and this doesn't work for userspace pages due to
++               * the virtually tagged icache.
++               */
++              iccci((void *)start);
++              mb(); /* sync */
++              isync();
++      } else
++              invalidate_icache_range(start, stop);
++}
++EXPORT_SYMBOL(flush_icache_range);
++
++#if !defined(CONFIG_PPC_8xx) && !defined(CONFIG_PPC64)
++/**
++ * flush_dcache_icache_phys() - Flush a page by it's physical address
++ * @physaddr: the physical address of the page
++ */
++static void flush_dcache_icache_phys(unsigned long physaddr)
++{
++      unsigned long bytes = l1_dcache_bytes();
++      unsigned long nb = PAGE_SIZE / bytes;
++      unsigned long addr = physaddr & PAGE_MASK;
++      unsigned long msr, msr0;
++      unsigned long loop1 = addr, loop2 = addr;
++
++      msr0 = mfmsr();
++      msr = msr0 & ~MSR_DR;
++      /*
++       * This must remain as ASM to prevent potential memory accesses
++       * while the data MMU is disabled
++       */
++      asm volatile(
++              "   mtctr %2;\n"
++              "   mtmsr %3;\n"
++              "   isync;\n"
++              "0: dcbst   0, %0;\n"
++              "   addi    %0, %0, %4;\n"
++              "   bdnz    0b;\n"
++              "   sync;\n"
++              "   mtctr %2;\n"
++              "1: icbi    0, %1;\n"
++              "   addi    %1, %1, %4;\n"
++              "   bdnz    1b;\n"
++              "   sync;\n"
++              "   mtmsr %5;\n"
++              "   isync;\n"
++              : "+&r" (loop1), "+&r" (loop2)
++              : "r" (nb), "r" (msr), "i" (bytes), "r" (msr0)
++              : "ctr", "memory");
++}
++#endif // !defined(CONFIG_PPC_8xx) && !defined(CONFIG_PPC64)
++
+ /*
+  * This is called when a page has been modified by the kernel.
+  * It just marks the page as not i-cache clean.  We do the i-cache
+@@ -380,12 +494,46 @@ void flush_dcache_icache_page(struct page *page)
+               __flush_dcache_icache(start);
+               kunmap_atomic(start);
+       } else {
+-              __flush_dcache_icache_phys(page_to_pfn(page) << PAGE_SHIFT);
++              unsigned long addr = page_to_pfn(page) << PAGE_SHIFT;
++
++              if (flush_coherent_icache(addr))
++                      return;
++              flush_dcache_icache_phys(addr);
+       }
+ #endif
+ }
+ EXPORT_SYMBOL(flush_dcache_icache_page);
++/**
++ * __flush_dcache_icache(): Flush a particular page from the data cache to RAM.
++ * Note: this is necessary because the instruction cache does *not*
++ * snoop from the data cache.
++ *
++ * @page: the address of the page to flush
++ */
++void __flush_dcache_icache(void *p)
++{
++      unsigned long addr = (unsigned long)p;
++
++      if (flush_coherent_icache(addr))
++              return;
++
++      clean_dcache_range(addr, addr + PAGE_SIZE);
++
++      /*
++       * We don't flush the icache on 44x. Those have a virtual icache and we
++       * don't have access to the virtual address here (it's not the page
++       * vaddr but where it's mapped in user space). The flushing of the
++       * icache on these is handled elsewhere, when a change in the address
++       * space occurs, before returning to user space.
++       */
++
++      if (cpu_has_feature(MMU_FTR_TYPE_44x))
++              return;
++
++      invalidate_icache_range(addr, addr + PAGE_SIZE);
++}
++
+ void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
+ {
+       clear_page(page);
+-- 
+2.20.1
+
diff --git a/queue-5.4/powerpc-define-helpers-to-get-l1-icache-sizes.patch b/queue-5.4/powerpc-define-helpers-to-get-l1-icache-sizes.patch
new file mode 100644 (file)
index 0000000..06c76fd
--- /dev/null
@@ -0,0 +1,116 @@
+From 14251a37e901a8d373d2adb7bbc2ed6e8107f074 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Nov 2019 13:32:55 +1100
+Subject: powerpc: define helpers to get L1 icache sizes
+
+From: Alastair D'Silva <alastair@d-silva.org>
+
+[ Upstream commit 7a0745c5e03ff1129864bc6d80f5c4417e8d7893 ]
+
+This patch adds helpers to retrieve icache sizes, and renames the existing
+helpers to make it clear that they are for dcache.
+
+Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/20191104023305.9581-4-alastair@au1.ibm.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/include/asm/cache.h      | 29 +++++++++++++++++++++++----
+ arch/powerpc/include/asm/cacheflush.h | 12 +++++------
+ 2 files changed, 31 insertions(+), 10 deletions(-)
+
+diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
+index 45e3137ccd71c..afb88754e0e07 100644
+--- a/arch/powerpc/include/asm/cache.h
++++ b/arch/powerpc/include/asm/cache.h
+@@ -55,25 +55,46 @@ struct ppc64_caches {
+ extern struct ppc64_caches ppc64_caches;
+-static inline u32 l1_cache_shift(void)
++static inline u32 l1_dcache_shift(void)
+ {
+       return ppc64_caches.l1d.log_block_size;
+ }
+-static inline u32 l1_cache_bytes(void)
++static inline u32 l1_dcache_bytes(void)
+ {
+       return ppc64_caches.l1d.block_size;
+ }
++
++static inline u32 l1_icache_shift(void)
++{
++      return ppc64_caches.l1i.log_block_size;
++}
++
++static inline u32 l1_icache_bytes(void)
++{
++      return ppc64_caches.l1i.block_size;
++}
+ #else
+-static inline u32 l1_cache_shift(void)
++static inline u32 l1_dcache_shift(void)
+ {
+       return L1_CACHE_SHIFT;
+ }
+-static inline u32 l1_cache_bytes(void)
++static inline u32 l1_dcache_bytes(void)
+ {
+       return L1_CACHE_BYTES;
+ }
++
++static inline u32 l1_icache_shift(void)
++{
++      return L1_CACHE_SHIFT;
++}
++
++static inline u32 l1_icache_bytes(void)
++{
++      return L1_CACHE_BYTES;
++}
++
+ #endif
+ #endif /* ! __ASSEMBLY__ */
+diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
+index eef388f2659f4..ed57843ef4524 100644
+--- a/arch/powerpc/include/asm/cacheflush.h
++++ b/arch/powerpc/include/asm/cacheflush.h
+@@ -63,8 +63,8 @@ static inline void __flush_dcache_icache_phys(unsigned long physaddr)
+  */
+ static inline void flush_dcache_range(unsigned long start, unsigned long stop)
+ {
+-      unsigned long shift = l1_cache_shift();
+-      unsigned long bytes = l1_cache_bytes();
++      unsigned long shift = l1_dcache_shift();
++      unsigned long bytes = l1_dcache_bytes();
+       void *addr = (void *)(start & ~(bytes - 1));
+       unsigned long size = stop - (unsigned long)addr + (bytes - 1);
+       unsigned long i;
+@@ -89,8 +89,8 @@ static inline void flush_dcache_range(unsigned long start, unsigned long stop)
+  */
+ static inline void clean_dcache_range(unsigned long start, unsigned long stop)
+ {
+-      unsigned long shift = l1_cache_shift();
+-      unsigned long bytes = l1_cache_bytes();
++      unsigned long shift = l1_dcache_shift();
++      unsigned long bytes = l1_dcache_bytes();
+       void *addr = (void *)(start & ~(bytes - 1));
+       unsigned long size = stop - (unsigned long)addr + (bytes - 1);
+       unsigned long i;
+@@ -108,8 +108,8 @@ static inline void clean_dcache_range(unsigned long start, unsigned long stop)
+ static inline void invalidate_dcache_range(unsigned long start,
+                                          unsigned long stop)
+ {
+-      unsigned long shift = l1_cache_shift();
+-      unsigned long bytes = l1_cache_bytes();
++      unsigned long shift = l1_dcache_shift();
++      unsigned long bytes = l1_dcache_bytes();
+       void *addr = (void *)(start & ~(bytes - 1));
+       unsigned long size = stop - (unsigned long)addr + (bytes - 1);
+       unsigned long i;
+-- 
+2.20.1
+
diff --git a/queue-5.4/powerpc-mm-fix-missing-kuap-disable-in-flush_coheren.patch b/queue-5.4/powerpc-mm-fix-missing-kuap-disable-in-flush_coheren.patch
new file mode 100644 (file)
index 0000000..6f7bd01
--- /dev/null
@@ -0,0 +1,92 @@
+From 87892beab5dde8ba26f7b211eeba745481ba7eb4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Mar 2020 23:28:47 +1100
+Subject: powerpc/mm: Fix missing KUAP disable in flush_coherent_icache()
+
+From: Michael Ellerman <mpe@ellerman.id.au>
+
+[ Upstream commit 59bee45b9712c759ea4d3dcc4eff1752f3a66558 ]
+
+Stefan reported a strange kernel fault which turned out to be due to a
+missing KUAP disable in flush_coherent_icache() called from
+flush_icache_range().
+
+The fault looks like:
+
+  Kernel attempted to access user page (7fffc30d9c00) - exploit attempt? (uid: 1009)
+  BUG: Unable to handle kernel data access on read at 0x7fffc30d9c00
+  Faulting instruction address: 0xc00000000007232c
+  Oops: Kernel access of bad area, sig: 11 [#1]
+  LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=2048 NUMA PowerNV
+  CPU: 35 PID: 5886 Comm: sigtramp Not tainted 5.6.0-rc2-gcc-8.2.0-00003-gfc37a1632d40 #79
+  NIP:  c00000000007232c LR: c00000000003b7fc CTR: 0000000000000000
+  REGS: c000001e11093940 TRAP: 0300   Not tainted  (5.6.0-rc2-gcc-8.2.0-00003-gfc37a1632d40)
+  MSR:  900000000280b033 <SF,HV,VEC,VSX,EE,FP,ME,IR,DR,RI,LE>  CR: 28000884  XER: 00000000
+  CFAR: c0000000000722fc DAR: 00007fffc30d9c00 DSISR: 08000000 IRQMASK: 0
+  GPR00: c00000000003b7fc c000001e11093bd0 c0000000023ac200 00007fffc30d9c00
+  GPR04: 00007fffc30d9c18 0000000000000000 c000001e11093bd4 0000000000000000
+  GPR08: 0000000000000000 0000000000000001 0000000000000000 c000001e1104ed80
+  GPR12: 0000000000000000 c000001fff6ab380 c0000000016be2d0 4000000000000000
+  GPR16: c000000000000000 bfffffffffffffff 0000000000000000 0000000000000000
+  GPR20: 00007fffc30d9c00 00007fffc30d8f58 00007fffc30d9c18 00007fffc30d9c20
+  GPR24: 00007fffc30d9c18 0000000000000000 c000001e11093d90 c000001e1104ed80
+  GPR28: c000001e11093e90 0000000000000000 c0000000023d9d18 00007fffc30d9c00
+  NIP flush_icache_range+0x5c/0x80
+  LR  handle_rt_signal64+0x95c/0xc2c
+  Call Trace:
+    0xc000001e11093d90 (unreliable)
+    handle_rt_signal64+0x93c/0xc2c
+    do_notify_resume+0x310/0x430
+    ret_from_except_lite+0x70/0x74
+  Instruction dump:
+  409e002c 7c0802a6 3c62ff31 3863f6a0 f8010080 48195fed 60000000 48fe4c8d
+  60000000 e8010080 7c0803a6 7c0004ac <7c00ffac> 7c0004ac 4c00012c 38210070
+
+This path through handle_rt_signal64() to setup_trampoline() and
+flush_icache_range() is only triggered by 64-bit processes that have
+unmapped their VDSO, which is rare.
+
+flush_icache_range() takes a range of addresses to flush. In
+flush_coherent_icache() we implement an optimisation for CPUs where we
+know we don't actually have to flush the whole range, we just need to
+do a single icbi.
+
+However we still execute the icbi on the user address of the start of
+the range we're flushing. On CPUs that also implement KUAP (Power9)
+that leads to the spurious fault above.
+
+We should be able to pass any address, including a kernel address, to
+the icbi on these CPUs, which would avoid any interaction with KUAP.
+But I don't want to make that change in a bug fix, just in case it
+surfaces some strange behaviour on some CPU.
+
+So for now just disable KUAP around the icbi. Note the icbi is treated
+as a load, so we allow read access, not write as you'd expect.
+
+Fixes: 890274c2dc4c ("powerpc/64s: Implement KUAP for Radix MMU")
+Cc: stable@vger.kernel.org # v5.2+
+Reported-by: Stefan Berger <stefanb@linux.ibm.com>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/20200303235708.26004-1-mpe@ellerman.id.au
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/mm/mem.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
+index 6612796ea69c2..96ca90ce0264a 100644
+--- a/arch/powerpc/mm/mem.c
++++ b/arch/powerpc/mm/mem.c
+@@ -363,7 +363,9 @@ static inline bool flush_coherent_icache(unsigned long addr)
+        */
+       if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
+               mb(); /* sync */
++              allow_read_from_user((const void __user *)addr, L1_CACHE_BYTES);
+               icbi((void *)addr);
++              prevent_read_from_user((const void __user *)addr, L1_CACHE_BYTES);
+               mb(); /* sync */
+               isync();
+               return true;
+-- 
+2.20.1
+
index 34e12817aa21c53f9046176be9600adf34f017f4..f3ca991eca10d2b3d353a4d9a735f806269e4b03 100644 (file)
@@ -120,3 +120,6 @@ asoc-topology-fix-memleak-in-soc_tplg_manifest_load.patch
 asoc-sof-fix-snd_sof_ipc_stream_posn.patch
 asoc-intel-skl-fix-pin-debug-prints.patch
 asoc-intel-skl-fix-possible-buffer-overflow-in-debug-outputs.patch
+powerpc-define-helpers-to-get-l1-icache-sizes.patch
+powerpc-convert-flush_icache_range-friends-to-c.patch
+powerpc-mm-fix-missing-kuap-disable-in-flush_coheren.patch