public inbox for kexec@lists.infradead.org
 help / color / mirror / Atom feed
From: Yinghai Lu <yinghai@kernel.org>
To: Simon Horman <horms@verge.net.au>,
	"H. Peter Anvin" <hpa@zytor.com>, Vivek Goyal <vgoyal@redhat.com>,
	"Eric W. Biederman" <ebiederm@xmission.com>
Cc: Yinghai Lu <yinghai@kernel.org>, kexec@lists.infradead.org
Subject: [PATCH v8 4/7] kexec, x86: Fix bzImage real-mode booting
Date: Wed, 30 Jan 2013 13:25:17 -0800	[thread overview]
Message-ID: <1359581120-24397-5-git-send-email-yinghai@kernel.org> (raw)
In-Reply-To: <1359581120-24397-1-git-send-email-yinghai@kernel.org>

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 file changed, 50 insertions(+), 13 deletions(-)

diff --git a/kexec/arch/i386/kexec-bzImage.c b/kexec/arch/i386/kexec-bzImage.c
index 1dfa3d7..add0646 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);
@@ -278,11 +302,18 @@ 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 && real_mode->protocol_version >= 0x0201) {
+		real_mode->loader_flags |= 0x80; /* CAN_USE_HEAP */
+		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));
 	/*
 
@@ -301,16 +332,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;
@@ -330,10 +363,14 @@ 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;
+	cmdline_end = setup_base + kern16_size_needed + command_line_len - 1;
 	elf_rel_set_symbol(&info->rhdr, "cmdline_end", &cmdline_end,
 			   sizeof(unsigned long));
 
-- 
1.7.10.4


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

  parent reply	other threads:[~2013-01-30 21:25 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-30 21:25 [PATCH v8 0/7] kexec: put bzImage and ramdisk above 4G for x86 64bit Yinghai Lu
2013-01-30 21:25 ` [PATCH v8 1/7] kexec, x86: set booloader id in setup_header Yinghai Lu
2013-01-30 21:25 ` [PATCH v8 2/7] kexec, x86: add boot header member for version 2.12 Yinghai Lu
2013-01-30 21:25 ` [PATCH v8 3/7] kexec, x86: clean boot_params area for entry-32bit path Yinghai Lu
2013-01-30 21:34   ` H. Peter Anvin
2013-01-30 22:09     ` Yinghai Lu
2013-01-30 22:11       ` H. Peter Anvin
2013-01-30 21:25 ` Yinghai Lu [this message]
2013-01-30 21:25 ` [PATCH v8 5/7] kexec, x86: put ramdisk/cmd_line above 4G for 64bit bzImage Yinghai Lu
2013-01-30 21:25 ` [PATCH v8 6/7] kexec, x86_64: Load bzImage64 above 4G Yinghai Lu
2013-01-30 21:25 ` [PATCH v8 7/7] kexec, x86: handle Crash low kernel range Yinghai Lu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1359581120-24397-5-git-send-email-yinghai@kernel.org \
    --to=yinghai@kernel.org \
    --cc=ebiederm@xmission.com \
    --cc=horms@verge.net.au \
    --cc=hpa@zytor.com \
    --cc=kexec@lists.infradead.org \
    --cc=vgoyal@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox