Ian Campbell
2008-Feb-13 12:56 UTC
[PATCHv3 1/3] x86: use ELF format in compressed images.
This allows other boot loaders such as the Xen domain builder the opportunity to extract the ELF file. Signed-off-by: Ian Campbell <ijc@hellion.org.uk> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Jeremy Fitzhardinge <jeremy@goop.org> Cc: virtualization@lists.linux-foundation.org --- 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 deletions(-) diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt index fc49b79..b5f5ba1 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 f88458e..9695aff 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 d2b9f3b..92fdd35 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 8182e32..69aec2f 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 <linux/linkage.h> #include <linux/screen_info.h> +#include <linux/elf.h> #include <asm/io.h> #include <asm/page.h> #include <asm/boot.h> @@ -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; i<ehdr.e_phnum; i++) { + phdr = &phdrs[i]; + + switch (phdr->p_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 64ad901..8471658 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -22,6 +22,7 @@ #include <asm/page.h> #include <asm/setup.h> #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" -- 1.5.4
Mark McLoughlin
2008-Feb-14 11:34 UTC
[PATCHv3 1/3] x86: use ELF format in compressed images.
On Wed, 2008-02-13 at 20:54 +0000, Ian Campbell wrote:> This allows other boot loaders such as the Xen domain builder the > opportunity to extract the ELF file.Right, Xen currently can't boot bzImage (it needs the ELF image) so you still can't use the same kernel image on Xen as bare-metal.> +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.Should probably mention that the payload format is expected to be ELF.> diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile > index f88458e..9695aff 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.hHow about this? +sed-offsets := -e 's/^00*/0/' \ + -e 's/^\([0-9a-fA-F]*\) . \(input_data\|input_data_end\)$$/-D\2=0x\1 /p' + +$(obj)/header.o: AFLAGS_header.o += $(shell $(NM) $(obj)/compressed/vmlinux | sed -n $(sed-offsets)) +$(obj)/header.o: $(obj)/compressed/vmlinux FORCE Cheers, Mark.
On Wed, Feb 13, 2008 at 1:54 PM, Ian Campbell <ijc at hellion.org.uk> wrote:> This allows other boot loaders such as the Xen domain builder the > opportunity to extract the ELF file. > > Signed-off-by: Ian Campbell <ijc at hellion.org.uk> > Cc: Thomas Gleixner <tglx at linutronix.de> > Cc: Ingo Molnar <mingo at redhat.com> > Cc: H. Peter Anvin <hpa at zytor.com> > Cc: Jeremy Fitzhardinge <jeremy at goop.org> > Cc: virtualization at lists.linux-foundation.org > --- > 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 deletions(-) > > diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt > index fc49b79..b5f5ba1 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 f88458e..9695aff 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 d2b9f3b..92fdd35 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 8182e32..69aec2f 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 <linux/linkage.h> > #include <linux/screen_info.h> > +#include <linux/elf.h> > #include <asm/io.h> > #include <asm/page.h> > #include <asm/boot.h> > @@ -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; i<ehdr.e_phnum; i++) { > + phdr = &phdrs[i]; > + > + switch (phdr->p_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;so will cost every bzImage extra memory copy? that could be 18M or even more big. wonder if can have one some other kind elf format, and offset load address to avoid that mem copy. YH
Ian Campbell
2008-Apr-06 10:22 UTC
[PATCHv3 1/3] x86: use ELF format in compressed images.
On Sun, 2008-04-06 at 00:03 -0700, Yinghai Lu wrote:> so will cost every bzImage extra memory copy? that could be 18M or > even more big.Is it a huge deal for something that happens exactly once on boot? How does the time take compare with the time to do the decompression? 18M seems like an awfully large kernel image to me. My distro (Debian) kernel is more like 3M uncompressed. If someone was interested in fast booting presumably they would either build a kernel with exactly what they need.> wonder if can have one some other kind elf format, and offset load > address to avoid that mem copy.I guess you could reduce the load address by sizeof(headers) and add a dest == (output + phdr->p_offset) test before the copy. Another possibility, which is much more complex, is that the ELF parsing could be integrated into the decompressor such that the data is decompressed into the correct location directly. Ian. -- Ian Campbell People who have no faults are terrible; there is no way of taking advantage of them. -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: This is a digitally signed message part Url : http://lists.linux-foundation.org/pipermail/virtualization/attachments/20080406/2f87d9cd/attachment.pgp
H. Peter Anvin
2008-Apr-06 16:38 UTC
[PATCHv3 1/3] x86: use ELF format in compressed images.
Yinghai Lu wrote:> so will cost every bzImage extra memory copy? that could be 18M or > even more big.I wouldn't worry about that. You will typically have several copies of the images during the execution of the boot loader. -hpa
Reasonably Related Threads
- [PATCHv3 1/3] x86: use ELF format in compressed images.
- [PATCH] x86: use ELF format in compressed images.
- [PATCH] x86: use ELF format in compressed images.
- [PATCHv2 1/3] x86: use ELF format in compressed images.
- [PATCHv2 1/3] x86: use ELF format in compressed images.