^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Port on Texas Instruments TMS320C6x architecture
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2005, 2009, 2010, 2011 Texas Instruments Incorporated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Thomas Charleux (thomas.charleux@jaluna.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/moduleloader.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/elf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static inline int fixup_pcr(u32 *ip, Elf32_Addr dest, u32 maskbits, int shift)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) u32 opcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) long ep = (long)ip & ~31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) long delta = ((long)dest - ep) >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) long mask = (1 << maskbits) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) if ((delta >> (maskbits - 1)) == 0 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) (delta >> (maskbits - 1)) == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) opcode = *ip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) opcode &= ~(mask << shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) opcode |= ((delta & mask) << shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *ip = opcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) pr_debug("REL PCR_S%d[%p] dest[%p] opcode[%08x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) maskbits, ip, (void *)dest, opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) pr_err("PCR_S%d reloc %p -> %p out of range!\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) maskbits, ip, (void *)dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * apply a RELA relocation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) int apply_relocate_add(Elf32_Shdr *sechdrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) const char *strtab,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) unsigned int symindex,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unsigned int relsec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct module *me)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) Elf32_Rela *rel = (void *) sechdrs[relsec].sh_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) Elf_Sym *sym;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) u32 *location, opcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) Elf32_Addr v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) Elf_Addr offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) pr_debug("Applying relocate section %u to %u with offset 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) relsec, sechdrs[relsec].sh_info, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* This is where to make the change */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) + rel[i].r_offset - offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* This is the symbol it is referring to. Note that all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) undefined symbols have been resolved. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) sym = (Elf_Sym *)sechdrs[symindex].sh_addr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) + ELF32_R_SYM(rel[i].r_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /* this is the adjustment to be made */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) v = sym->st_value + rel[i].r_addend;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) switch (ELF32_R_TYPE(rel[i].r_info)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) case R_C6000_ABS32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) pr_debug("RELA ABS32: [%p] = 0x%x\n", location, v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) *location = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) case R_C6000_ABS16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) pr_debug("RELA ABS16: [%p] = 0x%x\n", location, v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) *(u16 *)location = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) case R_C6000_ABS8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) pr_debug("RELA ABS8: [%p] = 0x%x\n", location, v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) *(u8 *)location = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) case R_C6000_ABS_L16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) opcode = *location;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) opcode &= ~0x7fff80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) opcode |= ((v & 0xffff) << 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) pr_debug("RELA ABS_L16[%p] v[0x%x] opcode[0x%x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) location, v, opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) *location = opcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) case R_C6000_ABS_H16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) opcode = *location;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) opcode &= ~0x7fff80;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) opcode |= ((v >> 9) & 0x7fff80);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) pr_debug("RELA ABS_H16[%p] v[0x%x] opcode[0x%x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) location, v, opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) *location = opcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) case R_C6000_PCR_S21:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (fixup_pcr(location, v, 21, 7))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return -ENOEXEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) case R_C6000_PCR_S12:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (fixup_pcr(location, v, 12, 16))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return -ENOEXEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) case R_C6000_PCR_S10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (fixup_pcr(location, v, 10, 13))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -ENOEXEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) pr_err("module %s: Unknown RELA relocation: %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) me->name, ELF32_R_TYPE(rel[i].r_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return -ENOEXEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }