summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcognet <cognet@FreeBSD.org>2005-12-05 12:55:46 +0000
committercognet <cognet@FreeBSD.org>2005-12-05 12:55:46 +0000
commit7ad0083d3a7514fb013251dafb3ab56969392bbc (patch)
tree47b961107a7dca68c5e0ca8d44fa3c80097cc130
parent2d1f0805dac87b79aa2bfd75db0f44e672070411 (diff)
downloadFreeBSD-src-7ad0083d3a7514fb013251dafb3ab56969392bbc.zip
FreeBSD-src-7ad0083d3a7514fb013251dafb3ab56969392bbc.tar.gz
Teach the elf trampoline how to deal with gzipped kernels.
-rw-r--r--sys/arm/arm/elf_trampoline.c225
-rw-r--r--sys/arm/arm/inckern.S1
-rw-r--r--sys/conf/Makefile.arm21
3 files changed, 192 insertions, 55 deletions
diff --git a/sys/arm/arm/elf_trampoline.c b/sys/arm/arm/elf_trampoline.c
index aad5d85..5c55176 100644
--- a/sys/arm/arm/elf_trampoline.c
+++ b/sys/arm/arm/elf_trampoline.c
@@ -28,21 +28,19 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/elf32.h>
#include <sys/param.h>
+#include <sys/inflate.h>
#include <machine/elf.h>
#include <stdlib.h>
#include "opt_global.h"
+#include "opt_kernname.h"
extern char kernel_start[];
extern char kernel_end[];
void __start(void);
-void
-_start(void)
-{
- __start();
-}
+#define GZ_HEAD 0xa
static __inline void *
memcpy(void *dst, const void *src, int len)
@@ -50,34 +48,145 @@ memcpy(void *dst, const void *src, int len)
const char *s = src;
char *d = dst;
- while (len--) {
- *d++ = *s++;
+ while (len) {
+ if (len >= 4 && !((vm_offset_t)d & 3) && !((vm_offset_t)s & 3)) {
+ *(uint32_t *)d = *(uint32_t *)s;
+ s += 4;
+ d += 4;
+ len -= 4;
+ } else {
+ *d++ = *s++;
+ len--;
+ }
}
return (dst);
}
static __inline void
-bzero(char *addr, int count)
+bzero(void *addr, int count)
{
+ char *tmp = (char *)addr;
+
while (count > 0) {
- *addr = 0;
- addr++;
- count--;
+ if (count >= 4 && !((vm_offset_t)tmp & 3)) {
+ *(uint32_t *)tmp = 0;
+ tmp += 4;
+ count -= 4;
+ } else {
+ *tmp = 0;
+ tmp++;
+ count--;
+ }
+ }
+}
+
+void
+_start(void)
+{
+ __start();
+}
+
+#ifdef KZIP
+static unsigned char *orig_input, *i_input, *i_output;
+
+
+static u_int memcnt; /* Memory allocated: blocks */
+static size_t memtot; /* Memory allocated: bytes */
+/*
+ * Library functions required by inflate().
+ */
+
+#define MEMSIZ 0x8000
+
+/*
+ * Allocate memory block.
+ */
+unsigned char *
+kzipmalloc(int size)
+{
+ void *ptr;
+ static u_char mem[MEMSIZ];
+
+ if (memtot + size > MEMSIZ)
+ return NULL;
+ ptr = mem + memtot;
+ memtot += size;
+ memcnt++;
+ return ptr;
+}
+
+/*
+ * Free allocated memory block.
+ */
+void
+kzipfree(void *ptr)
+{
+ memcnt--;
+ if (!memcnt)
+ memtot = 0;
+}
+
+void
+putstr(char *dummy)
+{
+}
+
+static int
+input(void *dummy)
+{
+ if ((size_t)(i_input - orig_input) >= KERNSIZE) {
+ return (GZ_EOF);
+ }
+ return *i_input++;
+}
+
+static int
+output(void *dummy, unsigned char *ptr, unsigned long len)
+{
+
+ memcpy(i_output, ptr, len);
+ i_output += len;
+ return (0);
+}
+
+static void *
+inflate_kernel(void *kernel, void *startaddr)
+{
+ struct inflate infl;
+ char slide[GZ_WSIZE];
+
+ orig_input = kernel;
+ i_input = (char *)kernel + GZ_HEAD;
+ if (((char *)kernel)[3] & 0x18) {
+ while (*i_input)
+ i_input++;
+ i_input++;
}
+ i_output = startaddr;
+ bzero(&infl, sizeof(infl));
+ infl.gz_input = input;
+ infl.gz_output = output;
+ infl.gz_slide = slide;
+ inflate(&infl);
+ return ((char *)(((vm_offset_t)i_output & ~3) + 4));
}
+#endif
+
+
void *
-load_kernel(unsigned int kstart, unsigned int kend, unsigned int curaddr,unsigned int func_end, int d)
+load_kernel(unsigned int kstart, unsigned int curaddr,unsigned int func_end,
+ int d)
{
Elf32_Ehdr *eh;
Elf32_Phdr phdr[512] /* XXX */, *php;
Elf32_Shdr *shdr;
int i,j;
void *entry_point;
- int symtabindex;
- int symstrindex;
+ int symtabindex = -1;
+ int symstrindex = -1;
vm_offset_t lastaddr = 0;
- Elf_Addr ssym, esym;
+ Elf_Addr ssym = 0, esym = 0;
Elf_Dyn *dp;
eh = (Elf32_Ehdr *)kstart;
@@ -93,11 +202,10 @@ load_kernel(unsigned int kstart, unsigned int kend, unsigned int curaddr,unsigne
curaddr + phdr[i].p_memsz;
}
- /* Now grab the symbol tables. */
+ /* Save the symbol tables, as there're about to be scratched. */
lastaddr = roundup(lastaddr, sizeof(long));
if (eh->e_shnum * eh->e_shentsize != 0 &&
eh->e_shoff != 0) {
- symtabindex = symstrindex = -1;
shdr = (Elf_Shdr *)(kstart + eh->e_shoff);
for (i = 0; i < eh->e_shnum; i++) {
if (shdr[i].sh_type == SHT_SYMTAB) {
@@ -132,29 +240,15 @@ load_kernel(unsigned int kstart, unsigned int kend, unsigned int curaddr,unsigne
shdr[symtabindex].sh_size),
(void *)(shdr[symstrindex].sh_offset +
kstart), shdr[symstrindex].sh_size);
- *(Elf_Size *)lastaddr =
- shdr[symtabindex].sh_size;
+ } else {
+ lastaddr += shdr[symtabindex].sh_size;
+ lastaddr = roundup(lastaddr,
+ sizeof(shdr[symtabindex].sh_size));
+ lastaddr += sizeof(shdr[symstrindex].sh_size);
+ lastaddr += shdr[symstrindex].sh_size;
+ lastaddr = roundup(lastaddr,
+ sizeof(shdr[symstrindex].sh_size));
}
- lastaddr += sizeof(shdr[symtabindex].sh_size);
- if (d)
- memcpy((void*)lastaddr,
- (void *)func_end,
- shdr[symtabindex].sh_size);
- lastaddr += shdr[symtabindex].sh_size;
- lastaddr = roundup(lastaddr,
- sizeof(shdr[symtabindex].sh_size));
- if (d)
- *(Elf_Size *)lastaddr =
- shdr[symstrindex].sh_size;
- lastaddr += sizeof(shdr[symstrindex].sh_size);
- if (d)
- memcpy((void*)lastaddr,
- (void*)(func_end +
- shdr[symtabindex].sh_size),
- shdr[symstrindex].sh_size);
- lastaddr += shdr[symstrindex].sh_size;
- lastaddr = roundup(lastaddr,
- sizeof(shdr[symstrindex].sh_size));
}
}
@@ -164,9 +258,9 @@ load_kernel(unsigned int kstart, unsigned int kend, unsigned int curaddr,unsigne
j = eh->e_phnum;
for (i = 0; i < j; i++) {
volatile char c;
- if (phdr[i].p_type != PT_LOAD) {
+
+ if (phdr[i].p_type != PT_LOAD)
continue;
- }
memcpy((void *)(phdr[i].p_vaddr - KERNVIRTADDR + curaddr),
(void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz);
/* Clean space from oversized segments, eg: bss. */
@@ -176,10 +270,31 @@ load_kernel(unsigned int kstart, unsigned int kend, unsigned int curaddr,unsigne
phdr[i].p_filesz);
}
/* Now grab the symbol tables. */
- *(Elf_Addr *)curaddr = MAGIC_TRAMP_NUMBER;
- *((Elf_Addr *)curaddr + 1) = ssym - curaddr + KERNVIRTADDR;
- *((Elf_Addr *)curaddr + 2) = lastaddr - curaddr + KERNVIRTADDR;
-
+ if (symtabindex >= 0 && symstrindex >= 0) {
+ *(Elf_Size *)lastaddr =
+ shdr[symtabindex].sh_size;
+ lastaddr += sizeof(shdr[symtabindex].sh_size);
+ memcpy((void*)lastaddr,
+ (void *)func_end,
+ shdr[symtabindex].sh_size);
+ lastaddr += shdr[symtabindex].sh_size;
+ lastaddr = roundup(lastaddr,
+ sizeof(shdr[symtabindex].sh_size));
+ *(Elf_Size *)lastaddr =
+ shdr[symstrindex].sh_size;
+ lastaddr += sizeof(shdr[symstrindex].sh_size);
+ memcpy((void*)lastaddr,
+ (void*)(func_end +
+ shdr[symtabindex].sh_size),
+ shdr[symstrindex].sh_size);
+ lastaddr += shdr[symstrindex].sh_size;
+ lastaddr = roundup(lastaddr,
+ sizeof(shdr[symstrindex].sh_size));
+ *(Elf_Addr *)curaddr = MAGIC_TRAMP_NUMBER;
+ *((Elf_Addr *)curaddr + 1) = ssym - curaddr + KERNVIRTADDR;
+ *((Elf_Addr *)curaddr + 2) = lastaddr - curaddr + KERNVIRTADDR;
+ } else
+ *(Elf_Addr *)curaddr = 0;
/* Jump to the entry point. */
((void(*)(void))(entry_point - KERNVIRTADDR + curaddr))();
__asm __volatile(".globl func_end\n"
@@ -189,20 +304,30 @@ load_kernel(unsigned int kstart, unsigned int kend, unsigned int curaddr,unsigne
extern char func_end[];
+extern void *_end;
void __start(void)
{
void *curaddr;
+ void *dst;
+ char *kernel = (char *)&kernel_start;
__asm __volatile("mov %0, pc" :
"=r" (curaddr));
curaddr = (void*)((unsigned int)curaddr & 0xfff00000);
- void *dst = 4 + load_kernel((unsigned int)&kernel_start,
- (unsigned int)&kernel_end, (unsigned int)curaddr,
+#ifdef KZIP
+ if (*kernel == 0x1f && kernel[1] == 0x8b) {
+ /* Gzipped kernel */
+ dst = inflate_kernel(kernel, &_end);
+ kernel = (char *)&_end;
+ } else
+#endif
+ dst = 4 + load_kernel((unsigned int)&kernel_start,
+ (unsigned int)curaddr,
(unsigned int)&func_end, 0);
memcpy((void *)dst, (void *)&load_kernel, (unsigned int)&func_end -
(unsigned int)&load_kernel);
- ((void (*)())dst)((unsigned int)&kernel_start,
- (unsigned int)&kernel_end, (unsigned int)curaddr,
- dst + (unsigned int)&func_end -
+ ((void (*)())dst)((unsigned int)kernel,
+ (unsigned int)curaddr,
+ dst + (unsigned int)(&func_end) -
(unsigned int)(&load_kernel), 1);
}
diff --git a/sys/arm/arm/inckern.S b/sys/arm/arm/inckern.S
index d47295b..8610196 100644
--- a/sys/arm/arm/inckern.S
+++ b/sys/arm/arm/inckern.S
@@ -32,4 +32,3 @@ kernel_start:
.incbin KERNNAME
.globl kernel_end;
kernel_end:
-.space 0x10000
diff --git a/sys/conf/Makefile.arm b/sys/conf/Makefile.arm
index 8e3c95d..f240377 100644
--- a/sys/conf/Makefile.arm
+++ b/sys/conf/Makefile.arm
@@ -44,6 +44,7 @@ SYSTEM_LD += -EB
.if !defined(DEBUG)
CFLAGS += -mno-apcs-frame
+STRIP_FLAGS = -S
.endif
DDB_ENABLED!= grep DDB opt_ddb.h || true
@@ -58,10 +59,10 @@ SYSTEM_LD_TAIL +=; cat ldscript.$M| \
${OBJCOPY} -S -O binary ${FULLKERNEL}.noheader \
${KERNEL_KO}.bin; \
rm ${FULLKERNEL}.noheader
-.if ${DDB_ENABLED} != ""
+.if ${DDB_ENABLED} != "" || defined(BUILD_ELF_TRAMPOLINE)
SYSTEM_LD_TAIL += ;echo "\#define KERNNAME \"${KERNEL_KO}.tmp\"" \
>opt_kernname.h ;\
- ${OBJCOPY} --strip-symbol '$$d' --strip-symbol '$$a' \
+ ${OBJCOPY} ${STRIP_FLAGS} --strip-symbol '$$d' --strip-symbol '$$a' \
-g --strip-symbol '$$t' ${FULLKERNEL} ${KERNEL_KO}.tmp;\
${CC} -O -nostdlib -I. -Xlinker -T -Xlinker ldscript.arm \
$S/$M/$M/elf_trampoline.c $S/$M/$M/inckern.S -o ${KERNEL_KO}.tramp;\
@@ -70,8 +71,20 @@ SYSTEM_LD_TAIL += ;echo "\#define KERNNAME \"${KERNEL_KO}.tmp\"" \
${KERNEL_KO}.tramp.noheader; \
${OBJCOPY} -S -O binary ${KERNEL_KO}.tramp.noheader \
${KERNEL_KO}.tramp.bin; \
- rm ${KERNEL_KO}.tmp ${KERNEL_KO}.tramp.noheader; \
-
+ gzip -9 ${KERNEL_KO}.tmp; \
+ echo "\#define KERNNAME \"${KERNEL_KO}.tmp.gz\"" \
+ >opt_kernname.h ;\
+ eval $$(stat -s ${KERNEL_KO}.tmp.gz) && \
+ echo "\#define KERNSIZE $$st_size" >>opt_kernname.h;\
+ ${CC} -O -nostdlib -I. -Xlinker -T -Xlinker ldscript.arm \
+ -DKZIP $S/$M/$M/elf_trampoline.c $S/kern/inflate.c $S/$M/$M/inckern.S \
+ -o ${KERNEL_KO}.gz.tramp;\
+ ${CC} -O -nostdlib -I. -Xlinker -T -Xlinker ldscript.arm.noheader \
+ -DKZIP $S/$M/$M/elf_trampoline.c $S/kern/inflate.c $S/$M/$M/inckern.S \
+ -o ${KERNEL_KO}.tramp.noheader; \
+ ${OBJCOPY} -S -O binary ${KERNEL_KO}.tramp.noheader \
+ ${KERNEL_KO}.gz.tramp.bin; \
+ rm ${KERNEL_KO}.tmp.gz ${KERNEL_KO}.tramp.noheader opt_kernname.h;
.endif
CLEANFILES += ldscript.$M ldscript.$M.noheader ${KERNEL_KO}.bin \
OpenPOWER on IntegriCloud