1246145Shselasky/* SPDX-License-Identifier: GPL-2.0 */
2246145Shselasky/*
3246145Shselasky * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4246145Shselasky */
5246145Shselasky#ifndef _ASM_MODULE_H
6246145Shselasky#define _ASM_MODULE_H
7246145Shselasky
8246145Shselasky#include <asm/inst.h>
9246145Shselasky#include <asm/orc_types.h>
10246145Shselasky#include <asm-generic/module.h>
11246145Shselasky
12246145Shselasky#define RELA_STACK_DEPTH 16
13246145Shselasky
14246145Shselaskystruct mod_section {
15246145Shselasky	int shndx;
16246145Shselasky	int num_entries;
17246145Shselasky	int max_entries;
18246145Shselasky};
19246145Shselasky
20246145Shselaskystruct mod_arch_specific {
21246145Shselasky	struct mod_section got;
22246145Shselasky	struct mod_section plt;
23246145Shselasky	struct mod_section plt_idx;
24246145Shselasky
25246145Shselasky#ifdef CONFIG_UNWINDER_ORC
26246145Shselasky	unsigned int num_orcs;
27246145Shselasky	int *orc_unwind_ip;
28246145Shselasky	struct orc_entry *orc_unwind;
29246363Shselasky#endif
30246363Shselasky
31246145Shselasky	/* For CONFIG_DYNAMIC_FTRACE */
32246145Shselasky	struct plt_entry *ftrace_trampolines;
33246145Shselasky};
34246145Shselasky
35246145Shselaskystruct got_entry {
36246145Shselasky	Elf_Addr symbol_addr;
37246145Shselasky};
38291405Szbb
39291405Szbbstruct plt_entry {
40291405Szbb	u32 inst_lu12iw;
41291405Szbb	u32 inst_lu32id;
42246145Shselasky	u32 inst_lu52id;
43246145Shselasky	u32 inst_jirl;
44246145Shselasky};
45246145Shselasky
46246145Shselaskystruct plt_idx_entry {
47246145Shselasky	Elf_Addr symbol_addr;
48246145Shselasky};
49246145Shselasky
50294547SwmaElf_Addr module_emit_got_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val);
51294547SwmaElf_Addr module_emit_plt_entry(struct module *mod, Elf_Shdr *sechdrs, Elf_Addr val);
52294547Swma
53294547Swmastatic inline struct got_entry emit_got_entry(Elf_Addr val)
54294547Swma{
55294547Swma	return (struct got_entry) { val };
56294547Swma}
57294547Swma
58294547Swmastatic inline struct plt_entry emit_plt_entry(unsigned long val)
59294547Swma{
60294547Swma	u32 lu12iw, lu32id, lu52id, jirl;
61294547Swma
62294547Swma	lu12iw = larch_insn_gen_lu12iw(LOONGARCH_GPR_T1, ADDR_IMM(val, LU12IW));
63294547Swma	lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val, LU32ID));
64294547Swma	lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1, LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID));
65294547Swma	jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, ADDR_IMM(val, ORI));
66294547Swma
67294547Swma	return (struct plt_entry) { lu12iw, lu32id, lu52id, jirl };
68294547Swma}
69294547Swma
70294547Swmastatic inline struct plt_idx_entry emit_plt_idx_entry(unsigned long val)
71294547Swma{
72294547Swma	return (struct plt_idx_entry) { val };
73294547Swma}
74294547Swma
75294547Swmastatic inline int get_plt_idx(unsigned long val, Elf_Shdr *sechdrs, const struct mod_section *sec)
76294547Swma{
77294547Swma	int i;
78315221Spfg	struct plt_idx_entry *plt_idx = (struct plt_idx_entry *)sechdrs[sec->shndx].sh_addr;
79294547Swma
80294547Swma	for (i = 0; i < sec->num_entries; i++) {
81294547Swma		if (plt_idx[i].symbol_addr == val)
82294547Swma			return i;
83294547Swma	}
84294547Swma
85294547Swma	return -1;
86294547Swma}
87294547Swma
88294547Swmastatic inline struct plt_entry *get_plt_entry(unsigned long val,
89294547Swma					      Elf_Shdr *sechdrs,
90294547Swma					      const struct mod_section *sec_plt,
91294547Swma					      const struct mod_section *sec_plt_idx)
92294547Swma{
93294547Swma	int plt_idx = get_plt_idx(val, sechdrs, sec_plt_idx);
94294547Swma	struct plt_entry *plt = (struct plt_entry *)sechdrs[sec_plt->shndx].sh_addr;
95294547Swma
96294547Swma	if (plt_idx < 0)
97294547Swma		return NULL;
98294547Swma
99294547Swma	return plt + plt_idx;
100294547Swma}
101294547Swma
102294547Swmastatic inline struct got_entry *get_got_entry(Elf_Addr val,
103294547Swma					      Elf_Shdr *sechdrs,
104294547Swma					      const struct mod_section *sec)
105294547Swma{
106294547Swma	int i;
107294547Swma	struct got_entry *got = (struct got_entry *)sechdrs[sec->shndx].sh_addr;
108294547Swma
109294547Swma	for (i = 0; i < sec->num_entries; i++)
110294547Swma		if (got[i].symbol_addr == val)
111294547Swma			return &got[i];
112294547Swma	return NULL;
113294547Swma}
114294547Swma
115294547Swma#endif /* _ASM_MODULE_H */
116294547Swma