Making the powerpc64 relocatable

Nathan Whitehorn nwhitehorn at freebsd.org
Wed Jan 21 19:32:26 UTC 2015


In order to run natively on POWER8 hardware, the 64-bit PPC kernel needs 
to be relocatable. Some architectures do this by executing the kernel at 
a fixed virtual address with varying physical addresses. For PPC64, the 
kernel has a 1:1 direct map and the ABI is always PIC, so it's easier 
just to keep the 1:1 mapping and make both the kernel physical and 
virtual address range float (patch attached and at 
http://people.freebsd.org/~nwhitehorn/ppc64-pie-kernel.diff in case it 
gets stripped).

This is the first architecture to have a PIE kernel, however, so I'd 
like some feedback on the approach. The major immediate difficulty is 
that PIE kernels are ET_DYN ELF executables. loader, however, thinks the 
kernel must be ET_EXEC and that anything that is ET_DYN is a loadable 
module. I have a somewhat hacky workaround in the patches to loader and 
kmod.mk, which uses the ELF entrypoint to decide whether something is a 
kernel or not (setting it to zero for modules). It's the simplest 
approach but I'm not sure the best one.
-Nathan
-------------- next part --------------
Index: boot/common/load_elf.c
===================================================================
--- boot/common/load_elf.c	(revision 277438)
+++ boot/common/load_elf.c	(working copy)
@@ -175,7 +175,11 @@
      * Check to see what sort of module we are.
      */
     kfp = file_findfile(NULL, __elfN(kerneltype));
+#if defined(__powerpc__) && __ELF_WORD_SIZE == 64
+    if (ehdr->e_type == ET_DYN && ehdr->e_entry == 0) {
+#else
     if (ehdr->e_type == ET_DYN) {
+#endif
 	/* Looks like a kld module */
 	if (multiboot != 0) {
 		printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: can't load module as multiboot\n");
@@ -195,7 +199,12 @@
 	/* Looks OK, got ahead */
 	ef.kernel = 0;
 
+#if defined(__powerpc__) && __ELF_WORD_SIZE == 64
+    } else if (ehdr->e_type == ET_EXEC ||
+      (ehdr->e_type == ET_DYN && ehdr->e_entry != 0)) {
+#else
     } else if (ehdr->e_type == ET_EXEC) {
+#endif
 	/* Looks like a kernel */
 	if (kfp != NULL) {
 	    printf("elf" __XSTRING(__ELF_WORD_SIZE) "_loadfile: kernel already loaded\n");
Index: conf/Makefile.powerpc
===================================================================
--- conf/Makefile.powerpc	(revision 277438)
+++ conf/Makefile.powerpc	(working copy)
@@ -37,6 +37,11 @@
 
 CFLAGS+= -msoft-float -Wa,-many
 
+.if ${MACHINE_ARCH} == "powerpc64"
+CFLAGS+= -fPIC
+LDFLAGS+= -pie
+.endif
+
 .if !empty(DDB_ENABLED)
 CFLAGS+=	-fno-omit-frame-pointer
 .endif
Index: conf/kmod.mk
===================================================================
--- conf/kmod.mk	(revision 277438)
+++ conf/kmod.mk	(working copy)
@@ -179,6 +179,9 @@
 	${OBJCOPY} --only-keep-debug ${FULLPROG} ${.TARGET}
 .endif
 
+# Don't add a fake entry point to modules
+_LDFLAGS+= -e 0
+
 .if ${__KLD_SHARED} == yes
 ${FULLPROG}: ${KMOD}.kld
 	${LD} -Bshareable ${_LDFLAGS} -o ${.TARGET} ${KMOD}.kld


More information about the freebsd-ppc mailing list