@@ -205,9 +205,6 @@ void __init poking_init(void)
205205{
206206 int ret ;
207207
208- if (!IS_ENABLED (CONFIG_STRICT_KERNEL_RWX ))
209- return ;
210-
211208 if (mm_patch_enabled ())
212209 ret = cpuhp_setup_state (CPUHP_AP_ONLINE_DYN ,
213210 "powerpc/text_poke_mm:online" ,
@@ -375,6 +372,144 @@ int patch_instruction(u32 *addr, ppc_inst_t instr)
375372}
376373NOKPROBE_SYMBOL (patch_instruction );
377374
375+ static int __patch_instructions (u32 * patch_addr , u32 * code , size_t len , bool repeat_instr )
376+ {
377+ unsigned long start = (unsigned long )patch_addr ;
378+
379+ /* Repeat instruction */
380+ if (repeat_instr ) {
381+ ppc_inst_t instr = ppc_inst_read (code );
382+
383+ if (ppc_inst_prefixed (instr )) {
384+ u64 val = ppc_inst_as_ulong (instr );
385+
386+ memset64 ((u64 * )patch_addr , val , len / 8 );
387+ } else {
388+ u32 val = ppc_inst_val (instr );
389+
390+ memset32 (patch_addr , val , len / 4 );
391+ }
392+ } else {
393+ memcpy (patch_addr , code , len );
394+ }
395+
396+ smp_wmb (); /* smp write barrier */
397+ flush_icache_range (start , start + len );
398+ return 0 ;
399+ }
400+
401+ /*
402+ * A page is mapped and instructions that fit the page are patched.
403+ * Assumes 'len' to be (PAGE_SIZE - offset_in_page(addr)) or below.
404+ */
405+ static int __do_patch_instructions_mm (u32 * addr , u32 * code , size_t len , bool repeat_instr )
406+ {
407+ struct mm_struct * patching_mm , * orig_mm ;
408+ unsigned long pfn = get_patch_pfn (addr );
409+ unsigned long text_poke_addr ;
410+ spinlock_t * ptl ;
411+ u32 * patch_addr ;
412+ pte_t * pte ;
413+ int err ;
414+
415+ patching_mm = __this_cpu_read (cpu_patching_context .mm );
416+ text_poke_addr = __this_cpu_read (cpu_patching_context .addr );
417+ patch_addr = (u32 * )(text_poke_addr + offset_in_page (addr ));
418+
419+ pte = get_locked_pte (patching_mm , text_poke_addr , & ptl );
420+ if (!pte )
421+ return - ENOMEM ;
422+
423+ __set_pte_at (patching_mm , text_poke_addr , pte , pfn_pte (pfn , PAGE_KERNEL ), 0 );
424+
425+ /* order PTE update before use, also serves as the hwsync */
426+ asm volatile ("ptesync" ::: "memory" );
427+
428+ /* order context switch after arbitrary prior code */
429+ isync ();
430+
431+ orig_mm = start_using_temp_mm (patching_mm );
432+
433+ err = __patch_instructions (patch_addr , code , len , repeat_instr );
434+
435+ /* context synchronisation performed by __patch_instructions */
436+ stop_using_temp_mm (patching_mm , orig_mm );
437+
438+ pte_clear (patching_mm , text_poke_addr , pte );
439+ /*
440+ * ptesync to order PTE update before TLB invalidation done
441+ * by radix__local_flush_tlb_page_psize (in _tlbiel_va)
442+ */
443+ local_flush_tlb_page_psize (patching_mm , text_poke_addr , mmu_virtual_psize );
444+
445+ pte_unmap_unlock (pte , ptl );
446+
447+ return err ;
448+ }
449+
450+ /*
451+ * A page is mapped and instructions that fit the page are patched.
452+ * Assumes 'len' to be (PAGE_SIZE - offset_in_page(addr)) or below.
453+ */
454+ static int __do_patch_instructions (u32 * addr , u32 * code , size_t len , bool repeat_instr )
455+ {
456+ unsigned long pfn = get_patch_pfn (addr );
457+ unsigned long text_poke_addr ;
458+ u32 * patch_addr ;
459+ pte_t * pte ;
460+ int err ;
461+
462+ text_poke_addr = (unsigned long )__this_cpu_read (cpu_patching_context .addr ) & PAGE_MASK ;
463+ patch_addr = (u32 * )(text_poke_addr + offset_in_page (addr ));
464+
465+ pte = __this_cpu_read (cpu_patching_context .pte );
466+ __set_pte_at (& init_mm , text_poke_addr , pte , pfn_pte (pfn , PAGE_KERNEL ), 0 );
467+ /* See ptesync comment in radix__set_pte_at() */
468+ if (radix_enabled ())
469+ asm volatile ("ptesync" ::: "memory" );
470+
471+ err = __patch_instructions (patch_addr , code , len , repeat_instr );
472+
473+ pte_clear (& init_mm , text_poke_addr , pte );
474+ flush_tlb_kernel_range (text_poke_addr , text_poke_addr + PAGE_SIZE );
475+
476+ return err ;
477+ }
478+
479+ /*
480+ * Patch 'addr' with 'len' bytes of instructions from 'code'.
481+ *
482+ * If repeat_instr is true, the same instruction is filled for
483+ * 'len' bytes.
484+ */
485+ int patch_instructions (u32 * addr , u32 * code , size_t len , bool repeat_instr )
486+ {
487+ while (len > 0 ) {
488+ unsigned long flags ;
489+ size_t plen ;
490+ int err ;
491+
492+ plen = min_t (size_t , PAGE_SIZE - offset_in_page (addr ), len );
493+
494+ local_irq_save (flags );
495+ if (mm_patch_enabled ())
496+ err = __do_patch_instructions_mm (addr , code , plen , repeat_instr );
497+ else
498+ err = __do_patch_instructions (addr , code , plen , repeat_instr );
499+ local_irq_restore (flags );
500+ if (err )
501+ return err ;
502+
503+ len -= plen ;
504+ addr = (u32 * )((unsigned long )addr + plen );
505+ if (!repeat_instr )
506+ code = (u32 * )((unsigned long )code + plen );
507+ }
508+
509+ return 0 ;
510+ }
511+ NOKPROBE_SYMBOL (patch_instructions );
512+
378513int patch_branch (u32 * addr , unsigned long target , int flags )
379514{
380515 ppc_inst_t instr ;
0 commit comments