powerpc: Add set_memory_{p/np}() and remove set_memory_attr()
authorChristophe Leroy <christophe.leroy@csgroup.eu>
Fri, 24 Dec 2021 11:07:40 +0000 (11:07 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 8 Apr 2022 12:24:04 +0000 (14:24 +0200)
commit f222ab83df92acf72691a2021e1f0d99880dcdf1 upstream.

set_memory_attr() was implemented by commit 4d1755b6a762 ("powerpc/mm:
implement set_memory_attr()") because the set_memory_xx() couldn't
be used at that time to modify memory "on the fly" as explained it
the commit.

But set_memory_attr() uses set_pte_at() which leads to warnings when
CONFIG_DEBUG_VM is selected, because set_pte_at() is unexpected for
updating existing page table entries.

The check could be bypassed by using __set_pte_at() instead,
as it was the case before commit c988cfd38e48 ("powerpc/32:
use set_memory_attr()") but since commit 9f7853d7609d ("powerpc/mm:
Fix set_memory_*() against concurrent accesses") it is now possible
to use set_memory_xx() functions to update page table entries
"on the fly" because the update is now atomic.

For DEBUG_PAGEALLOC we need to clear and set back _PAGE_PRESENT.
Add set_memory_np() and set_memory_p() for that.

Replace all uses of set_memory_attr() by the relevant set_memory_xx()
and remove set_memory_attr().

Fixes: c988cfd38e48 ("powerpc/32: use set_memory_attr()")
Cc: stable@vger.kernel.org
Reported-by: Maxime Bizon <mbizon@freebox.fr>
Signed-off-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Tested-by: Maxime Bizon <mbizon@freebox.fr>
Reviewed-by: Russell Currey <ruscur@russell.cc>
Depends-on: 9f7853d7609d ("powerpc/mm: Fix set_memory_*() against concurrent accesses")
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/cda2b44b55c96f9ac69fa92e68c01084ec9495c5.1640344012.git.christophe.leroy@csgroup.eu
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/powerpc/include/asm/set_memory.h
arch/powerpc/mm/pageattr.c
arch/powerpc/mm/pgtable_32.c

index b040094f792020e584d175c847ba05c0e24a986e..7ebc807aa8cc85bc8ca6ac6a0c9ef13fa9de4fe6 100644 (file)
@@ -6,6 +6,8 @@
 #define SET_MEMORY_RW  1
 #define SET_MEMORY_NX  2
 #define SET_MEMORY_X   3
+#define SET_MEMORY_NP  4       /* Set memory non present */
+#define SET_MEMORY_P   5       /* Set memory present */
 
 int change_memory_attr(unsigned long addr, int numpages, long action);
 
@@ -29,6 +31,14 @@ static inline int set_memory_x(unsigned long addr, int numpages)
        return change_memory_attr(addr, numpages, SET_MEMORY_X);
 }
 
-int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot);
+static inline int set_memory_np(unsigned long addr, int numpages)
+{
+       return change_memory_attr(addr, numpages, SET_MEMORY_NP);
+}
+
+static inline int set_memory_p(unsigned long addr, int numpages)
+{
+       return change_memory_attr(addr, numpages, SET_MEMORY_P);
+}
 
 #endif
index edea388e9d3fbbf4076c113ac8e14179dce18cac..3bb9d168e3b317aa0bf09915fe7283188f56cd4e 100644 (file)
@@ -48,6 +48,12 @@ static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)
        case SET_MEMORY_X:
                pte = pte_mkexec(pte);
                break;
+       case SET_MEMORY_NP:
+               pte_update(&init_mm, addr, ptep, _PAGE_PRESENT, 0, 0);
+               break;
+       case SET_MEMORY_P:
+               pte_update(&init_mm, addr, ptep, 0, _PAGE_PRESENT, 0);
+               break;
        default:
                WARN_ON_ONCE(1);
                break;
@@ -96,36 +102,3 @@ int change_memory_attr(unsigned long addr, int numpages, long action)
        return apply_to_existing_page_range(&init_mm, start, size,
                                            change_page_attr, (void *)action);
 }
-
-/*
- * Set the attributes of a page:
- *
- * This function is used by PPC32 at the end of init to set final kernel memory
- * protection. It includes changing the maping of the page it is executing from
- * and data pages it is using.
- */
-static int set_page_attr(pte_t *ptep, unsigned long addr, void *data)
-{
-       pgprot_t prot = __pgprot((unsigned long)data);
-
-       spin_lock(&init_mm.page_table_lock);
-
-       set_pte_at(&init_mm, addr, ptep, pte_modify(*ptep, prot));
-       flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
-
-       spin_unlock(&init_mm.page_table_lock);
-
-       return 0;
-}
-
-int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot)
-{
-       unsigned long start = ALIGN_DOWN(addr, PAGE_SIZE);
-       unsigned long sz = numpages * PAGE_SIZE;
-
-       if (numpages <= 0)
-               return 0;
-
-       return apply_to_existing_page_range(&init_mm, start, sz, set_page_attr,
-                                           (void *)pgprot_val(prot));
-}
index fde1ed445ca4687576e621b30beada719ae48243..f288597714407af94389404d3ea0c91b5d82eb2d 100644 (file)
@@ -138,10 +138,12 @@ void mark_initmem_nx(void)
        unsigned long numpages = PFN_UP((unsigned long)_einittext) -
                                 PFN_DOWN((unsigned long)_sinittext);
 
-       if (v_block_mapped((unsigned long)_sinittext))
+       if (v_block_mapped((unsigned long)_sinittext)) {
                mmu_mark_initmem_nx();
-       else
-               set_memory_attr((unsigned long)_sinittext, numpages, PAGE_KERNEL);
+       } else {
+               set_memory_nx((unsigned long)_sinittext, numpages);
+               set_memory_rw((unsigned long)_sinittext, numpages);
+       }
 }
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
@@ -155,18 +157,14 @@ void mark_rodata_ro(void)
                return;
        }
 
-       numpages = PFN_UP((unsigned long)_etext) -
-                  PFN_DOWN((unsigned long)_stext);
-
-       set_memory_attr((unsigned long)_stext, numpages, PAGE_KERNEL_ROX);
        /*
-        * mark .rodata as read only. Use __init_begin rather than __end_rodata
-        * to cover NOTES and EXCEPTION_TABLE.
+        * mark .text and .rodata as read only. Use __init_begin rather than
+        * __end_rodata to cover NOTES and EXCEPTION_TABLE.
         */
        numpages = PFN_UP((unsigned long)__init_begin) -
-                  PFN_DOWN((unsigned long)__start_rodata);
+                  PFN_DOWN((unsigned long)_stext);
 
-       set_memory_attr((unsigned long)__start_rodata, numpages, PAGE_KERNEL_RO);
+       set_memory_ro((unsigned long)_stext, numpages);
 
        // mark_initmem_nx() should have already run by now
        ptdump_check_wx();
@@ -182,8 +180,8 @@ void __kernel_map_pages(struct page *page, int numpages, int enable)
                return;
 
        if (enable)
-               set_memory_attr(addr, numpages, PAGE_KERNEL);
+               set_memory_p(addr, numpages);
        else
-               set_memory_attr(addr, numpages, __pgprot(0));
+               set_memory_np(addr, numpages);
 }
 #endif /* CONFIG_DEBUG_PAGEALLOC */