Commit 84bd7e08 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'loongarch-fixes-6.2-1' of...

Merge tag 'loongarch-fixes-6.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson

Pull LoongArch fixes from Huacai Chen:
 "Fix a missing elf_hwcap, fix some stack unwinder bugs and two trivial
  cleanups"

* tag 'loongarch-fixes-6.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson:
  LoongArch: Add generic ex-handler unwind in prologue unwinder
  LoongArch: Strip guess unwinder out from prologue unwinder
  LoongArch: Use correct sp value to get graph addr in stack unwinders
  LoongArch: Get frame info in unwind_start() when regs is not available
  LoongArch: Adjust PC value when unwind next frame in unwinder
  LoongArch: Simplify larch_insn_gen_xxx implementation
  LoongArch: Use common function sign_extend64()
  LoongArch: Add HWCAP_LOONGARCH_CPUCFG to elf_hwcap
parents c1649ec5 dc74a9e8
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -10,8 +10,6 @@
#define FTRACE_REGS_PLT_IDX	1
#define NR_FTRACE_PLTS		2

#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))

#ifdef CONFIG_FUNCTION_TRACER

#define MCOUNT_INSN_SIZE 4		/* sizeof mcount call */
+1 −8
Original line number Diff line number Diff line
@@ -377,14 +377,6 @@ static inline bool unsigned_imm_check(unsigned long val, unsigned int bit)
	return val < (1UL << bit);
}

static inline unsigned long sign_extend(unsigned long val, unsigned int idx)
{
	if (!is_imm_negative(val, idx + 1))
		return ((1UL << idx) - 1) & val;
	else
		return ~((1UL << idx) - 1) | val;
}

#define DEF_EMIT_REG0I26_FORMAT(NAME, OP)				\
static inline void emit_##NAME(union loongarch_instruction *insn,	\
			       int offset)				\
@@ -401,6 +393,7 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \
}

DEF_EMIT_REG0I26_FORMAT(b, b_op)
DEF_EMIT_REG0I26_FORMAT(bl, bl_op)

#define DEF_EMIT_REG1I20_FORMAT(NAME, OP)				\
static inline void emit_##NAME(union loongarch_instruction *insn,	\
+40 −1
Original line number Diff line number Diff line
@@ -8,7 +8,9 @@
#define _ASM_UNWIND_H

#include <linux/sched.h>
#include <linux/ftrace.h>

#include <asm/ptrace.h>
#include <asm/stacktrace.h>

enum unwinder_type {
@@ -20,11 +22,13 @@ struct unwind_state {
	char type; /* UNWINDER_XXX */
	struct stack_info stack_info;
	struct task_struct *task;
	bool first, error, is_ftrace;
	bool first, error, reset;
	int graph_idx;
	unsigned long sp, pc, ra;
};

bool default_next_frame(struct unwind_state *state);

void unwind_start(struct unwind_state *state,
		  struct task_struct *task, struct pt_regs *regs);
bool unwind_next_frame(struct unwind_state *state);
@@ -40,4 +44,39 @@ static inline bool unwind_error(struct unwind_state *state)
	return state->error;
}

#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))

static inline unsigned long unwind_graph_addr(struct unwind_state *state,
					unsigned long pc, unsigned long cfa)
{
	return ftrace_graph_ret_addr(state->task, &state->graph_idx,
				     pc, (unsigned long *)(cfa - GRAPH_FAKE_OFFSET));
}

static __always_inline void __unwind_start(struct unwind_state *state,
					struct task_struct *task, struct pt_regs *regs)
{
	memset(state, 0, sizeof(*state));
	if (regs) {
		state->sp = regs->regs[3];
		state->pc = regs->csr_era;
		state->ra = regs->regs[1];
	} else if (task && task != current) {
		state->sp = thread_saved_fp(task);
		state->pc = thread_saved_ra(task);
		state->ra = 0;
	} else {
		state->sp = (unsigned long)__builtin_frame_address(0);
		state->pc = (unsigned long)__builtin_return_address(0);
		state->ra = 0;
	}
	state->task = task;
	get_stack_info(state->sp, state->task, &state->stack_info);
	state->pc = unwind_graph_addr(state, state->pc, state->sp);
}

static __always_inline unsigned long __unwind_get_return_address(struct unwind_state *state)
{
	return unwind_done(state) ? 0 : state->pc;
}
#endif /* _ASM_UNWIND_H */
+1 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@ extra-y := vmlinux.lds
obj-y		+= head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
		   traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \
		   elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o \
		   alternative.o unaligned.o
		   alternative.o unaligned.o unwind.o

obj-$(CONFIG_ACPI)		+= acpi.o
obj-$(CONFIG_EFI) 		+= efi.o
+3 −3
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ static void __init_or_module recompute_jump(union loongarch_instruction *buf,
	switch (src->reg0i26_format.opcode) {
	case b_op:
	case bl_op:
		jump_addr = cur_pc + sign_extend((si_h << 16 | si_l) << 2, 27);
		jump_addr = cur_pc + sign_extend64((si_h << 16 | si_l) << 2, 27);
		if (in_alt_jump(jump_addr, start, end))
			return;
		offset = jump_addr - pc;
@@ -93,7 +93,7 @@ static void __init_or_module recompute_jump(union loongarch_instruction *buf,
		fallthrough;
	case beqz_op:
	case bnez_op:
		jump_addr = cur_pc + sign_extend((si_h << 16 | si_l) << 2, 22);
		jump_addr = cur_pc + sign_extend64((si_h << 16 | si_l) << 2, 22);
		if (in_alt_jump(jump_addr, start, end))
			return;
		offset = jump_addr - pc;
@@ -112,7 +112,7 @@ static void __init_or_module recompute_jump(union loongarch_instruction *buf,
	case bge_op:
	case bltu_op:
	case bgeu_op:
		jump_addr = cur_pc + sign_extend(si << 2, 17);
		jump_addr = cur_pc + sign_extend64(si << 2, 17);
		if (in_alt_jump(jump_addr, start, end))
			return;
		offset = jump_addr - pc;
Loading