1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Copyright (C) 2020 Loongson Technology Corporation Limited
4  */
5 #ifndef _ASM_MODULE_H
6 #define _ASM_MODULE_H
7 
8 #include <asm/inst.h>
9 #include <asm-generic/module.h>
10 #include <asm/orc_types.h>
11 
12 #define RELA_STACK_DEPTH 16
13 
14 struct mod_section {
15 	int shndx;
16 	int num_entries;
17 	int max_entries;
18 };
19 
20 struct mod_arch_specific {
21 	struct mod_section got;
22 	struct mod_section plt;
23 	struct mod_section plt_idx;
24 #ifdef CONFIG_UNWINDER_ORC
25 	unsigned int num_orcs;
26 	int *orc_unwind_ip;
27 	struct orc_entry *orc_unwind;
28 #endif
29 
30 	/* for CONFIG_DYNAMIC_FTRACE */
31 	struct plt_entry *ftrace_trampolines;
32 };
33 
34 struct got_entry {
35 	Elf_Addr symbol_addr;
36 };
37 
38 struct plt_entry {
39 	u32 inst_addu16id;
40 	u32 inst_lu32id;
41 	u32 inst_lu52id;
42 	u32 inst_jirl;
43 };
44 
45 struct plt_idx_entry {
46 	Elf_Addr symbol_addr;
47 };
48 
49 Elf_Addr module_emit_got_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val);
50 Elf_Addr module_emit_plt_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val);
51 
emit_got_entry(Elf_Addr val)52 static inline struct got_entry emit_got_entry(Elf_Addr val)
53 {
54 	return (struct got_entry) { val };
55 }
56 
emit_plt_entry(unsigned long val)57 static inline struct plt_entry emit_plt_entry(unsigned long val)
58 {
59 	u32 addu16id, lu32id, lu52id, jirl;
60 
61 	addu16id = larch_insn_gen_addu16id(REG_T1, REG_ZERO, ADDR_IMM(val, ADDU16ID));
62 	lu32id = larch_insn_gen_lu32id(REG_T1, ADDR_IMM(val, LU32ID));
63 	lu52id = larch_insn_gen_lu52id(REG_T1, REG_T1, ADDR_IMM(val, LU52ID));
64 	jirl = larch_insn_gen_jirl(0, REG_T1, 0, (val & 0xffff));
65 
66 	return (struct plt_entry) { addu16id, lu32id, lu52id, jirl };
67 }
68 
emit_plt_idx_entry(unsigned long val)69 static inline struct plt_idx_entry emit_plt_idx_entry(unsigned long val)
70 {
71 	return (struct plt_idx_entry) { val };
72 }
73 
get_plt_idx(unsigned long val, Elf_Shdr *sechdrs, const struct mod_section *sec)74 static inline int get_plt_idx(unsigned long val, Elf_Shdr *sechdrs, const struct mod_section *sec)
75 {
76 	int i;
77 	struct plt_idx_entry *plt_idx = (struct plt_idx_entry *)sechdrs[sec->shndx].sh_addr;
78 
79 	for (i = 0; i < sec->num_entries; i++) {
80 		if (plt_idx[i].symbol_addr == val)
81 			return i;
82 	}
83 
84 	return -1;
85 }
86 
get_plt_entry(unsigned long val, Elf_Shdr *sechdrs, const struct mod_section *sec_plt, const struct mod_section *sec_plt_idx)87 static inline struct plt_entry *get_plt_entry(unsigned long val,
88 					      Elf_Shdr *sechdrs,
89 					      const struct mod_section *sec_plt,
90 					      const struct mod_section *sec_plt_idx)
91 {
92 	int plt_idx = get_plt_idx(val, sechdrs, sec_plt_idx);
93 	struct plt_entry *plt = (struct plt_entry *)sechdrs[sec_plt->shndx].sh_addr;
94 
95 	if (plt_idx < 0)
96 		return NULL;
97 
98 	return plt + plt_idx;
99 }
100 
get_got_entry(Elf_Addr val, Elf_Shdr *sechdrs, const struct mod_section *sec)101 static inline struct got_entry *get_got_entry(Elf_Addr val,
102 					      Elf_Shdr *sechdrs,
103 					      const struct mod_section *sec)
104 {
105 	int i;
106 	struct got_entry *got = (struct got_entry *)sechdrs[sec->shndx].sh_addr;
107 
108 	for (i = 0; i < sec->num_entries; i++)
109 		if (got[i].symbol_addr == val)
110 			return &got[i];
111 	return NULL;
112 }
113 
114 #endif /* _ASM_MODULE_H */
115