diff options
author | cognet <cognet@FreeBSD.org> | 2005-12-05 12:55:46 +0000 |
---|---|---|
committer | cognet <cognet@FreeBSD.org> | 2005-12-05 12:55:46 +0000 |
commit | 7ad0083d3a7514fb013251dafb3ab56969392bbc (patch) | |
tree | 47b961107a7dca68c5e0ca8d44fa3c80097cc130 | |
parent | 2d1f0805dac87b79aa2bfd75db0f44e672070411 (diff) | |
download | FreeBSD-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.c | 225 | ||||
-rw-r--r-- | sys/arm/arm/inckern.S | 1 | ||||
-rw-r--r-- | sys/conf/Makefile.arm | 21 |
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 \ |