/*
* IA-64-specific support for kernel module loader.
*
* Copyright (C) 2003 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com>
*
* Loosely based on patch by Rusty Russell.
*/
/* relocs tested so far:
DIR64LSB
FPTR64LSB
GPREL22
LDXMOV
LDXMOV
LTOFF22
LTOFF22X
LTOFF22X
LTOFF_FPTR22
PCREL21B (for br.call only; br.cond is not supported out of modules!)
PCREL60B (for brl.cond only; brl.call is not supported for modules!)
PCREL64LSB
SECREL32LSB
SEGREL64LSB
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/elf.h>
#include <linux/moduleloader.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <asm/patch.h>
#include <asm/unaligned.h>
#define ARCH_MODULE_DEBUG 0
#if ARCH_MODULE_DEBUG
# define DEBUGP printk
# define inline
#else
# define DEBUGP(fmt , a...)
#endif
#ifdef CONFIG_ITANIUM
# define USE_BRL 0
#else
# define USE_BRL 1
#endif
#define MAX_LTOFF ((uint64_t) (1 << 22)) /* max. allowable linkage-table offset */
/* Define some relocation helper macros/types: */
#define FORMAT_SHIFT 0
#define FORMAT_BITS 3
#define FORMAT_MASK ((1 << FORMAT_BITS) - 1)
#define VALUE_SHIFT 3
#define VALUE_BITS 5
#define VALUE_MASK ((1 << VALUE_BITS) - 1)
enum reloc_target_format {
/* direct encoded formats: */
RF_NONE = 0,
RF_INSN14 = 1,
RF_INSN22 = 2,
RF_INSN64 = 3,
RF_32MSB = 4,
RF_32LSB = 5,
RF_64MSB = 6,
RF_64LSB = 7,
/* formats that cannot be directly decoded: */
RF_INSN60,
RF_INSN21B, /* imm21 form 1 */
RF_INSN21M, /* imm21 form 2 */
RF_INSN21F /* imm21 form 3 */
};
enum reloc_value_formula {
RV_DIRECT = 4, /* S + A */
RV_GPREL = 5, /* @gprel(S + A) */
RV_LTREL = 6, /* @ltoff(S + A) */
RV_PLTREL = 7, /* @pltoff(S + A) */
RV_FPTR = 8, /* @fptr(S + A) */
RV_PCREL = 9, /* S + A - P */
RV_LTREL_FPTR = 10, /* @ltoff(@fptr(S + A)) */
RV_SEGREL = 11, /* @segrel(S + A) */
RV_SECREL = 12, /* @secrel(S + A) */
RV_BDREL = 13, /* BD + A */
RV_LTV = 14, /* S + A (like RV_DIRECT, except frozen at static link-time) */
RV_PCREL2 = 15, /* S + A - P */
RV_SPECIAL = 16, /* various (see below) */
RV_RSVD17 = 17,
RV_TPREL = 18, /* @tprel(S + A) */
RV_LTREL_TPREL = 19, /* @ltoff(@tprel(S + A)) */
RV_DTPMOD = 20, /* @dtpmod(S + A) */
RV_LTREL_DTPMOD = 21, /* @ltoff(@dtpmod(S + A)) */
RV_DTPREL = 22, /* @dtprel(S + A) */
RV_LTREL_DTPREL = 23, /* @ltoff(@dtprel(S + A)) */
RV_RSVD24 = 24,
RV_RSVD25 = 25,
RV_RSVD26 = 26,
RV_RSVD27 = 27
/* 28-31 reserved for implementation-specific purposes. */
};
#define N(reloc) [R_IA64_##reloc] = #reloc
static const char *reloc_name[256] = {
N(NONE), N(IMM14), N(IMM22), N(IMM64),
N(DIR32MSB), N(DIR32LSB), N(DIR64MSB), N(DIR64LSB),
N(GPREL22), N(GPREL64I), N(GPREL32MSB), N(GPREL32LSB),
N(GPREL64MSB), N(GPREL64LSB), N(LTOFF22), N(LTOFF64I),
N(PLTOFF22), N(PLTOFF64I), N(PLTOFF64MSB), N(PLTOFF64LSB),
N(FPTR64I), N(FPTR32MSB), N(FPTR32LSB), N(FPTR64MSB),
N(FPTR64LSB), N(PCREL60B), N(PCREL21B), N(PCREL21M),
N(PCREL21F), N(PCREL32MSB), N(PCREL32LSB), N(PCREL64MSB),
N(PCREL64LSB), N(LTOFF_FPTR22), N(LTOFF_FPTR64I), N(LTOFF_FPTR32MSB),
N(LTOFF_FPTR32LSB), N(LTOFF_FPTR64MSB), N(LTOFF_FPTR64LSB), N(SEGREL32MSB),
N(SEGREL32LSB), N(SEGREL64MSB), N(SEGREL64LSB), N(SECREL32MSB),
N(SECREL32LSB), N(SECREL64MSB), N(SECREL64LSB), N(REL32MSB),
N(REL32LSB), N(REL64MSB), N(REL64LSB), N(LTV32MSB),
N(LTV32LSB), N(LTV64MSB), N(LTV64LSB), N(PCREL21BI),
N(PCREL22), N(PCREL64I), N(IPLTMSB), N(IPLTLSB),
N(COPY), N(LTOFF22X), N(LDXMOV), N(TPREL14),
N(TPREL22), N(TPREL64I), N(TPREL64MSB), N(TPREL64LSB),
N(LTOFF_TPREL22), N(DTPMOD64MSB), N(DTPMOD64LSB), N(LTOFF_DTPMOD22),
N(DTPREL14), N(DTPREL22), N(DTPREL64I), N(DTPREL32MSB),
N(DTPREL32LSB), N(DTPREL64MSB), N(DTPREL64LSB), N(LTOFF_DTPREL22)
};
#undef N
struct got_entry {
uint64_t val;
};
struct fdesc {
uint64_t ip;
uint64_t gp;
};
/* Opaque struct for insns, to protect against derefs. */
struct insn;
static inline uint64_t
bundle (const struct insn *insn)
{
return (uint64_t) insn & ~0xfUL;
}
static inline int
slot (const struct insn *insn)
{
return (uint64_t) insn & 0x3;
}
static int
apply_imm64 (struct