linux-stable/arch/arm/boot/deflate_xip_data.sh
Nicolas Pitre ca8b5d97d6 ARM: XIP kernel: store .data compressed in ROM
The .data segment stored in ROM is only copied to RAM once at boot time
and never referenced afterwards. This is arguably a suboptimal usage of
ROM resources.

This patch allows for compressing the .data segment before storing it
into ROM and decompressing it to RAM rather than simply copying it,
saving on precious ROM space.

Because global data is not available yet (obviously) we must allocate
decompressor workspace memory on the stack. The .bss area is used as a
stack area for that purpose before it is cleared. The required stack
frame is 9568 bytes for __inflate_kernel_data() alone, so make sure
the .bss is large enough to cope with that plus extra room for called
functions or fail the build.

Those numbers were picked arbitrarily based on the above 9568 byte
stack frame:

10240 (2.5 * PAGE_SIZE): used to override -Wframe-larger-than whose
default value is 1024.
12288 (3 * PAGE_SIZE): minimum .bss size to contain the stack.

Signed-off-by: Nicolas Pitre <nico@linaro.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Tested-by: Chris Brandt <Chris.Brandt@renesas.com>
2017-09-10 19:34:53 -04:00

64 lines
1.7 KiB
Bash
Executable file

#!/bin/sh
# XIP kernel .data segment compressor
#
# Created by: Nicolas Pitre, August 2017
# Copyright: (C) 2017 Linaro Limited
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
# This script locates the start of the .data section in xipImage and
# substitutes it with a compressed version. The needed offsets are obtained
# from symbol addresses in vmlinux. It is expected that .data extends to
# the end of xipImage.
set -e
VMLINUX="$1"
XIPIMAGE="$2"
DD="dd status=none"
# Use "make V=1" to debug this script.
case "$KBUILD_VERBOSE" in
*1*)
set -x
;;
esac
sym_val() {
# extract hex value for symbol in $1
local val=$($NM "$VMLINUX" | sed -n "/ $1$/{s/ .*$//p;q}")
[ "$val" ] || { echo "can't find $1 in $VMLINUX" 1>&2; exit 1; }
# convert from hex to decimal
echo $((0x$val))
}
__data_loc=$(sym_val __data_loc)
_edata_loc=$(sym_val _edata_loc)
base_offset=$(sym_val _xiprom)
# convert to file based offsets
data_start=$(($__data_loc - $base_offset))
data_end=$(($_edata_loc - $base_offset))
# Make sure data occupies the last part of the file.
file_end=$(stat -c "%s" "$XIPIMAGE")
if [ "$file_end" != "$data_end" ]; then
printf "end of xipImage doesn't match with _edata_loc (%#x vs %#x)\n" \
$(($file_end + $base_offset)) $_edata_loc 2>&1
exit 1;
fi
# be ready to clean up
trap 'rm -f "$XIPIMAGE.tmp"' 0 1 2 3
# substitute the data section by a compressed version
$DD if="$XIPIMAGE" count=$data_start iflag=count_bytes of="$XIPIMAGE.tmp"
$DD if="$XIPIMAGE" skip=$data_start iflag=skip_bytes |
gzip -9 >> "$XIPIMAGE.tmp"
# replace kernel binary
mv -f "$XIPIMAGE.tmp" "$XIPIMAGE"