Skip to content

Commit

Permalink
MIPS: Add support for GZIP / BZIP2 / LZMA compressed kernel images
Browse files Browse the repository at this point in the history
This patch helps to generate smaller kernel images for linux-MIPS,

Here is the effect when using lzma:

$ ls -sh vmlinux
7.1M vmlinux
$ ls -sh vmlinuz
1.5M vmlinuz

Have tested the 32bit kernel on Qemu/Malta and 64bit kernel on FuLoong
Mini PC. both of them work well. and also, tested by Alexander Clouter
on an AR7 based Linksys WAG54Gv2, and by Manuel Lauss on an Alchemy
board.

This -v2 version incorporate the feedback from Ralf, and add the
following changes:

1. add .ecoff, .bin, .erec format support
2. only enable it and the debug source code for the machines we tested
3. a dozen of fixups and cleanups

and if you want to enable it for your board, please try to select
SYS_SUPPORTS_ZBOOT for it, and if the board have an 16550 compatible
uart, you can select SYS_SUPPORTS_ZBOOT_UART16550 directly. and then
sending the relative patches to Ralf.

Tested-by: Manuel Lauss <manuel.lauss@googlemail.com>
Tested-by: Alexander Clouter <alex@digriz.org.uk>
Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
  • Loading branch information
Wu Zhangjin authored and Ralf Baechle committed Dec 17, 2009
1 parent bea4c89 commit 1b93b3c
Show file tree
Hide file tree
Showing 9 changed files with 558 additions and 3 deletions.
14 changes: 14 additions & 0 deletions arch/mips/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ choice

config MACH_ALCHEMY
bool "Alchemy processor based machines"
select SYS_SUPPORTS_ZBOOT

config AR7
bool "Texas Instruments AR7"
Expand All @@ -36,6 +37,7 @@ config AR7
select SYS_HAS_EARLY_PRINTK
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_ZBOOT_UART16550
select GENERIC_GPIO
select GCD
select VLYNQ
Expand Down Expand Up @@ -192,6 +194,7 @@ config LASAT

config MACH_LOONGSON
bool "Loongson family of machines"
select SYS_SUPPORTS_ZBOOT_UART16550
help
This enables the support of Loongson family of machines.

Expand Down Expand Up @@ -233,6 +236,7 @@ config MIPS_MALTA
select SYS_SUPPORTS_MIPS_CMP
select SYS_SUPPORTS_MULTITHREADING
select SYS_SUPPORTS_SMARTMIPS
select SYS_SUPPORTS_ZBOOT
help
This enables support for the MIPS Technologies Malta evaluation
board.
Expand Down Expand Up @@ -1294,6 +1298,16 @@ config CPU_CAVIUM_OCTEON

endchoice

config SYS_SUPPORTS_ZBOOT
bool
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA

config SYS_SUPPORTS_ZBOOT_UART16550
bool
select SYS_SUPPORTS_ZBOOT

config CPU_LOONGSON2
bool
select CPU_SUPPORTS_32BIT_KERNEL
Expand Down
31 changes: 28 additions & 3 deletions arch/mips/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ endif

all-$(CONFIG_BOOT_ELF32) := $(vmlinux-32)
all-$(CONFIG_BOOT_ELF64) := $(vmlinux-64)
all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz

#
# GCC uses -G 0 -mabicalls -fpic as default. We don't want PIC in the kernel
Expand Down Expand Up @@ -331,7 +332,7 @@ load-$(CONFIG_LEMOTE_FULOONG2E) +=0xffffffff80100000
core-$(CONFIG_MIPS_MALTA) += arch/mips/mti-malta/
cflags-$(CONFIG_MIPS_MALTA) += -I$(srctree)/arch/mips/include/asm/mach-malta
load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
all-$(CONFIG_MIPS_MALTA) := vmlinux.bin
all-$(CONFIG_MIPS_MALTA) := vmlinuz.bin

#
# MIPS SIM
Expand Down Expand Up @@ -581,7 +582,7 @@ load-$(CONFIG_SNI_RM) += 0xffffffff80600000
else
load-$(CONFIG_SNI_RM) += 0xffffffff80030000
endif
all-$(CONFIG_SNI_RM) := vmlinux.ecoff
all-$(CONFIG_SNI_RM) := vmlinuz.ecoff

#
# Common TXx9
Expand Down Expand Up @@ -699,9 +700,23 @@ vmlinux.64: vmlinux
$(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@

makeboot =$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) $(1)
makezboot =$(Q)$(MAKE) $(build)=arch/mips/boot/compressed \
VMLINUX_LOAD_ADDRESS=$(load-y) 32bit-bfd=$(32bit-bfd) $(1)

all: $(all-y)

vmlinuz: vmlinux FORCE
+@$(call makezboot,$@)

vmlinuz.bin: vmlinux
+@$(call makezboot,$@)

vmlinuz.ecoff: vmlinux
+@$(call makezboot,$@)

vmlinuz.srec: vmlinux
+@$(call makezboot,$@)

vmlinux.bin: $(vmlinux-32)
+@$(call makeboot,$@)

