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