]>
Commit | Line | Data |
---|---|---|
ab1ef68e ZL |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* Copyright (C) 2017 Andes Technology Corporation */ | |
3 | ||
4 | #ifndef _ASM_RISCV_MODULE_H | |
5 | #define _ASM_RISCV_MODULE_H | |
6 | ||
7 | #include <asm-generic/module.h> | |
8 | ||
0138ebb9 | 9 | struct module; |
2cffc956 ZL |
10 | unsigned long module_emit_got_entry(struct module *mod, unsigned long val); |
11 | unsigned long module_emit_plt_entry(struct module *mod, unsigned long val); | |
ab1ef68e ZL |
12 | |
13 | #ifdef CONFIG_MODULE_SECTIONS | |
14 | struct mod_section { | |
2cffc956 | 15 | Elf_Shdr *shdr; |
ab1ef68e ZL |
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; | |
b8bde0ef | 23 | struct mod_section got_plt; |
ab1ef68e ZL |
24 | }; |
25 | ||
26 | struct got_entry { | |
2cffc956 | 27 | unsigned long symbol_addr; /* the real variable address */ |
ab1ef68e ZL |
28 | }; |
29 | ||
2cffc956 | 30 | static inline struct got_entry emit_got_entry(unsigned long val) |
ab1ef68e ZL |
31 | { |
32 | return (struct got_entry) {val}; | |
33 | } | |
34 | ||
2cffc956 | 35 | static inline struct got_entry *get_got_entry(unsigned long val, |
ab1ef68e ZL |
36 | const struct mod_section *sec) |
37 | { | |
2cffc956 | 38 | struct got_entry *got = (struct got_entry *)(sec->shdr->sh_addr); |
ab1ef68e ZL |
39 | int i; |
40 | for (i = 0; i < sec->num_entries; i++) { | |
41 | if (got[i].symbol_addr == val) | |
42 | return &got[i]; | |
43 | } | |
44 | return NULL; | |
45 | } | |
46 | ||
47 | struct plt_entry { | |
48 | /* | |
49 | * Trampoline code to real target address. The return address | |
50 | * should be the original (pc+4) before entring plt entry. | |
ab1ef68e ZL |
51 | */ |
52 | u32 insn_auipc; /* auipc t0, 0x0 */ | |
53 | u32 insn_ld; /* ld t1, 0x10(t0) */ | |
54 | u32 insn_jr; /* jr t1 */ | |
ab1ef68e ZL |
55 | }; |
56 | ||
57 | #define OPC_AUIPC 0x0017 | |
58 | #define OPC_LD 0x3003 | |
59 | #define OPC_JALR 0x0067 | |
60 | #define REG_T0 0x5 | |
61 | #define REG_T1 0x6 | |
ab1ef68e | 62 | |
2cffc956 ZL |
63 | static inline struct plt_entry emit_plt_entry(unsigned long val, |
64 | unsigned long plt, | |
65 | unsigned long got_plt) | |
ab1ef68e ZL |
66 | { |
67 | /* | |
68 | * U-Type encoding: | |
69 | * +------------+----------+----------+ | |
70 | * | imm[31:12] | rd[11:7] | opc[6:0] | | |
71 | * +------------+----------+----------+ | |
72 | * | |
73 | * I-Type encoding: | |
74 | * +------------+------------+--------+----------+----------+ | |
75 | * | imm[31:20] | rs1[19:15] | funct3 | rd[11:7] | opc[6:0] | | |
76 | * +------------+------------+--------+----------+----------+ | |
77 | * | |
78 | */ | |
2cffc956 | 79 | unsigned long offset = got_plt - plt; |
b8bde0ef ZL |
80 | u32 hi20 = (offset + 0x800) & 0xfffff000; |
81 | u32 lo12 = (offset - hi20); | |
ab1ef68e | 82 | return (struct plt_entry) { |
b8bde0ef ZL |
83 | OPC_AUIPC | (REG_T0 << 7) | hi20, |
84 | OPC_LD | (lo12 << 20) | (REG_T0 << 15) | (REG_T1 << 7), | |
85 | OPC_JALR | (REG_T1 << 15) | |
ab1ef68e ZL |
86 | }; |
87 | } | |
88 | ||
2cffc956 | 89 | static inline int get_got_plt_idx(unsigned long val, const struct mod_section *sec) |
ab1ef68e | 90 | { |
b8bde0ef | 91 | struct got_entry *got_plt = (struct got_entry *)sec->shdr->sh_addr; |
ab1ef68e ZL |
92 | int i; |
93 | for (i = 0; i < sec->num_entries; i++) { | |
b8bde0ef ZL |
94 | if (got_plt[i].symbol_addr == val) |
95 | return i; | |
ab1ef68e | 96 | } |
b8bde0ef ZL |
97 | return -1; |
98 | } | |
99 | ||
2cffc956 ZL |
100 | static inline struct plt_entry *get_plt_entry(unsigned long val, |
101 | const struct mod_section *sec_plt, | |
102 | const struct mod_section *sec_got_plt) | |
b8bde0ef ZL |
103 | { |
104 | struct plt_entry *plt = (struct plt_entry *)sec_plt->shdr->sh_addr; | |
105 | int got_plt_idx = get_got_plt_idx(val, sec_got_plt); | |
106 | if (got_plt_idx >= 0) | |
107 | return plt + got_plt_idx; | |
108 | else | |
109 | return NULL; | |
ab1ef68e ZL |
110 | } |
111 | ||
112 | #endif /* CONFIG_MODULE_SECTIONS */ | |
113 | ||
114 | #endif /* _ASM_RISCV_MODULE_H */ |