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