Expand All @@ -726,22 +741,32 @@ endif

install:
$(Q)install -D -m 755 vmlinux $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE)
$(Q)install -D -m 755 vmlinuz $(INSTALL_PATH)/vmlinuz-$(KERNELRELEASE)
$(Q)install -D -m 644 .config $(INSTALL_PATH)/config-$(KERNELRELEASE)
$(Q)install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE)

archclean:
@$(MAKE) $(clean)=arch/mips/boot
@$(MAKE) $(clean)=arch/mips/boot/compressed
@$(MAKE) $(clean)=arch/mips/lasat

define archhelp
echo ' install - install kernel into $(INSTALL_PATH)'
echo ' vmlinux.ecoff - ECOFF boot image'
echo ' vmlinux.bin - Raw binary boot image'
echo ' vmlinux.srec - SREC boot image'
echo ' vmlinuz - Compressed boot(zboot) image'
echo ' vmlinuz.ecoff - ECOFF zboot image'
echo ' vmlinuz.bin - Raw binary zboot image'
echo ' vmlinuz.srec - SREC zboot image'
echo
echo ' These will be default as apropriate for a configured platform.'
endef

CLEAN_FILES += vmlinux.32 \
vmlinux.64 \
vmlinux.ecoff
vmlinux.ecoff \
vmlinuz \
vmlinuz.ecoff \
vmlinuz.bin \
vmlinuz.srec
100 changes: 100 additions & 0 deletions arch/mips/boot/compressed/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#
# This file is subject to the terms and conditions of the GNU General Public
# License.
#
# Adapted for MIPS Pete Popov, Dan Malek
#
# Copyright (C) 1994 by Linus Torvalds
# Adapted for PowerPC by Gary Thomas
# modified by Cort (cort@cs.nmt.edu)
#
# Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University
# Author: Wu Zhangjin <wuzj@lemote.com>
#

# compressed kernel load addr: VMLINUZ_LOAD_ADDRESS > VMLINUX_LOAD_ADDRESS + VMLINUX_SIZE
VMLINUX_SIZE := $(shell wc -c $(objtree)/$(KBUILD_IMAGE) 2>/dev/null | cut -d' ' -f1)
VMLINUX_SIZE := $(shell [ -n "$(VMLINUX_SIZE)" ] && echo $$(($(VMLINUX_SIZE) + (65536 - $(VMLINUX_SIZE) % 65536))))
VMLINUZ_LOAD_ADDRESS := 0x$(shell [ -n "$(VMLINUX_SIZE)" ] && printf %x $$(($(VMLINUX_LOAD_ADDRESS) + $(VMLINUX_SIZE))))

# set the default size of the mallocing area for decompressing
BOOT_HEAP_SIZE := 0x400000

# Disable Function Tracer
KBUILD_CFLAGS := $(shell echo $(KBUILD_CFLAGS) | sed -e "s/-pg//")

KBUILD_CFLAGS := $(LINUXINCLUDE) $(KBUILD_CFLAGS) -D__KERNEL__ \
-DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull" \

KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
-DKERNEL_ENTRY=0x$(shell $(NM) $(objtree)/$(KBUILD_IMAGE) 2>/dev/null | grep " kernel_entry" | cut -f1 -d \ ) \
-DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE)

obj-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o

obj-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o

OBJCOPYFLAGS_vmlinux.bin := $(OBJCOPYFLAGS) -O binary -R .comment -S
$(obj)/vmlinux.bin: $(KBUILD_IMAGE)
$(call if_changed,objcopy)

suffix_$(CONFIG_KERNEL_GZIP) = gz
suffix_$(CONFIG_KERNEL_BZIP2) = bz2
suffix_$(CONFIG_KERNEL_LZMA) = lzma
tool_$(CONFIG_KERNEL_GZIP) = gzip
tool_$(CONFIG_KERNEL_BZIP2) = bzip2
tool_$(CONFIG_KERNEL_LZMA) = lzma
$(obj)/vmlinux.$(suffix_y): $(obj)/vmlinux.bin
$(call if_changed,$(tool_y))

$(obj)/piggy.o: $(obj)/vmlinux.$(suffix_y) $(obj)/dummy.o
$(Q)$(OBJCOPY) $(OBJCOPYFLAGS) \
--add-section=.image=$< \
--set-section-flags=.image=contents,alloc,load,readonly,data \
$(obj)/dummy.o $@

LDFLAGS_vmlinuz := $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T
vmlinuz: $(src)/ld.script $(obj-y) $(obj)/piggy.o
$(call if_changed,ld)
$(Q)$(OBJCOPY) $(OBJCOPYFLAGS) -R .comment -R .stab -R .stabstr -R .initrd -R .sysmap $@

#
# Some DECstations need all possible sections of an ECOFF executable
#
ifdef CONFIG_MACH_DECSTATION
E2EFLAGS = -a
else
E2EFLAGS =
endif

# elf2ecoff can only handle 32bit image

ifdef CONFIG_32BIT
VMLINUZ = vmlinuz
else
VMLINUZ = vmlinuz.32
endif

