Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions arch/loongarch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ config LOONGARCH
select HAVE_KVM
select HAVE_MOD_ARCH_SPECIFIC
select HAVE_NMI
select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS && AS_HAS_THIN_ADD_SUB && !CC_IS_CLANG
select HAVE_PCI
select HAVE_PERF_EVENTS
select HAVE_PERF_REGS
Expand All @@ -145,6 +146,7 @@ config LOONGARCH
select HAVE_SAMPLE_FTRACE_DIRECT
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
select HAVE_SETUP_PER_CPU_AREA if NUMA
select HAVE_STACK_VALIDATION if HAVE_OBJTOOL
select HAVE_STACKPROTECTOR
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_TIF_NOHZ
Expand Down Expand Up @@ -258,6 +260,9 @@ config AS_HAS_EXPLICIT_RELOCS
config AS_HAS_FCSR_CLASS
def_bool $(as-instr,movfcsr2gr \$t0$(comma)\$fcsr0)

config AS_HAS_THIN_ADD_SUB
def_bool $(cc-option,-Wa$(comma)-mthin-add-sub)

config AS_HAS_LSX_EXTENSION
def_bool $(as-instr,vld \$vr0$(comma)\$a0$(comma)0)

Expand Down
12 changes: 12 additions & 0 deletions arch/loongarch/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,16 @@ config UNWINDER_PROLOGUE
Some of the addresses it reports may be incorrect (but better than the
Guess unwinder).

config UNWINDER_ORC
bool "ORC unwinder"
depends on HAVE_OBJTOOL
select OBJTOOL
help
This option enables the ORC (Oops Rewind Capability) unwinder for
unwinding kernel stack traces. It uses a custom data format which is
a simplified version of the DWARF Call Frame Information standard.

Enabling this option will increase the kernel's runtime memory usage
by roughly 2-4MB, depending on your kernel config.

endchoice
23 changes: 21 additions & 2 deletions arch/loongarch/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ endif
32bit-emul = elf32loongarch
64bit-emul = elf64loongarch

ifdef CONFIG_UNWINDER_ORC
orc_hash_h := arch/$(SRCARCH)/include/generated/asm/orc_hash.h
orc_hash_sh := $(srctree)/scripts/orc_hash.sh
targets += $(orc_hash_h)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR: trailing whitespace

quiet_cmd_orc_hash = GEN $@

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR: trailing whitespace

cmd_orc_hash = mkdir -p $(dir $@); \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Prefer a maximum 75 chars per line (possible unwrapped commit description?)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR: patch seems to be corrupt (line wrapped?)

$(CONFIG_SHELL) $(orc_hash_sh) < $< > $@
$(orc_hash_h): $(srctree)/arch/loongarch/include/asm/orc_types.h $(orc_hash_sh) FORCE

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR: trailing whitespace

$(call if_changed,orc_hash)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR: trailing whitespace

archprepare: $(orc_hash_h)
endif

ifdef CONFIG_DYNAMIC_FTRACE
KBUILD_CPPFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR: Avoid using diff content in the commit message - patch(1) might not work

CC_FLAGS_FTRACE := -fpatchable-function-entry=2
Expand Down Expand Up @@ -68,8 +80,6 @@ LDFLAGS_vmlinux += -static -n -nostdlib
ifdef CONFIG_AS_HAS_EXPLICIT_RELOCS
cflags-y += $(call cc-option,-mexplicit-relocs)
KBUILD_CFLAGS_KERNEL += $(call cc-option,-mdirect-extern-access)
KBUILD_AFLAGS_MODULE += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
else
cflags-y += $(call cc-option,-mno-explicit-relocs)
KBUILD_AFLAGS_KERNEL += -Wa,-mla-global-with-pcrel
Expand All @@ -78,6 +88,15 @@ KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs
KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
endif

KBUILD_AFLAGS += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
KBUILD_CFLAGS += $(call cc-option,-mno-relax) $(call cc-option,-Wa$(comma)-mno-relax)
KBUILD_AFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub)
KBUILD_CFLAGS += $(call cc-option,-mthin-add-sub) $(call cc-option,-Wa$(comma)-mthin-add-sub)

ifdef CONFIG_OBJTOOL
KBUILD_CFLAGS += -fno-jump-tables
endif

ifeq ($(CONFIG_RELOCATABLE),y)
KBUILD_CFLAGS_KERNEL += -fPIE
LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext $(call ld-option, --apply-dynamic-relocs)
Expand Down
2 changes: 2 additions & 0 deletions arch/loongarch/include/asm/Kbuild
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
generated-y += orc_hash.h

generic-y += dma-contiguous.h
generic-y += mcs_spinlock.h
generic-y += parport.h
Expand Down
1 change: 1 addition & 0 deletions arch/loongarch/include/asm/bug.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
do { \
instrumentation_begin(); \
__BUG_FLAGS(BUGFLAG_WARNING|(flags)); \
annotate_reachable(); \
instrumentation_end(); \
} while (0)

