Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
0003 
0004 #include <linux/moduleloader.h>
0005 #include <linux/elf.h>
0006 #include <linux/mm.h>
0007 #include <linux/vmalloc.h>
0008 #include <linux/slab.h>
0009 #include <linux/fs.h>
0010 #include <linux/string.h>
0011 #include <linux/kernel.h>
0012 #include <linux/spinlock.h>
0013 
0014 #ifdef CONFIG_CPU_CK810
0015 #define IS_BSR32(hi16, lo16)        (((hi16) & 0xFC00) == 0xE000)
0016 #define IS_JSRI32(hi16, lo16)       ((hi16) == 0xEAE0)
0017 
0018 #define CHANGE_JSRI_TO_LRW(addr) do {                   \
0019     *(uint16_t *)(addr) = (*(uint16_t *)(addr) & 0xFF9F) | 0x001a;  \
0020     *((uint16_t *)(addr) + 1) = *((uint16_t *)(addr) + 1) & 0xFFFF; \
0021 } while (0)
0022 
0023 #define SET_JSR32_R26(addr) do {        \
0024     *(uint16_t *)(addr) = 0xE8Fa;       \
0025     *((uint16_t *)(addr) + 1) = 0x0000; \
0026 } while (0)
0027 
0028 static void jsri_2_lrw_jsr(uint32_t *location)
0029 {
0030     uint16_t *location_tmp = (uint16_t *)location;
0031 
0032     if (IS_BSR32(*location_tmp, *(location_tmp + 1)))
0033         return;
0034 
0035     if (IS_JSRI32(*location_tmp, *(location_tmp + 1))) {
0036         /* jsri 0x...  --> lrw r26, 0x... */
0037         CHANGE_JSRI_TO_LRW(location);
0038         /* lsli r0, r0 --> jsr r26 */
0039         SET_JSR32_R26(location + 1);
0040     }
0041 }
0042 #else
0043 static void inline jsri_2_lrw_jsr(uint32_t *location)
0044 {
0045     return;
0046 }
0047 #endif
0048 
0049 int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
0050         unsigned int symindex, unsigned int relsec, struct module *me)
0051 {
0052     unsigned int i;
0053     Elf32_Rela  *rel = (void *) sechdrs[relsec].sh_addr;
0054     Elf32_Sym   *sym;
0055     uint32_t    *location;
0056     short       *temp;
0057 
0058     for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
0059         /* This is where to make the change */
0060         location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
0061                             + rel[i].r_offset;
0062         sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
0063                         + ELF32_R_SYM(rel[i].r_info);
0064 
0065         switch (ELF32_R_TYPE(rel[i].r_info)) {
0066         case R_CSKY_32:
0067             /* We add the value into the location given */
0068             *location = rel[i].r_addend + sym->st_value;
0069             break;
0070         case R_CSKY_PC32:
0071             /* Add the value, subtract its position */
0072             *location = rel[i].r_addend + sym->st_value
0073                             - (uint32_t)location;
0074             break;
0075         case R_CSKY_PCRELJSR_IMM11BY2:
0076             break;
0077         case R_CSKY_PCRELJSR_IMM26BY2:
0078             jsri_2_lrw_jsr(location);
0079             break;
0080         case R_CSKY_ADDR_HI16:
0081             temp = ((short  *)location) + 1;
0082             *temp = (short)
0083                 ((rel[i].r_addend + sym->st_value) >> 16);
0084             break;
0085         case R_CSKY_ADDR_LO16:
0086             temp = ((short  *)location) + 1;
0087             *temp = (short)
0088                 ((rel[i].r_addend + sym->st_value) & 0xffff);
0089             break;
0090         default:
0091             pr_err("module %s: Unknown relocation: %u\n",
0092                 me->name, ELF32_R_TYPE(rel[i].r_info));
0093             return -ENOEXEC;
0094         }
0095     }
0096     return 0;
0097 }