mirror of
https://github.com/torvalds/linux.git
synced 2025-11-01 00:58:39 +02:00
s390/kprobes: Remove custom insn slot allocator
Since commit c98d2ecae0 ("s390/mm: Uncouple physical vs virtual address
spaces") the kernel image and module area are within the same 4GB area.
This eliminates the need of a custom insn slot allocator for kprobes within
the kernel image, since standard module_alloc() allocated pages are
sufficient for PC relative instructions with a signed 32 bit offset.
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
parent
e7dec0b792
commit
d890e6af50
4 changed files with 10 additions and 89 deletions
|
|
@ -59,7 +59,6 @@ obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o
|
||||||
obj-$(CONFIG_COMPAT) += $(compat-obj-y)
|
obj-$(CONFIG_COMPAT) += $(compat-obj-y)
|
||||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||||
obj-$(CONFIG_KPROBES) += kprobes.o
|
obj-$(CONFIG_KPROBES) += kprobes.o
|
||||||
obj-$(CONFIG_KPROBES) += kprobes_insn_page.o
|
|
||||||
obj-$(CONFIG_KPROBES) += mcount.o
|
obj-$(CONFIG_KPROBES) += mcount.o
|
||||||
obj-$(CONFIG_RETHOOK) += rethook.o
|
obj-$(CONFIG_RETHOOK) += rethook.o
|
||||||
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
|
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@
|
||||||
#include <asm/set_memory.h>
|
#include <asm/set_memory.h>
|
||||||
#include <asm/sections.h>
|
#include <asm/sections.h>
|
||||||
#include <asm/dis.h>
|
#include <asm/dis.h>
|
||||||
#include "kprobes.h"
|
|
||||||
#include "entry.h"
|
#include "entry.h"
|
||||||
|
|
||||||
DEFINE_PER_CPU(struct kprobe *, current_kprobe);
|
DEFINE_PER_CPU(struct kprobe *, current_kprobe);
|
||||||
|
|
@ -32,8 +31,6 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
|
||||||
|
|
||||||
struct kretprobe_blackpoint kretprobe_blacklist[] = { };
|
struct kretprobe_blackpoint kretprobe_blacklist[] = { };
|
||||||
|
|
||||||
static int insn_page_in_use;
|
|
||||||
|
|
||||||
void *alloc_insn_page(void)
|
void *alloc_insn_page(void)
|
||||||
{
|
{
|
||||||
void *page;
|
void *page;
|
||||||
|
|
@ -45,26 +42,6 @@ void *alloc_insn_page(void)
|
||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *alloc_s390_insn_page(void)
|
|
||||||
{
|
|
||||||
if (xchg(&insn_page_in_use, 1) == 1)
|
|
||||||
return NULL;
|
|
||||||
return &kprobes_insn_page;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_s390_insn_page(void *page)
|
|
||||||
{
|
|
||||||
xchg(&insn_page_in_use, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct kprobe_insn_cache kprobe_s390_insn_slots = {
|
|
||||||
.mutex = __MUTEX_INITIALIZER(kprobe_s390_insn_slots.mutex),
|
|
||||||
.alloc = alloc_s390_insn_page,
|
|
||||||
.free = free_s390_insn_page,
|
|
||||||
.pages = LIST_HEAD_INIT(kprobe_s390_insn_slots.pages),
|
|
||||||
.insn_size = MAX_INSN_SIZE,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void copy_instruction(struct kprobe *p)
|
static void copy_instruction(struct kprobe *p)
|
||||||
{
|
{
|
||||||
kprobe_opcode_t insn[MAX_INSN_SIZE];
|
kprobe_opcode_t insn[MAX_INSN_SIZE];
|
||||||
|
|
@ -78,10 +55,10 @@ static void copy_instruction(struct kprobe *p)
|
||||||
if (probe_is_insn_relative_long(&insn[0])) {
|
if (probe_is_insn_relative_long(&insn[0])) {
|
||||||
/*
|
/*
|
||||||
* For pc-relative instructions in RIL-b or RIL-c format patch
|
* For pc-relative instructions in RIL-b or RIL-c format patch
|
||||||
* the RI2 displacement field. We have already made sure that
|
* the RI2 displacement field. The insn slot for the to be
|
||||||
* the insn slot for the patched instruction is within the same
|
* patched instruction is within the same 4GB area like the
|
||||||
* 2GB area as the original instruction (either kernel image or
|
* original instruction. Therefore the new displacement will
|
||||||
* module area). Therefore the new displacement will always fit.
|
* always fit.
|
||||||
*/
|
*/
|
||||||
disp = *(s32 *)&insn[1];
|
disp = *(s32 *)&insn[1];
|
||||||
addr = (u64)(unsigned long)p->addr;
|
addr = (u64)(unsigned long)p->addr;
|
||||||
|
|
@ -93,34 +70,6 @@ static void copy_instruction(struct kprobe *p)
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(copy_instruction);
|
NOKPROBE_SYMBOL(copy_instruction);
|
||||||
|
|
||||||
static int s390_get_insn_slot(struct kprobe *p)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Get an insn slot that is within the same 2GB area like the original
|
|
||||||
* instruction. That way instructions with a 32bit signed displacement
|
|
||||||
* field can be patched and executed within the insn slot.
|
|
||||||
*/
|
|
||||||
p->ainsn.insn = NULL;
|
|
||||||
if (is_kernel((unsigned long)p->addr))
|
|
||||||
p->ainsn.insn = get_s390_insn_slot();
|
|
||||||
else if (is_module_addr(p->addr))
|
|
||||||
p->ainsn.insn = get_insn_slot();
|
|
||||||
return p->ainsn.insn ? 0 : -ENOMEM;
|
|
||||||
}
|
|
||||||
NOKPROBE_SYMBOL(s390_get_insn_slot);
|
|
||||||
|
|
||||||
static void s390_free_insn_slot(struct kprobe *p)
|
|
||||||
{
|
|
||||||
if (!p->ainsn.insn)
|
|
||||||
return;
|
|
||||||
if (is_kernel((unsigned long)p->addr))
|
|
||||||
free_s390_insn_slot(p->ainsn.insn, 0);
|
|
||||||
else
|
|
||||||
free_insn_slot(p->ainsn.insn, 0);
|
|
||||||
p->ainsn.insn = NULL;
|
|
||||||
}
|
|
||||||
NOKPROBE_SYMBOL(s390_free_insn_slot);
|
|
||||||
|
|
||||||
/* Check if paddr is at an instruction boundary */
|
/* Check if paddr is at an instruction boundary */
|
||||||
static bool can_probe(unsigned long paddr)
|
static bool can_probe(unsigned long paddr)
|
||||||
{
|
{
|
||||||
|
|
@ -174,7 +123,8 @@ int arch_prepare_kprobe(struct kprobe *p)
|
||||||
/* Make sure the probe isn't going on a difficult instruction */
|
/* Make sure the probe isn't going on a difficult instruction */
|
||||||
if (probe_is_prohibited_opcode(p->addr))
|
if (probe_is_prohibited_opcode(p->addr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (s390_get_insn_slot(p))
|
p->ainsn.insn = get_insn_slot();
|
||||||
|
if (!p->ainsn.insn)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
copy_instruction(p);
|
copy_instruction(p);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -216,7 +166,10 @@ NOKPROBE_SYMBOL(arch_disarm_kprobe);
|
||||||
|
|
||||||
void arch_remove_kprobe(struct kprobe *p)
|
void arch_remove_kprobe(struct kprobe *p)
|
||||||
{
|
{
|
||||||
s390_free_insn_slot(p);
|
if (!p->ainsn.insn)
|
||||||
|
return;
|
||||||
|
free_insn_slot(p->ainsn.insn, 0);
|
||||||
|
p->ainsn.insn = NULL;
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(arch_remove_kprobe);
|
NOKPROBE_SYMBOL(arch_remove_kprobe);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
||||||
#ifndef _ARCH_S390_KPROBES_H
|
|
||||||
#define _ARCH_S390_KPROBES_H
|
|
||||||
|
|
||||||
#include <linux/kprobes.h>
|
|
||||||
|
|
||||||
DEFINE_INSN_CACHE_OPS(s390_insn);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
|
|
||||||
#include <linux/linkage.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* insn_page is a special 4k aligned dummy function for kprobes.
|
|
||||||
* It will contain all kprobed instructions that are out-of-line executed.
|
|
||||||
* The page must be within the kernel image to guarantee that the
|
|
||||||
* out-of-line instructions are within 2GB distance of their original
|
|
||||||
* location. Using a dummy function ensures that the insn_page is within
|
|
||||||
* the text section of the kernel and mapped read-only/executable from
|
|
||||||
* the beginning on, thus avoiding to split large mappings if the page
|
|
||||||
* would be in the data section instead.
|
|
||||||
*/
|
|
||||||
.section .kprobes.text, "ax"
|
|
||||||
.balign 4096
|
|
||||||
SYM_CODE_START(kprobes_insn_page)
|
|
||||||
.rept 2048
|
|
||||||
.word 0x07fe
|
|
||||||
.endr
|
|
||||||
SYM_CODE_END(kprobes_insn_page)
|
|
||||||
.previous
|
|
||||||
Loading…
Reference in a new issue