18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2020 Loongson Technology Corporation Limited
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#ifndef _ASM_MODULE_H
68c2ecf20Sopenharmony_ci#define _ASM_MODULE_H
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <asm/inst.h>
98c2ecf20Sopenharmony_ci#include <asm-generic/module.h>
108c2ecf20Sopenharmony_ci#include <asm/orc_types.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define RELA_STACK_DEPTH 16
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cistruct mod_section {
158c2ecf20Sopenharmony_ci	int shndx;
168c2ecf20Sopenharmony_ci	int num_entries;
178c2ecf20Sopenharmony_ci	int max_entries;
188c2ecf20Sopenharmony_ci};
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistruct mod_arch_specific {
218c2ecf20Sopenharmony_ci	struct mod_section got;
228c2ecf20Sopenharmony_ci	struct mod_section plt;
238c2ecf20Sopenharmony_ci	struct mod_section plt_idx;
248c2ecf20Sopenharmony_ci#ifdef CONFIG_UNWINDER_ORC
258c2ecf20Sopenharmony_ci	unsigned int num_orcs;
268c2ecf20Sopenharmony_ci	int *orc_unwind_ip;
278c2ecf20Sopenharmony_ci	struct orc_entry *orc_unwind;
288c2ecf20Sopenharmony_ci#endif
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	/* for CONFIG_DYNAMIC_FTRACE */
318c2ecf20Sopenharmony_ci	struct plt_entry *ftrace_trampolines;
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct got_entry {
358c2ecf20Sopenharmony_ci	Elf_Addr symbol_addr;
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistruct plt_entry {
398c2ecf20Sopenharmony_ci	u32 inst_addu16id;
408c2ecf20Sopenharmony_ci	u32 inst_lu32id;
418c2ecf20Sopenharmony_ci	u32 inst_lu52id;
428c2ecf20Sopenharmony_ci	u32 inst_jirl;
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct plt_idx_entry {
468c2ecf20Sopenharmony_ci	Elf_Addr symbol_addr;
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciElf_Addr module_emit_got_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val);
508c2ecf20Sopenharmony_ciElf_Addr module_emit_plt_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic inline struct got_entry emit_got_entry(Elf_Addr val)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	return (struct got_entry) { val };
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic inline struct plt_entry emit_plt_entry(unsigned long val)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	u32 addu16id, lu32id, lu52id, jirl;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	addu16id = larch_insn_gen_addu16id(REG_T1, REG_ZERO, ADDR_IMM(val, ADDU16ID));
628c2ecf20Sopenharmony_ci	lu32id = larch_insn_gen_lu32id(REG_T1, ADDR_IMM(val, LU32ID));
638c2ecf20Sopenharmony_ci	lu52id = larch_insn_gen_lu52id(REG_T1, REG_T1, ADDR_IMM(val, LU52ID));
648c2ecf20Sopenharmony_ci	jirl = larch_insn_gen_jirl(0, REG_T1, 0, (val & 0xffff));
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	return (struct plt_entry) { addu16id, lu32id, lu52id, jirl };
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic inline struct plt_idx_entry emit_plt_idx_entry(unsigned long val)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	return (struct plt_idx_entry) { val };
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic inline int get_plt_idx(unsigned long val, Elf_Shdr *sechdrs, const struct mod_section *sec)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	int i;
778c2ecf20Sopenharmony_ci	struct plt_idx_entry *plt_idx = (struct plt_idx_entry *)sechdrs[sec->shndx].sh_addr;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	for (i = 0; i < sec->num_entries; i++) {
808c2ecf20Sopenharmony_ci		if (plt_idx[i].symbol_addr == val)
818c2ecf20Sopenharmony_ci			return i;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	return -1;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic inline struct plt_entry *get_plt_entry(unsigned long val,
888c2ecf20Sopenharmony_ci					      Elf_Shdr *sechdrs,
898c2ecf20Sopenharmony_ci					      const struct mod_section *sec_plt,
908c2ecf20Sopenharmony_ci					      const struct mod_section *sec_plt_idx)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	int plt_idx = get_plt_idx(val, sechdrs, sec_plt_idx);
938c2ecf20Sopenharmony_ci	struct plt_entry *plt = (struct plt_entry *)sechdrs[sec_plt->shndx].sh_addr;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (plt_idx < 0)
968c2ecf20Sopenharmony_ci		return NULL;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return plt + plt_idx;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic inline struct got_entry *get_got_entry(Elf_Addr val,
1028c2ecf20Sopenharmony_ci					      Elf_Shdr *sechdrs,
1038c2ecf20Sopenharmony_ci					      const struct mod_section *sec)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	int i;
1068c2ecf20Sopenharmony_ci	struct got_entry *got = (struct got_entry *)sechdrs[sec->shndx].sh_addr;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	for (i = 0; i < sec->num_entries; i++)
1098c2ecf20Sopenharmony_ci		if (got[i].symbol_addr == val)
1108c2ecf20Sopenharmony_ci			return &got[i];
1118c2ecf20Sopenharmony_ci	return NULL;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#endif /* _ASM_MODULE_H */
115