From: Jordan Niethe <hidden> Date: 2021-04-29 03:17:30
Adding more Strict RWX support on powerpc, in particular Strict Module RWX.
Thanks for all of the feedback everyone.
It is now rebased on linux-next.
For reference the previous revision is available here:
https://lore.kernel.org/linuxppc-dev/20210330045132.722243-1-jniethe5@gmail.com/
The changes in v11 for each patch:
Christophe Leroy (2):
powerpc/mm: implement set_memory_attr()
powerpc/32: use set_memory_attr()
Jordan Niethe (4):
powerpc/lib/code-patching: Set up Strict RWX patching earlier
powerpc: Always define MODULES_{VADDR,END}
v11: - Consider more places MODULES_VADDR was being used
powerpc/bpf: Remove bpf_jit_free()
v11: - New to series
powerpc/bpf: Write protect JIT code
v11: - Remove CONFIG_STRICT_MODULE_RWX conditional
Russell Currey (3):
powerpc/mm: Implement set_memory() routines
v11: - Update copywrite dates
- Allow set memory functions to be used without Strict RW
- Hash: Disallow certain regions and add comment explaining why
- Have change_page_attr() take function pointers to manipulate ptes
- Clarify change_page_attr()'s comment
- Radix: Add ptesync after set_pte_at()
powerpc/kprobes: Mark newly allocated probes as ROX
v11: Neaten up
powerpc: Set ARCH_HAS_STRICT_MODULE_RWX
v11: Neaten up
Some patches were dropped from this revision:
powerpc/mm/ptdump: debugfs handler for W+X checks at runtime
- Will use Christophe's generic ptdump series
powerpc/configs: Enable STRICT_MODULE_RWX in skiroot_defconfig
- Will enable STRICT_MODULE_RWX by default later
arch/powerpc/Kconfig | 2 +
arch/powerpc/include/asm/pgtable.h | 11 ++
arch/powerpc/include/asm/set_memory.h | 12 +++
arch/powerpc/kernel/kprobes.c | 11 ++
arch/powerpc/kernel/module.c | 14 +--
arch/powerpc/lib/code-patching.c | 12 +--
arch/powerpc/mm/Makefile | 2 +-
arch/powerpc/mm/kasan/kasan_init_32.c | 10 +-
arch/powerpc/mm/pageattr.c | 138 ++++++++++++++++++++++++++
arch/powerpc/mm/pgtable_32.c | 60 ++---------
arch/powerpc/mm/ptdump/ptdump.c | 4 +-
arch/powerpc/net/bpf_jit_comp.c | 13 +--
12 files changed, 204 insertions(+), 85 deletions(-)
create mode 100644 arch/powerpc/include/asm/set_memory.h
create mode 100644 arch/powerpc/mm/pageattr.c
--
2.25.1
From: Jordan Niethe <hidden> Date: 2021-04-29 03:17:07
From: Russell Currey <redacted>
The set_memory_{ro/rw/nx/x}() functions are required for
STRICT_MODULE_RWX, and are generally useful primitives to have. This
implementation is designed to be generic across powerpc's many MMUs.
It's possible that this could be optimised to be faster for specific
MMUs.
This implementation does not handle cases where the caller is attempting
to change the mapping of the page it is executing from, or if another
CPU is concurrently using the page being altered. These cases likely
shouldn't happen, but a more complex implementation with MMU-specific code
could safely handle them.
On hash, the linear mapping is not kept in the linux pagetable, so this
will not change the protection if used on that range. Currently these
functions are not used on the linear map so just WARN for now.
Reviewed-by: Daniel Axtens <redacted>
Signed-off-by: Russell Currey <redacted>
Signed-off-by: Christophe Leroy <redacted>
[jpn: - Allow set memory functions to be used without Strict RWX
- Hash: Disallow certain regions
- Have change_page_attr() take function pointers to manipulate ptes
- Radix: Add ptesync after set_pte_at()]
Signed-off-by: Jordan Niethe <redacted>
---
v10: WARN if trying to change the hash linear map
v11: - Update copywrite dates
- Allow set memory functions to be used without Strict RWX
- Hash: Disallow certain regions and add comment explaining why
- Have change_page_attr() take function pointers to manipulate ptes
- Clarify change_page_attr()'s comment
- Radix: Add ptesync after set_pte_at()
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/set_memory.h | 10 +++
arch/powerpc/mm/Makefile | 2 +-
arch/powerpc/mm/pageattr.c | 105 ++++++++++++++++++++++++++
4 files changed, 117 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/set_memory.h
create mode 100644 arch/powerpc/mm/pageattr.c
@@ -0,0 +1,105 @@+// SPDX-License-Identifier: GPL-2.0++/*+*MMU-genericset_memoryimplementationforpowerpc+*+*Copyright2019-2021,IBMCorporation.+*/++#include<linux/mm.h>+#include<linux/set_memory.h>++#include<asm/mmu.h>+#include<asm/page.h>+#include<asm/pgtable.h>+++/*+*Updatestheattributesofapageinthreesteps:+*+*1.invalidatethepagetableentry+*2.flushtheTLB+*3.installthenewentrywiththeupdatedattributes+*+*Invalidatingtheptemeanstherearesituationswherethiswillnotwork+*whenintheoryitshould.+*Forexample:+*-removingwritefrompagewhilstitisbeingexecuted+*-settingapageread-onlywhilstitisbeingreadbyanotherCPU+*+*/+staticintchange_page_attr(pte_t*ptep,unsignedlongaddr,void*data)+{+pte_t(*fn)(pte_t)=data;+pte_tpte;++spin_lock(&init_mm.page_table_lock);++/* invalidate the PTE so it's safe to modify */+pte=ptep_get_and_clear(&init_mm,addr,ptep);+flush_tlb_kernel_range(addr,addr+PAGE_SIZE);++/* modify the PTE bits as desired, then apply */+pte=fn(pte);++set_pte_at(&init_mm,addr,ptep,pte);++/* See ptesync comment in radix__set_pte_at() */+if(radix_enabled())+asmvolatile("ptesync":::"memory");+spin_unlock(&init_mm.page_table_lock);++return0;+}++staticintchange_memory_attr(unsignedlongaddr,intnumpages,pte_t(*fn)(pte_t))+{+unsignedlongstart=ALIGN_DOWN(addr,PAGE_SIZE);+unsignedlongsize=numpages*PAGE_SIZE;++if(!numpages)+return0;++#ifdef CONFIG_PPC_BOOK3S_64+/*+*Onhash,thelinearmappingisnotintheLinuxpagetableso+*apply_to_existing_page_range()willhavenoeffect.Ifinthefuture+*theset_memory_*functionsareusedonthelinearmapthiswillneed+*tobeupdated.+*/+if(!radix_enabled()){+intregion=get_region_id(addr);++if(WARN_ON_ONCE(region!=VMALLOC_REGION_ID&®ion!=IO_REGION_ID))+return-EINVAL;+}+#endif++returnapply_to_existing_page_range(&init_mm,start,size,+change_page_attr,fn);+}++intset_memory_ro(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_wrprotect);+}++staticpte_tpte_mkdirtywrite(pte_tpte)+{+returnpte_mkwrite(pte_mkdirty(pte));+}++intset_memory_rw(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_mkdirtywrite);+}++intset_memory_nx(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_exprotect);+}++intset_memory_x(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_mkexec);+}
From: Jordan Niethe <hidden> Date: 2021-04-29 03:17:55
setup_text_poke_area() is a late init call so it runs before
mark_rodata_ro() and after the init calls. This lets all the init code
patching simply write to their locations. In the future, kprobes is
going to allocate its instruction pages RO which means they will need
setup_text__poke_area() to have been already called for their code
patching. However, init_kprobes() (which allocates and patches some
instruction pages) is an early init call so it happens before
setup_text__poke_area().
start_kernel() calls poking_init() before any of the init calls. On
powerpc, poking_init() is currently a nop. setup_text_poke_area() relies
on kernel virtual memory, cpu hotplug and per_cpu_areas being setup.
setup_per_cpu_areas(), boot_cpu_hotplug_init() and mm_init() are called
before poking_init().
Turn setup_text_poke_area() into poking_init().
Reviewed-by: Russell Currey <redacted>
Signed-off-by: Jordan Niethe <redacted>
---
v9: New to series
---
arch/powerpc/lib/code-patching.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
@@ -70,14 +70,11 @@ static int text_area_cpu_down(unsigned int cpu)}/*-*Runasalateinitcall.Thisallowsalltheboottimepatchingtobedone-*simplybypatchingthecode,andthenwe'recalledherepriorto-*mark_rodata_ro(),whichhappensafterallinitcallsarerun.Although-*BUG_ON()isrude,inthiscaseitshouldonlyhappenifENOMEM,andwejudge-*itasbeingpreferabletoakernelthatwillcrashlaterwhensomeonetries-*tousepatch_instruction().+*AlthoughBUG_ON()isrude,inthiscaseitshouldonlyhappenifENOMEM,and+*wejudgeitasbeingpreferabletoakernelthatwillcrashlaterwhen+*someonetriestousepatch_instruction().*/-staticint__initsetup_text_poke_area(void)+int__initpoking_init(void){BUG_ON(!cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,"powerpc/text_poke:online",text_area_cpu_up,
@@ -85,7 +82,6 @@ static int __init setup_text_poke_area(void)return0;}-late_initcall(setup_text_poke_area);/**Thiscanbecalledforkerneltextoramodule.
From: Jordan Niethe <hidden> Date: 2021-04-29 03:18:20
If MODULES_{VADDR,END} are not defined set them to VMALLOC_START and
VMALLOC_END respectively. This reduces the need for special cases. For
example, powerpc's module_alloc() was previously predicated on
MODULES_VADDR being defined but now is unconditionally defined.
This will be useful reducing conditional code in other places that need
to allocate from the module region (i.e., kprobes).
Signed-off-by: Jordan Niethe <redacted>
---
v10: New to series
v11: - Consider more places MODULES_VADDR was being used
---
arch/powerpc/include/asm/pgtable.h | 11 +++++++++++
arch/powerpc/kernel/module.c | 5 +----
arch/powerpc/mm/kasan/kasan_init_32.c | 10 +++++-----
arch/powerpc/mm/ptdump/ptdump.c | 4 ++--
4 files changed, 19 insertions(+), 11 deletions(-)
@@ -88,7 +89,6 @@ int module_finalize(const Elf_Ehdr *hdr,return0;}-#ifdef MODULES_VADDRstatic__always_inlinevoid*__module_alloc(unsignedlongsize,unsignedlongstart,unsignedlongend){
@@ -102,8 +102,6 @@ void *module_alloc(unsigned long size)unsignedlonglimit=(unsignedlong)_etext-SZ_32M;void*ptr=NULL;-BUILD_BUG_ON(TASK_SIZE>MODULES_VADDR);-/* First try within 32M limit from _etext to avoid branch trampolines */if(MODULES_VADDR<PAGE_OFFSET&&MODULES_END>limit)ptr=__module_alloc(size,limit,MODULES_END);
@@ -113,4 +111,3 @@ void *module_alloc(unsigned long size)returnptr;}-#endif
From: Jordan Niethe <hidden> Date: 2021-04-29 03:18:49
From: Russell Currey <redacted>
Add the arch specific insn page allocator for powerpc. This allocates
ROX pages if STRICT_KERNEL_RWX is enabled. These pages are only written
to with patch_instruction() which is able to write RO pages.
Reviewed-by: Daniel Axtens <redacted>
Signed-off-by: Russell Currey <redacted>
Signed-off-by: Christophe Leroy <redacted>
[jpn: Reword commit message, switch to __vmalloc_node_range()]
Signed-off-by: Jordan Niethe <redacted>
---
v9: - vmalloc_exec() no longer exists
- Set the page to RW before freeing it
v10: - use __vmalloc_node_range()
v11: - Neaten up
---
arch/powerpc/kernel/kprobes.c | 11 +++++++++++
1 file changed, 11 insertions(+)
From: Jordan Niethe <hidden> Date: 2021-04-29 03:19:14
Commit 74451e66d516 ("bpf: make jited programs visible in traces") added
a default bpf_jit_free() implementation. Powerpc did not use the default
bpf_jit_free() as powerpc did not set the images read-only. The default
bpf_jit_free() called bpf_jit_binary_unlock_ro() is why it could not be
used for powerpc.
Commit d53d2f78cead ("bpf: Use vmalloc special flag") moved keeping
track of read-only memory to vmalloc. This included removing
bpf_jit_binary_unlock_ro(). Therefore there is no reason powerpc needs
its own bpf_jit_free(). Remove it.
Signed-off-by: Jordan Niethe <redacted>
---
v11: New to series
---
arch/powerpc/net/bpf_jit_comp.c | 12 ------------
1 file changed, 12 deletions(-)
From: Jordan Niethe <hidden> Date: 2021-04-29 03:19:37
Add the necessary call to bpf_jit_binary_lock_ro() to remove write and
add exec permissions to the JIT image after it has finished being
written.
Without CONFIG_STRICT_MODULE_RWX the image will be writable and
executable until the call to bpf_jit_binary_lock_ro().
Signed-off-by: Jordan Niethe <redacted>
---
v10: New to series
v11: Remove CONFIG_STRICT_MODULE_RWX conditional
---
arch/powerpc/net/bpf_jit_comp.c | 1 +
1 file changed, 1 insertion(+)
From: Jordan Niethe <hidden> Date: 2021-04-29 03:20:01
From: Russell Currey <redacted>
To enable strict module RWX on powerpc, set:
CONFIG_STRICT_MODULE_RWX=y
You should also have CONFIG_STRICT_KERNEL_RWX=y set to have any real
security benefit.
ARCH_HAS_STRICT_MODULE_RWX is set to require ARCH_HAS_STRICT_KERNEL_RWX.
This is due to a quirk in arch/Kconfig and arch/powerpc/Kconfig that
makes STRICT_MODULE_RWX *on by default* in configurations where
STRICT_KERNEL_RWX is *unavailable*.
Since this doesn't make much sense, and module RWX without kernel RWX
doesn't make much sense, having the same dependencies as kernel RWX
works around this problem.
With STRICT_MODULE_RWX, now make module_alloc() allocate pages with
KERNEL_PAGE protection rather than KERNEL_PAGE_EXEC.
Book32s/32 processors with a hash mmu (i.e. 604 core) can not set memory
protection on a page by page basis so do not enable.
Signed-off-by: Russell Currey <redacted>
[jpn: - predicate on !PPC_BOOK3S_604
- make module_alloc() use PAGE_KERNEL protection]
Signed-off-by: Jordan Niethe <redacted>
---
v10: - Predicate on !PPC_BOOK3S_604
- Make module_alloc() use PAGE_KERNEL protection
v11: - Neaten up
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/kernel/module.c | 9 ++++++---
2 files changed, 7 insertions(+), 3 deletions(-)
From: Jordan Niethe <hidden> Date: 2021-04-29 03:20:30
From: Christophe Leroy <redacted>
In addition to the set_memory_xx() functions which allows to change
the memory attributes of not (yet) used memory regions, implement a
set_memory_attr() function to:
- set the final memory protection after init on currently used
kernel regions.
- enable/disable kernel memory regions in the scope of DEBUG_PAGEALLOC.
Unlike the set_memory_xx() which can act in three step as the regions
are unused, this function must modify 'on the fly' as the kernel is
executing from them. At the moment only PPC32 will use it and changing
page attributes on the fly is not an issue.
Signed-off-by: Christophe Leroy <redacted>
Reported-by: kbuild test robot <redacted>
[ruscur: cast "data" to unsigned long instead of int]
Signed-off-by: Russell Currey <redacted>
Signed-off-by: Jordan Niethe <redacted>
---
arch/powerpc/include/asm/set_memory.h | 2 ++
arch/powerpc/mm/pageattr.c | 33 +++++++++++++++++++++++++++
2 files changed, 35 insertions(+)
@@ -7,4 +7,6 @@ int set_memory_rw(unsigned long addr, int numpages);intset_memory_nx(unsignedlongaddr,intnumpages);intset_memory_x(unsignedlongaddr,intnumpages);+intset_memory_attr(unsignedlongaddr,intnumpages,pgprot_tprot);+#endif
@@ -103,3 +103,36 @@ int set_memory_x(unsigned long addr, int numpages){returnchange_memory_attr(addr,numpages,pte_mkexec);}++/*+*Settheattributesofapage:+*+*ThisfunctionisusedbyPPC32attheendofinittosetfinalkernelmemory+*protection.Itincludeschangingthemapingofthepageitisexecutingfrom+*anddatapagesitisusing.+*/+staticintset_page_attr(pte_t*ptep,unsignedlongaddr,void*data)+{+pgprot_tprot=__pgprot((unsignedlong)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);++return0;+}++intset_memory_attr(unsignedlongaddr,intnumpages,pgprot_tprot)+{+unsignedlongstart=ALIGN_DOWN(addr,PAGE_SIZE);+unsignedlongsz=numpages*PAGE_SIZE;++if(numpages<=0)+return0;++returnapply_to_existing_page_range(&init_mm,start,sz,set_page_attr,+(void*)pgprot_val(prot));+}
From: Jordan Niethe <hidden> Date: 2021-04-29 03:21:01
From: Christophe Leroy <redacted>
Use set_memory_attr() instead of the PPC32 specific change_page_attr()
change_page_attr() was checking that the address was not mapped by
blocks and was handling highmem, but that's unneeded because the
affected pages can't be in highmem and block mapping verification
is already done by the callers.
Signed-off-by: Christophe Leroy <redacted>
[ruscur: rebase on powerpc/merge with Christophe's new patches]
Signed-off-by: Russell Currey <redacted>
Signed-off-by: Jordan Niethe <redacted>
---
arch/powerpc/mm/pgtable_32.c | 60 ++++++------------------------------
1 file changed, 10 insertions(+), 50 deletions(-)
@@ -198,20 +155,18 @@ void mark_rodata_ro(void)return;}-page=virt_to_page(_stext);numpages=PFN_UP((unsignedlong)_etext)-PFN_DOWN((unsignedlong)_stext);-change_page_attr(page,numpages,PAGE_KERNEL_ROX);+set_memory_attr((unsignedlong)_stext,numpages,PAGE_KERNEL_ROX);/**mark.rodataasreadonly.Use__init_beginratherthan__end_rodata*tocoverNOTESandEXCEPTION_TABLE.*/-page=virt_to_page(__start_rodata);numpages=PFN_UP((unsignedlong)__init_begin)-PFN_DOWN((unsignedlong)__start_rodata);-change_page_attr(page,numpages,PAGE_KERNEL_RO);+set_memory_attr((unsignedlong)__start_rodata,numpages,PAGE_KERNEL_RO);// mark_initmem_nx() should have already run by nowptdump_check_wx();
setup_text_poke_area() is a late init call so it runs before
mark_rodata_ro() and after the init calls. This lets all the init code
patching simply write to their locations. In the future, kprobes is
going to allocate its instruction pages RO which means they will need
setup_text__poke_area() to have been already called for their code
patching. However, init_kprobes() (which allocates and patches some
instruction pages) is an early init call so it happens before
setup_text__poke_area().
start_kernel() calls poking_init() before any of the init calls. On
powerpc, poking_init() is currently a nop. setup_text_poke_area() relies
on kernel virtual memory, cpu hotplug and per_cpu_areas being setup.
setup_per_cpu_areas(), boot_cpu_hotplug_init() and mm_init() are called
before poking_init().
Turn setup_text_poke_area() into poking_init().
I can't remember, maybe I already asked the question:
Have you done some performance measurement or at least some performance analysis ?
Christophe
quoted hunk
Reviewed-by: Russell Currey <redacted>
Signed-off-by: Jordan Niethe <redacted>
---
v9: New to series
---
arch/powerpc/lib/code-patching.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
@@ -70,14 +70,11 @@ static int text_area_cpu_down(unsigned int cpu)}/*-*Runasalateinitcall.Thisallowsalltheboottimepatchingtobedone-*simplybypatchingthecode,andthenwe'recalledherepriorto-*mark_rodata_ro(),whichhappensafterallinitcallsarerun.Although-*BUG_ON()isrude,inthiscaseitshouldonlyhappenifENOMEM,andwejudge-*itasbeingpreferabletoakernelthatwillcrashlaterwhensomeonetries-*tousepatch_instruction().+*AlthoughBUG_ON()isrude,inthiscaseitshouldonlyhappenifENOMEM,and+*wejudgeitasbeingpreferabletoakernelthatwillcrashlaterwhen+*someonetriestousepatch_instruction().*/-staticint__initsetup_text_poke_area(void)+int__initpoking_init(void){BUG_ON(!cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,"powerpc/text_poke:online",text_area_cpu_up,
@@ -85,7 +82,6 @@ static int __init setup_text_poke_area(void)return0;}-late_initcall(setup_text_poke_area);/**Thiscanbecalledforkerneltextoramodule.
If MODULES_{VADDR,END} are not defined set them to VMALLOC_START and
VMALLOC_END respectively. This reduces the need for special cases. For
example, powerpc's module_alloc() was previously predicated on
MODULES_VADDR being defined but now is unconditionally defined.
This will be useful reducing conditional code in other places that need
to allocate from the module region (i.e., kprobes).
Signed-off-by: Jordan Niethe <redacted>
---
v10: New to series
v11: - Consider more places MODULES_VADDR was being used
---
arch/powerpc/include/asm/pgtable.h | 11 +++++++++++
arch/powerpc/kernel/module.c | 5 +----
arch/powerpc/mm/kasan/kasan_init_32.c | 10 +++++-----
arch/powerpc/mm/ptdump/ptdump.c | 4 ++--
4 files changed, 19 insertions(+), 11 deletions(-)
No no.
TASK_SIZE > MODULES_VADDR is ALWAYS wrong, for any target, in any configuration.
Why is it a problem to leave the test as a BUILD_BUG_ON() in module_alloc() ?
quoted hunk
+#if TASK_SIZE > MODULES_VADDR
+#error TASK_SIZE > MODULES_VADDR
+#endif
+#endif
+
#ifndef __ASSEMBLY__
/* Keep these as a macros to avoid include dependency mess */
@@ -88,7 +89,6 @@ int module_finalize(const Elf_Ehdr *hdr,return0;}-#ifdef MODULES_VADDRstatic__always_inlinevoid*__module_alloc(unsignedlongsize,unsignedlongstart,unsignedlongend){
@@ -102,8 +102,6 @@ void *module_alloc(unsigned long size)unsignedlonglimit=(unsignedlong)_etext-SZ_32M;void*ptr=NULL;-BUILD_BUG_ON(TASK_SIZE>MODULES_VADDR);-/* First try within 32M limit from _etext to avoid branch trampolines */if(MODULES_VADDR<PAGE_OFFSET&&MODULES_END>limit)ptr=__module_alloc(size,limit,MODULES_END);
@@ -113,4 +111,3 @@ void *module_alloc(unsigned long size)returnptr;}-#endif
From: Russell Currey <redacted>
The set_memory_{ro/rw/nx/x}() functions are required for
STRICT_MODULE_RWX, and are generally useful primitives to have. This
implementation is designed to be generic across powerpc's many MMUs.
It's possible that this could be optimised to be faster for specific
MMUs.
This implementation does not handle cases where the caller is attempting
to change the mapping of the page it is executing from, or if another
CPU is concurrently using the page being altered. These cases likely
shouldn't happen, but a more complex implementation with MMU-specific code
could safely handle them.
On hash, the linear mapping is not kept in the linux pagetable, so this
will not change the protection if used on that range. Currently these
functions are not used on the linear map so just WARN for now.
Reviewed-by: Daniel Axtens <redacted>
Signed-off-by: Russell Currey <redacted>
Signed-off-by: Christophe Leroy <redacted>
[jpn: - Allow set memory functions to be used without Strict RWX
- Hash: Disallow certain regions
- Have change_page_attr() take function pointers to manipulate ptes
Did you look at the resulting generated code ? I find it awful.
pte manipulation helpers are meant to be inlined. Here you force the compiler to outline them. This
also means that the input and output goes through memory.
And now set_memory_xx are not tiny inlined functions anymore.
What is the reason you abandonned the way it was done up to now, through the use of an 'action'
value ? With the previous approach the generated code was a lot lighter.
quoted hunk
- Radix: Add ptesync after set_pte_at()]
Signed-off-by: Jordan Niethe <redacted>
---
v10: WARN if trying to change the hash linear map
v11: - Update copywrite dates
- Allow set memory functions to be used without Strict RWX
- Hash: Disallow certain regions and add comment explaining why
- Have change_page_attr() take function pointers to manipulate ptes
- Clarify change_page_attr()'s comment
- Radix: Add ptesync after set_pte_at()
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/set_memory.h | 10 +++
arch/powerpc/mm/Makefile | 2 +-
arch/powerpc/mm/pageattr.c | 105 ++++++++++++++++++++++++++
4 files changed, 117 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/set_memory.h
create mode 100644 arch/powerpc/mm/pageattr.c
@@ -0,0 +1,105 @@+// SPDX-License-Identifier: GPL-2.0++/*+*MMU-genericset_memoryimplementationforpowerpc+*+*Copyright2019-2021,IBMCorporation.+*/++#include<linux/mm.h>+#include<linux/set_memory.h>++#include<asm/mmu.h>+#include<asm/page.h>+#include<asm/pgtable.h>+++/*+*Updatestheattributesofapageinthreesteps:+*+*1.invalidatethepagetableentry+*2.flushtheTLB+*3.installthenewentrywiththeupdatedattributes+*+*Invalidatingtheptemeanstherearesituationswherethiswillnotwork+*whenintheoryitshould.+*Forexample:+*-removingwritefrompagewhilstitisbeingexecuted+*-settingapageread-onlywhilstitisbeingreadbyanotherCPU+*+*/+staticintchange_page_attr(pte_t*ptep,unsignedlongaddr,void*data)+{+pte_t(*fn)(pte_t)=data;+pte_tpte;++spin_lock(&init_mm.page_table_lock);++/* invalidate the PTE so it's safe to modify */+pte=ptep_get_and_clear(&init_mm,addr,ptep);+flush_tlb_kernel_range(addr,addr+PAGE_SIZE);++/* modify the PTE bits as desired, then apply */+pte=fn(pte);++set_pte_at(&init_mm,addr,ptep,pte);++/* See ptesync comment in radix__set_pte_at() */+if(radix_enabled())+asmvolatile("ptesync":::"memory");+spin_unlock(&init_mm.page_table_lock);++return0;+}++staticintchange_memory_attr(unsignedlongaddr,intnumpages,pte_t(*fn)(pte_t))+{+unsignedlongstart=ALIGN_DOWN(addr,PAGE_SIZE);+unsignedlongsize=numpages*PAGE_SIZE;++if(!numpages)+return0;++#ifdef CONFIG_PPC_BOOK3S_64+/*+*Onhash,thelinearmappingisnotintheLinuxpagetableso+*apply_to_existing_page_range()willhavenoeffect.Ifinthefuture+*theset_memory_*functionsareusedonthelinearmapthiswillneed+*tobeupdated.+*/+if(!radix_enabled()){+intregion=get_region_id(addr);++if(WARN_ON_ONCE(region!=VMALLOC_REGION_ID&®ion!=IO_REGION_ID))+return-EINVAL;+}+#endif++returnapply_to_existing_page_range(&init_mm,start,size,+change_page_attr,fn);+}++intset_memory_ro(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_wrprotect);+}++staticpte_tpte_mkdirtywrite(pte_tpte)+{+returnpte_mkwrite(pte_mkdirty(pte));+}++intset_memory_rw(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_mkdirtywrite);+}++intset_memory_nx(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_exprotect);+}++intset_memory_x(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_mkexec);+}
From: Jordan Niethe <hidden> Date: 2021-05-03 05:03:30
On Thu, Apr 29, 2021 at 5:32 PM Christophe Leroy
[off-list ref] wrote:
Le 29/04/2021 à 05:15, Jordan Niethe a écrit :
quoted
From: Russell Currey <redacted>
The set_memory_{ro/rw/nx/x}() functions are required for
STRICT_MODULE_RWX, and are generally useful primitives to have. This
implementation is designed to be generic across powerpc's many MMUs.
It's possible that this could be optimised to be faster for specific
MMUs.
This implementation does not handle cases where the caller is attempting
to change the mapping of the page it is executing from, or if another
CPU is concurrently using the page being altered. These cases likely
shouldn't happen, but a more complex implementation with MMU-specific code
could safely handle them.
On hash, the linear mapping is not kept in the linux pagetable, so this
will not change the protection if used on that range. Currently these
functions are not used on the linear map so just WARN for now.
Reviewed-by: Daniel Axtens <redacted>
Signed-off-by: Russell Currey <redacted>
Signed-off-by: Christophe Leroy <redacted>
[jpn: - Allow set memory functions to be used without Strict RWX
- Hash: Disallow certain regions
- Have change_page_attr() take function pointers to manipulate ptes
Did you look at the resulting generated code ? I find it awful.
pte manipulation helpers are meant to be inlined. Here you force the compiler to outline them. This
also means that the input and output goes through memory.
And now set_memory_xx are not tiny inlined functions anymore.
What is the reason you abandonned the way it was done up to now, through the use of an 'action'
value ? With the previous approach the generated code was a lot lighter.
When I was looking at the patch again, it started to look to me like
the action values were an unneeded abstraction. But yeah doing it like
this makes the generated code much worse. I'll change back in the next
version.
quoted
- Radix: Add ptesync after set_pte_at()]
Signed-off-by: Jordan Niethe <redacted>
---
v10: WARN if trying to change the hash linear map
v11: - Update copywrite dates
- Allow set memory functions to be used without Strict RWX
- Hash: Disallow certain regions and add comment explaining why
- Have change_page_attr() take function pointers to manipulate ptes
- Clarify change_page_attr()'s comment
- Radix: Add ptesync after set_pte_at()
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/set_memory.h | 10 +++
arch/powerpc/mm/Makefile | 2 +-
arch/powerpc/mm/pageattr.c | 105 ++++++++++++++++++++++++++
4 files changed, 117 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/set_memory.h
create mode 100644 arch/powerpc/mm/pageattr.c
@@ -0,0 +1,105 @@+// SPDX-License-Identifier: GPL-2.0++/*+*MMU-genericset_memoryimplementationforpowerpc+*+*Copyright2019-2021,IBMCorporation.+*/++#include<linux/mm.h>+#include<linux/set_memory.h>++#include<asm/mmu.h>+#include<asm/page.h>+#include<asm/pgtable.h>+++/*+*Updatestheattributesofapageinthreesteps:+*+*1.invalidatethepagetableentry+*2.flushtheTLB+*3.installthenewentrywiththeupdatedattributes+*+*Invalidatingtheptemeanstherearesituationswherethiswillnotwork+*whenintheoryitshould.+*Forexample:+*-removingwritefrompagewhilstitisbeingexecuted+*-settingapageread-onlywhilstitisbeingreadbyanotherCPU+*+*/+staticintchange_page_attr(pte_t*ptep,unsignedlongaddr,void*data)+{+pte_t(*fn)(pte_t)=data;+pte_tpte;++spin_lock(&init_mm.page_table_lock);++/* invalidate the PTE so it's safe to modify */+pte=ptep_get_and_clear(&init_mm,addr,ptep);+flush_tlb_kernel_range(addr,addr+PAGE_SIZE);++/* modify the PTE bits as desired, then apply */+pte=fn(pte);++set_pte_at(&init_mm,addr,ptep,pte);++/* See ptesync comment in radix__set_pte_at() */+if(radix_enabled())+asmvolatile("ptesync":::"memory");+spin_unlock(&init_mm.page_table_lock);++return0;+}++staticintchange_memory_attr(unsignedlongaddr,intnumpages,pte_t(*fn)(pte_t))+{+unsignedlongstart=ALIGN_DOWN(addr,PAGE_SIZE);+unsignedlongsize=numpages*PAGE_SIZE;++if(!numpages)+return0;++#ifdef CONFIG_PPC_BOOK3S_64+/*+*Onhash,thelinearmappingisnotintheLinuxpagetableso+*apply_to_existing_page_range()willhavenoeffect.Ifinthefuture+*theset_memory_*functionsareusedonthelinearmapthiswillneed+*tobeupdated.+*/+if(!radix_enabled()){+intregion=get_region_id(addr);++if(WARN_ON_ONCE(region!=VMALLOC_REGION_ID&®ion!=IO_REGION_ID))+return-EINVAL;+}+#endif++returnapply_to_existing_page_range(&init_mm,start,size,+change_page_attr,fn);+}++intset_memory_ro(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_wrprotect);+}++staticpte_tpte_mkdirtywrite(pte_tpte)+{+returnpte_mkwrite(pte_mkdirty(pte));+}++intset_memory_rw(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_mkdirtywrite);+}++intset_memory_nx(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_exprotect);+}++intset_memory_x(unsignedlongaddr,intnumpages)+{+returnchange_memory_attr(addr,numpages,pte_mkexec);+}
From: Jordan Niethe <hidden> Date: 2021-05-03 05:40:03
On Thu, Apr 29, 2021 at 3:04 PM Christophe Leroy
[off-list ref] wrote:
Le 29/04/2021 à 05:15, Jordan Niethe a écrit :
quoted
If MODULES_{VADDR,END} are not defined set them to VMALLOC_START and
VMALLOC_END respectively. This reduces the need for special cases. For
example, powerpc's module_alloc() was previously predicated on
MODULES_VADDR being defined but now is unconditionally defined.
This will be useful reducing conditional code in other places that need
to allocate from the module region (i.e., kprobes).
Signed-off-by: Jordan Niethe <redacted>
---
v10: New to series
v11: - Consider more places MODULES_VADDR was being used
---
arch/powerpc/include/asm/pgtable.h | 11 +++++++++++
arch/powerpc/kernel/module.c | 5 +----
arch/powerpc/mm/kasan/kasan_init_32.c | 10 +++++-----
arch/powerpc/mm/ptdump/ptdump.c | 4 ++--
4 files changed, 19 insertions(+), 11 deletions(-)
No no.
TASK_SIZE > MODULES_VADDR is ALWAYS wrong, for any target, in any configuration.
Why is it a problem to leave the test as a BUILD_BUG_ON() in module_alloc() ?
On ppc64s, MODULES_VADDR is __vmalloc_start (a variable) and
TASK_SIZE depends on current.
Also for nohash like 44x, MODULES_VADDR is defined based on high_memory.
If I put it back in module_alloc() and wrap it with #ifdef
CONFIG_PPC_BOOK3S_32 will that be fine?
quoted
+#if TASK_SIZE > MODULES_VADDR
+#error TASK_SIZE > MODULES_VADDR
+#endif
+#endif
+
#ifndef __ASSEMBLY__
/* Keep these as a macros to avoid include dependency mess */
@@ -88,7 +89,6 @@ int module_finalize(const Elf_Ehdr *hdr,return0;}-#ifdef MODULES_VADDRstatic__always_inlinevoid*__module_alloc(unsignedlongsize,unsignedlongstart,unsignedlongend){
@@ -102,8 +102,6 @@ void *module_alloc(unsigned long size)unsignedlonglimit=(unsignedlong)_etext-SZ_32M;void*ptr=NULL;-BUILD_BUG_ON(TASK_SIZE>MODULES_VADDR);-/* First try within 32M limit from _etext to avoid branch trampolines */if(MODULES_VADDR<PAGE_OFFSET&&MODULES_END>limit)ptr=__module_alloc(size,limit,MODULES_END);
@@ -113,4 +111,3 @@ void *module_alloc(unsigned long size)returnptr;}-#endif
I tried to do it like that originally but with stuff like
#define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) &
~(VMALLOC_OFFSET-1)))
it doesn't work.
If it doesn't work, then it has to be
#if defined(CONFIG_BOOK32_32) || defined(CONFIG_PPC_8xx)
On Thu, Apr 29, 2021 at 3:04 PM Christophe Leroy
[off-list ref] wrote:
quoted
Le 29/04/2021 à 05:15, Jordan Niethe a écrit :
quoted
If MODULES_{VADDR,END} are not defined set them to VMALLOC_START and
VMALLOC_END respectively. This reduces the need for special cases. For
example, powerpc's module_alloc() was previously predicated on
MODULES_VADDR being defined but now is unconditionally defined.
This will be useful reducing conditional code in other places that need
to allocate from the module region (i.e., kprobes).
Signed-off-by: Jordan Niethe <redacted>
---
v10: New to series
v11: - Consider more places MODULES_VADDR was being used
---
arch/powerpc/include/asm/pgtable.h | 11 +++++++++++
arch/powerpc/kernel/module.c | 5 +----
arch/powerpc/mm/kasan/kasan_init_32.c | 10 +++++-----
arch/powerpc/mm/ptdump/ptdump.c | 4 ++--
4 files changed, 19 insertions(+), 11 deletions(-)
No no.
TASK_SIZE > MODULES_VADDR is ALWAYS wrong, for any target, in any configuration.
Why is it a problem to leave the test as a BUILD_BUG_ON() in module_alloc() ?
On ppc64s, MODULES_VADDR is __vmalloc_start (a variable) and
TASK_SIZE depends on current.
Also for nohash like 44x, MODULES_VADDR is defined based on high_memory.
If I put it back in module_alloc() and wrap it with #ifdef
CONFIG_PPC_BOOK3S_32 will that be fine?
Thinking about it once more, I think the best approach is the one taken by Nick in
https://patchwork.ozlabs.org/project/linuxppc-dev/patch/20210502110050.324953-1-npiggin@gmail.com/
Use MODULES_VADDR/MODULES_END when it exists, use VMALLOC_START/VMALLOC_END otherwise.
I know I suggested to always define MODULES_VADDR, but maybe that's not the best solution at the end.
For kprobes, is there a way to re-use functions from modules.c in alloc_insn_page() ?
Christophe
From: Jordan Niethe <hidden> Date: 2021-05-03 06:17:35
On Mon, May 3, 2021 at 3:57 PM Christophe Leroy
[off-list ref] wrote:
Le 03/05/2021 à 07:39, Jordan Niethe a écrit :
quoted
On Thu, Apr 29, 2021 at 3:04 PM Christophe Leroy
[off-list ref] wrote:
quoted
Le 29/04/2021 à 05:15, Jordan Niethe a écrit :
quoted
If MODULES_{VADDR,END} are not defined set them to VMALLOC_START and
VMALLOC_END respectively. This reduces the need for special cases. For
example, powerpc's module_alloc() was previously predicated on
MODULES_VADDR being defined but now is unconditionally defined.
This will be useful reducing conditional code in other places that need
to allocate from the module region (i.e., kprobes).
Signed-off-by: Jordan Niethe <redacted>
---
v10: New to series
v11: - Consider more places MODULES_VADDR was being used
---
arch/powerpc/include/asm/pgtable.h | 11 +++++++++++
arch/powerpc/kernel/module.c | 5 +----
arch/powerpc/mm/kasan/kasan_init_32.c | 10 +++++-----
arch/powerpc/mm/ptdump/ptdump.c | 4 ++--
4 files changed, 19 insertions(+), 11 deletions(-)
No no.
TASK_SIZE > MODULES_VADDR is ALWAYS wrong, for any target, in any configuration.
Why is it a problem to leave the test as a BUILD_BUG_ON() in module_alloc() ?
On ppc64s, MODULES_VADDR is __vmalloc_start (a variable) and
TASK_SIZE depends on current.
Also for nohash like 44x, MODULES_VADDR is defined based on high_memory.
If I put it back in module_alloc() and wrap it with #ifdef
CONFIG_PPC_BOOK3S_32 will that be fine?
On Mon, May 3, 2021 at 3:57 PM Christophe Leroy
[off-list ref] wrote:
quoted
Le 03/05/2021 à 07:39, Jordan Niethe a écrit :
quoted
On Thu, Apr 29, 2021 at 3:04 PM Christophe Leroy
[off-list ref] wrote:
quoted
Le 29/04/2021 à 05:15, Jordan Niethe a écrit :
quoted
If MODULES_{VADDR,END} are not defined set them to VMALLOC_START and
VMALLOC_END respectively. This reduces the need for special cases. For
example, powerpc's module_alloc() was previously predicated on
MODULES_VADDR being defined but now is unconditionally defined.
This will be useful reducing conditional code in other places that need
to allocate from the module region (i.e., kprobes).
Signed-off-by: Jordan Niethe <redacted>
---
v10: New to series
v11: - Consider more places MODULES_VADDR was being used
---
arch/powerpc/include/asm/pgtable.h | 11 +++++++++++
arch/powerpc/kernel/module.c | 5 +----
arch/powerpc/mm/kasan/kasan_init_32.c | 10 +++++-----
arch/powerpc/mm/ptdump/ptdump.c | 4 ++--
4 files changed, 19 insertions(+), 11 deletions(-)
No no.
TASK_SIZE > MODULES_VADDR is ALWAYS wrong, for any target, in any configuration.
Why is it a problem to leave the test as a BUILD_BUG_ON() in module_alloc() ?
On ppc64s, MODULES_VADDR is __vmalloc_start (a variable) and
TASK_SIZE depends on current.
Also for nohash like 44x, MODULES_VADDR is defined based on high_memory.
If I put it back in module_alloc() and wrap it with #ifdef
CONFIG_PPC_BOOK3S_32 will that be fine?
Yes, more or less, but using module_alloc() instead of vmalloc().
And module_alloc() implies EXEC, so only the set_memory_ro() will be required.
I see no point in doing any set_memory_xxx() in free_insn_page(), because as soon as you do a
vfree() the page is not mapped anymore so any access will lead to a fault.
Christophe
From: Jordan Niethe <hidden> Date: 2021-05-03 06:27:41
On Mon, May 3, 2021 at 4:22 PM Christophe Leroy
[off-list ref] wrote:
Le 03/05/2021 à 08:16, Jordan Niethe a écrit :
quoted
On Mon, May 3, 2021 at 3:57 PM Christophe Leroy
[off-list ref] wrote:
quoted
Le 03/05/2021 à 07:39, Jordan Niethe a écrit :
quoted
On Thu, Apr 29, 2021 at 3:04 PM Christophe Leroy
[off-list ref] wrote:
quoted
Le 29/04/2021 à 05:15, Jordan Niethe a écrit :
quoted
If MODULES_{VADDR,END} are not defined set them to VMALLOC_START and
VMALLOC_END respectively. This reduces the need for special cases. For
example, powerpc's module_alloc() was previously predicated on
MODULES_VADDR being defined but now is unconditionally defined.
This will be useful reducing conditional code in other places that need
to allocate from the module region (i.e., kprobes).
Signed-off-by: Jordan Niethe <redacted>
---
v10: New to series
v11: - Consider more places MODULES_VADDR was being used
---
arch/powerpc/include/asm/pgtable.h | 11 +++++++++++
arch/powerpc/kernel/module.c | 5 +----
arch/powerpc/mm/kasan/kasan_init_32.c | 10 +++++-----
arch/powerpc/mm/ptdump/ptdump.c | 4 ++--
4 files changed, 19 insertions(+), 11 deletions(-)
No no.
TASK_SIZE > MODULES_VADDR is ALWAYS wrong, for any target, in any configuration.
Why is it a problem to leave the test as a BUILD_BUG_ON() in module_alloc() ?
On ppc64s, MODULES_VADDR is __vmalloc_start (a variable) and
TASK_SIZE depends on current.
Also for nohash like 44x, MODULES_VADDR is defined based on high_memory.
If I put it back in module_alloc() and wrap it with #ifdef
CONFIG_PPC_BOOK3S_32 will that be fine?
Yes, more or less, but using module_alloc() instead of vmalloc().
And module_alloc() implies EXEC, so only the set_memory_ro() will be required.
Yep.
I see no point in doing any set_memory_xxx() in free_insn_page(), because as soon as you do a
vfree() the page is not mapped anymore so any access will lead to a fault.
Yeah, I'd not realised we had VM_FLUSH_RESET_PERMS when I added that.
I agree it's pointless.
On Mon, May 3, 2021 at 4:22 PM Christophe Leroy
[off-list ref] wrote:
quoted
Le 03/05/2021 à 08:16, Jordan Niethe a écrit :
quoted
On Mon, May 3, 2021 at 3:57 PM Christophe Leroy
[off-list ref] wrote:
quoted
Le 03/05/2021 à 07:39, Jordan Niethe a écrit :
quoted
On Thu, Apr 29, 2021 at 3:04 PM Christophe Leroy
[off-list ref] wrote:
quoted
Le 29/04/2021 à 05:15, Jordan Niethe a écrit :
quoted
If MODULES_{VADDR,END} are not defined set them to VMALLOC_START and
VMALLOC_END respectively. This reduces the need for special cases. For
example, powerpc's module_alloc() was previously predicated on
MODULES_VADDR being defined but now is unconditionally defined.
This will be useful reducing conditional code in other places that need
to allocate from the module region (i.e., kprobes).
Signed-off-by: Jordan Niethe <redacted>
---
v10: New to series
v11: - Consider more places MODULES_VADDR was being used
---
arch/powerpc/include/asm/pgtable.h | 11 +++++++++++
arch/powerpc/kernel/module.c | 5 +----
arch/powerpc/mm/kasan/kasan_init_32.c | 10 +++++-----
arch/powerpc/mm/ptdump/ptdump.c | 4 ++--
4 files changed, 19 insertions(+), 11 deletions(-)
No no.
TASK_SIZE > MODULES_VADDR is ALWAYS wrong, for any target, in any configuration.
Why is it a problem to leave the test as a BUILD_BUG_ON() in module_alloc() ?
On ppc64s, MODULES_VADDR is __vmalloc_start (a variable) and
TASK_SIZE depends on current.
Also for nohash like 44x, MODULES_VADDR is defined based on high_memory.
If I put it back in module_alloc() and wrap it with #ifdef
CONFIG_PPC_BOOK3S_32 will that be fine?
Yes, more or less, but using module_alloc() instead of vmalloc().
And module_alloc() implies EXEC, so only the set_memory_ro() will be required.
Yep.
quoted
I see no point in doing any set_memory_xxx() in free_insn_page(), because as soon as you do a
vfree() the page is not mapped anymore so any access will lead to a fault.
Yeah, I'd not realised we had VM_FLUSH_RESET_PERMS when I added that.
I agree it's pointless.
At the end if should be quite similar to what S390 architecture does.
From: Jordan Niethe <hidden> Date: 2021-05-05 05:23:02
On Thu, Apr 29, 2021 at 2:53 PM Christophe Leroy
[off-list ref] wrote:
Le 29/04/2021 à 05:15, Jordan Niethe a écrit :
quoted
setup_text_poke_area() is a late init call so it runs before
mark_rodata_ro() and after the init calls. This lets all the init code
patching simply write to their locations. In the future, kprobes is
going to allocate its instruction pages RO which means they will need
setup_text__poke_area() to have been already called for their code
patching. However, init_kprobes() (which allocates and patches some
instruction pages) is an early init call so it happens before
setup_text__poke_area().
start_kernel() calls poking_init() before any of the init calls. On
powerpc, poking_init() is currently a nop. setup_text_poke_area() relies
on kernel virtual memory, cpu hotplug and per_cpu_areas being setup.
setup_per_cpu_areas(), boot_cpu_hotplug_init() and mm_init() are called
before poking_init().
Turn setup_text_poke_area() into poking_init().
I can't remember, maybe I already asked the question:
Have you done some performance measurement or at least some performance analysis ?
No I don't think you have asked and it is a good question.
Here are some results on a Power9 (T2P9D01 REV 1.01) running powernv_defconfig
Timestamp at "Run /init as init process"
Before: ~1.059326
After: ~1.273105
Turning on more testing the difference is greater:
For example, turning on CONFIG_FTRACE_STARTUP_TEST
Timestamp at "Run /init as init process"
Before: ~7.176759
After: ~15.967576
Running with initcall_debug:
Before: initcall init_trace_selftests+0x0/0x1b4 returned 0 after 2880859 usecs
After: initcall init_trace_selftests+0x0/0x1b4 returned 0 after 10048828 usecs
So it does slow it down.
But it also might be a good thing for testing that these tests using
code patching now will use the same code path for patching that would
be used on a fully booted system.
Christophe
quoted
Reviewed-by: Russell Currey <redacted>
Signed-off-by: Jordan Niethe <redacted>
---
v9: New to series
---
arch/powerpc/lib/code-patching.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
@@ -70,14 +70,11 @@ static int text_area_cpu_down(unsigned int cpu)}/*-*Runasalateinitcall.Thisallowsalltheboottimepatchingtobedone-*simplybypatchingthecode,andthenwe'recalledherepriorto-*mark_rodata_ro(),whichhappensafterallinitcallsarerun.Although-*BUG_ON()isrude,inthiscaseitshouldonlyhappenifENOMEM,andwejudge-*itasbeingpreferabletoakernelthatwillcrashlaterwhensomeonetries-*tousepatch_instruction().+*AlthoughBUG_ON()isrude,inthiscaseitshouldonlyhappenifENOMEM,and+*wejudgeitasbeingpreferabletoakernelthatwillcrashlaterwhen+*someonetriestousepatch_instruction().*/-staticint__initsetup_text_poke_area(void)+int__initpoking_init(void){BUG_ON(!cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,"powerpc/text_poke:online",text_area_cpu_up,
@@ -85,7 +82,6 @@ static int __init setup_text_poke_area(void)return0;}-late_initcall(setup_text_poke_area);/**Thiscanbecalledforkerneltextoramodule.