Loading arch/s390/kernel/kprobes.c +39 −18 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ * s390 port, used ppc64 as template. Mike Grundy <grundym@us.ibm.com> */ #include <linux/moduleloader.h> #include <linux/kprobes.h> #include <linux/ptrace.h> #include <linux/preempt.h> Loading @@ -32,17 +33,33 @@ DEFINE_INSN_CACHE_OPS(s390_insn); static int insn_page_in_use; static char insn_page[PAGE_SIZE] __aligned(PAGE_SIZE); void *alloc_insn_page(void) { void *page; page = module_alloc(PAGE_SIZE); if (!page) return NULL; __set_memory((unsigned long) page, 1, SET_MEMORY_RO | SET_MEMORY_X); return page; } void free_insn_page(void *page) { module_memfree(page); } static void *alloc_s390_insn_page(void) { if (xchg(&insn_page_in_use, 1) == 1) return NULL; set_memory_x((unsigned long) &insn_page, 1); __set_memory((unsigned long) &insn_page, 1, SET_MEMORY_RO | SET_MEMORY_X); return &insn_page; } static void free_s390_insn_page(void *page) { set_memory_nx((unsigned long) page, 1); __set_memory((unsigned long) page, 1, SET_MEMORY_RW | SET_MEMORY_NX); xchg(&insn_page_in_use, 0); } Loading @@ -56,25 +73,29 @@ struct kprobe_insn_cache kprobe_s390_insn_slots = { static void copy_instruction(struct kprobe *p) { kprobe_opcode_t insn[MAX_INSN_SIZE]; s64 disp, new_disp; u64 addr, new_addr; unsigned int len; memcpy(p->ainsn.insn, p->addr, insn_length(*p->addr >> 8)); p->opcode = p->ainsn.insn[0]; if (!probe_is_insn_relative_long(p->ainsn.insn)) return; len = insn_length(*p->addr >> 8); memcpy(&insn, p->addr, len); p->opcode = insn[0]; if (probe_is_insn_relative_long(&insn[0])) { /* * For pc-relative instructions in RIL-b or RIL-c format patch the * RI2 displacement field. We have already made sure that the insn * slot for the patched instruction is within the same 2GB area * as the original instruction (either kernel image or module area). * Therefore the new displacement will always fit. * For pc-relative instructions in RIL-b or RIL-c format patch * the RI2 displacement field. We have already made sure that * the insn slot for the patched instruction is within the same * 2GB area as the original instruction (either kernel image or * module area). Therefore the new displacement will always fit. */ disp = *(s32 *)&p->ainsn.insn[1]; disp = *(s32 *)&insn[1]; addr = (u64)(unsigned long)p->addr; new_addr = (u64)(unsigned long)p->ainsn.insn; new_disp = ((addr + (disp * 2)) - new_addr) / 2; *(s32 *)&p->ainsn.insn[1] = new_disp; *(s32 *)&insn[1] = new_disp; } s390_kernel_write(p->ainsn.insn, &insn, len); } NOKPROBE_SYMBOL(copy_instruction); Loading Loading
arch/s390/kernel/kprobes.c +39 −18 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ * s390 port, used ppc64 as template. Mike Grundy <grundym@us.ibm.com> */ #include <linux/moduleloader.h> #include <linux/kprobes.h> #include <linux/ptrace.h> #include <linux/preempt.h> Loading @@ -32,17 +33,33 @@ DEFINE_INSN_CACHE_OPS(s390_insn); static int insn_page_in_use; static char insn_page[PAGE_SIZE] __aligned(PAGE_SIZE); void *alloc_insn_page(void) { void *page; page = module_alloc(PAGE_SIZE); if (!page) return NULL; __set_memory((unsigned long) page, 1, SET_MEMORY_RO | SET_MEMORY_X); return page; } void free_insn_page(void *page) { module_memfree(page); } static void *alloc_s390_insn_page(void) { if (xchg(&insn_page_in_use, 1) == 1) return NULL; set_memory_x((unsigned long) &insn_page, 1); __set_memory((unsigned long) &insn_page, 1, SET_MEMORY_RO | SET_MEMORY_X); return &insn_page; } static void free_s390_insn_page(void *page) { set_memory_nx((unsigned long) page, 1); __set_memory((unsigned long) page, 1, SET_MEMORY_RW | SET_MEMORY_NX); xchg(&insn_page_in_use, 0); } Loading @@ -56,25 +73,29 @@ struct kprobe_insn_cache kprobe_s390_insn_slots = { static void copy_instruction(struct kprobe *p) { kprobe_opcode_t insn[MAX_INSN_SIZE]; s64 disp, new_disp; u64 addr, new_addr; unsigned int len; memcpy(p->ainsn.insn, p->addr, insn_length(*p->addr >> 8)); p->opcode = p->ainsn.insn[0]; if (!probe_is_insn_relative_long(p->ainsn.insn)) return; len = insn_length(*p->addr >> 8); memcpy(&insn, p->addr, len); p->opcode = insn[0]; if (probe_is_insn_relative_long(&insn[0])) { /* * For pc-relative instructions in RIL-b or RIL-c format patch the * RI2 displacement field. We have already made sure that the insn * slot for the patched instruction is within the same 2GB area * as the original instruction (either kernel image or module area). * Therefore the new displacement will always fit. * For pc-relative instructions in RIL-b or RIL-c format patch * the RI2 displacement field. We have already made sure that * the insn slot for the patched instruction is within the same * 2GB area as the original instruction (either kernel image or * module area). Therefore the new displacement will always fit. */ disp = *(s32 *)&p->ainsn.insn[1]; disp = *(s32 *)&insn[1]; addr = (u64)(unsigned long)p->addr; new_addr = (u64)(unsigned long)p->ainsn.insn; new_disp = ((addr + (disp * 2)) - new_addr) / 2; *(s32 *)&p->ainsn.insn[1] = new_disp; *(s32 *)&insn[1] = new_disp; } s390_kernel_write(p->ainsn.insn, &insn, len); } NOKPROBE_SYMBOL(copy_instruction); Loading