public inbox for kexec@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH v4 0/6] kexec: put bzImage and ramdisk above 4G for x86 64bit
@ 2012-11-24 20:47 Yinghai Lu
  2012-11-24 20:47 ` [PATCH v4 1/6] kexec, x86: clean boot_params area for entry-32bit path Yinghai Lu
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Yinghai Lu @ 2012-11-24 20:47 UTC (permalink / raw)
  To: Simon Horman, H. Peter Anvin, Vivek Goyal, Haren Myneni,
	Eric W. Biederman
  Cc: Yinghai Lu, kexec

Now we have limit kdump reserved under 896M, because kexec has the limitation.
and also bzImage need to stay under 4g.

kernel parts changes could be found at:
        git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-x86-boot

here patches are for kexec tools to load bzImage and ramdisk high acccording
to new added boot header fields.

-v3: address review from Eric to use locate_hole at first.
     use xloadflags instead.
-v4: remove the restriction about bzImage not crossing GB boundary.
     add real-mode fix for bzImage.
     add --entry-32bit and --real-mode for skip bzImage64.

Yinghai Lu (6):
  kexec, x86: clean boot_params area for entry-32bit path
  kexec, x86: Fix bzImage real-mode booting
  kexec, x86: add boot header member for version 2.12
  kexec, x86: put ramdisk high for 64bit bzImage
  kexec, x86: set ext_cmd_line_ptr when boot_param is above 4g
  kexec, x86_64: Load bzImage64 above 4G

 include/x86/x86-linux.h                |   32 +++-
 kexec/arch/i386/include/arch/options.h |    4 +-
 kexec/arch/i386/kexec-bzImage.c        |   80 +++++++--
 kexec/arch/i386/x86-linux-setup.c      |   25 ++-
 kexec/arch/x86_64/Makefile             |    1 +
 kexec/arch/x86_64/kexec-bzImage64.c    |  334 ++++++++++++++++++++++++++++++++
 kexec/arch/x86_64/kexec-x86_64.c       |    1 +
 kexec/arch/x86_64/kexec-x86_64.h       |    5 +
 8 files changed, 460 insertions(+), 22 deletions(-)
 create mode 100644 kexec/arch/x86_64/kexec-bzImage64.c

-- 
1.7.7


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v4 1/6] kexec, x86: clean boot_params area for entry-32bit path
  2012-11-24 20:47 [PATCH v4 0/6] kexec: put bzImage and ramdisk above 4G for x86 64bit Yinghai Lu
@ 2012-11-24 20:47 ` Yinghai Lu
  2012-11-24 20:47 ` [PATCH v4 2/6] kexec, x86: Fix bzImage real-mode booting Yinghai Lu
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Yinghai Lu @ 2012-11-24 20:47 UTC (permalink / raw)
  To: Simon Horman, H. Peter Anvin, Vivek Goyal, Haren Myneni,
	Eric W. Biederman
  Cc: Yinghai Lu, kexec

kexec bzImage path setup data is shared with real-mode path, and
setup_header is copied together with setup_code.
Later 32bit just use whole area as boot_params for real_mode_data.
but those area for boot_params around setup_header is
not cleaned that will leave some field in boot_param as
non-zero value.

So clean around setup_header area for non real-mode entry path.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 kexec/arch/i386/kexec-bzImage.c |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/kexec/arch/i386/kexec-bzImage.c b/kexec/arch/i386/kexec-bzImage.c
index 6998587..80d09e7 100644
--- a/kexec/arch/i386/kexec-bzImage.c
+++ b/kexec/arch/i386/kexec-bzImage.c
@@ -98,6 +98,19 @@ void bzImage_usage(void)
        
 }
 
+static void clean_boot_params(unsigned char *real_mode, unsigned long size)
+{
+	unsigned long end;
+
+	/* clear value before header */
+	memset(real_mode, 0, 0x1f1);
+	/* clear value after setup_header  */
+	end = *(real_mode + 0x201);
+	end += 0x202;
+	if (end < size)
+		memset(real_mode + end, 0, size - end);
+}
+
 int do_bzImage_load(struct kexec_info *info,
 	const char *kernel, off_t kernel_len,
 	const char *command_line, off_t command_line_len,
@@ -212,6 +225,8 @@ int do_bzImage_load(struct kexec_info *info,
 	setup_size = kern16_size + command_line_len + PURGATORY_CMDLINE_SIZE;
 	real_mode = xmalloc(setup_size);
 	memcpy(real_mode, kernel, kern16_size);
+	if (!real_mode_entry)
+		clean_boot_params((unsigned char *)real_mode, kern16_size);
 
 	if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) {
 		/* If using bzImage for capture kernel, then we will not be
-- 
1.7.7


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 2/6] kexec, x86: Fix bzImage real-mode booting
  2012-11-24 20:47 [PATCH v4 0/6] kexec: put bzImage and ramdisk above 4G for x86 64bit Yinghai Lu
  2012-11-24 20:47 ` [PATCH v4 1/6] kexec, x86: clean boot_params area for entry-32bit path Yinghai Lu
@ 2012-11-24 20:47 ` Yinghai Lu
  2012-11-24 20:47 ` [PATCH v4 3/6] kexec, x86: add boot header member for version 2.12 Yinghai Lu
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Yinghai Lu @ 2012-11-24 20:47 UTC (permalink / raw)
  To: Simon Horman, H. Peter Anvin, Vivek Goyal, Haren Myneni,
	Eric W. Biederman
  Cc: Yinghai Lu, kexec

We need to keep space for bss, heap/stack before command line.
otherwise command_line will be cleared by kernel 16bit init code.

also need to set 32bit start in real_mode header, kernel 16bit code
need to jump there.

Also don't touch regs16 if --real-mode is not specified.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 kexec/arch/i386/kexec-bzImage.c |   63 +++++++++++++++++++++++++++++++-------
 1 files changed, 51 insertions(+), 12 deletions(-)