Expand Down
2 changes: 2 additions & 0 deletions arch/loongarch/include/asm/exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <asm/ptrace.h>
#include <linux/kprobes.h>

extern void *exception_table[];

void show_registers(struct pt_regs *regs);

asmlinkage void cache_parity_error(void);
Expand Down
2 changes: 1 addition & 1 deletion arch/loongarch/include/asm/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ ftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs)
static __always_inline void
ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip)
{
regs_set_return_value(&fregs->regs, ip);
instruction_pointer_set(&fregs->regs, ip);
}

#define ftrace_regs_get_argument(fregs, n) \
Expand Down
7 changes: 7 additions & 0 deletions arch/loongarch/include/asm/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define _ASM_MODULE_H

#include <asm/inst.h>
#include <asm/orc_types.h>
#include <asm-generic/module.h>

#define RELA_STACK_DEPTH 16
Expand All @@ -21,6 +22,12 @@ struct mod_arch_specific {
struct mod_section plt;
struct mod_section plt_idx;

#ifdef CONFIG_UNWINDER_ORC
unsigned int num_orcs;
int *orc_unwind_ip;
struct orc_entry *orc_unwind;
#endif

/* For CONFIG_DYNAMIC_FTRACE */
struct plt_entry *ftrace_trampolines;
};
Expand Down
18 changes: 18 additions & 0 deletions arch/loongarch/include/asm/orc_header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */

#ifndef _ORC_HEADER_H
#define _ORC_HEADER_H

#include <linux/types.h>
#include <linux/compiler.h>
#include <asm/orc_hash.h>

/*
* The header is currently a 20-byte hash of the ORC entry definition; see
* scripts/orc_hash.sh.
*/
#define ORC_HEADER \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Prefer a maximum 75 chars per line (possible unwrapped commit description?)

__used __section(".orc_header") __aligned(4) \
static const u8 orc_header[] = { ORC_HASH }

#endif /* _ORC_HEADER_H */
31 changes: 31 additions & 0 deletions arch/loongarch/include/asm/orc_lookup.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _ORC_LOOKUP_H
#define _ORC_LOOKUP_H

/*
* This is a lookup table for speeding up access to the .orc_unwind table.
* Given an input address offset, the corresponding lookup table entry
* specifies a subset of the .orc_unwind table to search.
*
* Each block represents the end of the previous range and the start of the

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Prefer a maximum 75 chars per line (possible unwrapped commit description?)

* next range. An extra block is added to give the last range an end.
*
* The block size should be a power of 2 to avoid a costly 'div' instruction.
*
* A block size of 256 was chosen because it roughly doubles unwinder
* performance while only adding ~5% to the ORC data footprint.
*/
#define LOOKUP_BLOCK_ORDER 8
#define LOOKUP_BLOCK_SIZE (1 << LOOKUP_BLOCK_ORDER)

#ifndef LINKER_SCRIPT

extern unsigned int orc_lookup[];
extern unsigned int orc_lookup_end[];

#define LOOKUP_START_IP (unsigned long)_stext
#define LOOKUP_STOP_IP (unsigned long)_etext

#endif /* LINKER_SCRIPT */

#endif /* _ORC_LOOKUP_H */
58 changes: 58 additions & 0 deletions arch/loongarch/include/asm/orc_types.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _ORC_TYPES_H
#define _ORC_TYPES_H

#include <linux/types.h>

/*
* The ORC_REG_* registers are base registers which are used to find other
* registers on the stack.
*
* ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the
* address of the previous frame: the caller's SP before it called the current

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Prefer a maximum 75 chars per line (possible unwrapped commit description?)

* function.
*
* ORC_REG_UNDEFINED means the corresponding register's value didn't change in
* the current frame.
*
* The most commonly used base registers are SP and FP -- which the previous SP
* is usually based on -- and PREV_SP and UNDEFINED -- which the previous FP is
* usually based on.
*
* The rest of the base registers are needed for special cases like entry code
* and GCC realigned stacks.
*/
#define ORC_REG_UNDEFINED 0
#define ORC_REG_PREV_SP 1
#define ORC_REG_SP 2
#define ORC_REG_FP 3
#define ORC_REG_MAX 4

#define ORC_TYPE_UNDEFINED 0
#define ORC_TYPE_END_OF_STACK 1
#define ORC_TYPE_CALL 2
#define ORC_TYPE_REGS 3
#define ORC_TYPE_REGS_PARTIAL 4

#ifndef __ASSEMBLY__
/*
* This struct is more or less a vastly simplified version of the DWARF Call
* Frame Information standard. It contains only the necessary parts of DWARF
* CFI, simplified for ease of access by the in-kernel unwinder. It tells the
* unwinder how to find the previous SP and FP (and sometimes entry regs) on
* the stack for a given code address. Each instance of the struct corresponds
* to one or more code locations.
*/
struct orc_entry {
s16 sp_offset;
s16 fp_offset;
s16 ra_offset;
unsigned int sp_reg:4;
unsigned int fp_reg:4;
unsigned int ra_reg:4;
unsigned int type:3;
unsigned int signal:1;
};
#endif /* __ASSEMBLY__ */

