aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJayachandran C. <jchandra@FreeBSD.org>2011-07-16 17:22:01 +0000
committerJayachandran C. <jchandra@FreeBSD.org>2011-07-16 17:22:01 +0000
commit578828c8d200a4610f18d4fcf00753175853eaa4 (patch)
tree0401aa1dab1f3e6c850f6b4852214727f7591e40 /sys
parent53b93f2f8acc25df7960a70b27ecb5aae33de31d (diff)
downloadsrc-578828c8d200a4610f18d4fcf00753175853eaa4.tar.gz
src-578828c8d200a4610f18d4fcf00753175853eaa4.zip
Support compiling MIPS elf trampoline with a different ABI.
Allow changing the trampoline ABI with makeoptions, this will allow us to have a trampoline with a different ABI from the kernel. Useful in cases where we have to boot a 64 bit kernel from a bootloader which supports only 32 bit or vice versa. Approved by: bz(re), jmallett, imp
Notes
Notes: svn path=/head/; revision=224105
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/Makefile.mips21
-rw-r--r--sys/mips/mips/elf_trampoline.c47
2 files changed, 45 insertions, 23 deletions
diff --git a/sys/conf/Makefile.mips b/sys/conf/Makefile.mips
index 55d57e62b192..ab2b40ac8c76 100644
--- a/sys/conf/Makefile.mips
+++ b/sys/conf/Makefile.mips
@@ -50,7 +50,13 @@ HACK_EXTRA_FLAGS=-shared
# is extremely poor, as well as -mno-abicalls to force no ABI usage.
CFLAGS+=${EXTRA_FLAGS} $(ARCH_FLAGS)
HACK_EXTRA_FLAGS+=${EXTRA_FLAGS} $(ARCH_FLAGS)
-TRAMP_EXTRA_FLAGS=${EXTRA_FLAGS} $(ARCH_FLAGS)
+TRAMP_ARCH_FLAGS?=$(ARCH_FLAGS)
+TRAMP_EXTRA_FLAGS=${EXTRA_FLAGS} ${TRAMP_ARCH_FLAGS}
+.if ${MACHINE_ARCH:Mmips64*} != ""
+TRAMP_ELFSIZE=64
+.else
+TRAMP_ELFSIZE=32
+.endif
# XXX hardcoded kernel entry point
ASM_CFLAGS+=${CFLAGS} -D_LOCORE -DLOCORE
@@ -64,11 +70,12 @@ ${KERNEL_KO}.tramp.bin: ${KERNEL_KO} $S/$M/$M/elf_trampoline.c \
sed -e s/${KERNLOADADDR}/${TRAMPLOADADDR}/ -e s/" + SIZEOF_HEADERS"// \
${LDSCRIPT_NAME} > ${LDSCRIPT_NAME}.tramp.noheader
${CC} -O -nostdlib -I. -I$S ${TRAMP_EXTRA_FLAGS} ${TRAMP_LDFLAGS} -Xlinker \
- -T -Xlinker ${LDSCRIPT_NAME}.tramp.noheader \
- -DKERNNAME="\"${KERNEL_KO}.tmp\"" $S/$M/$M/elf_trampoline.c \
- $S/$M/$M/inckern.S -o ${KERNEL_KO}.tramp.noheader
- ${OBJCOPY} -S -O binary ${KERNEL_KO}.tramp.noheader \
- ${KERNEL_KO}.tramp.bin \
+ -T -Xlinker ${LDSCRIPT_NAME}.tramp.noheader \
+ -DKERNNAME="\"${KERNEL_KO}.tmp\"" -DELFSIZE=${TRAMP_ELFSIZE} \
+ $S/$M/$M/elf_trampoline.c $S/$M/$M/inckern.S \
+ -o ${KERNEL_KO}.tramp.elf
+ ${OBJCOPY} -S -O binary ${KERNEL_KO}.tramp.elf \
+ ${KERNEL_KO}.tramp.bin
%BEFORE_DEPEND
@@ -83,7 +90,7 @@ ${KERNEL_KO}.tramp.bin: ${KERNEL_KO} $S/$M/$M/elf_trampoline.c \
%CLEAN
CLEAN+= ${LDSCRIPT_NAME} ${LDSCRIPT_NAME}.tramp.noheader \
- ${KERNEL_KO}.tramp.noheader ${KERNEL_KO}.tramp.bin
+ ${KERNEL_KO}.tramp.elf ${KERNEL_KO}.tramp.bin
${LDSCRIPT_NAME}: $S/conf/${LDSCRIPT_NAME}
sed s/KERNLOADADDR/${KERNLOADADDR}/g $S/conf/${LDSCRIPT_NAME} \
diff --git a/sys/mips/mips/elf_trampoline.c b/sys/mips/mips/elf_trampoline.c
index 70aedebc167b..7d8324a733bf 100644
--- a/sys/mips/mips/elf_trampoline.c
+++ b/sys/mips/mips/elf_trampoline.c
@@ -27,7 +27,7 @@ __FBSDID("$FreeBSD$");
#include <machine/asm.h>
#include <sys/param.h>
-#ifdef __mips_n64
+#if ELFSIZE == 64
#include <sys/elf64.h>
#else
#include <sys/elf32.h>
@@ -90,13 +90,19 @@ bzero(void *addr, size_t count)
}
/*
+ * Convert number to pointer, truncate on 64->32 case, sign extend
+ * in 32->64 case
+ */
+#define mkptr(x) ((void *)(intptr_t)(int)(x))
+
+/*
* Relocate PT_LOAD segements of kernel ELF image to their respective
* virtual addresses and return entry point
*/
void *
load_kernel(void * kstart)
{
-#ifdef __mips_n64
+#if ELFSIZE == 64
Elf64_Ehdr *eh;
Elf64_Phdr phdr[64] /* XXX */;
Elf64_Shdr shdr[64] /* XXX */;
@@ -107,17 +113,19 @@ load_kernel(void * kstart)
#endif
int i, j;
void *entry_point;
- vm_offset_t lastaddr = 0;
+ vm_offset_t loadend = 0;
+ intptr_t lastaddr;
int symtabindex = -1;
int symstrindex = -1;
+ Elf_Size tmp;
-#ifdef __mips_n64
+#if ELFSIZE == 64
eh = (Elf64_Ehdr *)kstart;
#else
eh = (Elf32_Ehdr *)kstart;
#endif
- entry_point = (void*)eh->e_entry;
- memcpy(phdr, (void *)(kstart + eh->e_phoff ),
+ entry_point = mkptr(eh->e_entry);
+ memcpy(phdr, (void *)(kstart + eh->e_phoff),
eh->e_phnum * sizeof(phdr[0]));
memcpy(shdr, (void *)(kstart + eh->e_shoff),
@@ -147,27 +155,31 @@ load_kernel(void * kstart)
if (phdr[i].p_type != PT_LOAD)
continue;
- memcpy((void *)(phdr[i].p_vaddr),
+ memcpy(mkptr(phdr[i].p_vaddr),
(void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz);
/* Clean space from oversized segments, eg: bss. */
if (phdr[i].p_filesz < phdr[i].p_memsz)
- bzero((void *)(phdr[i].p_vaddr + phdr[i].p_filesz),
+ bzero(mkptr(phdr[i].p_vaddr + phdr[i].p_filesz),
phdr[i].p_memsz - phdr[i].p_filesz);
- if (lastaddr < phdr[i].p_vaddr + phdr[i].p_memsz)
- lastaddr = phdr[i].p_vaddr + phdr[i].p_memsz;
+ if (loadend < phdr[i].p_vaddr + phdr[i].p_memsz)
+ loadend = phdr[i].p_vaddr + phdr[i].p_memsz;
}
/* Now grab the symbol tables. */
+ lastaddr = (intptr_t)(int)loadend;
if (symtabindex >= 0 && symstrindex >= 0) {
- *(Elf_Size *)lastaddr = SYMTAB_MAGIC;
+ tmp = SYMTAB_MAGIC;
+ memcpy((void *)lastaddr, &tmp, sizeof(tmp));
lastaddr += sizeof(Elf_Size);
- *(Elf_Size *)lastaddr = shdr[symtabindex].sh_size +
+ tmp = shdr[symtabindex].sh_size +
shdr[symstrindex].sh_size + 2*sizeof(Elf_Size);
+ memcpy((void *)lastaddr, &tmp, sizeof(tmp));
lastaddr += sizeof(Elf_Size);
/* .symtab size */
- *(Elf_Size *)lastaddr = shdr[symtabindex].sh_size;
+ tmp = shdr[symtabindex].sh_size;
+ memcpy((void *)lastaddr, &tmp, sizeof(tmp));
lastaddr += sizeof(shdr[symtabindex].sh_size);
/* .symtab data */
memcpy((void*)lastaddr,
@@ -176,16 +188,19 @@ load_kernel(void * kstart)
lastaddr += shdr[symtabindex].sh_size;
/* .strtab size */
- *(Elf_Size *)lastaddr = shdr[symstrindex].sh_size;
+ tmp = shdr[symstrindex].sh_size;
+ memcpy((void *)lastaddr, &tmp, sizeof(tmp));
lastaddr += sizeof(shdr[symstrindex].sh_size);
/* .strtab data */
memcpy((void*)lastaddr,
shdr[symstrindex].sh_offset + kstart,
shdr[symstrindex].sh_size);
- } else
+ } else {
/* Do not take any chances */
- *(Elf_Size *)lastaddr = 0;
+ tmp = 0;
+ memcpy((void *)lastaddr, &tmp, sizeof(tmp));
+ }
return entry_point;
}