vmlinuz.32: vmlinuz
$(Q)$(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@

vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ)
$(Q)$(obj)/../elf2ecoff $(VMLINUZ) vmlinuz.ecoff $(E2EFLAGS)

$(obj)/../elf2ecoff: $(src)/../elf2ecoff.c
$(Q)$(HOSTCC) -o $@ $^

drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options
strip-flags = $(addprefix --remove-section=,$(drop-sections))

OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary $(strip-flags)
vmlinuz.bin: vmlinuz
$(call if_changed,objcopy)

OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec $(strip-flags)
vmlinuz.srec: vmlinuz
$(call if_changed,objcopy)

clean:
clean-files += *.o \
vmlinu*
37 changes: 37 additions & 0 deletions arch/mips/boot/compressed/dbg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* MIPS-specific debug support for pre-boot environment
*
* NOTE: putc() is board specific, if your board have a 16550 compatible uart,
* please select SYS_SUPPORTS_ZBOOT_UART16550 for your machine. othewise, you
* need to implement your own putc().
*/

#include <linux/init.h>
#include <linux/types.h>

void __attribute__ ((weak)) putc(char c)
{
}

void puts(const char *s)
{
char c;
while ((c = *s++) != '\0') {
putc(c);
if (c == '\n')
putc('\r');
}
}

void puthex(unsigned long long val)
{

unsigned char buf[10];
int i;
for (i = 7; i >= 0; i--) {
buf[i] = "0123456789ABCDEF"[val & 0x0F];
val >>= 4;
}
buf[8] = '\0';
puts(buf);
}
126 changes: 126 additions & 0 deletions arch/mips/boot/compressed/decompress.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Misc. bootloader code for many machines.
*
* Copyright 2001 MontaVista Software Inc.
* Author: Matt Porter <mporter@mvista.com> Derived from
* arch/ppc/boot/prep/misc.c
*
* Copyright (C) 2009 Lemote, Inc. & Institute of Computing Technology
* Author: Wu Zhangjin <wuzj@lemote.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/

#include <linux/types.h>
#include <linux/kernel.h>

#include <asm/addrspace.h>

/* These two variables specify the free mem region
* that can be used for temporary malloc area
*/
unsigned long free_mem_ptr;
unsigned long free_mem_end_ptr;
char *zimage_start;

/* The linker tells us where the image is. */
extern unsigned char __image_begin, __image_end;
extern unsigned char __ramdisk_begin, __ramdisk_end;
unsigned long initrd_size;

/* debug interfaces */
extern void puts(const char *s);
extern void puthex(unsigned long long val);

void error(char *x)
{
puts("\n\n");
puts(x);
puts("\n\n -- System halted");

while (1)
; /* Halt */
}

/* activate the code for pre-boot environment */
#define STATIC static

#ifdef CONFIG_KERNEL_GZIP
void *memcpy(void *dest, const void *src, size_t n)
{
int i;
const char *s = src;
char *d = dest;

for (i = 0; i < n; i++)
d[i] = s[i];
return dest;
}
#include "../../../../lib/decompress_inflate.c"
#endif

#ifdef CONFIG_KERNEL_BZIP2
void *memset(void *s, int c, size_t n)
{
int i;
char *ss = s;

for (i = 0; i < n; i++)
ss[i] = c;
return s;
}
#include "../../../../lib/decompress_bunzip2.c"
#endif

#ifdef CONFIG_KERNEL_LZMA
#include "../../../../lib/decompress_unlzma.c"
#endif

void decompress_kernel(unsigned long boot_heap_start)
{
int zimage_size;

/*
* We link ourself to an arbitrary low address. When we run, we
* relocate outself to that address. __image_beign points to
* the part of the image where the zImage is. -- Tom
*/
zimage_start = (char *)(unsigned long)(&__image_begin);
zimage_size = (unsigned long)(&__image_end) -
(unsigned long)(&__image_begin);

/*
* The zImage and initrd will be between start and _end, so they've
* already been moved once. We're good to go now. -- Tom
*/
puts("zimage at: ");
puthex((unsigned long)zimage_start);
puts(" ");
puthex((unsigned long)(zimage_size + zimage_start));
puts("\n");

if (initrd_size) {
puts("initrd at: ");
puthex((unsigned long)(&__ramdisk_begin));
puts(" ");
puthex((unsigned long)(&__ramdisk_end));
puts("\n");
}

/* this area are prepared for mallocing when decompressing */
free_mem_ptr = boot_heap_start;
free_mem_end_ptr = boot_heap_start + BOOT_HEAP_SIZE;

/* Display standard Linux/MIPS boot prompt for kernel args */
puts("Uncompressing Linux at load address ");
puthex(VMLINUX_LOAD_ADDRESS_ULL);
puts("\n");
/* Decompress the kernel with according algorithm */
decompress(zimage_start, zimage_size, 0, 0,
(void *)VMLINUX_LOAD_ADDRESS_ULL, 0, error);
/* FIXME: is there a need to flush cache here? */
puts("Now, booting the kernel...\n");
}
Loading

0 comments on commit 1b93b3c

Please sign in to comment.