diff options
Diffstat (limited to 'kexec/arch/s390/kexec-elf-rel-s390.c')
-rw-r--r-- | kexec/arch/s390/kexec-elf-rel-s390.c | 66 |
1 files changed, 58 insertions, 8 deletions
diff --git a/kexec/arch/s390/kexec-elf-rel-s390.c b/kexec/arch/s390/kexec-elf-rel-s390.c index ffa0347..80bcd1b 100644 --- a/kexec/arch/s390/kexec-elf-rel-s390.c +++ b/kexec/arch/s390/kexec-elf-rel-s390.c @@ -1,7 +1,7 @@ /* * kexec/arch/s390/kexec-elf-rel-s390.c * - * (C) Copyright IBM Corp. 2005 + * Copyright IBM Corp. 2005,2011 * * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> * @@ -12,15 +12,65 @@ #include "../../kexec.h" #include "../../kexec-elf.h" -int machine_verify_elf_rel(struct mem_ehdr *UNUSED(ehdr)) +int machine_verify_elf_rel(struct mem_ehdr *ehdr) { - return 0; + if (ehdr->ei_data != ELFDATA2MSB) + return 0; + if (ehdr->ei_class != ELFCLASS64) + return 0; + if (ehdr->e_machine != EM_S390) + return 0; + return 1; } -void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr), - unsigned long UNUSED(r_type), - void *UNUSED(location), - unsigned long UNUSED(address), - unsigned long UNUSED(value)) +void machine_apply_elf_rel(struct mem_ehdr *ehdr, + unsigned long r_type, + void *loc, + unsigned long address, + unsigned long val) { + switch (r_type) { + case R_390_8: /* Direct 8 bit. */ + case R_390_12: /* Direct 12 bit. */ + case R_390_16: /* Direct 16 bit. */ + case R_390_20: /* Direct 20 bit. */ + case R_390_32: /* Direct 32 bit. */ + case R_390_64: /* Direct 64 bit. */ + if (r_type == R_390_8) + *(unsigned char *) loc = val; + else if (r_type == R_390_12) + *(unsigned short *) loc = (val & 0xfff) | + (*(unsigned short *) loc & 0xf000); + else if (r_type == R_390_16) + *(unsigned short *) loc = val; + else if (r_type == R_390_20) + *(unsigned int *) loc = + (*(unsigned int *) loc & 0xf00000ff) | + (val & 0xfff) << 16 | (val & 0xff000) >> 4; + else if (r_type == R_390_32) + *(unsigned int *) loc = val; + else if (r_type == R_390_64) + *(unsigned long *) loc = val; + break; + case R_390_PC16: /* PC relative 16 bit. */ + case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */ + case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */ + case R_390_PC32: /* PC relative 32 bit. */ + case R_390_PC64: /* PC relative 64 bit. */ + val -= address; + if (r_type == R_390_PC16) + *(unsigned short *) loc = val; + else if (r_type == R_390_PC16DBL) + *(unsigned short *) loc = val >> 1; + else if (r_type == R_390_PC32DBL) + *(unsigned int *) loc = val >> 1; + else if (r_type == R_390_PC32) + *(unsigned int *) loc = val; + else if (r_type == R_390_PC64) + *(unsigned long *) loc = val; + break; + default: + die("Unknown rela relocation: 0x%lx 0x%lx\n", r_type, address); + break; + } } |