Skip to content

Commit

Permalink
x86, boot: determine compressed code offset at compile time
Browse files Browse the repository at this point in the history
Determine the compressed code offset (from the kernel runtime address)
at compile time.  This allows some minor optimizations in
arch/x86/boot/compressed/head_*.S, but more importantly it makes this
value available to the build process, which will enable a future patch
to export the necessary linear memory footprint into the bzImage
header.

[ Impact: cleanup, future patch enabling ]

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
  • Loading branch information
H. Peter Anvin committed May 9, 2009
1 parent 36d3793 commit 02a884c
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 60 deletions.
11 changes: 8 additions & 3 deletions arch/x86/boot/compressed/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
LDFLAGS := -m elf_$(UTS_MACHINE)
LDFLAGS_vmlinux := -T

hostprogs-y := mkpiggy

$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o $(obj)/piggy.o FORCE
$(call if_changed,ld)
@:
Expand Down Expand Up @@ -50,6 +52,9 @@ suffix-$(CONFIG_KERNEL_GZIP) := gz
suffix-$(CONFIG_KERNEL_BZIP2) := bz2
suffix-$(CONFIG_KERNEL_LZMA) := lzma

LDFLAGS_piggy.o := -r --format binary --oformat $(CONFIG_OUTPUT_FORMAT) -T
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) FORCE
$(call if_changed,ld)
quiet_cmd_mkpiggy = MKPIGGY $@
cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false )