diff --git a/kexec/arch/i386/kexec-bzImage.c b/kexec/arch/i386/kexec-bzImage.c
index 80d09e7..d83f0a9 100644
--- a/kexec/arch/i386/kexec-bzImage.c
+++ b/kexec/arch/i386/kexec-bzImage.c
@@ -130,6 +130,8 @@ int do_bzImage_load(struct kexec_info *info,
 	unsigned long kernel32_load_addr;
 	char *modified_cmdline;
 	unsigned long cmdline_end;
+	unsigned long kern16_size_needed;
+	unsigned long heap_size = 0;
 
 	/*
 	 * Find out about the file I am about to load.
@@ -221,9 +223,31 @@ int do_bzImage_load(struct kexec_info *info,
 		elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
 					0x3000, 640*1024, -1, 0);
 	dbgprintf("Loaded purgatory at addr 0x%lx\n", info->rhdr.rel_addr);
+
 	/* The argument/parameter segment */
-	setup_size = kern16_size + command_line_len + PURGATORY_CMDLINE_SIZE;
+	if (real_mode_entry) {
+		/* need to include size for bss and heap etc */
+		if (setup_header.protocol_version >= 0x0201)
+			kern16_size_needed = setup_header.heap_end_ptr;
+		else
+			kern16_size_needed = kern16_size + 8192; /* bss */
+		if (kern16_size_needed < kern16_size)
+			kern16_size_needed = kern16_size;
+		if (kern16_size_needed > 0xfffc)
+			die("kern16_size_needed is more then 64k\n");
+		heap_size = 0xfffc - kern16_size_needed; /* less 64k */
+		heap_size &= ~(0x200 - 1);
+		kern16_size_needed += heap_size;
+	} else {
+		kern16_size_needed = kern16_size;
+		/* need to bigger than size of struct bootparams */
+		if (kern16_size_needed < 4096)
+			kern16_size_needed = 4096;
+	}
+	setup_size = kern16_size_needed + command_line_len +
+			 PURGATORY_CMDLINE_SIZE;
 	real_mode = xmalloc(setup_size);
+	memset(real_mode, 0, setup_size);
 	memcpy(real_mode, kernel, kern16_size);
 	if (!real_mode_entry)
 		clean_boot_params((unsigned char *)real_mode, kern16_size);
@@ -280,11 +304,20 @@ int do_bzImage_load(struct kexec_info *info,
 
 	/* Tell the kernel what is going on */
 	setup_linux_bootloader_parameters(info, real_mode, setup_base,
-		kern16_size, command_line, command_line_len,
+		kern16_size_needed, command_line, command_line_len,
 		initrd, initrd_len);
 
+	if (real_mode_entry) {
+		/* restore can use heap and load high */
+		real_mode->loader_flags = 0x81;
+		if (real_mode->protocol_version >= 0x0201)
+			real_mode->heap_end_ptr += heap_size - 0x200; /*stack*/
+	}
+
 	/* Get the initial register values */
-	elf_rel_get_symbol(&info->rhdr, "entry16_regs", &regs16, sizeof(regs16));
+	if (real_mode_entry)
+		elf_rel_get_symbol(&info->rhdr, "entry16_regs",
+					 &regs16, sizeof(regs16));
 	elf_rel_get_symbol(&info->rhdr, "entry32_regs", &regs32, sizeof(regs32));
 	/*
 
@@ -303,16 +336,18 @@ int do_bzImage_load(struct kexec_info *info,
 	/*
 	 * Initialize the 16bit start information.
 	 */
-	regs16.ds = regs16.es = regs16.fs = regs16.gs = setup_base >> 4;
-	regs16.cs = regs16.ds + 0x20;
-	regs16.ip = 0;
-	/* XXX: Documentation/i386/boot.txt says 'ss' must equal 'ds' */
-	regs16.ss = (elf_rel_get_addr(&info->rhdr, "stack_end") - 64*1024) >> 4;
-	/* XXX: Documentation/i386/boot.txt says 'sp' must equal heap_end */
-	regs16.esp = 0xFFFC;
 	if (real_mode_entry) {
+		regs16.ds = regs16.es = regs16.fs = regs16.gs = setup_base >> 4;
+		regs16.cs = regs16.ds + 0x20;
+		regs16.ip = 0;
+		/* XXX: Documentation/i386/boot.txt says 'ss' must equal 'ds' */
+		regs16.ss = (elf_rel_get_addr(&info->rhdr, "stack_end") - 64*1024) >> 4;
+		/* XXX: Documentation/i386/boot.txt says 'sp' must equal heap_end */
+		regs16.esp = 0xFFFC;
+
 		printf("Starting the kernel in real mode\n");
 		regs32.eip = elf_rel_get_addr(&info->rhdr, "entry16");
+		real_mode->kernel_start = kernel32_load_addr;
 	}
 	if (real_mode_entry && kexec_debug) {
 		unsigned long entry16_debug, pre32, first32;
@@ -332,8 +367,12 @@ int do_bzImage_load(struct kexec_info *info,
 	
 		regs32.eip = entry16_debug;
 	}
-	elf_rel_set_symbol(&info->rhdr, "entry16_regs", &regs16, sizeof(regs16));
-	elf_rel_set_symbol(&info->rhdr, "entry16_debug_regs", &regs16, sizeof(regs16));
+	if (real_mode_entry) {
+		elf_rel_set_symbol(&info->rhdr, "entry16_regs",
+					 &regs16, sizeof(regs16));
+		elf_rel_set_symbol(&info->rhdr, "entry16_debug_regs",
+					 &regs16, sizeof(regs16));
+	}
 	elf_rel_set_symbol(&info->rhdr, "entry32_regs", &regs32, sizeof(regs32));
 	cmdline_end = setup_base + kern16_size + command_line_len - 1;
 	elf_rel_set_symbol(&info->rhdr, "cmdline_end", &cmdline_end,
-- 
1.7.7


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 3/6] kexec, x86: add boot header member for version 2.12
  2012-11-24 20:47 [PATCH v4 0/6] kexec: put bzImage and ramdisk above 4G for x86 64bit Yinghai Lu
  2012-11-24 20:47 ` [PATCH v4 1/6] kexec, x86: clean boot_params area for entry-32bit path Yinghai Lu
  2012-11-24 20:47 ` [PATCH v4 2/6] kexec, x86: Fix bzImage real-mode booting Yinghai Lu
@ 2012-11-24 20:47 ` Yinghai Lu
  2012-11-24 20:47 ` [PATCH v4 4/6] kexec, x86: put ramdisk high for 64bit bzImage Yinghai Lu
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Yinghai Lu @ 2012-11-24 20:47 UTC (permalink / raw)
  To: Simon Horman, H. Peter Anvin, Vivek Goyal, Haren Myneni,
	Eric W. Biederman
  Cc: Yinghai Lu, kexec

will use ext_ramdisk_image/size, and xloadflags to put
ramdisk and bzImage high for 64bit.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 include/x86/x86-linux.h |   32 +++++++++++++++++++++++++++-----
 1 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/include/x86/x86-linux.h b/include/x86/x86-linux.h
index 27af02b..a2452f2 100644
--- a/include/x86/x86-linux.h
+++ b/include/x86/x86-linux.h
@@ -32,7 +32,7 @@ struct drive_info_struct {
 };
 struct sys_desc_table {
 	uint16_t length;
-	uint8_t  table[318];
+	uint8_t  table[30];
 };
 
 struct apm_bios_info {
@@ -112,6 +112,10 @@ struct x86_linux_param_header {
 	struct apm_bios_info apm_bios_info;	/* 0x40 */
 	struct drive_info_struct drive_info;	/* 0x80 */
 	struct sys_desc_table sys_desc_table;	/* 0xa0 */
+	uint32_t ext_ramdisk_image;		/* 0xc0 */
+	uint32_t ext_ramdisk_size;		/* 0xc4 */
+	uint32_t ext_cmd_line_ptr;		/* 0xc8 */
+	uint8_t reserved4_1[0x1e0 - 0xcc];	/* 0xcc */
 	uint32_t alt_mem_k;			/* 0x1e0 */
 	uint8_t  reserved5[4];			/* 0x1e4 */
 	uint8_t  e820_map_nr;			/* 0x1e8 */
@@ -174,11 +178,18 @@ struct x86_linux_param_header {
 	/* 2.04+ */
 	uint32_t kernel_alignment;		/* 0x230 */
 	uint8_t  relocatable_kernel;		/* 0x234 */
-	uint8_t  reserved15[3];			/* 0x235 */
+	uint8_t  min_alignment;			/* 0x235 */
+	uint16_t xloadflags;			/* 0x236 */
 	uint32_t cmdline_size;			/* 0x238 */
 	uint32_t hardware_subarch;		/* 0x23C */
 	uint64_t hardware_subarch_data;		/* 0x240 */
-	uint8_t  reserved16[0x290 - 0x248];	/* 0x248 */
+	uint32_t payload_offset;		/* 0x248 */
+	uint32_t payload_length;		/* 0x24C */
+	uint64_t setup_data;			/* 0x250 */
+	uint64_t pref_address;			/* 0x258 */
+	uint32_t init_size;			/* 0x260 */
+	uint32_t handover_offset;		/* 0x264 */
+	uint8_t  reserved16[0x290 - 0x268];	/* 0x268 */
 	uint32_t edd_mbr_sig_buffer[EDD_MBR_SIG_MAX];	/* 0x290 */
 #endif
 	struct 	e820entry e820_map[E820MAX];	/* 0x2d0 */
@@ -195,7 +206,11 @@ struct x86_linux_faked_param_header {
 };
 
 struct x86_linux_header {
-	uint8_t  reserved1[0x1f1];		/* 0x000 */
+	uint8_t  reserved1[0xc0];		/* 0x000 */
+	uint32_t ext_ramdisk_image;		/* 0x0c0 */
+	uint32_t ext_ramdisk_size;		/* 0x0c4 */
+	uint32_t ext_cmd_line_ptr;		/* 0x0c8 */
+	uint8_t  reserved1_1[0x1f1-0xcc];	/* 0x0cc */
 	uint8_t  setup_sects;			/* 0x1f1 */
 	uint16_t root_flags;			/* 0x1f2 */
 	uint16_t syssize;			/* 0x1f4 */
@@ -241,10 +256,17 @@ struct x86_linux_header {
 #else
 	uint32_t kernel_alignment;		/* 0x230 */
 	uint8_t  relocatable_kernel;		/* 0x234 */
-	uint8_t  reserved6[3];			/* 0x235 */
+	uint8_t  min_alignment;			/* 0x235 */
+	uint16_t xloadflags;			/* 0x236 */
 	uint32_t cmdline_size;                  /* 0x238 */
 	uint32_t hardware_subarch;              /* 0x23C */
 	uint64_t hardware_subarch_data;         /* 0x240 */
+	uint32_t payload_offset;		/* 0x248 */
+	uint32_t payload_length;		/* 0x24C */
+	uint64_t setup_data;			/* 0x250 */
+	uint64_t pref_address;			/* 0x258 */
+	uint32_t init_size;			/* 0x260 */
+	uint32_t handover_offset;		/* 0x264 */
 #endif
 } PACKED;
 
-- 
1.7.7


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 4/6] kexec, x86: put ramdisk high for 64bit bzImage
  2012-11-24 20:47 [PATCH v4 0/6] kexec: put bzImage and ramdisk above 4G for x86 64bit Yinghai Lu
                   ` (2 preceding siblings ...)
  2012-11-24 20:47 ` [PATCH v4 3/6] kexec, x86: add boot header member for version 2.12 Yinghai Lu
@ 2012-11-24 20:47 ` Yinghai Lu
  2012-11-25  0:37   ` Yinghai Lu
  2012-11-24 20:47 ` [PATCH v4 5/6] kexec, x86: set ext_cmd_line_ptr when boot_param is above 4g Yinghai Lu
  2012-11-24 20:47 ` [PATCH v4 6/6] kexec, x86_64: Load bzImage64 above 4G Yinghai Lu
  5 siblings, 1 reply; 10+ messages in thread
From: Yinghai Lu @ 2012-11-24 20:47 UTC (permalink / raw)
  To: Simon Horman, H. Peter Anvin, Vivek Goyal, Haren Myneni,
	Eric W. Biederman
  Cc: Yinghai Lu, kexec

We could put ramdisk high for bzImage on 64bit for protocol 2.12.

-v2: change ext_... handling to way that eric like.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 kexec/arch/i386/kexec-bzImage.c   |    2 ++
 kexec/arch/i386/x86-linux-setup.c |   18 +++++++++++++++---
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/kexec/arch/i386/kexec-bzImage.c b/kexec/arch/i386/kexec-bzImage.c
index d83f0a9..30c38e2 100644
--- a/kexec/arch/i386/kexec-bzImage.c
+++ b/kexec/arch/i386/kexec-bzImage.c
@@ -251,6 +251,8 @@ int do_bzImage_load(struct kexec_info *info,
 	memcpy(real_mode, kernel, kern16_size);
 	if (!real_mode_entry)
 		clean_boot_params((unsigned char *)real_mode, kern16_size);
+	/* disable loading above 4g */
+	real_mode->xloadflags &= ~1;
 
 	if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) {
 		/* If using bzImage for capture kernel, then we will not be
diff --git a/kexec/arch/i386/x86-linux-setup.c b/kexec/arch/i386/x86-linux-setup.c
index b7ab8ea..3c31f64 100644
--- a/kexec/arch/i386/x86-linux-setup.c
+++ b/kexec/arch/i386/x86-linux-setup.c
@@ -64,7 +64,11 @@ void setup_linux_bootloader_parameters(
 	/* Find the maximum initial ramdisk address */
 	initrd_addr_max = DEFAULT_INITRD_ADDR_MAX;
 	if (real_mode->protocol_version >= 0x0203) {
-		initrd_addr_max = real_mode->initrd_addr_max;
+		if (real_mode->protocol_version >= 0x020c &&
+		    real_mode->xloadflags & 1)
+			initrd_addr_max = ULONG_MAX;
+		else
+			initrd_addr_max = real_mode->initrd_addr_max;
 		dbgprintf("initrd_addr_max is 0x%lx\n", initrd_addr_max);
 	}
 
@@ -81,8 +85,16 @@ void setup_linux_bootloader_parameters(
 	}
 
 	/* Ramdisk address and size */
-	real_mode->initrd_start = initrd_base;
-	real_mode->initrd_size  = initrd_size;
+	real_mode->initrd_start = initrd_base & 0xffffffffUL;
+	real_mode->initrd_size  = initrd_size & 0xffffffffUL;
+
+	if (real_mode->protocol_version >= 0x020c &&
+	    (initrd_base & 0xffffffffUL) != initrd_base)
+		real_mode->ext_ramdisk_image = initrd_base >> 32;
+
+	if (real_mode->protocol_version >= 0x020c &&
+	    (initrd_size & 0xffffffffUL) != initrd_size)
+		real_mode->ext_ramdisk_size = initrd_size >> 32;
 
 	/* The location of the command line */
 	/* if (real_mode_base == 0x90000) { */
-- 
1.7.7


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 5/6] kexec, x86: set ext_cmd_line_ptr when boot_param is above 4g
  2012-11-24 20:47 [PATCH v4 0/6] kexec: put bzImage and ramdisk above 4G for x86 64bit Yinghai Lu
                   ` (3 preceding siblings ...)
  2012-11-24 20:47 ` [PATCH v4 4/6] kexec, x86: put ramdisk high for 64bit bzImage Yinghai Lu
@ 2012-11-24 20:47 ` Yinghai Lu
  2012-11-24 20:47 ` [PATCH v4 6/6] kexec, x86_64: Load bzImage64 above 4G Yinghai Lu
  5 siblings, 0 replies; 10+ messages in thread
From: Yinghai Lu @ 2012-11-24 20:47 UTC (permalink / raw)
  To: Simon Horman, H. Peter Anvin, Vivek Goyal, Haren Myneni,
	Eric W. Biederman
  Cc: Yinghai Lu, kexec

update ext_cmd_line_ptr for bzImage from protocal 2.12
that could have command line above 4g.

-v2: update ext_... handling to the way that Eric likes.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 kexec/arch/i386/x86-linux-setup.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/kexec/arch/i386/x86-linux-setup.c b/kexec/arch/i386/x86-linux-setup.c
index 3c31f64..d12dab1 100644
--- a/kexec/arch/i386/x86-linux-setup.c
+++ b/kexec/arch/i386/x86-linux-setup.c
@@ -103,7 +103,12 @@ void setup_linux_bootloader_parameters(
 		/* setup_move_size */
 	/* } */
 	if (real_mode->protocol_version >= 0x0202) {
-		real_mode->cmd_line_ptr = real_mode_base + cmdline_offset;
+		unsigned long cmd_line_ptr = real_mode_base + cmdline_offset;
+
+		real_mode->cmd_line_ptr = cmd_line_ptr & 0xffffffffUL;
+		if ((real_mode->protocol_version >= 0x020c) &&
+		    ((cmd_line_ptr & 0xffffffffUL) != cmd_line_ptr))
+			real_mode->ext_cmd_line_ptr = cmd_line_ptr >> 32;
 	}
 
 	/* Fill in the command line */
-- 
1.7.7


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 6/6] kexec, x86_64: Load bzImage64 above 4G
  2012-11-24 20:47 [PATCH v4 0/6] kexec: put bzImage and ramdisk above 4G for x86 64bit Yinghai Lu
                   ` (4 preceding siblings ...)
  2012-11-24 20:47 ` [PATCH v4 5/6] kexec, x86: set ext_cmd_line_ptr when boot_param is above 4g Yinghai Lu
@ 2012-11-24 20:47 ` Yinghai Lu
  2012-11-25  0:38   ` Yinghai Lu
  5 siblings, 1 reply; 10+ messages in thread
From: Yinghai Lu @ 2012-11-24 20:47 UTC (permalink / raw)
  To: Simon Horman, H. Peter Anvin, Vivek Goyal, Haren Myneni,
	Eric W. Biederman
  Cc: Yinghai Lu, kexec

need to check xloadflags to see the bzImage is for 64bit relocatable.

-v2: add kexec-bzImage64.c according to Eric.
-v3: don't need to purgatory under 2g after Eric's change to purgatory code.
-v4: use locate_hole find position first then add_buffer... suggested by Eric
     add buffer for kernel image at last to make kexec-load faster.
     use xloadflags in setup_header to tell if is bzImage64.
     remove not cross GB boundary searching.
     add --entry-32bit and --real-mode for skipping bzImage64.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 kexec/arch/i386/include/arch/options.h |    4 +-
 kexec/arch/x86_64/Makefile             |    1 +
 kexec/arch/x86_64/kexec-bzImage64.c    |  334 ++++++++++++++++++++++++++++++++
 kexec/arch/x86_64/kexec-x86_64.c       |    1 +
 kexec/arch/x86_64/kexec-x86_64.h       |    5 +
 5 files changed, 344 insertions(+), 1 deletions(-)
 create mode 100644 kexec/arch/x86_64/kexec-bzImage64.c

diff --git a/kexec/arch/i386/include/arch/options.h b/kexec/arch/i386/include/arch/options.h
index 89dbd26..aaac731 100644
--- a/kexec/arch/i386/include/arch/options.h
+++ b/kexec/arch/i386/include/arch/options.h
@@ -29,6 +29,7 @@
 #define OPT_MOD 		(OPT_ARCH_MAX+7)
 #define OPT_VGA 		(OPT_ARCH_MAX+8)
 #define OPT_REAL_MODE		(OPT_ARCH_MAX+9)
+#define OPT_ENTRY_32BIT		(OPT_ARCH_MAX+10)
 
 /* Options relevant to the architecture (excluding loader-specific ones): */
 #define KEXEC_ARCH_OPTIONS \
@@ -68,7 +69,8 @@
 	{ "args-linux",		0, NULL, OPT_ARGS_LINUX },	\
 	{ "args-none",		0, NULL, OPT_ARGS_NONE },	\
 	{ "module",		1, 0, OPT_MOD },		\
-	{ "real-mode",		0, NULL, OPT_REAL_MODE },
+	{ "real-mode",		0, NULL, OPT_REAL_MODE },	\
+	{ "entry-32bit",	0, NULL, OPT_ENTRY_32BIT },
 
 #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR
 
diff --git a/kexec/arch/x86_64/Makefile b/kexec/arch/x86_64/Makefile
index 405bdf5..1cf10f9 100644
--- a/kexec/arch/x86_64/Makefile
+++ b/kexec/arch/x86_64/Makefile
@@ -13,6 +13,7 @@ x86_64_KEXEC_SRCS += kexec/arch/i386/crashdump-x86.c
 x86_64_KEXEC_SRCS_native =  kexec/arch/x86_64/kexec-x86_64.c
 x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-elf-x86_64.c
 x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-elf-rel-x86_64.c
+x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-bzImage64.c
 
 x86_64_KEXEC_SRCS += $(x86_64_KEXEC_SRCS_native)
 
diff --git a/kexec/arch/x86_64/kexec-bzImage64.c b/kexec/arch/x86_64/kexec-bzImage64.c
new file mode 100644
index 0000000..289442f
--- /dev/null
+++ b/kexec/arch/x86_64/kexec-bzImage64.c
@@ -0,0 +1,334 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003-2010  Eric Biederman (ebiederm@xmission.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 (version 2 of the License).
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <elf.h>
+#include <boot/elf_boot.h>
+#include <ip_checksum.h>
+#include <x86/x86-linux.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
+#include "kexec-x86_64.h"
+#include "../i386/x86-linux-setup.h"
+#include "../i386/crashdump-x86.h"
+#include <arch/options.h>
+
+static const int probe_debug = 0;
+
+int bzImage64_probe(const char *buf, off_t len)
+{
+	const struct x86_linux_header *header;
+
+	if ((uintmax_t)len < (uintmax_t)(2 * 512)) {
+		if (probe_debug)
+			fprintf(stderr, "File is too short to be a bzImage!\n");
+		return -1;
+	}
+	header = (const struct x86_linux_header *)buf;
+	if (memcmp(header->header_magic, "HdrS", 4) != 0) {
+		if (probe_debug)
+			fprintf(stderr, "Not a bzImage\n");
+		return -1;
+	}
+	if (header->boot_sector_magic != 0xAA55) {
+		if (probe_debug)
+			fprintf(stderr, "No x86 boot sector present\n");
+		/* No x86 boot sector present */
+		return -1;
+	}
+	if (header->protocol_version < 0x020C) {
+		if (probe_debug)
+			fprintf(stderr, "Must be at least protocol version 2.12\n");
+		/* Must be at least protocol version 2.12 */
+		return -1;
+	}
+	if ((header->loadflags & 1) == 0) {
+		if (probe_debug)
+			fprintf(stderr, "zImage not a bzImage\n");
+		/* Not a bzImage */
+		return -1;
+	}
+	if (!(header->xloadflags & 1)) {
+		if (probe_debug)
+			fprintf(stderr, "Not a bzImage64\n");
+		/* Must be LOADED_ABOVE_4G */
+		return -1;
+	}
+	/* I've got a bzImage64 */
+	if (probe_debug)
+		fprintf(stderr, "It's a bzImage64\n");
+	return 0;
+}
+
+void bzImage64_usage(void)
+{
+	printf( "    --entry-32bit         Use the kernels 32bit entry point.\n"
+		"    --real-mode           Use the kernels real mode entry point.\n"
+		"    --command-line=STRING Set the kernel command line to STRING.\n"
+		"    --append=STRING       Set the kernel command line to STRING.\n"
+		"    --reuse-cmdline       Use kernel command line from running system.\n"
+		"    --initrd=FILE         Use FILE as the kernel's initial ramdisk.\n"
+		"    --ramdisk=FILE        Use FILE as the kernel's initial ramdisk.\n"
+		);
+}
+
+static void clean_boot_params(unsigned char *real_mode, unsigned long size)
+{
+	unsigned long end;
+
+	/* clear value before header */
+	memset(real_mode, 0, 0x1f1);
+	/* clear value after setup_header  */
+	end = *(real_mode + 0x201);
+	end += 0x202;
+	if (end < size)
+		memset(real_mode + end, 0, size - end);
+}
+
+static int do_bzImage64_load(struct kexec_info *info,
+			const char *kernel, off_t kernel_len,
+			const char *command_line, off_t command_line_len,
+			const char *initrd, off_t initrd_len)
+{
+	struct x86_linux_header setup_header;
+	struct x86_linux_param_header *real_mode;
+	int setup_sects;
+	size_t size;
+	int kern16_size;
+	unsigned long setup_base, setup_size;
+	struct entry64_regs regs64;
+	char *modified_cmdline;
+	unsigned long cmdline_end;
+	unsigned long align, addr, k_size;
+	unsigned kern16_size_needed;
+
+	/*
+	 * Find out about the file I am about to load.
+	 */
+	if ((uintmax_t)kernel_len < (uintmax_t)(2 * 512))
+		return -1;
+
+	memcpy(&setup_header, kernel, sizeof(setup_header));
+	setup_sects = setup_header.setup_sects;
+	if (setup_sects == 0)
+		setup_sects = 4;
+	kern16_size = (setup_sects + 1) * 512;
+	if (kernel_len < kern16_size) {
+		fprintf(stderr, "BzImage truncated?\n");
+		return -1;
+	}
+
+	if ((uintmax_t)command_line_len > (uintmax_t)setup_header.cmdline_size) {
+		dbgprintf("Kernel command line too long for kernel!\n");
+		return -1;
+	}
+
+	/* Need to append some command line parameters internally in case of
+	 * taking crash dumps.
+	 */
+	if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) {
+		modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
+		memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
+		if (command_line) {
+			strncpy(modified_cmdline, command_line,
+					COMMAND_LINE_SIZE);
+			modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+		}
+
+		/* If panic kernel is being loaded, additional segments need
+		 * to be created. load_crashdump_segments will take care of
+		 * loading the segments as high in memory as possible, hence
+		 * in turn as away as possible from kernel to avoid being
+		 * stomped by the kernel.
+		 */
+		if (load_crashdump_segments(info, modified_cmdline, -1, 0) < 0)
+			return -1;
+
+		/* Use new command line buffer */
+		command_line = modified_cmdline;
+		command_line_len = strlen(command_line) + 1;
+	}
+
+	/* x86_64 purgatory could be anywhere */
+	elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
+				0x3000, -1, -1, 0);
+	dbgprintf("Loaded purgatory at addr 0x%lx\n", info->rhdr.rel_addr);
+	/* The argument/parameter segment */
+	kern16_size_needed = kern16_size;
+	if (kern16_size_needed < 4096)
+		kern16_size_needed = 4096;
+	setup_size = kern16_size_needed + command_line_len +
+				PURGATORY_CMDLINE_SIZE;
+	real_mode = xmalloc(setup_size);
+	memset(real_mode, 0, setup_size);
+	memcpy(real_mode, kernel, kern16_size);
+	clean_boot_params((unsigned char *)real_mode, kern16_size);
+
+	/* No real mode code will be executing. setup segment can be loaded
+	 * anywhere as we will be just reading command line.
+	 */
+	setup_base = add_buffer(info, real_mode, setup_size, setup_size,
+				16, 0x3000, -1, -1);
+
+	dbgprintf("Loaded real_mode_data and command line at 0x%lx\n",
+			setup_base);
+
+	/* Tell the kernel what is going on */
+	setup_linux_bootloader_parameters(info, real_mode, setup_base,
+			kern16_size_needed, command_line, command_line_len,
+			initrd, initrd_len);
+
+	/*
+	 * add kernel at last, to make kexec load big kernel faster.
+	 * we are finding buffer with run-time size, and only add buffer
+	 * with image size that is smaller than run-time size.
+	 * later kexec_load will take less time with small range.
+	 * otherwise kexec_load will allocate big range but only
+	 * copy small buffer and waste time on allocating not needed
+	 * range.
+	 */
+
+	/* The main kernel segment */
+	k_size = kernel_len - kern16_size;
+
+	/* need to use run-time size for buffer searching */
+	dbgprintf("kernel init_size 0x%x\n", real_mode->init_size);
+	size = (real_mode->init_size + (4096 - 1)) & ~(4096 - 1);
+
+	/* need to sort segments before locate_hole */
+	if (sort_segments(info) < 0)
+		die("sort_segments failed\n");
+
+	align = real_mode->kernel_alignment;
+	addr = locate_hole(info, size, align, 0x100000, -1, -1);
+	if (addr == ULONG_MAX)
+		die("can not load bzImage64");
+	dbgprintf("Found kernel buffer at %lx size %lx\n", addr, size);
+
+	/* put compressed image at start of buffer */
+	addr = add_buffer(info, kernel + kern16_size, k_size, k_size, align,
+				addr, addr + size, 1);
+	if (addr == ULONG_MAX)
+		die("can not load bzImage64");
+	dbgprintf("Loaded 64bit kernel at 0x%lx\n", addr);
+
+	elf_rel_get_symbol(&info->rhdr, "entry64_regs", &regs64,
+				 sizeof(regs64));
+	regs64.rbx = 0;           /* Bootstrap processor */
+	regs64.rsi = setup_base;  /* Pointer to the parameters */
+	regs64.rip = addr + 0x200; /* the entry point for startup_64 */
+	regs64.rsp = elf_rel_get_addr(&info->rhdr, "stack_end"); /* Stack, unused */
+	elf_rel_set_symbol(&info->rhdr, "entry64_regs", &regs64,
+				 sizeof(regs64));
+
+	cmdline_end = setup_base + kern16_size + command_line_len - 1;
+	elf_rel_set_symbol(&info->rhdr, "cmdline_end", &cmdline_end,
+			   sizeof(unsigned long));
+
+	/* Fill in the information BIOS calls would normally provide. */
+	setup_linux_system_parameters(real_mode, info->kexec_flags);
+
+	return 0;
+}
+
+int bzImage64_load(int argc, char **argv, const char *buf, off_t len,
+	struct kexec_info *info)
+{
+	char *command_line = NULL;
+	const char *ramdisk = NULL, *append = NULL;
+	char *ramdisk_buf;
+	off_t ramdisk_length = 0;
+	int command_line_len;
+	int entry_16bit = 0, entry_32bit = 0;
+	int opt;
+	int result;
+
+	/* See options.h -- add any more there, too. */
+	static const struct option options[] = {
+		KEXEC_ARCH_OPTIONS
+		{ "command-line",	1, 0, OPT_APPEND },
+		{ "append",		1, 0, OPT_APPEND },
+		{ "reuse-cmdline",	0, 0, OPT_REUSE_CMDLINE },
+		{ "initrd",		1, 0, OPT_RAMDISK },
+		{ "ramdisk",		1, 0, OPT_RAMDISK },
+		{ "real-mode",		0, 0, OPT_REAL_MODE },
+		{ "entry-32bit",	0, 0, OPT_ENTRY_32BIT },
+		{ 0,			0, 0, 0 },
+	};
+	static const char short_options[] = KEXEC_ARCH_OPT_STR "d";
+
+	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
+		switch (opt) {
+		default:
+			/* Ignore core options */
+			if (opt < OPT_ARCH_MAX)
+				break;
+		case '?':
+			usage();
+			return -1;
+			break;
+		case OPT_APPEND:
+			append = optarg;
+			break;
+		case OPT_REUSE_CMDLINE:
+			command_line = get_command_line();
+			break;
+		case OPT_RAMDISK:
+			ramdisk = optarg;
+			break;
+		case OPT_REAL_MODE:
+			entry_16bit = 1;
+			break;
+		case OPT_ENTRY_32BIT:
+			entry_32bit = 1;
+			break;
+		}
+	}
+	command_line = concat_cmdline(command_line, append);
+	command_line_len = 0;
+	if (command_line)
+		command_line_len = strlen(command_line) + 1;
+	ramdisk_buf = 0;
+	if (ramdisk)
+		ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
+
+	if (entry_16bit || entry_32bit)
+		result = do_bzImage_load(info, buf, len, command_line,
+					command_line_len, ramdisk_buf,
+					ramdisk_length, entry_16bit);
+	else
+		result = do_bzImage64_load(info, buf, len, command_line,
+					command_line_len, ramdisk_buf,
+					ramdisk_length);
+
+	free(command_line);
+	return result;
+}
diff --git a/kexec/arch/x86_64/kexec-x86_64.c b/kexec/arch/x86_64/kexec-x86_64.c
index 6c42c32..5c23e01 100644
--- a/kexec/arch/x86_64/kexec-x86_64.c
+++ b/kexec/arch/x86_64/kexec-x86_64.c
@@ -37,6 +37,7 @@ struct file_type file_type[] = {
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
 	{ "elf-x86", elf_x86_probe, elf_x86_load, elf_x86_usage },
+	{ "bzImage64", bzImage64_probe, bzImage64_load, bzImage64_usage },
 	{ "bzImage", bzImage_probe, bzImage_load, bzImage_usage },
 	{ "beoboot-x86", beoboot_probe, beoboot_load, beoboot_usage },
 	{ "nbi-x86", nbi_probe, nbi_load, nbi_usage },
diff --git a/kexec/arch/x86_64/kexec-x86_64.h b/kexec/arch/x86_64/kexec-x86_64.h
index a97cd71..4cdeffb 100644
--- a/kexec/arch/x86_64/kexec-x86_64.h
+++ b/kexec/arch/x86_64/kexec-x86_64.h
@@ -28,4 +28,9 @@ int elf_x86_64_load(int argc, char **argv, const char *buf, off_t len,
 	struct kexec_info *info);
 void elf_x86_64_usage(void);
 
+int bzImage64_probe(const char *buf, off_t len);
+int bzImage64_load(int argc, char **argv, const char *buf, off_t len,
+			struct kexec_info *info);
+void bzImage64_usage(void);
+
 #endif /* KEXEC_X86_64_H */
-- 
1.7.7


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 4/6] kexec, x86: put ramdisk high for 64bit bzImage
  2012-11-24 20:47 ` [PATCH v4 4/6] kexec, x86: put ramdisk high for 64bit bzImage Yinghai Lu
@ 2012-11-25  0:37   ` Yinghai Lu
  0 siblings, 0 replies; 10+ messages in thread
From: Yinghai Lu @ 2012-11-25  0:37 UTC (permalink / raw)
  To: Simon Horman, H. Peter Anvin, Vivek Goyal, Haren Myneni,
	Eric W. Biederman
  Cc: Yinghai Lu, kexec

[-- Attachment #1: Type: text/plain, Size: 211 bytes --]

On Sat, Nov 24, 2012 at 12:47 PM, Yinghai Lu <yinghai@kernel.org> wrote:
> We could put ramdisk high for bzImage on 64bit for protocol 2.12.
>
> -v2: change ext_... handling to way that eric like.

-v5 attached

[-- Attachment #2: ramdisk_high_mem_64_x_6_v5.patch --]
[-- Type: application/octet-stream, Size: 1784 bytes --]

Subject: [PATCH v5 4/6] kexec, x86: put ramdisk high for 64bit bzImage

We could put ramdisk high for bzImage on 64bit for protocol 2.12.

-v2: change ext_... handling to way that eric like.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>

---
 kexec/arch/i386/x86-linux-setup.c |   18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

Index: kexec-tools/kexec/arch/i386/x86-linux-setup.c
===================================================================
--- kexec-tools.orig/kexec/arch/i386/x86-linux-setup.c
+++ kexec-tools/kexec/arch/i386/x86-linux-setup.c
@@ -64,7 +64,11 @@ void setup_linux_bootloader_parameters(
 	/* Find the maximum initial ramdisk address */
 	initrd_addr_max = DEFAULT_INITRD_ADDR_MAX;
 	if (real_mode->protocol_version >= 0x0203) {
-		initrd_addr_max = real_mode->initrd_addr_max;
+		if (real_mode->protocol_version >= 0x020c &&
+		    real_mode->xloadflags & (1<<15)) /* USE_EXT_BOOT_PARAMS */
+			initrd_addr_max = ULONG_MAX;
+		else
+			initrd_addr_max = real_mode->initrd_addr_max;
 		dbgprintf("initrd_addr_max is 0x%lx\n", initrd_addr_max);
 	}
 
@@ -81,8 +85,16 @@ void setup_linux_bootloader_parameters(
 	}
 
 	/* Ramdisk address and size */
-	real_mode->initrd_start = initrd_base;
-	real_mode->initrd_size  = initrd_size;
+	real_mode->initrd_start = initrd_base & 0xffffffffUL;
+	real_mode->initrd_size  = initrd_size & 0xffffffffUL;
+
+	if (real_mode->protocol_version >= 0x020c &&
+	    (initrd_base & 0xffffffffUL) != initrd_base)
+		real_mode->ext_ramdisk_image = initrd_base >> 32;
+
+	if (real_mode->protocol_version >= 0x020c &&
+	    (initrd_size & 0xffffffffUL) != initrd_size)
+		real_mode->ext_ramdisk_size = initrd_size >> 32;
 
 	/* The location of the command line */
 	/* if (real_mode_base == 0x90000) { */

[-- Attachment #3: Type: text/plain, Size: 143 bytes --]

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 6/6] kexec, x86_64: Load bzImage64 above 4G
  2012-11-24 20:47 ` [PATCH v4 6/6] kexec, x86_64: Load bzImage64 above 4G Yinghai Lu
@ 2012-11-25  0:38   ` Yinghai Lu
  2012-11-25  0:42     ` H. Peter Anvin
  0 siblings, 1 reply; 10+ messages in thread
From: Yinghai Lu @ 2012-11-25  0:38 UTC (permalink / raw)
  To: Simon Horman, H. Peter Anvin, Vivek Goyal, Haren Myneni,
	Eric W. Biederman
  Cc: Yinghai Lu, kexec

[-- Attachment #1: Type: text/plain, Size: 667 bytes --]

On Sat, Nov 24, 2012 at 12:47 PM, Yinghai Lu <yinghai@kernel.org> wrote:
> need to check xloadflags to see the bzImage is for 64bit relocatable.
>
> -v2: add kexec-bzImage64.c according to Eric.
> -v3: don't need to purgatory under 2g after Eric's change to purgatory code.
> -v4: use locate_hole find position first then add_buffer... suggested by Eric
>      add buffer for kernel image at last to make kexec-load faster.
>      use xloadflags in setup_header to tell if is bzImage64.
>      remove not cross GB boundary searching.
>      add --entry-32bit and --real-mode for skipping bzImage64.

-v5: attached. that is using USE_EXT_BOOT_PARAMS bit in xloadflags

[-- Attachment #2: 64bit_bzImage_start_v5.patch --]
[-- Type: application/octet-stream, Size: 14372 bytes --]

Subject: [PATCH v5 6/6] kexec, x86_64: Load bzImage64 above 4G

need to check xloadflags to see the bzImage is for 64bit relocatable.

-v2: add kexec-bzImage64.c according to Eric.
-v3: don't need to purgatory under 2g after Eric's change to purgatory code.
-v4: use locate_hole find position first then add_buffer... suggested by Eric
     add buffer for kernel image at last to make kexec-load faster.
     use xloadflags in setup_header to tell if is bzImage64.
     remove not cross GB boundary searching.
     add --entry-32bit and --real-mode for skipping bzImage64.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>

---
 kexec/arch/i386/include/arch/options.h |    4 
 kexec/arch/x86_64/Makefile             |    1 
 kexec/arch/x86_64/kexec-bzImage64.c    |  335 +++++++++++++++++++++++++++++++++
 kexec/arch/x86_64/kexec-x86_64.c       |    1 
 kexec/arch/x86_64/kexec-x86_64.h       |    5 
 5 files changed, 345 insertions(+), 1 deletion(-)

Index: kexec-tools/kexec/arch/x86_64/Makefile
===================================================================
--- kexec-tools.orig/kexec/arch/x86_64/Makefile
+++ kexec-tools/kexec/arch/x86_64/Makefile
@@ -13,6 +13,7 @@ x86_64_KEXEC_SRCS += kexec/arch/i386/cra
 x86_64_KEXEC_SRCS_native =  kexec/arch/x86_64/kexec-x86_64.c
 x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-elf-x86_64.c
 x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-elf-rel-x86_64.c
+x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-bzImage64.c
 
 x86_64_KEXEC_SRCS += $(x86_64_KEXEC_SRCS_native)
 
Index: kexec-tools/kexec/arch/x86_64/kexec-bzImage64.c
===================================================================
--- /dev/null
+++ kexec-tools/kexec/arch/x86_64/kexec-bzImage64.c
@@ -0,0 +1,335 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003-2010  Eric Biederman (ebiederm@xmission.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 (version 2 of the License).
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define _GNU_SOURCE
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <elf.h>
+#include <boot/elf_boot.h>
+#include <ip_checksum.h>
+#include <x86/x86-linux.h>
+#include "../../kexec.h"
+#include "../../kexec-elf.h"
+#include "../../kexec-syscall.h"
+#include "kexec-x86_64.h"
+#include "../i386/x86-linux-setup.h"
+#include "../i386/crashdump-x86.h"
+#include <arch/options.h>
+
+static const int probe_debug = 0;
+
+int bzImage64_probe(const char *buf, off_t len)
+{
+	const struct x86_linux_header *header;
+
+	if ((uintmax_t)len < (uintmax_t)(2 * 512)) {
+		if (probe_debug)
+			fprintf(stderr, "File is too short to be a bzImage!\n");
+		return -1;
+	}
+	header = (const struct x86_linux_header *)buf;
+	if (memcmp(header->header_magic, "HdrS", 4) != 0) {
+		if (probe_debug)
+			fprintf(stderr, "Not a bzImage\n");
+		return -1;
+	}
+	if (header->boot_sector_magic != 0xAA55) {
+		if (probe_debug)
+			fprintf(stderr, "No x86 boot sector present\n");
+		/* No x86 boot sector present */
+		return -1;
+	}
+	if (header->protocol_version < 0x020C) {
+		if (probe_debug)
+			fprintf(stderr, "Must be at least protocol version 2.12\n");
+		/* Must be at least protocol version 2.12 */
+		return -1;
+	}
+	if ((header->loadflags & 1) == 0) {
+		if (probe_debug)
+			fprintf(stderr, "zImage not a bzImage\n");
+		/* Not a bzImage */
+		return -1;
+	}
+	if (!(header->xloadflags & 1)) {
+		if (probe_debug)
+			fprintf(stderr, "Not a bzImage64\n");
+		/* Must be CAN_BE_LOADED_ABOVE_4G */
+		return -1;
+	}
+	/* I've got a bzImage64 */
+	if (probe_debug)
+		fprintf(stderr, "It's a bzImage64\n");
+	return 0;
+}
+
+void bzImage64_usage(void)
+{
+	printf( "    --entry-32bit         Use the kernels 32bit entry point.\n"
+		"    --real-mode           Use the kernels real mode entry point.\n"
+		"    --command-line=STRING Set the kernel command line to STRING.\n"
+		"    --append=STRING       Set the kernel command line to STRING.\n"
+		"    --reuse-cmdline       Use kernel command line from running system.\n"
+		"    --initrd=FILE         Use FILE as the kernel's initial ramdisk.\n"
+		"    --ramdisk=FILE        Use FILE as the kernel's initial ramdisk.\n"
+		);
+}
+
+static void clean_boot_params(unsigned char *real_mode, unsigned long size)
+{
+	unsigned long end;
+
+	/* clear value before header */
+	memset(real_mode, 0, 0x1f1);
+	/* clear value after setup_header  */
+	end = *(real_mode + 0x201);
+	end += 0x202;
+	if (end < size)
+		memset(real_mode + end, 0, size - end);
+}
+
+static int do_bzImage64_load(struct kexec_info *info,
+			const char *kernel, off_t kernel_len,
+			const char *command_line, off_t command_line_len,
+			const char *initrd, off_t initrd_len)
+{
+	struct x86_linux_header setup_header;
+	struct x86_linux_param_header *real_mode;
+	int setup_sects;
+	size_t size;
+	int kern16_size;
+	unsigned long setup_base, setup_size;
+	struct entry64_regs regs64;
+	char *modified_cmdline;
+	unsigned long cmdline_end;
+	unsigned long align, addr, k_size;
+	unsigned kern16_size_needed;
+
+	/*
+	 * Find out about the file I am about to load.
+	 */
+	if ((uintmax_t)kernel_len < (uintmax_t)(2 * 512))
+		return -1;
+
+	memcpy(&setup_header, kernel, sizeof(setup_header));
+	setup_sects = setup_header.setup_sects;
+	if (setup_sects == 0)
+		setup_sects = 4;
+	kern16_size = (setup_sects + 1) * 512;
+	if (kernel_len < kern16_size) {
+		fprintf(stderr, "BzImage truncated?\n");
+		return -1;
+	}
+
+	if ((uintmax_t)command_line_len > (uintmax_t)setup_header.cmdline_size) {
+		dbgprintf("Kernel command line too long for kernel!\n");
+		return -1;
+	}
+
+	/* Need to append some command line parameters internally in case of
+	 * taking crash dumps.
+	 */
+	if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) {
+		modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
+		memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
+		if (command_line) {
+			strncpy(modified_cmdline, command_line,
+					COMMAND_LINE_SIZE);
+			modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
+		}
+
+		/* If panic kernel is being loaded, additional segments need
+		 * to be created. load_crashdump_segments will take care of
+		 * loading the segments as high in memory as possible, hence
+		 * in turn as away as possible from kernel to avoid being
+		 * stomped by the kernel.
+		 */
+		if (load_crashdump_segments(info, modified_cmdline, -1, 0) < 0)
+			return -1;
+
+		/* Use new command line buffer */
+		command_line = modified_cmdline;
+		command_line_len = strlen(command_line) + 1;
+	}
+
+	/* x86_64 purgatory could be anywhere */
+	elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
+				0x3000, -1, -1, 0);
+	dbgprintf("Loaded purgatory at addr 0x%lx\n", info->rhdr.rel_addr);
+	/* The argument/parameter segment */
+	kern16_size_needed = kern16_size;
+	if (kern16_size_needed < 4096)
+		kern16_size_needed = 4096;
+	setup_size = kern16_size_needed + command_line_len +
+				PURGATORY_CMDLINE_SIZE;
+	real_mode = xmalloc(setup_size);
+	memset(real_mode, 0, setup_size);
+	memcpy(real_mode, kernel, kern16_size);
+	clean_boot_params((unsigned char *)real_mode, kern16_size);
+	real_mode->xloadflags |= (1<<15); /* USE_EXT_BOOT_PARAMS */
+
+	/* No real mode code will be executing. setup segment can be loaded
+	 * anywhere as we will be just reading command line.
+	 */
+	setup_base = add_buffer(info, real_mode, setup_size, setup_size,
+				16, 0x3000, -1, -1);
+
+	dbgprintf("Loaded real_mode_data and command line at 0x%lx\n",
+			setup_base);
+
+	/* Tell the kernel what is going on */
+	setup_linux_bootloader_parameters(info, real_mode, setup_base,
+			kern16_size_needed, command_line, command_line_len,
+			initrd, initrd_len);
+
+	/*
+	 * add kernel at last, to make kexec load big kernel faster.
+	 * we are finding buffer with run-time size, and only add buffer
+	 * with image size that is smaller than run-time size.
+	 * later kexec_load will take less time with small range.
+	 * otherwise kexec_load will allocate big range but only
+	 * copy small buffer and waste time on allocating not needed
+	 * range.
+	 */
+
+	/* The main kernel segment */
+	k_size = kernel_len - kern16_size;
+
+	/* need to use run-time size for buffer searching */
+	dbgprintf("kernel init_size 0x%x\n", real_mode->init_size);
+	size = (real_mode->init_size + (4096 - 1)) & ~(4096 - 1);
+
+	/* need to sort segments before locate_hole */
+	if (sort_segments(info) < 0)
+		die("sort_segments failed\n");
+
+	align = real_mode->kernel_alignment;
+	addr = locate_hole(info, size, align, 0x100000, -1, -1);
+	if (addr == ULONG_MAX)
+		die("can not load bzImage64");
+	dbgprintf("Found kernel buffer at %lx size %lx\n", addr, size);
+
+	/* put compressed image at start of buffer */
+	addr = add_buffer(info, kernel + kern16_size, k_size, k_size, align,
+				addr, addr + size, 1);
+	if (addr == ULONG_MAX)
+		die("can not load bzImage64");
+	dbgprintf("Loaded 64bit kernel at 0x%lx\n", addr);
+
+	elf_rel_get_symbol(&info->rhdr, "entry64_regs", &regs64,
+				 sizeof(regs64));
+	regs64.rbx = 0;           /* Bootstrap processor */
+	regs64.rsi = setup_base;  /* Pointer to the parameters */
+	regs64.rip = addr + 0x200; /* the entry point for startup_64 */
+	regs64.rsp = elf_rel_get_addr(&info->rhdr, "stack_end"); /* Stack, unused */
+	elf_rel_set_symbol(&info->rhdr, "entry64_regs", &regs64,
+				 sizeof(regs64));
+
+	cmdline_end = setup_base + kern16_size + command_line_len - 1;
+	elf_rel_set_symbol(&info->rhdr, "cmdline_end", &cmdline_end,
+			   sizeof(unsigned long));
+
+	/* Fill in the information BIOS calls would normally provide. */
+	setup_linux_system_parameters(real_mode, info->kexec_flags);
+
+	return 0;
+}
+
+int bzImage64_load(int argc, char **argv, const char *buf, off_t len,
+	struct kexec_info *info)
+{
+	char *command_line = NULL;
+	const char *ramdisk = NULL, *append = NULL;
+	char *ramdisk_buf;
+	off_t ramdisk_length = 0;
+	int command_line_len;
+	int entry_16bit = 0, entry_32bit = 0;
+	int opt;
+	int result;
+
+	/* See options.h -- add any more there, too. */
+	static const struct option options[] = {
+		KEXEC_ARCH_OPTIONS
+		{ "command-line",	1, 0, OPT_APPEND },
+		{ "append",		1, 0, OPT_APPEND },
+		{ "reuse-cmdline",	0, 0, OPT_REUSE_CMDLINE },
+		{ "initrd",		1, 0, OPT_RAMDISK },
+		{ "ramdisk",		1, 0, OPT_RAMDISK },
+		{ "real-mode",		0, 0, OPT_REAL_MODE },
+		{ "entry-32bit",	0, 0, OPT_ENTRY_32BIT },
+		{ 0,			0, 0, 0 },
+	};
+	static const char short_options[] = KEXEC_ARCH_OPT_STR "d";
+
+	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
+		switch (opt) {
+		default:
+			/* Ignore core options */
+			if (opt < OPT_ARCH_MAX)
+				break;
+		case '?':
+			usage();
+			return -1;
+			break;
+		case OPT_APPEND:
+			append = optarg;
+			break;
+		case OPT_REUSE_CMDLINE:
+			command_line = get_command_line();
+			break;
+		case OPT_RAMDISK:
+			ramdisk = optarg;
+			break;
+		case OPT_REAL_MODE:
+			entry_16bit = 1;
+			break;
+		case OPT_ENTRY_32BIT:
+			entry_32bit = 1;
+			break;
+		}
+	}
+	command_line = concat_cmdline(command_line, append);
+	command_line_len = 0;
+	if (command_line)
+		command_line_len = strlen(command_line) + 1;
+	ramdisk_buf = 0;
+	if (ramdisk)
+		ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
+
+	if (entry_16bit || entry_32bit)
+		result = do_bzImage_load(info, buf, len, command_line,
+					command_line_len, ramdisk_buf,
+					ramdisk_length, entry_16bit);
+	else
+		result = do_bzImage64_load(info, buf, len, command_line,
+					command_line_len, ramdisk_buf,
+					ramdisk_length);
+
+	free(command_line);
+	return result;
+}
Index: kexec-tools/kexec/arch/x86_64/kexec-x86_64.c
===================================================================
--- kexec-tools.orig/kexec/arch/x86_64/kexec-x86_64.c
+++ kexec-tools/kexec/arch/x86_64/kexec-x86_64.c
@@ -37,6 +37,7 @@ struct file_type file_type[] = {
 	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load,
 	  multiboot_x86_usage },
 	{ "elf-x86", elf_x86_probe, elf_x86_load, elf_x86_usage },
+	{ "bzImage64", bzImage64_probe, bzImage64_load, bzImage64_usage },
 	{ "bzImage", bzImage_probe, bzImage_load, bzImage_usage },
 	{ "beoboot-x86", beoboot_probe, beoboot_load, beoboot_usage },
 	{ "nbi-x86", nbi_probe, nbi_load, nbi_usage },
Index: kexec-tools/kexec/arch/x86_64/kexec-x86_64.h
===================================================================
--- kexec-tools.orig/kexec/arch/x86_64/kexec-x86_64.h
+++ kexec-tools/kexec/arch/x86_64/kexec-x86_64.h
@@ -28,4 +28,9 @@ int elf_x86_64_load(int argc, char **arg
 	struct kexec_info *info);
 void elf_x86_64_usage(void);
 
+int bzImage64_probe(const char *buf, off_t len);
+int bzImage64_load(int argc, char **argv, const char *buf, off_t len,
+			struct kexec_info *info);
+void bzImage64_usage(void);
+
 #endif /* KEXEC_X86_64_H */
Index: kexec-tools/kexec/arch/i386/include/arch/options.h
===================================================================
--- kexec-tools.orig/kexec/arch/i386/include/arch/options.h
+++ kexec-tools/kexec/arch/i386/include/arch/options.h
@@ -29,6 +29,7 @@
 #define OPT_MOD 		(OPT_ARCH_MAX+7)
 #define OPT_VGA 		(OPT_ARCH_MAX+8)
 #define OPT_REAL_MODE		(OPT_ARCH_MAX+9)
+#define OPT_ENTRY_32BIT		(OPT_ARCH_MAX+10)
 
 /* Options relevant to the architecture (excluding loader-specific ones): */
 #define KEXEC_ARCH_OPTIONS \
@@ -68,7 +69,8 @@
 	{ "args-linux",		0, NULL, OPT_ARGS_LINUX },	\
 	{ "args-none",		0, NULL, OPT_ARGS_NONE },	\
 	{ "module",		1, 0, OPT_MOD },		\
-	{ "real-mode",		0, NULL, OPT_REAL_MODE },
+	{ "real-mode",		0, NULL, OPT_REAL_MODE },	\
+	{ "entry-32bit",	0, NULL, OPT_ENTRY_32BIT },
 
 #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR
 

[-- Attachment #3: Type: text/plain, Size: 143 bytes --]

_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 6/6] kexec, x86_64: Load bzImage64 above 4G
  2012-11-25  0:38   ` Yinghai Lu
@ 2012-11-25  0:42     ` H. Peter Anvin
  0 siblings, 0 replies; 10+ messages in thread
From: H. Peter Anvin @ 2012-11-25  0:42 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Haren Myneni, Simon Horman, kexec, Eric W. Biederman, Vivek Goyal

On 11/24/2012 04:38 PM, Yinghai Lu wrote:
> On Sat, Nov 24, 2012 at 12:47 PM, Yinghai Lu <yinghai@kernel.org> wrote:
>> need to check xloadflags to see the bzImage is for 64bit relocatable.
>>
>> -v2: add kexec-bzImage64.c according to Eric.
>> -v3: don't need to purgatory under 2g after Eric's change to purgatory code.
>> -v4: use locate_hole find position first then add_buffer... suggested by Eric
>>       add buffer for kernel image at last to make kexec-load faster.
>>       use xloadflags in setup_header to tell if is bzImage64.
>>       remove not cross GB boundary searching.
>>       add --entry-32bit and --real-mode for skipping bzImage64.
>
> -v5: attached. that is using USE_EXT_BOOT_PARAMS bit in xloadflags
>

Yinghai, revving the patch is pointless until we agree on the proper 
architectural direction.

	-hpa

-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-11-25  0:42 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-24 20:47 [PATCH v4 0/6] kexec: put bzImage and ramdisk above 4G for x86 64bit Yinghai Lu
2012-11-24 20:47 ` [PATCH v4 1/6] kexec, x86: clean boot_params area for entry-32bit path Yinghai Lu
2012-11-24 20:47 ` [PATCH v4 2/6] kexec, x86: Fix bzImage real-mode booting Yinghai Lu
2012-11-24 20:47 ` [PATCH v4 3/6] kexec, x86: add boot header member for version 2.12 Yinghai Lu
2012-11-24 20:47 ` [PATCH v4 4/6] kexec, x86: put ramdisk high for 64bit bzImage Yinghai Lu
2012-11-25  0:37   ` Yinghai Lu
2012-11-24 20:47 ` [PATCH v4 5/6] kexec, x86: set ext_cmd_line_ptr when boot_param is above 4g Yinghai Lu
2012-11-24 20:47 ` [PATCH v4 6/6] kexec, x86_64: Load bzImage64 above 4G Yinghai Lu
2012-11-25  0:38   ` Yinghai Lu
2012-11-25  0:42     ` H. Peter Anvin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox