Commit b980761b authored by Zheng Yejian's avatar Zheng Yejian
Browse files

livepatch/ppc32: Adjust instruction replace order for KLP_STACK_OPTIMIZE mode

hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I9R2TB



--------------------------------

Signed-off-by: default avatarZheng Yejian <zhengyejian1@huawei.com>
parent 3bff6b09
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ void arch_klp_remove_breakpoint(struct arch_klp_data *arch_data, void *old_func)
long arch_klp_save_old_code(struct arch_klp_data *arch_data, void *old_func);
int arch_klp_module_check_calltrace(void *data);
int klp_unwind_frame(struct task_struct *tsk, struct stackframe *frame);
int klp_patch_text(u32 *dst, const u32 *src, int len);

#endif /* CONFIG_LIVEPATCH_FTRACE */

+22 −0
Original line number Diff line number Diff line
@@ -136,3 +136,25 @@ int klp_unwind_frame(struct task_struct *tsk, struct stackframe *frame)

	return 0;
}

int klp_patch_text(u32 *dst, const u32 *src, int len)
{
	int i;
	int ret;

	if (len <= 0)
		return -EINVAL;
	/* skip breakpoint at first */
	for (i = 1; i < len; i++) {
		ret = patch_instruction((struct ppc_inst *)(dst + i),
					ppc_inst(src[i]));
		if (ret)
			return ret;
	}
	/*
	 * Avoid compile optimization, make sure that instructions
	 * except first breakpoint has been patched.
	 */
	barrier();
	return patch_instruction((struct ppc_inst *)dst, ppc_inst(src[0]));
}
+9 −17
Original line number Diff line number Diff line
@@ -379,7 +379,6 @@ long arch_klp_save_old_code(struct arch_klp_data *arch_data, void *old_func)
static int do_patch(unsigned long pc, unsigned long new_addr)
{
	int ret;
	int i;
	u32 insns[LJMP_INSN_SIZE];

	if (offset_in_range(pc, new_addr, SZ_32M)) {
@@ -403,16 +402,12 @@ static int do_patch(unsigned long pc, unsigned long new_addr)
		insns[2] = 0x7d8903a6;
		insns[3] = 0x4e800420;

		for (i = 0; i < LJMP_INSN_SIZE; i++) {
			ret = patch_instruction((struct ppc_inst *)(((u32 *)pc) + i),
						ppc_inst(insns[i]));
		ret = klp_patch_text((u32 *)pc, insns, LJMP_INSN_SIZE);
		if (ret) {
				pr_err("patch instruction %d large range failed, ret=%d\n",
				       i, ret);
			pr_err("patch instruction large range failed, ret=%d\n", ret);
			return -EPERM;
		}
	}
	}
	return 0;
}

@@ -434,21 +429,18 @@ void arch_klp_unpatch_func(struct klp_func *func)
	struct klp_func_node *func_node;
	struct klp_func *next_func;
	unsigned long pc;
	int i;
	int ret;

	func_node = func->func_node;
	pc = (unsigned long)func_node->old_func;
	list_del_rcu(&func->stack_node);
	if (list_empty(&func_node->func_stack)) {
		for (i = 0; i < LJMP_INSN_SIZE; i++) {
			ret = patch_instruction((struct ppc_inst *)(((u32 *)pc) + i),
						ppc_inst(func_node->arch_data.old_insns[i]));
		ret = klp_patch_text((u32 *)pc, func_node->arch_data.old_insns,
				     LJMP_INSN_SIZE);
		if (ret) {
				pr_err("restore instruction %d failed, ret=%d\n", i, ret);
			pr_err("restore instruction failed, ret=%d\n", ret);
			return;
		}
		}
	} else {
		next_func = list_first_or_null_rcu(&func_node->func_stack,
					struct klp_func, stack_node);