#endif /* _ORC_TYPES_H */
3 changes: 3 additions & 0 deletions arch/loongarch/include/asm/stackframe.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <asm/asm-offsets.h>
#include <asm/loongarch.h>
#include <asm/thread_info.h>
#include <asm/unwind_hints.h>

/* Make the addition of cfi info a little easier. */
.macro cfi_rel_offset reg offset=0 docfi=0
Expand Down Expand Up @@ -162,6 +163,7 @@
li.w t0, CSR_CRMD_WE
csrxchg t0, t0, LOONGARCH_CSR_CRMD
#endif
UNWIND_HINT_REGS
.endm

.macro SAVE_ALL docfi=0
Expand Down Expand Up @@ -219,6 +221,7 @@

.macro RESTORE_SP_AND_RET docfi=0
cfi_ld sp, PT_R3, \docfi
UNWIND_HINT_FUNC
ertn
.endm

Expand Down
20 changes: 18 additions & 2 deletions arch/loongarch/include/asm/unwind.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
enum unwinder_type {
UNWINDER_GUESS,
UNWINDER_PROLOGUE,
UNWINDER_ORC,
};

struct unwind_state {
Expand All @@ -24,7 +25,7 @@ struct unwind_state {
struct task_struct *task;
bool first, error, reset;
int graph_idx;
unsigned long sp, pc, ra;
unsigned long sp, fp, pc, ra;
};

bool default_next_frame(struct unwind_state *state);
Expand Down Expand Up @@ -61,14 +62,17 @@ static __always_inline void __unwind_start(struct unwind_state *state,
state->sp = regs->regs[3];
state->pc = regs->csr_era;
state->ra = regs->regs[1];
state->fp = regs->regs[22];
} else if (task && task != current) {
state->sp = thread_saved_fp(task);
state->pc = thread_saved_ra(task);
state->ra = 0;
state->fp = 0;
} else {
state->sp = (unsigned long)__builtin_frame_address(0);
state->pc = (unsigned long)__builtin_return_address(0);
state->ra = 0;
state->fp = 0;
}
state->task = task;
get_stack_info(state->sp, state->task, &state->stack_info);
Expand All @@ -77,6 +81,18 @@ static __always_inline void __unwind_start(struct unwind_state *state,

static __always_inline unsigned long __unwind_get_return_address(struct unwind_state *state)
{
return unwind_done(state) ? 0 : state->pc;
if (unwind_done(state))
return 0;

return __kernel_text_address(state->pc) ? state->pc : 0;
}

#ifdef CONFIG_UNWINDER_ORC
void unwind_init(void);
void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size);
#else
static inline void unwind_init(void) {}
static inline void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size, void *orc, size_t orc_size) {}
#endif

#endif /* _ASM_UNWIND_H */
28 changes: 28 additions & 0 deletions arch/loongarch/include/asm/unwind_hints.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_LOONGARCH_UNWIND_HINTS_H
#define _ASM_LOONGARCH_UNWIND_HINTS_H

#include <linux/objtool.h>
#include <asm/orc_types.h>

#ifdef __ASSEMBLY__

.macro UNWIND_HINT_UNDEFINED
UNWIND_HINT type=UNWIND_HINT_TYPE_UNDEFINED
.endm

.macro UNWIND_HINT_END_OF_STACK
UNWIND_HINT type=UNWIND_HINT_TYPE_END_OF_STACK
.endm

.macro UNWIND_HINT_REGS
UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_REGS
.endm

.macro UNWIND_HINT_FUNC
UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_CALL
.endm

#endif /* __ASSEMBLY__ */

#endif /* _ASM_LOONGARCH_UNWIND_HINTS_H */
4 changes: 4 additions & 0 deletions arch/loongarch/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# Makefile for the Linux/LoongArch kernel.
#

OBJECT_FILES_NON_STANDARD_head.o := y

extra-y := vmlinux.lds

obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Prefer a maximum 75 chars per line (possible unwrapped commit description?)

Expand All @@ -22,6 +24,7 @@ obj-$(CONFIG_ARCH_STRICT_ALIGN) += unaligned.o

CFLAGS_module.o += $(call cc-option,-Wno-override-init,)
CFLAGS_syscall.o += $(call cc-option,-Wno-override-init,)
CFLAGS_traps.o += $(call cc-option,-Wno-override-init,)
CFLAGS_perf_event.o += $(call cc-option,-Wno-override-init,)

ifdef CONFIG_FUNCTION_TRACER
Expand Down Expand Up @@ -64,6 +67,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o

obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o
obj-$(CONFIG_UNWINDER_PROLOGUE) += unwind_prologue.o
obj-$(CONFIG_UNWINDER_ORC) += unwind_orc.o

obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_regs.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
Expand Down
Loading