Skip to content

Commit 84bd7e0

Browse files
committed
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
2 parents c1649ec + dc74a9e commit 84bd7e0

File tree

14 files changed

+247
-213
lines changed

14 files changed

+247
-213
lines changed

arch/loongarch/include/asm/ftrace.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
#define FTRACE_REGS_PLT_IDX 1
1111
#define NR_FTRACE_PLTS 2
1212

13-
#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
14-
1513
#ifdef CONFIG_FUNCTION_TRACER
1614

1715
#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */

arch/loongarch/include/asm/inst.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -377,14 +377,6 @@ static inline bool unsigned_imm_check(unsigned long val, unsigned int bit)
377377
return val < (1UL << bit);
378378
}
379379

380-
static inline unsigned long sign_extend(unsigned long val, unsigned int idx)
381-
{
382-
if (!is_imm_negative(val, idx + 1))
383-
return ((1UL << idx) - 1) & val;
384-
else
385-
return ~((1UL << idx) - 1) | val;
386-
}
387-
388380
#define DEF_EMIT_REG0I26_FORMAT(NAME, OP) \
389381
static inline void emit_##NAME(union loongarch_instruction *insn, \
390382
int offset) \
@@ -401,6 +393,7 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \
401393
}
402394

403395
DEF_EMIT_REG0I26_FORMAT(b, b_op)
396+
DEF_EMIT_REG0I26_FORMAT(bl, bl_op)
404397

405398
#define DEF_EMIT_REG1I20_FORMAT(NAME, OP) \
406399
static inline void emit_##NAME(union loongarch_instruction *insn, \

arch/loongarch/include/asm/unwind.h

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
#define _ASM_UNWIND_H
99

1010
#include <linux/sched.h>
11+
#include <linux/ftrace.h>
1112

13+
#include <asm/ptrace.h>
1214
#include <asm/stacktrace.h>
1315

1416
enum unwinder_type {
@@ -20,11 +22,13 @@ struct unwind_state {
2022
char type; /* UNWINDER_XXX */
2123
struct stack_info stack_info;
2224
struct task_struct *task;
23-
bool first, error, is_ftrace;
25+
bool first, error, reset;
2426
int graph_idx;
2527
unsigned long sp, pc, ra;
2628
};
2729

30+
bool default_next_frame(struct unwind_state *state);
31+
2832
void unwind_start(struct unwind_state *state,
2933
struct task_struct *task, struct pt_regs *regs);
3034
bool unwind_next_frame(struct unwind_state *state);
@@ -40,4 +44,39 @@ static inline bool unwind_error(struct unwind_state *state)
4044
return state->error;
4145
}
4246

47+
#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
48+
49+
static inline unsigned long unwind_graph_addr(struct unwind_state *state,
50+
unsigned long pc, unsigned long cfa)
51+
{
52+
return ftrace_graph_ret_addr(state->task, &state->graph_idx,
53+
pc, (unsigned long *)(cfa - GRAPH_FAKE_OFFSET));
54+
}
55+
56+
static __always_inline void __unwind_start(struct unwind_state *state,
57+
struct task_struct *task, struct pt_regs *regs)
58+
{
59+
memset(state, 0, sizeof(*state));
60+
if (regs) {
61+
state->sp = regs->regs[3];
62+
state->pc = regs->csr_era;
63+
state->ra = regs->regs[1];
64+
} else if (task && task != current) {
65+
state->sp = thread_saved_fp(task);
66+
state->pc = thread_saved_ra(task);
67+
state->ra = 0;
68+
} else {
69+
state->sp = (unsigned long)__builtin_frame_address(0);
70+
state->pc = (unsigned long)__builtin_return_address(0);
71+
state->ra = 0;
72+
}
73+
state->task = task;
74+
get_stack_info(state->sp, state->task, &state->stack_info);
75+
state->pc = unwind_graph_addr(state, state->pc, state->sp);
76+
}
77+
78+
static __always_inline unsigned long __unwind_get_return_address(struct unwind_state *state)
79+
{
80+
return unwind_done(state) ? 0 : state->pc;
81+
}
4382
#endif /* _ASM_UNWIND_H */

arch/loongarch/kernel/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ extra-y := vmlinux.lds
88
obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
99
traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \
1010
elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o \
11-
alternative.o unaligned.o
11+
alternative.o unaligned.o unwind.o
1212

