All of lore.kernel.org
 help / color / mirror / Atom feed
From: Huacai Chen <chenhuacai@loongson.cn>
To: Arnd Bergmann <arnd@arndb.de>, Andy Lutomirski <luto@kernel.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	Peter Zijlstra <peterz@infradead.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	David Airlie <airlied@linux.ie>, Jonathan Corbet <corbet@lwn.net>,
	Linus Torvalds <torvalds@linux-foundation.org>
Cc: linux-arch@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, Xuefeng Li <lixuefeng@loongson.cn>,
	Yanteng Si <siyanteng@loongson.cn>,
	Huacai Chen <chenhuacai@gmail.com>, Guo Ren <guoren@kernel.org>,
	Xuerui Wang <kernel@xen0n.name>,
	Jiaxun Yang <jiaxun.yang@flygoat.com>,
	Stephen Rothwell <sfr@canb.auug.org.au>,
	Huacai Chen <chenhuacai@loongson.cn>,
	Jessica Yu <jeyu@kernel.org>, WANG Xuerui <git@xen0n.name>,
	Luis Chamberlain <mcgrof@kernel.org>
Subject: [PATCH V11 15/22] LoongArch: Add ELF and module support
Date: Wed, 18 May 2022 17:26:12 +0800	[thread overview]
Message-ID: <20220518092619.1269111-16-chenhuacai@loongson.cn> (raw)
In-Reply-To: <20220518092619.1269111-1-chenhuacai@loongson.cn>

Add ELF-related definition and module relocation code for basic
LoongArch support.

Cc: Jessica Yu <jeyu@kernel.org>
Reviewed-by: WANG Xuerui <git@xen0n.name>
Reviewed-by: Luis Chamberlain <mcgrof@kernel.org>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
---
 arch/loongarch/include/asm/cpufeature.h  |  24 ++
 arch/loongarch/include/asm/elf.h         | 301 ++++++++++++++++++
 arch/loongarch/include/asm/exec.h        |  10 +
 arch/loongarch/include/asm/module.h      |  80 +++++
 arch/loongarch/include/asm/module.lds.h  |   7 +
 arch/loongarch/include/asm/vermagic.h    |  19 ++
 arch/loongarch/include/uapi/asm/auxvec.h |  17 ++
 arch/loongarch/include/uapi/asm/hwcap.h  |  20 ++
 arch/loongarch/kernel/elf.c              |  30 ++
 arch/loongarch/kernel/inst.c             |  40 +++
 arch/loongarch/kernel/module-sections.c  | 121 ++++++++
 arch/loongarch/kernel/module.c           | 374 +++++++++++++++++++++++
 12 files changed, 1043 insertions(+)
 create mode 100644 arch/loongarch/include/asm/cpufeature.h
 create mode 100644 arch/loongarch/include/asm/elf.h
 create mode 100644 arch/loongarch/include/asm/exec.h
 create mode 100644 arch/loongarch/include/asm/module.h
 create mode 100644 arch/loongarch/include/asm/module.lds.h
 create mode 100644 arch/loongarch/include/asm/vermagic.h
 create mode 100644 arch/loongarch/include/uapi/asm/auxvec.h
 create mode 100644 arch/loongarch/include/uapi/asm/hwcap.h
 create mode 100644 arch/loongarch/kernel/elf.c
 create mode 100644 arch/loongarch/kernel/inst.c
 create mode 100644 arch/loongarch/kernel/module-sections.c
 create mode 100644 arch/loongarch/kernel/module.c