targets += piggy.S
$(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE
$(call if_changed,mkpiggy)
24 changes: 5 additions & 19 deletions arch/x86/boot/compressed/head_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,8 @@ ENTRY(startup_32)
movl $LOAD_PHYSICAL_ADDR, %ebx
#endif

/* Replace the compressed data size with the uncompressed size */
subl input_len(%ebp), %ebx
movl output_len(%ebp), %eax
addl %eax, %ebx
/* Add 8 bytes for every 32K input block */
shrl $12, %eax
addl %eax, %ebx
/* Add 32K + 18 bytes of extra slack */
addl $(32768 + 18), %ebx
/* Align on a 4K boundary */
addl $4095, %ebx
andl $~4095, %ebx
/* Target address to relocate to for decompression */
addl $z_extract_offset, %ebx

/* Set up the stack */
leal boot_stack_end(%ebx), %esp
Expand Down Expand Up @@ -142,27 +132,23 @@ relocated:
/*
* Do the decompression, and jump to the new kernel..
*/
movl output_len(%ebx), %eax
pushl %eax
leal z_extract_offset_negative(%ebx), %ebp
/* push arguments for decompress_kernel: */
pushl %ebp /* output address */
movl input_len(%ebx), %eax
pushl %eax /* input_len */
pushl $z_input_len /* input_len */
leal input_data(%ebx), %eax
pushl %eax /* input_data */
leal boot_heap(%ebx), %eax
pushl %eax /* heap area */
pushl %esi /* real mode pointer */
call decompress_kernel
addl $20, %esp
popl %ecx

#if CONFIG_RELOCATABLE
/*
* Find the address of the relocations.
*/
movl %ebp, %edi
addl %ecx, %edi
leal z_output_len(%ebp), %edi

/*
* Calculate the delta between where vmlinux was compiled to run
Expand Down
41 changes: 13 additions & 28 deletions arch/x86/boot/compressed/head_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,8 @@ ENTRY(startup_32)
movl $CONFIG_PHYSICAL_START, %ebx
#endif

/* Replace the compressed data size with the uncompressed size */
subl input_len(%ebp), %ebx
movl output_len(%ebp), %eax
addl %eax, %ebx
/* Add 8 bytes for every 32K input block */
shrl $12, %eax
addl %eax, %ebx
/* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
addl $(32768 + 18 + 4095), %ebx
andl $~4095, %ebx
/* Target address to relocate to for decompression */
addl $z_extract_offset, %ebx

/*
* Prepare for entering 64 bit mode
Expand Down Expand Up @@ -224,6 +216,9 @@ ENTRY(startup_64)
* If it is a relocatable kernel then decompress and run the kernel
* from load address aligned to 2MB addr, otherwise decompress and
* run the kernel from CONFIG_PHYSICAL_START
*
* We cannot rely on the calculation done in 32-bit mode, since we
* may have been invoked via the 64-bit entry point.
*/

/* Start with the delta to where the kernel will run at. */
Expand All @@ -237,17 +232,8 @@ ENTRY(startup_64)
movq %rbp, %rbx
#endif

/* Replace the compressed data size with the uncompressed size */
movl input_len(%rip), %eax
subq %rax, %rbx
movl output_len(%rip), %eax
addq %rax, %rbx
/* Add 8 bytes for every 32K input block */
shrq $12, %rax
addq %rax, %rbx
/* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
addq $(32768 + 18 + 4095), %rbx
andq $~4095, %rbx
/* Target address to relocate to for decompression */
leaq z_extract_offset(%rbp), %rbx

/* Set up the stack */
leaq boot_stack_end(%rbx), %rsp
Expand Down Expand Up @@ -292,13 +278,12 @@ relocated:
/*
* Do the decompression, and jump to the new kernel..
*/
pushq %rsi # Save the real mode argument
movq %rsi, %rdi # real mode address
leaq boot_heap(%rip), %rsi # malloc area for uncompression
leaq input_data(%rip), %rdx # input_data
movl input_len(%rip), %eax
movq %rax, %rcx # input_len
movq %rbp, %r8 # output
pushq %rsi /* Save the real mode argument */
movq %rsi, %rdi /* real mode address */
leaq boot_heap(%rip), %rsi /* malloc area for uncompression */
leaq input_data(%rip), %rdx /* input_data */
movl $z_input_len, %ecx /* input_len */
movq %rbp, %r8 /* output target address */
call decompress_kernel
popq %rsi

Expand Down
97 changes: 97 additions & 0 deletions arch/x86/boot/compressed/mkpiggy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* ----------------------------------------------------------------------- *
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* 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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* H. Peter Anvin <hpa@linux.intel.com>
*
* ----------------------------------------------------------------------- */

/*
* Compute the desired load offset from a compressed program; outputs
* a small assembly wrapper with the appropriate symbols defined.
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

static uint32_t getle32(const void *p)
{
const uint8_t *cp = p;

return (uint32_t)cp[0] + ((uint32_t)cp[1] << 8) +
((uint32_t)cp[2] << 16) + ((uint32_t)cp[3] << 24);
}

int main(int argc, char *argv[])
{
uint32_t olen;
long ilen;
unsigned long offs;
FILE *f;

if (argc < 2) {
fprintf(stderr, "Usage: %s compressed_file\n", argv[0]);
return 1;
}

/* Get the information for the compressed kernel image first */

f = fopen(argv[1], "r");
if (!f) {
perror(argv[1]);
return 1;
}


if (fseek(f, -4L, SEEK_END)) {
perror(argv[1]);
}
fread(&olen, sizeof olen, 1, f);
ilen = ftell(f);
olen = getle32(&olen);
fclose(f);

/*
* Now we have the input (compressed) and output (uncompressed)
* sizes, compute the necessary decompression offset...
*/

offs = (olen > ilen) ? olen - ilen : 0;
offs += olen >> 12; /* Add 8 bytes for each 32K block */
offs += 32*1024 + 18; /* Add 32K + 18 bytes slack */
offs = (offs+4095) & ~4095; /* Round to a 4K boundary */

printf(".section \".rodata.compressed\",\"a\",@progbits\n");
printf(".globl z_input_len\n");
printf("z_input_len = %lu\n", ilen);
printf(".globl z_output_len\n");
printf("z_output_len = %lu\n", (unsigned long)olen);
printf(".globl z_extract_offset\n");
printf("z_extract_offset = 0x%lx\n", offs);
/* z_extract_offset_negative allows simplification of head_32.S */
printf(".globl z_extract_offset_negative\n");
printf("z_extract_offset_negative = -0x%lx\n", offs);

printf(".globl input_data, input_data_end\n");
printf("input_data:\n");
printf(".incbin \"%s\"\n", argv[1]);
printf("input_data_end:\n");

return 0;
}
10 changes: 0 additions & 10 deletions arch/x86/boot/compressed/vmlinux.scr

This file was deleted.

0 comments on commit 02a884c

Please sign in to comment.