1313
obj-$(CONFIG_ACPI) += acpi.o
1414
obj-$(CONFIG_EFI) += efi.o

arch/loongarch/kernel/alternative.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ static void __init_or_module recompute_jump(union loongarch_instruction *buf,
7474
switch (src->reg0i26_format.opcode) {
7575
case b_op:
7676
case bl_op:
77-
jump_addr = cur_pc + sign_extend((si_h << 16 | si_l) << 2, 27);
77+
jump_addr = cur_pc + sign_extend64((si_h << 16 | si_l) << 2, 27);
7878
if (in_alt_jump(jump_addr, start, end))
7979
return;
8080
offset = jump_addr - pc;
@@ -93,7 +93,7 @@ static void __init_or_module recompute_jump(union loongarch_instruction *buf,
9393
fallthrough;
9494
case beqz_op:
9595
case bnez_op:
96-
jump_addr = cur_pc + sign_extend((si_h << 16 | si_l) << 2, 22);
96+
jump_addr = cur_pc + sign_extend64((si_h << 16 | si_l) << 2, 22);
9797
if (in_alt_jump(jump_addr, start, end))
9898
return;
9999
offset = jump_addr - pc;
@@ -112,7 +112,7 @@ static void __init_or_module recompute_jump(union loongarch_instruction *buf,
112112
case bge_op:
113113
case bltu_op:
114114
case bgeu_op:
115-
jump_addr = cur_pc + sign_extend(si << 2, 17);
115+
jump_addr = cur_pc + sign_extend64(si << 2, 17);
116116
if (in_alt_jump(jump_addr, start, end))
117117
return;
118118
offset = jump_addr - pc;

arch/loongarch/kernel/cpu-probe.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c)
9494
c->options = LOONGARCH_CPU_CPUCFG | LOONGARCH_CPU_CSR |
9595
LOONGARCH_CPU_TLB | LOONGARCH_CPU_VINT | LOONGARCH_CPU_WATCH;
9696

97-
elf_hwcap |= HWCAP_LOONGARCH_CRC32;
97+
elf_hwcap = HWCAP_LOONGARCH_CPUCFG | HWCAP_LOONGARCH_CRC32;
9898

9999
config = read_cpucfg(LOONGARCH_CPUCFG1);
100100
if (config & CPUCFG1_UAL) {

arch/loongarch/kernel/genex.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,17 @@ SYM_FUNC_END(except_vec_cex)
6767
.macro BUILD_HANDLER exception handler prep
6868
.align 5
6969
SYM_FUNC_START(handle_\exception)
70+
666:
7071
BACKUP_T0T1
7172
SAVE_ALL
7273
build_prep_\prep
7374
move a0, sp
7475
la.abs t0, do_\handler
7576
jirl ra, t0, 0
77+
668:
7678
RESTORE_ALL_AND_RET
7779
SYM_FUNC_END(handle_\exception)
80+
SYM_DATA(unwind_hint_\exception, .word 668b - 666b)
7881
.endm
7982

8083
BUILD_HANDLER ade ade badv

arch/loongarch/kernel/inst.c

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -58,47 +58,29 @@ u32 larch_insn_gen_nop(void)
5858
u32 larch_insn_gen_b(unsigned long pc, unsigned long dest)
5959
{
6060
long offset = dest - pc;
61-
unsigned int immediate_l, immediate_h;
6261
union loongarch_instruction insn;
6362

6463
if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) {
6564
pr_warn("The generated b instruction is out of range.\n");
6665
return INSN_BREAK;
6766
}
6867

69-
offset >>= 2;
70-
71-
immediate_l = offset & 0xffff;
72-
offset >>= 16;
73-
immediate_h = offset & 0x3ff;
74-
75-
insn.reg0i26_format.opcode = b_op;
76-
insn.reg0i26_format.immediate_l = immediate_l;
77-
insn.reg0i26_format.immediate_h = immediate_h;
68+
emit_b(&insn, offset >> 2);
7869

7970
return insn.word;
8071
}
8172

8273
u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest)
8374
{
8475
long offset = dest - pc;
85-
unsigned int immediate_l, immediate_h;
8676
union loongarch_instruction insn;
8777

8878
if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) {
8979
pr_warn("The generated bl instruction is out of range.\n");
9080
return INSN_BREAK;
9181
}
9282

93-
offset >>= 2;
94-
95-
immediate_l = offset & 0xffff;
96-
offset >>= 16;
97-
immediate_h = offset & 0x3ff;
98-
99-
insn.reg0i26_format.opcode = bl_op;
100-
insn.reg0i26_format.immediate_l = immediate_l;
101-
insn.reg0i26_format.immediate_h = immediate_h;
83+
emit_bl(&insn, offset >> 2);
10284

10385
return insn.word;
10486
}
@@ -107,10 +89,7 @@ u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj, enum loongar
10789
{
10890
union loongarch_instruction insn;
10991

110-
insn.reg3_format.opcode = or_op;
111-
insn.reg3_format.rd = rd;
112-
insn.reg3_format.rj = rj;
113-
insn.reg3_format.rk = rk;
92+
emit_or(&insn, rd, rj, rk);
11493

11594
return insn.word;
11695
}
@@ -124,9 +103,7 @@ u32 larch_insn_gen_lu12iw(enum loongarch_gpr rd, int imm)
124103
{
125104
union loongarch_instruction insn;
126105

127-
insn.reg1i20_format.opcode = lu12iw_op;
128-
insn.reg1i20_format.rd = rd;
129-
insn.reg1i20_format.immediate = imm;
106+
emit_lu12iw(&insn, rd, imm);
130107

131108
return insn.word;
132109
}
@@ -135,9 +112,7 @@ u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm)
135112
{
136113
union loongarch_instruction insn;
137114

138-
insn.reg1i20_format.opcode = lu32id_op;
139-
insn.reg1i20_format.rd = rd;
140-
insn.reg1i20_format.immediate = imm;
115+
emit_lu32id(&insn, rd, imm);
141116

142117
return insn.word;
143118
}
@@ -146,10 +121,7 @@ u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm)
146121
{
147122
union loongarch_instruction insn;
148123

149-
insn.reg2i12_format.opcode = lu52id_op;
150-
insn.reg2i12_format.rd = rd;
151-
insn.reg2i12_format.rj = rj;
152-
insn.reg2i12_format.immediate = imm;
124+
emit_lu52id(&insn, rd, rj, imm);
153125

154126
return insn.word;
155127
}
@@ -158,10 +130,7 @@ u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned l
158130
{
159131
union loongarch_instruction insn;
160132

161-
insn.reg2i16_format.opcode = jirl_op;
162-
insn.reg2i16_format.rd = rd;
163-
insn.reg2i16_format.rj = rj;
164-
insn.reg2i16_format.immediate = (dest - pc) >> 2;
133+
emit_jirl(&insn, rj, rd, (dest - pc) >> 2);
165134

166135
return insn.word;
167136
}

