From 099e1377269a47ed30a00ee131001988e5bcaa9c Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 13 Feb 2008 20:54:58 +0000 Subject: [PATCH] x86: use ELF format in compressed images. Signed-off-by: Ian Campbell Cc: Ian Campbell Cc: Jeremy Fitzhardinge Cc: virtualization@lists.linux-foundation.org Cc: H. Peter Anvin Cc: Jeremy Fitzhardinge Cc: virtualization@lists.linux-foundation.org Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- Documentation/i386/boot.txt | 18 ++++++++++ arch/x86/boot/Makefile | 14 ++++++++ arch/x86/boot/compressed/Makefile | 2 +- arch/x86/boot/compressed/misc.c | 56 +++++++++++++++++++++++++++++++ arch/x86/boot/header.S | 6 ++++ 5 files changed, 95 insertions(+), 1 deletion(-) diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt index fc49b79bc1ab..b5f5ba1ea668 100644 --- a/Documentation/i386/boot.txt +++ b/Documentation/i386/boot.txt @@ -170,6 +170,8 @@ Offset Proto Name Meaning 0238/4 2.06+ cmdline_size Maximum size of the kernel command line 023C/4 2.07+ hardware_subarch Hardware subarchitecture 0240/8 2.07+ hardware_subarch_data Subarchitecture-specific data +0248/4 2.08+ compressed_payload_offset +024C/4 2.08+ compressed_payload_length (1) For backwards compatibility, if the setup_sects field contains 0, the real value is 4. @@ -512,6 +514,22 @@ Protocol: 2.07+ A pointer to data that is specific to hardware subarch +Field name: compressed_payload_offset +Type: read +Offset/size: 0x248/4 +Protocol: 2.08+ + + If non-zero then this field contains the offset from the end of the + real-mode code to the compressed payload. The compression format + should be determined using the standard magic number, currently only + gzip is used. + +Field name: compressed_payload_length +Type: read +Offset/size: 0x24c/4 +Protocol: 2.08+ + + The length of the compressed payload. **** THE KERNEL COMMAND LINE diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile index f88458e83ef0..9695affeb584 100644 --- a/arch/x86/boot/Makefile +++ b/arch/x86/boot/Makefile @@ -94,6 +94,20 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE SETUP_OBJS = $(addprefix $(obj)/,$(setup-y)) +sed-offsets := -e 's/^00*/0/' \ + -e 's/^\([0-9a-fA-F]*\) . \(input_data\|input_data_end\)$$/\#define \2 0x\1/p' + +quiet_cmd_offsets = OFFSETS $@ + cmd_offsets = $(NM) $< | sed -n $(sed-offsets) > $@ + +$(obj)/offsets.h: $(obj)/compressed/vmlinux FORCE + $(call if_changed,offsets) + +targets += offsets.h + +AFLAGS_header.o += -I$(obj) +$(obj)/header.o: $(obj)/offsets.h + LDFLAGS_setup.elf := -T $(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE $(call if_changed,ld) diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index d2b9f3bb87c0..92fdd35bd93e 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -22,7 +22,7 @@ $(obj)/vmlinux: $(src)/vmlinux_$(BITS).lds $(obj)/head_$(BITS).o $(obj)/misc.o $ $(call if_changed,ld) @: -OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S +OBJCOPYFLAGS_vmlinux.bin := -R .comment -S $(obj)/vmlinux.bin: vmlinux FORCE $(call if_changed,objcopy) diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index 8182e32c1b42..69aec2f4155d 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -15,6 +15,10 @@ * we just keep it from happening */ #undef CONFIG_PARAVIRT +#ifdef CONFIG_X86_32 +#define _ASM_DESC_H_ 1 +#endif + #ifdef CONFIG_X86_64 #define _LINUX_STRING_H_ 1 #define __LINUX_BITMAP_H 1 @@ -22,6 +26,7 @@ #include #include +#include #include #include #include @@ -365,6 +370,56 @@ static void error(char *x) asm("hlt"); } +static void parse_elf(void *output) +{ +#ifdef CONFIG_X86_64 + Elf64_Ehdr ehdr; + Elf64_Phdr *phdrs, *phdr; +#else + Elf32_Ehdr ehdr; + Elf32_Phdr *phdrs, *phdr; +#endif + void *dest; + int i; + + memcpy(&ehdr, output, sizeof(ehdr)); + if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || + ehdr.e_ident[EI_MAG1] != ELFMAG1 || + ehdr.e_ident[EI_MAG2] != ELFMAG2 || + ehdr.e_ident[EI_MAG3] != ELFMAG3) + { + error("Kernel is not a valid ELF file"); + return; + } + + putstr("Parsing ELF... "); + + phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum); + if (!phdrs) + error("Failed to allocate space for phdrs"); + + memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum); + + for (i=0; ip_type) { + case PT_LOAD: +#ifdef CONFIG_RELOCATABLE + dest = output; + dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR); +#else + dest = (void*)(phdr->p_paddr); +#endif + memcpy(dest, + output + phdr->p_offset, + phdr->p_filesz); + break; + default: /* Ignore other PT_* */ break; + } + } +} + asmlinkage void decompress_kernel(void *rmode, memptr heap, uch *input_data, unsigned long input_len, uch *output) @@ -408,6 +463,7 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap, makecrc(); putstr("\nDecompressing Linux... "); gunzip(); + parse_elf(output); putstr("done.\nBooting the kernel.\n"); return; } diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 64ad9016585a..8471658d5534 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -22,6 +22,7 @@ #include #include #include "boot.h" +#include "offsets.h" SETUPSECTS = 4 /* default nr of setup-sectors */ BOOTSEG = 0x07C0 /* original address of boot-sector */ @@ -223,6 +224,11 @@ hardware_subarch: .long 0 # subarchitecture, added with 2.07 hardware_subarch_data: .quad 0 +compressed_payload_offset: + .long input_data +compressed_payload_length: + .long input_data_end-input_data + # End of setup header ##################################################### .section ".inittext", "ax" -- 2.39.5