@@ -34,6 +34,16 @@ static inline int klp_check_compiler_support(void)
extern int klp_write_module_reloc(struct module *mod, unsigned long type,
unsigned long loc, unsigned long value);
+/*
+ * LivePatching works on PPC only when the kernel is compiled with
+ * -mprofile-kernel. The ftrace handler is called after the TOC load
+ * and LR save (16 bytes).
+ */
+static inline unsigned long klp_ftrace_location(unsigned long faddr)
+{
+ return faddr + 16;
+}
+
static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->nip = ip;
@@ -32,6 +32,15 @@ static inline int klp_write_module_reloc(struct module *mod, unsigned long
return -ENOSYS;
}
+/*
+ * LivePatching works only when the ftrace handler is called from the first
+ * instruction of the patched function on s390.
+ */
+static inline unsigned long klp_ftrace_location(unsigned long faddr)
+{
+ return faddr;
+}
+
static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->psw.addr = ip;
@@ -36,6 +36,16 @@ static inline int klp_check_compiler_support(void)
int klp_write_module_reloc(struct module *mod, unsigned long type,
unsigned long loc, unsigned long value);
+
+/*
+ * LivePatching works only when ftrace uses fentry on x86. Therefore
+ * the ftrace location is the same as the address of the function.
+ */
+static inline unsigned long klp_ftrace_location(unsigned long faddr)
+{
+ return faddr;
+}
+
static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
regs->ip = ip;
@@ -364,8 +364,10 @@ static void klp_disable_func(struct klp_func *func)
return;
if (list_is_singular(&ops->func_stack)) {
+ unsigned long ftrace_loc = klp_ftrace_location(func->old_addr);
+
WARN_ON(unregister_ftrace_function(&ops->fops));
- WARN_ON(ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0));
+ WARN_ON(ftrace_set_filter_ip(&ops->fops, ftrace_loc, 1, 0));
list_del_rcu(&func->stack_node);
list_del(&ops->node);
@@ -390,6 +392,8 @@ static int klp_enable_func(struct klp_func *func)
ops = klp_find_ops(func->old_addr);
if (!ops) {
+ unsigned long ftrace_loc = klp_ftrace_location(func->old_addr);
+
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
if (!ops)
return -ENOMEM;
@@ -404,7 +408,7 @@ static int klp_enable_func(struct klp_func *func)
INIT_LIST_HEAD(&ops->func_stack);
list_add_rcu(&func->stack_node, &ops->func_stack);
- ret = ftrace_set_filter_ip(&ops->fops, func->old_addr, 0, 0);
+ ret = ftrace_set_filter_ip(&ops->fops, ftrace_loc, 0, 0);
if (ret) {
pr_err("failed to set ftrace filter for function '%s' (%d)\n",
func->old_name, ret);
@@ -415,7 +419,7 @@ static int klp_enable_func(struct klp_func *func)
if (ret) {
pr_err("failed to register ftrace handler for function '%s' (%d)\n",
func->old_name, ret);
- ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0);
+ ftrace_set_filter_ip(&ops->fops, ftrace_loc, 1, 0);
goto err;
}