summaryrefslogtreecommitdiff
path: root/arch/s390/boot/startup.c
diff options
context:
space:
mode:
authorGerald Schaefer <gerald.schaefer@de.ibm.com>2019-02-03 21:35:45 +0100
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2019-04-29 10:47:10 +0200
commit805bc0bc238f7209fca5e39c152b0d3c12046ac9 (patch)
tree97edfcee4981bc71c2e6a9dc853353010ac4fa94 /arch/s390/boot/startup.c
parent833b441ec0f6f3c57cc2106ef628bb19d8fb0ee2 (diff)
s390/kernel: build a relocatable kernel
This patch adds support for building a relocatable kernel with -fPIE. The kernel will be relocated to 0 early in the boot process. Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> Reviewed-by: Philipp Rudo <prudo@linux.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/boot/startup.c')
-rw-r--r--arch/s390/boot/startup.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c
index 90898976a941..b7d6a76cb5e9 100644
--- a/arch/s390/boot/startup.c
+++ b/arch/s390/boot/startup.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/string.h>
+#include <linux/elf.h>
#include <asm/setup.h>
+#include <asm/kexec.h>
#include <asm/sclp.h>
#include <asm/uv.h>
#include "compressed/decompressor.h"
@@ -47,6 +49,29 @@ static void copy_bootdata(void)
memcpy((void *)vmlinux.bootdata_preserved_off, __boot_data_preserved_start, vmlinux.bootdata_preserved_size);
}
+static void handle_relocs(unsigned long offset)
+{
+ Elf64_Rela *rela_start, *rela_end, *rela;
+ int r_type, r_sym, rc;
+ Elf64_Addr loc, val;
+ Elf64_Sym *dynsym;
+
+ rela_start = (Elf64_Rela *) vmlinux.rela_dyn_start;
+ rela_end = (Elf64_Rela *) vmlinux.rela_dyn_end;
+ dynsym = (Elf64_Sym *) vmlinux.dynsym_start;
+ for (rela = rela_start; rela < rela_end; rela++) {
+ loc = rela->r_offset + offset;
+ val = rela->r_addend + offset;
+ r_sym = ELF64_R_SYM(rela->r_info);
+ if (r_sym)
+ val += dynsym[r_sym].st_value;
+ r_type = ELF64_R_TYPE(rela->r_info);
+ rc = arch_kexec_do_relocs(r_type, (void *) loc, val, 0);
+ if (rc)
+ error("Unknown relocation type");
+ }
+}
+
void startup_kernel(void)
{
unsigned long safe_addr;
@@ -67,5 +92,7 @@ void startup_kernel(void)
memmove((void *)vmlinux.default_lma, img, vmlinux.image_size);
}
copy_bootdata();
+ if (IS_ENABLED(CONFIG_RELOCATABLE))
+ handle_relocs(0);
vmlinux.entry();
}