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