Skip to content

Commit

Permalink
C6X: loadable module support
Browse files Browse the repository at this point in the history
Original port to early 2.6 kernel using TI COFF toolchain.
Brought up to date by Mark Salter <[email protected]>

Signed-off-by: Aurelien Jacquiot <[email protected]>
Signed-off-by: Mark Salter <[email protected]>
Acked-by: Arnd Bergmann <[email protected]>
  • Loading branch information
Aurelien Jacquiot authored and mosalter committed Oct 6, 2011
1 parent 784bdcd commit 64236ac
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 0 deletions.
33 changes: 33 additions & 0 deletions arch/c6x/include/asm/module.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
* Author: Aurelien Jacquiot ([email protected])
*
* Updated for 2.6.34 by: Mark Salter ([email protected])
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_C6X_MODULE_H
#define _ASM_C6X_MODULE_H

#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Addr Elf32_Addr
#define Elf_Word Elf32_Word

/*
* This file contains the C6x architecture specific module code.
*/
struct mod_arch_specific {
};

struct loaded_sections {
unsigned int new_vaddr;
unsigned int loaded;
};

#endif /* _ASM_C6X_MODULE_H */
66 changes: 66 additions & 0 deletions arch/c6x/kernel/c6x_ksyms.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Aurelien Jacquiot ([email protected])
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <asm/checksum.h>
#include <linux/io.h>

/*
* libgcc functions - used internally by the compiler...
*/
extern int __c6xabi_divi(int dividend, int divisor);
EXPORT_SYMBOL(__c6xabi_divi);

extern unsigned __c6xabi_divu(unsigned dividend, unsigned divisor);
EXPORT_SYMBOL(__c6xabi_divu);

extern int __c6xabi_remi(int dividend, int divisor);
EXPORT_SYMBOL(__c6xabi_remi);

extern unsigned __c6xabi_remu(unsigned dividend, unsigned divisor);
EXPORT_SYMBOL(__c6xabi_remu);

extern int __c6xabi_divremi(int dividend, int divisor);
EXPORT_SYMBOL(__c6xabi_divremi);

extern unsigned __c6xabi_divremu(unsigned dividend, unsigned divisor);
EXPORT_SYMBOL(__c6xabi_divremu);

extern unsigned long long __c6xabi_mpyll(unsigned long long src1,
unsigned long long src2);
EXPORT_SYMBOL(__c6xabi_mpyll);

extern long long __c6xabi_negll(long long src);
EXPORT_SYMBOL(__c6xabi_negll);

extern unsigned long long __c6xabi_llshl(unsigned long long src1, uint src2);
EXPORT_SYMBOL(__c6xabi_llshl);

extern long long __c6xabi_llshr(long long src1, uint src2);
EXPORT_SYMBOL(__c6xabi_llshr);

extern unsigned long long __c6xabi_llshru(unsigned long long src1, uint src2);
EXPORT_SYMBOL(__c6xabi_llshru);

extern void __c6xabi_strasgi(int *dst, const int *src, unsigned cnt);
EXPORT_SYMBOL(__c6xabi_strasgi);

extern void __c6xabi_push_rts(void);
EXPORT_SYMBOL(__c6xabi_push_rts);

extern void __c6xabi_pop_rts(void);
EXPORT_SYMBOL(__c6xabi_pop_rts);

extern void __c6xabi_strasgi_64plus(int *dst, const int *src, unsigned cnt);
EXPORT_SYMBOL(__c6xabi_strasgi_64plus);

/* lib functions */
EXPORT_SYMBOL(memcpy);
123 changes: 123 additions & 0 deletions arch/c6x/kernel/module.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Port on Texas Instruments TMS320C6x architecture
*
* Copyright (C) 2005, 2009, 2010, 2011 Texas Instruments Incorporated
* Author: Thomas Charleux ([email protected])
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/moduleloader.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
#include <linux/kernel.h>

static inline int fixup_pcr(u32 *ip, Elf32_Addr dest, u32 maskbits, int shift)
{
u32 opcode;
long ep = (long)ip & ~31;
long delta = ((long)dest - ep) >> 2;
long mask = (1 << maskbits) - 1;

if ((delta >> (maskbits - 1)) == 0 ||
(delta >> (maskbits - 1)) == -1) {
opcode = *ip;
opcode &= ~(mask << shift);
opcode |= ((delta & mask) << shift);
*ip = opcode;

pr_debug("REL PCR_S%d[%p] dest[%p] opcode[%08x]\n",
maskbits, ip, (void *)dest, opcode);

return 0;
}
pr_err("PCR_S%d reloc %p -> %p out of range!\n",
maskbits, ip, (void *)dest);

return -1;
}

/*
* apply a RELA relocation
*/
int apply_relocate_add(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
Elf32_Rela *rel = (void *) sechdrs[relsec].sh_addr;
Elf_Sym *sym;
u32 *location, opcode;
unsigned int i;
Elf32_Addr v;
Elf_Addr offset = 0;

pr_debug("Applying relocate section %u to %u with offset 0x%x\n",
relsec, sechdrs[relsec].sh_info, offset);

for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rel[i].r_offset - offset;

/* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
sym = (Elf_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM(rel[i].r_info);

/* this is the adjustment to be made */
v = sym->st_value + rel[i].r_addend;

switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_C6000_ABS32:
pr_debug("RELA ABS32: [%p] = 0x%x\n", location, v);
*location = v;
break;
case R_C6000_ABS16:
pr_debug("RELA ABS16: [%p] = 0x%x\n", location, v);
*(u16 *)location = v;
break;
case R_C6000_ABS8:
pr_debug("RELA ABS8: [%p] = 0x%x\n", location, v);
*(u8 *)location = v;
break;
case R_C6000_ABS_L16:
opcode = *location;
opcode &= ~0x7fff80;
opcode |= ((v & 0xffff) << 7);
pr_debug("RELA ABS_L16[%p] v[0x%x] opcode[0x%x]\n",
location, v, opcode);
*location = opcode;
break;
case R_C6000_ABS_H16:
opcode = *location;
opcode &= ~0x7fff80;
opcode |= ((v >> 9) & 0x7fff80);
pr_debug("RELA ABS_H16[%p] v[0x%x] opcode[0x%x]\n",
location, v, opcode);
*location = opcode;
break;
case R_C6000_PCR_S21:
if (fixup_pcr(location, v, 21, 7))
return -ENOEXEC;
break;
case R_C6000_PCR_S12:
if (fixup_pcr(location, v, 12, 16))
return -ENOEXEC;
break;
case R_C6000_PCR_S10:
if (fixup_pcr(location, v, 10, 13))
return -ENOEXEC;
break;
default:
pr_err("module %s: Unknown RELA relocation: %u\n",
me->name, ELF32_R_TYPE(rel[i].r_info));
return -ENOEXEC;
}
}

return 0;
}

0 comments on commit 64236ac

Please sign in to comment.