diff --git a/arch/loongarch/include/asm/cpufeature.h b/arch/loongarch/include/asm/cpufeature.h
new file mode 100644
index 000000000000..4da22a8e63de
--- /dev/null
+++ b/arch/loongarch/include/asm/cpufeature.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CPU feature definitions for module loading, used by
+ * module_cpu_feature_match(), see uapi/asm/hwcap.h for LoongArch CPU features.
+ *
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_CPUFEATURE_H
+#define __ASM_CPUFEATURE_H
+
+#include <uapi/asm/hwcap.h>
+#include <asm/elf.h>
+
+#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap))
+
+#define cpu_feature(x)		ilog2(HWCAP_ ## x)
+
+static inline bool cpu_have_feature(unsigned int num)
+{
+	return elf_hwcap & (1UL << num);
+}
+
+#endif /* __ASM_CPUFEATURE_H */
diff --git a/arch/loongarch/include/asm/elf.h b/arch/loongarch/include/asm/elf.h
new file mode 100644
index 000000000000..f3960b18a90e
--- /dev/null
+++ b/arch/loongarch/include/asm/elf.h
@@ -0,0 +1,301 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+#ifndef _ASM_ELF_H
+#define _ASM_ELF_H
+
+#include <linux/auxvec.h>
+#include <linux/fs.h>
+#include <uapi/linux/elf.h>
+
+#include <asm/current.h>
+#include <asm/vdso.h>
+
+/* The ABI of a file. */
+#define EF_LOONGARCH_ABI_LP64_SOFT_FLOAT	0x1
+#define EF_LOONGARCH_ABI_LP64_SINGLE_FLOAT	0x2
+#define EF_LOONGARCH_ABI_LP64_DOUBLE_FLOAT	0x3
+
+#define EF_LOONGARCH_ABI_ILP32_SOFT_FLOAT	0x5
+#define EF_LOONGARCH_ABI_ILP32_SINGLE_FLOAT	0x6
+#define EF_LOONGARCH_ABI_ILP32_DOUBLE_FLOAT	0x7
+
+/* LoongArch relocation types used by the dynamic linker */
+#define R_LARCH_NONE				0
+#define R_LARCH_32				1
+#define R_LARCH_64				2
+#define R_LARCH_RELATIVE			3
+#define R_LARCH_COPY				4
+#define R_LARCH_JUMP_SLOT			5
+#define R_LARCH_TLS_DTPMOD32			6
+#define R_LARCH_TLS_DTPMOD64			7
+#define R_LARCH_TLS_DTPREL32			8
+#define R_LARCH_TLS_DTPREL64			9
+#define R_LARCH_TLS_TPREL32			10
+#define R_LARCH_TLS_TPREL64			11
+#define R_LARCH_IRELATIVE			12
+#define R_LARCH_MARK_LA				20
+#define R_LARCH_MARK_PCREL			21
+#define R_LARCH_SOP_PUSH_PCREL			22
+#define R_LARCH_SOP_PUSH_ABSOLUTE		23
+#define R_LARCH_SOP_PUSH_DUP			24
+#define R_LARCH_SOP_PUSH_GPREL			25
+#define R_LARCH_SOP_PUSH_TLS_TPREL		26
+#define R_LARCH_SOP_PUSH_TLS_GOT		27
+#define R_LARCH_SOP_PUSH_TLS_GD			28
+#define R_LARCH_SOP_PUSH_PLT_PCREL		29
+#define R_LARCH_SOP_ASSERT			30
+#define R_LARCH_SOP_NOT				31
+#define R_LARCH_SOP_SUB				32
+#define R_LARCH_SOP_SL				33
+#define R_LARCH_SOP_SR				34
+#define R_LARCH_SOP_ADD				35
+#define R_LARCH_SOP_AND				36
+#define R_LARCH_SOP_IF_ELSE			37
+#define R_LARCH_SOP_POP_32_S_10_5		38
+#define R_LARCH_SOP_POP_32_U_10_12		39
+#define R_LARCH_SOP_POP_32_S_10_12		40
+#define R_LARCH_SOP_POP_32_S_10_16		41
+#define R_LARCH_SOP_POP_32_S_10_16_S2		42
+#define R_LARCH_SOP_POP_32_S_5_20		43
+#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2	44
+#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2	45
+#define R_LARCH_SOP_POP_32_U			46
+#define R_LARCH_ADD8				47
+#define R_LARCH_ADD16				48
+#define R_LARCH_ADD24				49
+#define R_LARCH_ADD32				50
+#define R_LARCH_ADD64				51
+#define R_LARCH_SUB8				52
+#define R_LARCH_SUB16				53
+#define R_LARCH_SUB24				54
+#define R_LARCH_SUB32				55
+#define R_LARCH_SUB64				56
+#define R_LARCH_GNU_VTINHERIT			57
+#define R_LARCH_GNU_VTENTRY			58
+
+#ifndef ELF_ARCH
+
+/* ELF register definitions */
+
+/*
+ * General purpose have the following registers:
+ *	Register	Number
+ *	GPRs		32
+ *	ORIG_A0		1
+ *	ERA		1
+ *	BADVADDR	1
+ *	CRMD		1
+ *	PRMD		1
+ *	EUEN		1
+ *	ECFG		1
+ *	ESTAT		1
+ *	Reserved	5
+ */
+#define ELF_NGREG	45
+
+/*
+ * Floating point have the following registers:
+ *	Register	Number
+ *	FPR		32
+ *	FCC		1
+ *	FCSR		1
+ */
+#define ELF_NFPREG	34
+
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+void loongarch_dump_regs64(u64 *uregs, const struct pt_regs *regs);
+
+#ifdef CONFIG_32BIT
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch elf32_check_arch
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS	ELFCLASS32
+
+#define ELF_CORE_COPY_REGS(dest, regs) \
+	loongarch_dump_regs32((u32 *)&(dest), (regs));
+
+#endif /* CONFIG_32BIT */
+
+#ifdef CONFIG_64BIT
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch elf64_check_arch
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS	ELFCLASS64
+
+#define ELF_CORE_COPY_REGS(dest, regs) \
+	loongarch_dump_regs64((u64 *)&(dest), (regs));
+
+#endif /* CONFIG_64BIT */
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_DATA	ELFDATA2LSB
+#define ELF_ARCH	EM_LOONGARCH
+
+#endif /* !defined(ELF_ARCH) */
+
+#define loongarch_elf_check_machine(x) ((x)->e_machine == EM_LOONGARCH)
+
+#define vmcore_elf32_check_arch loongarch_elf_check_machine
+#define vmcore_elf64_check_arch loongarch_elf_check_machine
+
+/*
+ * Return non-zero if HDR identifies an 32bit ELF binary.
+ */
+#define elf32_check_arch(hdr)						\
+({									\
+	int __res = 1;							\
+	struct elfhdr *__h = (hdr);					\
+									\
+	if (!loongarch_elf_check_machine(__h))				\
+		__res = 0;						\
+	if (__h->e_ident[EI_CLASS] != ELFCLASS32)			\
+		__res = 0;						\
+									\
+	__res;								\
+})
+
+/*
+ * Return non-zero if HDR identifies an 64bit ELF binary.
+ */
+#define elf64_check_arch(hdr)						\
+({									\
+	int __res = 1;							\
+	struct elfhdr *__h = (hdr);					\
+									\
+	if (!loongarch_elf_check_machine(__h))				\
+		__res = 0;						\
+	if (__h->e_ident[EI_CLASS] != ELFCLASS64)			\
+		__res = 0;						\
+									\
+	__res;								\
+})
+
+#ifdef CONFIG_32BIT
+
+#define SET_PERSONALITY2(ex, state)					\
+do {									\
+	current->thread.vdso = &vdso_info;				\
+									\
+	loongarch_set_personality_fcsr(state);				\
+									\
+	if (personality(current->personality) != PER_LINUX)		\
+		set_personality(PER_LINUX);				\
+} while (0)
+
+#endif /* CONFIG_32BIT */
+
+#ifdef CONFIG_64BIT
+
+#define SET_PERSONALITY2(ex, state)					\
+do {									\
+	unsigned int p;							\
+									\
+	clear_thread_flag(TIF_32BIT_REGS);				\
+	clear_thread_flag(TIF_32BIT_ADDR);				\
+									\
+	current->thread.vdso = &vdso_info;				\
+	loongarch_set_personality_fcsr(state);				\
+									\
+	p = personality(current->personality);				\
+	if (p != PER_LINUX32 && p != PER_LINUX)				\
+		set_personality(PER_LINUX);				\
+} while (0)
+
+#endif /* CONFIG_64BIT */
+
+#define CORE_DUMP_USE_REGSET
+#define ELF_EXEC_PAGESIZE	PAGE_SIZE
+
+/*
+ * This yields a mask that user programs can use to figure out what
+ * instruction set this cpu supports. This could be done in userspace,
+ * but it's not easy, and we've already done it here.
+ */
+
+#define ELF_HWCAP	(elf_hwcap)
+extern unsigned int elf_hwcap;
+#include <asm/hwcap.h>
+
+/*
+ * This yields a string that ld.so will use to load implementation
+ * specific libraries for optimization.	 This is more specific in
+ * intent than poking at uname or /proc/cpuinfo.
+ */
+
+#define ELF_PLATFORM  __elf_platform
+extern const char *__elf_platform;
+
+#define ELF_PLAT_INIT(_r, load_addr)	do { \
+	_r->regs[1] = _r->regs[2] = _r->regs[3] = _r->regs[4] = 0;	\
+	_r->regs[5] = _r->regs[6] = _r->regs[7] = _r->regs[8] = 0;	\
+	_r->regs[9] = _r->regs[10] = _r->regs[11] = _r->regs[12] = 0;	\
+	_r->regs[13] = _r->regs[14] = _r->regs[15] = _r->regs[16] = 0;	\
+	_r->regs[17] = _r->regs[18] = _r->regs[19] = _r->regs[20] = 0;	\
+	_r->regs[21] = _r->regs[22] = _r->regs[23] = _r->regs[24] = 0;	\
+	_r->regs[25] = _r->regs[26] = _r->regs[27] = _r->regs[28] = 0;	\
+	_r->regs[29] = _r->regs[30] = _r->regs[31] = 0;			\
+} while (0)
+
+/*
+ * This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ * use of this is to invoke "./ld.so someprog" to test out a new version of
+ * the loader. We need to make sure that it is out of the way of the program
+ * that it will "exec", and that there is sufficient room for the brk.
+ */
+
+#define ELF_ET_DYN_BASE		(TASK_SIZE / 3 * 2)
+
+/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
+#define ARCH_DLINFO							\
+do {									\
+	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
+		    (unsigned long)current->mm->context.vdso);		\
+} while (0)
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+				       int uses_interp);
+
+struct arch_elf_state {
+	int fp_abi;
+	int interp_fp_abi;
+};
+
+#define LOONGARCH_ABI_FP_ANY	(0)
+
+#define INIT_ARCH_ELF_STATE {			\
+	.fp_abi = LOONGARCH_ABI_FP_ANY,		\
+	.interp_fp_abi = LOONGARCH_ABI_FP_ANY,	\
+}
+
+#define elf_read_implies_exec(ex, exec_stk) (exec_stk == EXSTACK_DEFAULT)
+
+extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf,
+			    bool is_interp, struct arch_elf_state *state);
+
+extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr,
+			  struct arch_elf_state *state);
+
+extern void loongarch_set_personality_fcsr(struct arch_elf_state *state);
+
+#endif /* _ASM_ELF_H */
diff --git a/arch/loongarch/include/asm/exec.h b/arch/loongarch/include/asm/exec.h
new file mode 100644
index 000000000000..ba0220812ebb
--- /dev/null
+++ b/arch/loongarch/include/asm/exec.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+#ifndef _ASM_EXEC_H
+#define _ASM_EXEC_H
+
+extern unsigned long arch_align_stack(unsigned long sp);
+
+#endif /* _ASM_EXEC_H */
diff --git a/arch/loongarch/include/asm/module.h b/arch/loongarch/include/asm/module.h
new file mode 100644
index 000000000000..9f6718df1854
--- /dev/null
+++ b/arch/loongarch/include/asm/module.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+#ifndef _ASM_MODULE_H
+#define _ASM_MODULE_H
+
+#include <asm/inst.h>
+#include <asm-generic/module.h>
+
+#define RELA_STACK_DEPTH 16
+
+struct mod_section {
+	Elf_Shdr *shdr;
+	int num_entries;
+	int max_entries;
+};
+
+struct mod_arch_specific {
+	struct mod_section plt;
+	struct mod_section plt_idx;
+};
+
+struct plt_entry {
+	u32 inst_lu12iw;
+	u32 inst_lu32id;
+	u32 inst_lu52id;
+	u32 inst_jirl;
+};
+
+struct plt_idx_entry {
+	unsigned long symbol_addr;
+};
+
+Elf_Addr module_emit_plt_entry(struct module *mod, unsigned long val);
+
+static inline struct plt_entry emit_plt_entry(unsigned long val)
+{
+	u32 lu12iw, lu32id, lu52id, jirl;
+
+	lu12iw = (lu12iw_op << 25 | (((val >> 12) & 0xfffff) << 5) | LOONGARCH_GPR_T1);
+	lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val, LU32ID));
+	lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1, LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID));
+	jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xfff));
+
+	return (struct plt_entry) { lu12iw, lu32id, lu52id, jirl };
+}
+
+static inline struct plt_idx_entry emit_plt_idx_entry(unsigned long val)
+{
+	return (struct plt_idx_entry) { val };
+}
+
+static inline int get_plt_idx(unsigned long val, const struct mod_section *sec)
+{
+	int i;
+	struct plt_idx_entry *plt_idx = (struct plt_idx_entry *)sec->shdr->sh_addr;
+
+	for (i = 0; i < sec->num_entries; i++) {
+		if (plt_idx[i].symbol_addr == val)
+			return i;
+	}
+
+	return -1;
+}
+
+static inline struct plt_entry *get_plt_entry(unsigned long val,
+				      const struct mod_section *sec_plt,
+				      const struct mod_section *sec_plt_idx)
+{
+	int plt_idx = get_plt_idx(val, sec_plt_idx);
+	struct plt_entry *plt = (struct plt_entry *)sec_plt->shdr->sh_addr;
+
+	if (plt_idx < 0)
+		return NULL;
+
+	return plt + plt_idx;
+}
+
+#endif /* _ASM_MODULE_H */
diff --git a/arch/loongarch/include/asm/module.lds.h b/arch/loongarch/include/asm/module.lds.h
new file mode 100644
index 000000000000..31c1c0db11a3
--- /dev/null
+++ b/arch/loongarch/include/asm/module.lds.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020-2022 Loongson Technology Corporation Limited */
+SECTIONS {
+	. = ALIGN(4);
+	.plt : { BYTE(0) }
+	.plt.idx : { BYTE(0) }
+}
diff --git a/arch/loongarch/include/asm/vermagic.h b/arch/loongarch/include/asm/vermagic.h
new file mode 100644
index 000000000000..8b47ccfe3aad
--- /dev/null
+++ b/arch/loongarch/include/asm/vermagic.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+#ifndef _ASM_VERMAGIC_H
+#define _ASM_VERMAGIC_H
+
+#define MODULE_PROC_FAMILY "LOONGARCH "
+
+#ifdef CONFIG_32BIT
+#define MODULE_KERNEL_TYPE "32BIT "
+#elif defined CONFIG_64BIT
+#define MODULE_KERNEL_TYPE "64BIT "
+#endif
+
+#define MODULE_ARCH_VERMAGIC \
+	MODULE_PROC_FAMILY MODULE_KERNEL_TYPE
+
+#endif /* _ASM_VERMAGIC_H */
diff --git a/arch/loongarch/include/uapi/asm/auxvec.h b/arch/loongarch/include/uapi/asm/auxvec.h
new file mode 100644
index 000000000000..922d9e6b5058
--- /dev/null
+++ b/arch/loongarch/include/uapi/asm/auxvec.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Author: Hanlu Li <lihanlu@loongson.cn>
+ *         Huacai Chen <chenhuacai@loongson.cn>
+ *
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_AUXVEC_H
+#define __ASM_AUXVEC_H
+
+/* Location of VDSO image. */
+#define AT_SYSINFO_EHDR		33
+
+#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+
+#endif /* __ASM_AUXVEC_H */
diff --git a/arch/loongarch/include/uapi/asm/hwcap.h b/arch/loongarch/include/uapi/asm/hwcap.h
new file mode 100644
index 000000000000..8840b72fa8e8
--- /dev/null
+++ b/arch/loongarch/include/uapi/asm/hwcap.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_HWCAP_H
+#define _UAPI_ASM_HWCAP_H
+
+/* HWCAP flags */
+#define HWCAP_LOONGARCH_CPUCFG		(1 << 0)
+#define HWCAP_LOONGARCH_LAM		(1 << 1)
+#define HWCAP_LOONGARCH_UAL		(1 << 2)
+#define HWCAP_LOONGARCH_FPU		(1 << 3)
+#define HWCAP_LOONGARCH_LSX		(1 << 4)
+#define HWCAP_LOONGARCH_LASX		(1 << 5)
+#define HWCAP_LOONGARCH_CRC32		(1 << 6)
+#define HWCAP_LOONGARCH_COMPLEX		(1 << 7)
+#define HWCAP_LOONGARCH_CRYPTO		(1 << 8)
+#define HWCAP_LOONGARCH_LVZ		(1 << 9)
+#define HWCAP_LOONGARCH_LBT_X86		(1 << 10)
+#define HWCAP_LOONGARCH_LBT_ARM		(1 << 11)
+#define HWCAP_LOONGARCH_LBT_MIPS	(1 << 12)
+
+#endif /* _UAPI_ASM_HWCAP_H */
diff --git a/arch/loongarch/kernel/elf.c b/arch/loongarch/kernel/elf.c
new file mode 100644
index 000000000000..183e94fc9c69
--- /dev/null
+++ b/arch/loongarch/kernel/elf.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Huacai Chen <chenhuacai@loongson.cn>
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+
+#include <linux/binfmts.h>
+#include <linux/elf.h>
+#include <linux/export.h>
+#include <linux/sched.h>
+
+#include <asm/cpu-features.h>
+#include <asm/cpu-info.h>
+
+int arch_elf_pt_proc(void *_ehdr, void *_phdr, struct file *elf,
+		     bool is_interp, struct arch_elf_state *state)
+{
+	return 0;
+}
+
+int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr,
+		   struct arch_elf_state *state)
+{
+	return 0;
+}
+
+void loongarch_set_personality_fcsr(struct arch_elf_state *state)
+{
+	current->thread.fpu.fcsr = boot_cpu_data.fpu_csr0;
+}
diff --git a/arch/loongarch/kernel/inst.c b/arch/loongarch/kernel/inst.c
new file mode 100644
index 000000000000..b1df0ec34bd1
--- /dev/null
+++ b/arch/loongarch/kernel/inst.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+#include <asm/inst.h>
+
+u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm)
+{
+	union loongarch_instruction insn;
+
+	insn.reg1i20_format.opcode = lu32id_op;
+	insn.reg1i20_format.rd = rd;
+	insn.reg1i20_format.immediate = imm;
+
+	return insn.word;
+}
+
+u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm)
+{
+	union loongarch_instruction insn;
+
+	insn.reg2i12_format.opcode = lu52id_op;
+	insn.reg2i12_format.rd = rd;
+	insn.reg2i12_format.rj = rj;
+	insn.reg2i12_format.immediate = imm;
+
+	return insn.word;
+}
+
+u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest)
+{
+	union loongarch_instruction insn;
+
+	insn.reg2i16_format.opcode = jirl_op;
+	insn.reg2i16_format.rd = rd;
+	insn.reg2i16_format.rj = rj;
+	insn.reg2i16_format.immediate = (dest - pc) >> 2;
+
+	return insn.word;
+}
diff --git a/arch/loongarch/kernel/module-sections.c b/arch/loongarch/kernel/module-sections.c
new file mode 100644
index 000000000000..6d498288977d
--- /dev/null
+++ b/arch/loongarch/kernel/module-sections.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+
+#include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+Elf_Addr module_emit_plt_entry(struct module *mod, unsigned long val)
+{
+	int nr;
+	struct mod_section *plt_sec = &mod->arch.plt;
+	struct mod_section *plt_idx_sec = &mod->arch.plt_idx;
+	struct plt_entry *plt = get_plt_entry(val, plt_sec, plt_idx_sec);
+	struct plt_idx_entry *plt_idx;
+
+	if (plt)
+		return (Elf_Addr)plt;
+
+	nr = plt_sec->num_entries;
+
+	/* There is no duplicate entry, create a new one */
+	plt = (struct plt_entry *)plt_sec->shdr->sh_addr;
+	plt[nr] = emit_plt_entry(val);
+	plt_idx = (struct plt_idx_entry *)plt_idx_sec->shdr->sh_addr;
+	plt_idx[nr] = emit_plt_idx_entry(val);
+
+	plt_sec->num_entries++;
+	plt_idx_sec->num_entries++;
+	BUG_ON(plt_sec->num_entries > plt_sec->max_entries);
+
+	return (Elf_Addr)&plt[nr];
+}
+
+static int is_rela_equal(const Elf_Rela *x, const Elf_Rela *y)
+{
+	return x->r_info == y->r_info && x->r_addend == y->r_addend;
+}
+
+static bool duplicate_rela(const Elf_Rela *rela, int idx)
+{
+	int i;
+
+	for (i = 0; i < idx; i++) {
+		if (is_rela_equal(&rela[i], &rela[idx]))
+			return true;
+	}
+
+	return false;
+}
+
+static void count_max_entries(Elf_Rela *relas, int num, unsigned int *plts)
+{
+	unsigned int i, type;
+
+	for (i = 0; i < num; i++) {
+		type = ELF_R_TYPE(relas[i].r_info);
+		if (type == R_LARCH_SOP_PUSH_PLT_PCREL) {
+			if (!duplicate_rela(relas, i))
+				(*plts)++;
+		}
+	}
+}
+
+int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
+			      char *secstrings, struct module *mod)
+{
+	unsigned int i, num_plts = 0;
+
+	/*
+	 * Find the empty .plt sections.
+	 */
+	for (i = 0; i < ehdr->e_shnum; i++) {
+		if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt"))
+			mod->arch.plt.shdr = sechdrs + i;
+		else if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt.idx"))
+			mod->arch.plt_idx.shdr = sechdrs + i;
+	}
+
+	if (!mod->arch.plt.shdr) {
+		pr_err("%s: module PLT section(s) missing\n", mod->name);
+		return -ENOEXEC;
+	}
+	if (!mod->arch.plt_idx.shdr) {
+		pr_err("%s: module PLT.IDX section(s) missing\n", mod->name);
+		return -ENOEXEC;
+	}
+
+	/* Calculate the maxinum number of entries */
+	for (i = 0; i < ehdr->e_shnum; i++) {
+		int num_rela = sechdrs[i].sh_size / sizeof(Elf_Rela);
+		Elf_Rela *relas = (void *)ehdr + sechdrs[i].sh_offset;
+		Elf_Shdr *dst_sec = sechdrs + sechdrs[i].sh_info;
+
+		if (sechdrs[i].sh_type != SHT_RELA)
+			continue;
+
+		/* ignore relocations that operate on non-exec sections */
+		if (!(dst_sec->sh_flags & SHF_EXECINSTR))
+			continue;
+
+		count_max_entries(relas, num_rela, &num_plts);
+	}
+
+	mod->arch.plt.shdr->sh_type = SHT_NOBITS;
+	mod->arch.plt.shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
+	mod->arch.plt.shdr->sh_addralign = L1_CACHE_BYTES;
+	mod->arch.plt.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_entry);
+	mod->arch.plt.num_entries = 0;
+	mod->arch.plt.max_entries = num_plts;
+
+	mod->arch.plt_idx.shdr->sh_type = SHT_NOBITS;
+	mod->arch.plt_idx.shdr->sh_flags = SHF_ALLOC;
+	mod->arch.plt_idx.shdr->sh_addralign = L1_CACHE_BYTES;
+	mod->arch.plt_idx.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_idx_entry);
+	mod->arch.plt_idx.num_entries = 0;
+	mod->arch.plt_idx.max_entries = num_plts;
+
+	return 0;
+}
diff --git a/arch/loongarch/kernel/module.c b/arch/loongarch/kernel/module.c
new file mode 100644
index 000000000000..87b3768f1eef
--- /dev/null
+++ b/arch/loongarch/kernel/module.c
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Author: Hanlu Li <lihanlu@loongson.cn>
+ *         Huacai Chen <chenhuacai@loongson.cn>
+ *
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+
+#define pr_fmt(fmt) "kmod: " fmt
+
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+static inline bool signed_imm_check(long val, unsigned int bit)
+{
+	return -(1L << (bit - 1)) <= val && val < (1L << (bit - 1));
+}
+
+static inline bool unsigned_imm_check(unsigned long val, unsigned int bit)
+{
+	return val < (1UL << bit);
+}
+
+static int rela_stack_push(s64 stack_value, s64 *rela_stack, size_t *rela_stack_top)
+{
+	if (*rela_stack_top >= RELA_STACK_DEPTH)
+		return -ENOEXEC;
+
+	rela_stack[(*rela_stack_top)++] = stack_value;
+	pr_debug("%s stack_value = 0x%llx\n", __func__, stack_value);
+
+	return 0;
+}
+
+static int rela_stack_pop(s64 *stack_value, s64 *rela_stack, size_t *rela_stack_top)
+{
+	if (*rela_stack_top == 0)
+		return -ENOEXEC;
+
+	*stack_value = rela_stack[--(*rela_stack_top)];
+	pr_debug("%s stack_value = 0x%llx\n", __func__, *stack_value);
+
+	return 0;
+}
+
+static int apply_r_larch_none(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	return 0;
+}
+
+static int apply_r_larch_error(struct module *me, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	pr_err("%s: Unsupport relocation type %u, please add its support.\n", me->name, type);
+	return -EINVAL;
+}
+
+static int apply_r_larch_32(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	*location = v;
+	return 0;
+}
+
+static int apply_r_larch_64(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	*(Elf_Addr *)location = v;
+	return 0;
+}
+
+static int apply_r_larch_sop_push_pcrel(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	return rela_stack_push(v - (u64)location, rela_stack, rela_stack_top);
+}
+
+static int apply_r_larch_sop_push_absolute(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	return rela_stack_push(v, rela_stack, rela_stack_top);
+}
+
+static int apply_r_larch_sop_push_dup(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	int err = 0;
+	s64 opr1;
+
+	err = rela_stack_pop(&opr1, rela_stack, rela_stack_top);
+	if (err)
+		return err;
+	err = rela_stack_push(opr1, rela_stack, rela_stack_top);
+	if (err)
+		return err;
+	err = rela_stack_push(opr1, rela_stack, rela_stack_top);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int apply_r_larch_sop_push_plt_pcrel(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	ptrdiff_t offset = (void *)v - (void *)location;
+
+	if (offset >= SZ_128M)
+		v = module_emit_plt_entry(mod, v);
+
+	if (offset < -SZ_128M)
+		v = module_emit_plt_entry(mod, v);
+
+	return apply_r_larch_sop_push_pcrel(mod, location, v, rela_stack, rela_stack_top, type);
+}
+
+static int apply_r_larch_sop(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	int err = 0;
+	s64 opr1, opr2, opr3;
+
+	if (type == R_LARCH_SOP_IF_ELSE) {
+		err = rela_stack_pop(&opr3, rela_stack, rela_stack_top);
+		if (err)
+			return err;
+	}
+
+	err = rela_stack_pop(&opr2, rela_stack, rela_stack_top);
+	if (err)
+		return err;
+	err = rela_stack_pop(&opr1, rela_stack, rela_stack_top);
+	if (err)
+		return err;
+
+	switch (type) {
+	case R_LARCH_SOP_AND:
+		err = rela_stack_push(opr1 & opr2, rela_stack, rela_stack_top);
+		break;
+	case R_LARCH_SOP_ADD:
+		err = rela_stack_push(opr1 + opr2, rela_stack, rela_stack_top);
+		break;
+	case R_LARCH_SOP_SUB:
+		err = rela_stack_push(opr1 - opr2, rela_stack, rela_stack_top);
+		break;
+	case R_LARCH_SOP_SL:
+		err = rela_stack_push(opr1 << opr2, rela_stack, rela_stack_top);
+		break;
+	case R_LARCH_SOP_SR:
+		err = rela_stack_push(opr1 >> opr2, rela_stack, rela_stack_top);
+		break;
+	case R_LARCH_SOP_IF_ELSE:
+		err = rela_stack_push(opr1 ? opr2 : opr3, rela_stack, rela_stack_top);
+		break;
+	default:
+		pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
+		return -EINVAL;
+	}
+
+	return err;
+}
+
+static int apply_r_larch_sop_imm_field(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	int err = 0;
+	s64 opr1;
+	union loongarch_instruction *insn = (union loongarch_instruction *)location;
+
+	err = rela_stack_pop(&opr1, rela_stack, rela_stack_top);
+	if (err)
+		return err;
+
+	switch (type) {
+	case R_LARCH_SOP_POP_32_U_10_12:
+		if (!unsigned_imm_check(opr1, 12))
+			goto overflow;
+
+		/* (*(uint32_t *) PC) [21 ... 10] = opr [11 ... 0] */
+		insn->reg2i12_format.immediate = opr1 & 0xfff;
+		return 0;
+	case R_LARCH_SOP_POP_32_S_10_12:
+		if (!signed_imm_check(opr1, 12))
+			goto overflow;
+
+		insn->reg2i12_format.immediate = opr1 & 0xfff;
+		return 0;
+	case R_LARCH_SOP_POP_32_S_10_16:
+		if (!signed_imm_check(opr1, 16))
+			goto overflow;
+
+		insn->reg2i16_format.immediate = opr1 & 0xffff;
+		return 0;
+	case R_LARCH_SOP_POP_32_S_10_16_S2:
+		if (opr1 % 4)
+			goto unaligned;
+
+		if (!signed_imm_check(opr1, 18))
+			goto overflow;
+
+		insn->reg2i16_format.immediate = (opr1 >> 2) & 0xffff;
+		return 0;
+	case R_LARCH_SOP_POP_32_S_5_20:
+		if (!signed_imm_check(opr1, 20))
+			goto overflow;
+
+		insn->reg1i20_format.immediate = (opr1) & 0xfffff;
+		return 0;
+	case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:
+		if (opr1 % 4)
+			goto unaligned;
+
+		if (!signed_imm_check(opr1, 23))
+			goto overflow;
+
+		opr1 >>= 2;
+		insn->reg1i21_format.immediate_l = opr1 & 0xffff;
+		insn->reg1i21_format.immediate_h = (opr1 >> 16) & 0x1f;
+		return 0;
+	case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:
+		if (opr1 % 4)
+			goto unaligned;
+
+		if (!signed_imm_check(opr1, 28))
+			goto overflow;
+
+		opr1 >>= 2;
+		insn->reg0i26_format.immediate_l = opr1 & 0xffff;
+		insn->reg0i26_format.immediate_h = (opr1 >> 16) & 0x3ff;
+		return 0;
+	case R_LARCH_SOP_POP_32_U:
+		if (!unsigned_imm_check(opr1, 32))
+			goto overflow;
+
+		/* (*(uint32_t *) PC) = opr */
+		*location = (u32)opr1;
+		return 0;
+	default:
+		pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
+		return -EINVAL;
+	}
+
+overflow:
+	pr_err("module %s: opr1 = 0x%llx overflow! dangerous %s (%u) relocation\n",
+		mod->name, opr1, __func__, type);
+	return -ENOEXEC;
+
+unaligned:
+	pr_err("module %s: opr1 = 0x%llx unaligned! dangerous %s (%u) relocation\n",
+		mod->name, opr1, __func__, type);
+	return -ENOEXEC;
+}
+
+static int apply_r_larch_add_sub(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+	switch (type) {
+	case R_LARCH_ADD32:
+		*(s32 *)location += v;
+		return 0;
+	case R_LARCH_ADD64:
+		*(s64 *)location += v;
+		return 0;
+	case R_LARCH_SUB32:
+		*(s32 *)location -= v;
+		return 0;
+	case R_LARCH_SUB64:
+		*(s64 *)location -= v;
+		return 0;
+	default:
+		pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
+		return -EINVAL;
+	}
+}
+
+/*
+ * reloc_handlers_rela() - Apply a particular relocation to a module
+ * @mod: the module to apply the reloc to
+ * @location: the address at which the reloc is to be applied
+ * @v: the value of the reloc, with addend for RELA-style
+ * @rela_stack: the stack used for store relocation info, LOCAL to THIS module
+ * @rela_stac_top: where the stack operation(pop/push) applies to
+ *
+ * Return: 0 upon success, else -ERRNO
+ */
+typedef int (*reloc_rela_handler)(struct module *mod, u32 *location, Elf_Addr v,
+			s64 *rela_stack, size_t *rela_stack_top, unsigned int type);
+
+/* The handlers for known reloc types */
+static reloc_rela_handler reloc_rela_handlers[] = {
+	[R_LARCH_NONE ... R_LARCH_SUB64]		     = apply_r_larch_error,
+
+	[R_LARCH_NONE]					     = apply_r_larch_none,
+	[R_LARCH_32]					     = apply_r_larch_32,
+	[R_LARCH_64]					     = apply_r_larch_64,
+	[R_LARCH_MARK_LA]				     = apply_r_larch_none,
+	[R_LARCH_MARK_PCREL]				     = apply_r_larch_none,
+	[R_LARCH_SOP_PUSH_PCREL]			     = apply_r_larch_sop_push_pcrel,
+	[R_LARCH_SOP_PUSH_ABSOLUTE]			     = apply_r_larch_sop_push_absolute,
+	[R_LARCH_SOP_PUSH_DUP]				     = apply_r_larch_sop_push_dup,
+	[R_LARCH_SOP_PUSH_PLT_PCREL]			     = apply_r_larch_sop_push_plt_pcrel,
+	[R_LARCH_SOP_SUB ... R_LARCH_SOP_IF_ELSE] 	     = apply_r_larch_sop,
+	[R_LARCH_SOP_POP_32_S_10_5 ... R_LARCH_SOP_POP_32_U] = apply_r_larch_sop_imm_field,
+	[R_LARCH_ADD32 ... R_LARCH_SUB64]		     = apply_r_larch_add_sub,
+};
+
+int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
+		       unsigned int symindex, unsigned int relsec,
+		       struct module *mod)
+{
+	int i, err;
+	unsigned int type;
+	s64 rela_stack[RELA_STACK_DEPTH];
+	size_t rela_stack_top = 0;
+	reloc_rela_handler handler;
+	void *location;
+	Elf_Addr v;
+	Elf_Sym *sym;
+	Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr;
+
+	pr_debug("%s: Applying relocate section %u to %u\n", __func__, relsec,
+	       sechdrs[relsec].sh_info);
+
+	rela_stack_top = 0;
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+		/* This is where to make the change */
+		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset;
+		/* This is the symbol it is referring to */
+		sym = (Elf_Sym *)sechdrs[symindex].sh_addr + ELF_R_SYM(rel[i].r_info);
+		if (IS_ERR_VALUE(sym->st_value)) {
+			/* Ignore unresolved weak symbol */
+			if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
+				continue;
+			pr_warn("%s: Unknown symbol %s\n", mod->name, strtab + sym->st_name);
+			return -ENOENT;
+		}
+
+		type = ELF_R_TYPE(rel[i].r_info);
+
+		if (type < ARRAY_SIZE(reloc_rela_handlers))
+			handler = reloc_rela_handlers[type];
+		else
+			handler = NULL;
+
+		if (!handler) {
+			pr_err("%s: Unknown relocation type %u\n", mod->name, type);
+			return -EINVAL;
+		}
+
+		pr_debug("type %d st_value %llx r_addend %llx loc %llx\n",
+		       (int)ELF_R_TYPE(rel[i].r_info),
+		       sym->st_value, rel[i].r_addend, (u64)location);
+
+		v = sym->st_value + rel[i].r_addend;
+		err = handler(mod, location, v, rela_stack, &rela_stack_top, type);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+void *module_alloc(unsigned long size)
+{
+	return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
+			GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, __builtin_return_address(0));
+}
-- 
2.27.0


  parent reply	other threads:[~2022-05-18  9:43 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-18  9:25 [PATCH V11 00/22] arch: Add basic LoongArch support Huacai Chen
2022-05-18  9:25 ` [PATCH V11 01/22] Documentation: LoongArch: Add basic documentations Huacai Chen
2022-05-18 15:34   ` WANG Xuerui
2022-05-18  9:25 ` [PATCH V11 02/22] Documentation/zh_CN: Add basic LoongArch documentations Huacai Chen
2022-05-18 15:32   ` WANG Xuerui
2022-05-20  7:37   ` Guo Ren
2022-05-20  7:43     ` WANG Xuerui
2022-05-18  9:26 ` [PATCH V11 03/22] LoongArch: Add ELF-related definitions Huacai Chen
2022-05-18  9:26 ` [PATCH V11 04/22] LoongArch: Add writecombine support for drm Huacai Chen
2022-05-18  9:26   ` Huacai Chen
2022-05-18  9:26 ` [PATCH V11 05/22] LoongArch: Add build infrastructure Huacai Chen
2022-05-18 15:22   ` WANG Xuerui
2022-05-20  7:25   ` Guo Ren
2022-05-18  9:26 ` [PATCH V11 06/22] LoongArch: Add CPU definition headers Huacai Chen
2022-05-18 15:45   ` WANG Xuerui
2022-05-18 16:12     ` Huacai Chen
2022-05-18  9:26 ` [PATCH V11 07/22] LoongArch: Add atomic/locking headers Huacai Chen
2022-05-18 15:54   ` WANG Xuerui
2022-05-20  7:54   ` Guo Ren
2022-05-20  9:50     ` Huacai Chen
2022-05-20 18:14       ` Guo Ren
2022-05-21  1:55         ` Huacai Chen
2022-05-18  9:26 ` [PATCH V11 08/22] LoongArch: Add other common headers Huacai Chen
2022-05-18 16:04   ` WANG Xuerui
2022-05-18  9:26 ` [PATCH V11 09/22] LoongArch: Add boot and setup routines Huacai Chen
2022-05-18 15:17   ` WANG Xuerui
2022-05-18 16:08     ` Huacai Chen
2022-05-20  9:17   ` Ard Biesheuvel
2022-05-20  9:41     ` Javier Martinez Canillas
2022-05-20 14:09       ` Huacai Chen
2022-05-20 14:23         ` Javier Martinez Canillas
2022-05-20 15:19           ` Huacai Chen
2022-05-20 16:32             ` Javier Martinez Canillas
2022-05-21  1:40               ` Huacai Chen
2022-05-21  7:06                 ` Javier Martinez Canillas
2022-05-21  7:37                   ` Huacai Chen
2022-05-21  9:06                     ` Javier Martinez Canillas
2022-05-21  9:13                       ` Huacai Chen
2022-05-21  9:43                         ` Javier Martinez Canillas
2022-05-20 15:53     ` Huacai Chen
2022-05-24  8:27   ` Xi Ruoyao
2022-05-24 10:59     ` Huacai Chen
2022-05-24 12:48       ` 李超
2022-05-18  9:26 ` [PATCH V11 10/22] LoongArch: Add exception/interrupt handling Huacai Chen
2022-05-18  9:26 ` [PATCH V11 11/22] LoongArch: Add process management Huacai Chen
2022-05-18  9:26 ` [PATCH V11 12/22] LoongArch: Add memory management Huacai Chen
2022-05-18  9:26 ` [PATCH V11 13/22] LoongArch: Add system call support Huacai Chen
2022-05-18  9:26 ` [PATCH V11 14/22] LoongArch: Add signal handling support Huacai Chen
2022-05-18 16:13   ` WANG Xuerui
2022-05-18 16:39   ` Eric W. Biederman
2022-05-18 16:54     ` Huacai Chen
2022-05-18 17:17       ` WANG Xuerui
2022-05-18  9:26 ` Huacai Chen [this message]
2022-05-18  9:26 ` [PATCH V11 16/22] LoongArch: Add misc common routines Huacai Chen
2022-05-18  9:57 ` [PATCH V11 17/22] LoongArch: Add some library functions Huacai Chen
2022-05-18  9:57   ` [PATCH V11 18/22] LoongArch: Add PCI controller support Huacai Chen
2022-05-18  9:57   ` [PATCH V11 19/22] LoongArch: Add VDSO and VSYSCALL support Huacai Chen
2022-05-18  9:57   ` [PATCH V11 20/22] LoongArch: Add multi-processor (SMP) support Huacai Chen
2022-05-18  9:57   ` [PATCH V11 21/22] LoongArch: Add Non-Uniform Memory Access (NUMA) support Huacai Chen
2022-05-18  9:57   ` [PATCH V11 22/22] LoongArch: Add Loongson-3 default config file Huacai Chen
2022-05-18 13:42 ` [PATCH V11 00/22] arch: Add basic LoongArch support Arnd Bergmann
2022-05-18 17:18   ` Huacai Chen
2022-05-18 22:36   ` Stephen Rothwell
2022-05-22  4:18 ` WANG Xuerui

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220518092619.1269111-16-chenhuacai@loongson.cn \
    --to=chenhuacai@loongson.cn \
    --cc=airlied@linux.ie \
    --cc=akpm@linux-foundation.org \
    --cc=arnd@arndb.de \
    --cc=chenhuacai@gmail.com \
    --cc=corbet@lwn.net \
    --cc=git@xen0n.name \
    --cc=guoren@kernel.org \
    --cc=jeyu@kernel.org \
    --cc=jiaxun.yang@flygoat.com \
    --cc=kernel@xen0n.name \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lixuefeng@loongson.cn \
    --cc=luto@kernel.org \
    --cc=mcgrof@kernel.org \
    --cc=peterz@infradead.org \
    --cc=sfr@canb.auug.org.au \
    --cc=siyanteng@loongson.cn \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.