linux/arch/csky/kernel/module.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
   3
   4#include <linux/moduleloader.h>
   5#include <linux/elf.h>
   6#include <linux/mm.h>
   7#include <linux/vmalloc.h>
   8#include <linux/slab.h>
   9#include <linux/fs.h>
  10#include <linux/string.h>
  11#include <linux/kernel.h>
  12#include <linux/spinlock.h>
  13
  14#ifdef CONFIG_CPU_CK810
  15#define IS_BSR32(hi16, lo16)            (((hi16) & 0xFC00) == 0xE000)
  16#define IS_JSRI32(hi16, lo16)           ((hi16) == 0xEAE0)
  17
  18#define CHANGE_JSRI_TO_LRW(addr) do {                                   \
  19        *(uint16_t *)(addr) = (*(uint16_t *)(addr) & 0xFF9F) | 0x001a;  \
  20        *((uint16_t *)(addr) + 1) = *((uint16_t *)(addr) + 1) & 0xFFFF; \
  21} while (0)
  22
  23#define SET_JSR32_R26(addr) do {                \
  24        *(uint16_t *)(addr) = 0xE8Fa;           \
  25        *((uint16_t *)(addr) + 1) = 0x0000;     \
  26} while (0)
  27
  28static void jsri_2_lrw_jsr(uint32_t *location)
  29{
  30        uint16_t *location_tmp = (uint16_t *)location;
  31
  32        if (IS_BSR32(*location_tmp, *(location_tmp + 1)))
  33                return;
  34
  35        if (IS_JSRI32(*location_tmp, *(location_tmp + 1))) {
  36                /* jsri 0x...  --> lrw r26, 0x... */
  37                CHANGE_JSRI_TO_LRW(location);
  38                /* lsli r0, r0 --> jsr r26 */
  39                SET_JSR32_R26(location + 1);
  40        }
  41}
  42#else
  43static void inline jsri_2_lrw_jsr(uint32_t *location)
  44{
  45        return;
  46}
  47#endif
  48
  49int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
  50                unsigned int symindex, unsigned int relsec, struct module *me)
  51{
  52        unsigned int i;
  53        Elf32_Rela      *rel = (void *) sechdrs[relsec].sh_addr;
  54        Elf32_Sym       *sym;
  55        uint32_t        *location;
  56        short           *temp;
  57
  58        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
  59                /* This is where to make the change */
  60                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
  61                                                        + rel[i].r_offset;
  62                sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
  63                                                + ELF32_R_SYM(rel[i].r_info);
  64
  65                switch (ELF32_R_TYPE(rel[i].r_info)) {
  66                case R_CSKY_32:
  67                        /* We add the value into the location given */
  68                        *location = rel[i].r_addend + sym->st_value;
  69                        break;
  70                case R_CSKY_PC32:
  71                        /* Add the value, subtract its postition */
  72                        *location = rel[i].r_addend + sym->st_value
  73                                                        - (uint32_t)location;
  74                        break;
  75                case R_CSKY_PCRELJSR_IMM11BY2:
  76                        break;
  77                case R_CSKY_PCRELJSR_IMM26BY2:
  78                        jsri_2_lrw_jsr(location);
  79                        break;
  80                case R_CSKY_ADDR_HI16:
  81                        temp = ((short  *)location) + 1;
  82                        *temp = (short)
  83                                ((rel[i].r_addend + sym->st_value) >> 16);
  84                        break;
  85                case R_CSKY_ADDR_LO16:
  86                        temp = ((short  *)location) + 1;
  87                        *temp = (short)
  88                                ((rel[i].r_addend + sym->st_value) & 0xffff);
  89                        break;
  90                default:
  91                        pr_err("module %s: Unknown relocation: %u\n",
  92                                me->name, ELF32_R_TYPE(rel[i].r_info));
  93                        return -ENOEXEC;
  94                }
  95        }
  96        return 0;
  97}
  98