arch/loongarch/kernel/process.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -191,20 +191,14 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
191191

192192
unsigned long __get_wchan(struct task_struct *task)
193193
{
194-
unsigned long pc;
194+
unsigned long pc = 0;
195195
struct unwind_state state;
196196

197197
if (!try_get_task_stack(task))
198198
return 0;
199199

200-
unwind_start(&state, task, NULL);
201-
state.sp = thread_saved_fp(task);
202-
get_stack_info(state.sp, state.task, &state.stack_info);
203-
state.pc = thread_saved_ra(task);
204-
#ifdef CONFIG_UNWINDER_PROLOGUE
205-
state.type = UNWINDER_PROLOGUE;
206-
#endif
207-
for (; !unwind_done(&state); unwind_next_frame(&state)) {
200+
for (unwind_start(&state, task, NULL);
201+
!unwind_done(&state); unwind_next_frame(&state)) {
208202
pc = unwind_get_return_address(&state);
209203
if (!pc)
210204
break;

arch/loongarch/kernel/traps.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,6 @@ static void show_backtrace(struct task_struct *task, const struct pt_regs *regs,
7272
if (!task)
7373
task = current;
7474

75-
if (user_mode(regs))
76-
state.type = UNWINDER_GUESS;
77-
7875
printk("%sCall Trace:", loglvl);
7976
for (unwind_start(&state, task, pregs);
8077
!unwind_done(&state); unwind_next_frame(&state)) {

0 commit comments

Comments
 (0)