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