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