From: Greg Kroah-Hartman Date: Sun, 29 May 2016 21:42:54 +0000 (-0700) Subject: 4.6-stable patches X-Git-Tag: v3.14.71~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=735663c00aea313ce50b475e0efe5126401c406a;p=thirdparty%2Fkernel%2Fstable-queue.git 4.6-stable patches added patches: arm-arm64-kvm-enforce-break-before-make-on-stage-2-page-tables.patch arm64-cpuinfo-missing-null-terminator-in-compat_hwcap_str.patch arm64-ensure-pmd_present-returns-false-after-pmd_mknotpresent.patch arm64-fix-typo-in-the-pmdp_huge_get_and_clear-definition.patch arm64-implement-pmdp_set_access_flags-for-hardware-af-dbm.patch arm64-implement-ptep_set_access_flags-for-hardware-af-dbm.patch kvm-arm64-fix-ec-field-in-inject_abt64.patch --- diff --git a/queue-4.6/arm-arm64-kvm-enforce-break-before-make-on-stage-2-page-tables.patch b/queue-4.6/arm-arm64-kvm-enforce-break-before-make-on-stage-2-page-tables.patch new file mode 100644 index 00000000000..f2209cf72b8 --- /dev/null +++ b/queue-4.6/arm-arm64-kvm-enforce-break-before-make-on-stage-2-page-tables.patch @@ -0,0 +1,63 @@ +From d4b9e0790aa764c0b01e18d4e8d33e93ba36d51f Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Thu, 28 Apr 2016 16:16:31 +0100 +Subject: arm/arm64: KVM: Enforce Break-Before-Make on Stage-2 page tables + +From: Marc Zyngier + +commit d4b9e0790aa764c0b01e18d4e8d33e93ba36d51f upstream. + +The ARM architecture mandates that when changing a page table entry +from a valid entry to another valid entry, an invalid entry is first +written, TLB invalidated, and only then the new entry being written. + +The current code doesn't respect this, directly writing the new +entry and only then invalidating TLBs. Let's fix it up. + +Reported-by: Christoffer Dall +Signed-off-by: Marc Zyngier +Signed-off-by: Christoffer Dall +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm/kvm/mmu.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +--- a/arch/arm/kvm/mmu.c ++++ b/arch/arm/kvm/mmu.c +@@ -893,11 +893,14 @@ static int stage2_set_pmd_huge(struct kv + VM_BUG_ON(pmd_present(*pmd) && pmd_pfn(*pmd) != pmd_pfn(*new_pmd)); + + old_pmd = *pmd; +- kvm_set_pmd(pmd, *new_pmd); +- if (pmd_present(old_pmd)) ++ if (pmd_present(old_pmd)) { ++ pmd_clear(pmd); + kvm_tlb_flush_vmid_ipa(kvm, addr); +- else ++ } else { + get_page(virt_to_page(pmd)); ++ } ++ ++ kvm_set_pmd(pmd, *new_pmd); + return 0; + } + +@@ -946,12 +949,14 @@ static int stage2_set_pte(struct kvm *kv + + /* Create 2nd stage page table mapping - Level 3 */ + old_pte = *pte; +- kvm_set_pte(pte, *new_pte); +- if (pte_present(old_pte)) ++ if (pte_present(old_pte)) { ++ kvm_set_pte(pte, __pte(0)); + kvm_tlb_flush_vmid_ipa(kvm, addr); +- else ++ } else { + get_page(virt_to_page(pte)); ++ } + ++ kvm_set_pte(pte, *new_pte); + return 0; + } + diff --git a/queue-4.6/arm64-cpuinfo-missing-null-terminator-in-compat_hwcap_str.patch b/queue-4.6/arm64-cpuinfo-missing-null-terminator-in-compat_hwcap_str.patch new file mode 100644 index 00000000000..f5d6fdcb367 --- /dev/null +++ b/queue-4.6/arm64-cpuinfo-missing-null-terminator-in-compat_hwcap_str.patch @@ -0,0 +1,44 @@ +From f228b494e56d949be8d8ea09d4f973d1979201bf Mon Sep 17 00:00:00 2001 +From: Julien Grall +Date: Tue, 10 May 2016 15:40:31 +0100 +Subject: arm64: cpuinfo: Missing NULL terminator in compat_hwcap_str + +From: Julien Grall + +commit f228b494e56d949be8d8ea09d4f973d1979201bf upstream. + +The loop that browses the array compat_hwcap_str will stop when a NULL +is encountered, however NULL is missing at the end of array. This will +lead to overrun until a NULL is found somewhere in the following memory. +In reality, this works out because the compat_hwcap2_str array tends to +follow immediately in memory, and that *is* terminated correctly. +Furthermore, the unsigned int compat_elf_hwcap is checked before +printing each capability, so we end up doing the right thing because +the size of the two arrays is less than 32. Still, this is an obvious +mistake and should be fixed. + +Note for backporting: commit 12d11817eaafa414 ("arm64: Move +/proc/cpuinfo handling code") moved this code in v4.4. Prior to that +commit, the same change should be made in arch/arm64/kernel/setup.c. + +Fixes: 44b82b7700d0 "arm64: Fix up /proc/cpuinfo" +Signed-off-by: Julien Grall +Signed-off-by: Will Deacon +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/kernel/cpuinfo.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/arch/arm64/kernel/cpuinfo.c ++++ b/arch/arm64/kernel/cpuinfo.c +@@ -87,7 +87,8 @@ static const char *const compat_hwcap_st + "idivt", + "vfpd32", + "lpae", +- "evtstrm" ++ "evtstrm", ++ NULL + }; + + static const char *const compat_hwcap2_str[] = { diff --git a/queue-4.6/arm64-ensure-pmd_present-returns-false-after-pmd_mknotpresent.patch b/queue-4.6/arm64-ensure-pmd_present-returns-false-after-pmd_mknotpresent.patch new file mode 100644 index 00000000000..e8d06b5ac4d --- /dev/null +++ b/queue-4.6/arm64-ensure-pmd_present-returns-false-after-pmd_mknotpresent.patch @@ -0,0 +1,70 @@ +From 5bb1cc0ff9a6b68871970737e6c4c16919928d8b Mon Sep 17 00:00:00 2001 +From: Catalin Marinas +Date: Thu, 5 May 2016 10:44:02 +0100 +Subject: arm64: Ensure pmd_present() returns false after pmd_mknotpresent() + +From: Catalin Marinas + +commit 5bb1cc0ff9a6b68871970737e6c4c16919928d8b upstream. + +Currently, pmd_present() only checks for a non-zero value, returning +true even after pmd_mknotpresent() (which only clears the type bits). +This patch converts pmd_present() to using pte_present(), similar to the +other pmd_*() checks. As a side effect, it will return true for +PROT_NONE mappings, though they are not yet used by the kernel with +transparent huge pages. + +For consistency, also change pmd_mknotpresent() to only clear the +PMD_SECT_VALID bit, even though the PMD_TABLE_BIT is already 0 for block +mappings (no functional change). The unused PMD_SECT_PROT_NONE +definition is removed as transparent huge pages use the pte page prot +values. + +Fixes: 9c7e535fcc17 ("arm64: mm: Route pmd thp functions through pte equivalents") +Reviewed-by: Will Deacon +Signed-off-by: Catalin Marinas +Signed-off-by: Will Deacon +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/include/asm/pgtable-hwdef.h | 1 - + arch/arm64/include/asm/pgtable.h | 4 ++-- + 2 files changed, 2 insertions(+), 3 deletions(-) + +--- a/arch/arm64/include/asm/pgtable-hwdef.h ++++ b/arch/arm64/include/asm/pgtable-hwdef.h +@@ -133,7 +133,6 @@ + * Section + */ + #define PMD_SECT_VALID (_AT(pmdval_t, 1) << 0) +-#define PMD_SECT_PROT_NONE (_AT(pmdval_t, 1) << 58) + #define PMD_SECT_USER (_AT(pmdval_t, 1) << 6) /* AP[1] */ + #define PMD_SECT_RDONLY (_AT(pmdval_t, 1) << 7) /* AP[2] */ + #define PMD_SECT_S (_AT(pmdval_t, 3) << 8) +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -280,6 +280,7 @@ static inline pgprot_t mk_sect_prot(pgpr + #define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT)) + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + ++#define pmd_present(pmd) pte_present(pmd_pte(pmd)) + #define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd)) + #define pmd_young(pmd) pte_young(pmd_pte(pmd)) + #define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd))) +@@ -288,7 +289,7 @@ static inline pgprot_t mk_sect_prot(pgpr + #define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd))) + #define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) + #define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) +-#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK)) ++#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) & ~PMD_SECT_VALID)) + + #define __HAVE_ARCH_PMD_WRITE + #define pmd_write(pmd) pte_write(pmd_pte(pmd)) +@@ -327,7 +328,6 @@ extern pgprot_t phys_mem_access_prot(str + unsigned long size, pgprot_t vma_prot); + + #define pmd_none(pmd) (!pmd_val(pmd)) +-#define pmd_present(pmd) (pmd_val(pmd)) + + #define pmd_bad(pmd) (!(pmd_val(pmd) & 2)) + diff --git a/queue-4.6/arm64-fix-typo-in-the-pmdp_huge_get_and_clear-definition.patch b/queue-4.6/arm64-fix-typo-in-the-pmdp_huge_get_and_clear-definition.patch new file mode 100644 index 00000000000..fcfb976dedf --- /dev/null +++ b/queue-4.6/arm64-fix-typo-in-the-pmdp_huge_get_and_clear-definition.patch @@ -0,0 +1,40 @@ +From 911f56eeb87ee378f5e215469268a7a2f68a5a8a Mon Sep 17 00:00:00 2001 +From: Catalin Marinas +Date: Thu, 5 May 2016 10:43:59 +0100 +Subject: arm64: Fix typo in the pmdp_huge_get_and_clear() definition + +From: Catalin Marinas + +commit 911f56eeb87ee378f5e215469268a7a2f68a5a8a upstream. + +With hardware AF/DBM support, pmd modifications (transparent huge pages) +should be performed atomically using load/store exclusive. The initial +patches defined the get-and-clear function and __HAVE_ARCH_* macro +without the "huge" word, leaving the pmdp_huge_get_and_clear() to the +default, non-atomic implementation. + +Fixes: 2f4b829c625e ("arm64: Add support for hardware updates of the access and dirty pte bits") +Reviewed-by: Will Deacon +Signed-off-by: Catalin Marinas +Signed-off-by: Will Deacon +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/include/asm/pgtable.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -578,9 +578,9 @@ static inline pte_t ptep_get_and_clear(s + } + + #ifdef CONFIG_TRANSPARENT_HUGEPAGE +-#define __HAVE_ARCH_PMDP_GET_AND_CLEAR +-static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, +- unsigned long address, pmd_t *pmdp) ++#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR ++static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, ++ unsigned long address, pmd_t *pmdp) + { + return pte_pmd(ptep_get_and_clear(mm, address, (pte_t *)pmdp)); + } diff --git a/queue-4.6/arm64-implement-pmdp_set_access_flags-for-hardware-af-dbm.patch b/queue-4.6/arm64-implement-pmdp_set_access_flags-for-hardware-af-dbm.patch new file mode 100644 index 00000000000..f33e16c5ded --- /dev/null +++ b/queue-4.6/arm64-implement-pmdp_set_access_flags-for-hardware-af-dbm.patch @@ -0,0 +1,45 @@ +From 282aa7051b0169991b34716f0f22d9c2f59c46c4 Mon Sep 17 00:00:00 2001 +From: Catalin Marinas +Date: Thu, 5 May 2016 10:44:00 +0100 +Subject: arm64: Implement pmdp_set_access_flags() for hardware AF/DBM + +From: Catalin Marinas + +commit 282aa7051b0169991b34716f0f22d9c2f59c46c4 upstream. + +The update to the accessed or dirty states for block mappings must be +done atomically on hardware with support for automatic AF/DBM. The +ptep_set_access_flags() function has been fixed as part of commit +66dbd6e61a52 ("arm64: Implement ptep_set_access_flags() for hardware +AF/DBM"). This patch brings pmdp_set_access_flags() in line with the pte +counterpart. + +Fixes: 2f4b829c625e ("arm64: Add support for hardware updates of the access and dirty pte bits") +Reviewed-by: Will Deacon +Signed-off-by: Catalin Marinas +Signed-off-by: Will Deacon +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/include/asm/pgtable.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -531,6 +531,16 @@ extern int ptep_set_access_flags(struct + unsigned long address, pte_t *ptep, + pte_t entry, int dirty); + ++#ifdef CONFIG_TRANSPARENT_HUGEPAGE ++#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS ++static inline int pmdp_set_access_flags(struct vm_area_struct *vma, ++ unsigned long address, pmd_t *pmdp, ++ pmd_t entry, int dirty) ++{ ++ return ptep_set_access_flags(vma, address, (pte_t *)pmdp, pmd_pte(entry), dirty); ++} ++#endif ++ + /* + * Atomic pte/pmd modifications. + */ diff --git a/queue-4.6/arm64-implement-ptep_set_access_flags-for-hardware-af-dbm.patch b/queue-4.6/arm64-implement-ptep_set_access_flags-for-hardware-af-dbm.patch new file mode 100644 index 00000000000..3bd5ac79640 --- /dev/null +++ b/queue-4.6/arm64-implement-ptep_set_access_flags-for-hardware-af-dbm.patch @@ -0,0 +1,131 @@ +From 66dbd6e61a526ae7d11a208238ae2c17e5cacb6b Mon Sep 17 00:00:00 2001 +From: Catalin Marinas +Date: Wed, 13 Apr 2016 16:01:22 +0100 +Subject: arm64: Implement ptep_set_access_flags() for hardware AF/DBM + +From: Catalin Marinas + +commit 66dbd6e61a526ae7d11a208238ae2c17e5cacb6b upstream. + +When hardware updates of the access and dirty states are enabled, the +default ptep_set_access_flags() implementation based on calling +set_pte_at() directly is potentially racy. This triggers the "racy dirty +state clearing" warning in set_pte_at() because an existing writable PTE +is overridden with a clean entry. + +There are two main scenarios for this situation: + +1. The CPU getting an access fault does not support hardware updates of + the access/dirty flags. However, a different agent in the system + (e.g. SMMU) can do this, therefore overriding a writable entry with a + clean one could potentially lose the automatically updated dirty + status + +2. A more complex situation is possible when all CPUs support hardware + AF/DBM: + + a) Initial state: shareable + writable vma and pte_none(pte) + b) Read fault taken by two threads of the same process on different + CPUs + c) CPU0 takes the mmap_sem and proceeds to handling the fault. It + eventually reaches do_set_pte() which sets a writable + clean pte. + CPU0 releases the mmap_sem + d) CPU1 acquires the mmap_sem and proceeds to handle_pte_fault(). The + pte entry it reads is present, writable and clean and it continues + to pte_mkyoung() + e) CPU1 calls ptep_set_access_flags() + + If between (d) and (e) the hardware (another CPU) updates the dirty + state (clears PTE_RDONLY), CPU1 will override the PTR_RDONLY bit + marking the entry clean again. + +This patch implements an arm64-specific ptep_set_access_flags() function +to perform an atomic update of the PTE flags. + +Fixes: 2f4b829c625e ("arm64: Add support for hardware updates of the access and dirty pte bits") +Signed-off-by: Catalin Marinas +Reported-by: Ming Lei +Tested-by: Julien Grall +Cc: Will Deacon +[will: reworded comment] +Signed-off-by: Will Deacon +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/include/asm/pgtable.h | 5 +++ + arch/arm64/mm/fault.c | 50 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 55 insertions(+) + +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -526,6 +526,11 @@ static inline pmd_t pmd_modify(pmd_t pmd + } + + #ifdef CONFIG_ARM64_HW_AFDBM ++#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS ++extern int ptep_set_access_flags(struct vm_area_struct *vma, ++ unsigned long address, pte_t *ptep, ++ pte_t entry, int dirty); ++ + /* + * Atomic pte/pmd modifications. + */ +--- a/arch/arm64/mm/fault.c ++++ b/arch/arm64/mm/fault.c +@@ -81,6 +81,56 @@ void show_pte(struct mm_struct *mm, unsi + printk("\n"); + } + ++#ifdef CONFIG_ARM64_HW_AFDBM ++/* ++ * This function sets the access flags (dirty, accessed), as well as write ++ * permission, and only to a more permissive setting. ++ * ++ * It needs to cope with hardware update of the accessed/dirty state by other ++ * agents in the system and can safely skip the __sync_icache_dcache() call as, ++ * like set_pte_at(), the PTE is never changed from no-exec to exec here. ++ * ++ * Returns whether or not the PTE actually changed. ++ */ ++int ptep_set_access_flags(struct vm_area_struct *vma, ++ unsigned long address, pte_t *ptep, ++ pte_t entry, int dirty) ++{ ++ pteval_t old_pteval; ++ unsigned int tmp; ++ ++ if (pte_same(*ptep, entry)) ++ return 0; ++ ++ /* only preserve the access flags and write permission */ ++ pte_val(entry) &= PTE_AF | PTE_WRITE | PTE_DIRTY; ++ ++ /* ++ * PTE_RDONLY is cleared by default in the asm below, so set it in ++ * back if necessary (read-only or clean PTE). ++ */ ++ if (!pte_write(entry) || !dirty) ++ pte_val(entry) |= PTE_RDONLY; ++ ++ /* ++ * Setting the flags must be done atomically to avoid racing with the ++ * hardware update of the access/dirty state. ++ */ ++ asm volatile("// ptep_set_access_flags\n" ++ " prfm pstl1strm, %2\n" ++ "1: ldxr %0, %2\n" ++ " and %0, %0, %3 // clear PTE_RDONLY\n" ++ " orr %0, %0, %4 // set flags\n" ++ " stxr %w1, %0, %2\n" ++ " cbnz %w1, 1b\n" ++ : "=&r" (old_pteval), "=&r" (tmp), "+Q" (pte_val(*ptep)) ++ : "L" (~PTE_RDONLY), "r" (pte_val(entry))); ++ ++ flush_tlb_fix_spurious_fault(vma, address); ++ return 1; ++} ++#endif ++ + /* + * The kernel tried to access some page that wasn't present. + */ diff --git a/queue-4.6/kvm-arm64-fix-ec-field-in-inject_abt64.patch b/queue-4.6/kvm-arm64-fix-ec-field-in-inject_abt64.patch new file mode 100644 index 00000000000..b483197ef67 --- /dev/null +++ b/queue-4.6/kvm-arm64-fix-ec-field-in-inject_abt64.patch @@ -0,0 +1,33 @@ +From e4fe9e7dc3828bf6a5714eb3c55aef6260d823a2 Mon Sep 17 00:00:00 2001 +From: Matt Evans +Date: Mon, 16 May 2016 13:54:56 +0100 +Subject: kvm: arm64: Fix EC field in inject_abt64 + +From: Matt Evans + +commit e4fe9e7dc3828bf6a5714eb3c55aef6260d823a2 upstream. + +The EC field of the constructed ESR is conditionally modified by ORing in +ESR_ELx_EC_DABT_LOW for a data abort. However, ESR_ELx_EC_SHIFT is missing +from this condition. + +Signed-off-by: Matt Evans +Acked-by: Marc Zyngier +Signed-off-by: Christoffer Dall +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm64/kvm/inject_fault.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/kvm/inject_fault.c ++++ b/arch/arm64/kvm/inject_fault.c +@@ -162,7 +162,7 @@ static void inject_abt64(struct kvm_vcpu + esr |= (ESR_ELx_EC_IABT_CUR << ESR_ELx_EC_SHIFT); + + if (!is_iabt) +- esr |= ESR_ELx_EC_DABT_LOW; ++ esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT; + + vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT; + }