327 lines
11 KiB
Diff
327 lines
11 KiB
Diff
This patch increases the kernel command line size for x86_64 and i386
|
|
to 2048 characters. This is necessary because with kernel 2.6.20-rc6-mm
|
|
and newer, the kernel command line size has increased and kexec needs
|
|
lot of command line space, so this solves some "command line overflow"
|
|
problems.
|
|
|
|
To be able to warn users running older kernels that the command line
|
|
is too long (and don't wait that the kernel truncates it), the
|
|
patch tries to get the kernel command line length from the kernel
|
|
image that is loaded if possible by checking the length of the
|
|
static array that holds the kernel command line when booting.
|
|
|
|
If this is not possible or the command line is not in the range
|
|
[256; 2048], the default value is used (2048).
|
|
|
|
|
|
Signed-off-by: Bernhard Walle <bwalle@suse.de>
|
|
|
|
---
|
|
include/x86/x86-linux.h | 8 ++-----
|
|
kexec/arch/i386/crashdump-x86.c | 36 ++++++++++++++++++++++++++++++++---
|
|
kexec/arch/i386/crashdump-x86.h | 5 ++++
|
|
kexec/arch/i386/kexec-bzImage.c | 8 +++----
|
|
kexec/arch/i386/kexec-elf-x86.c | 8 +++----
|
|
kexec/arch/i386/x86-linux-setup.c | 6 +++--
|
|
kexec/arch/x86_64/crashdump-x86_64.c | 35 +++++++++++++++++++++++++++++++---
|
|
kexec/arch/x86_64/crashdump-x86_64.h | 3 ++
|
|
kexec/arch/x86_64/kexec-elf-x86_64.c | 11 ++++++----
|
|
9 files changed, 95 insertions(+), 25 deletions(-)
|
|
|
|
Index: b/include/x86/x86-linux.h
|
|
===================================================================
|
|
--- a/include/x86/x86-linux.h
|
|
+++ b/include/x86/x86-linux.h
|
|
@@ -148,14 +148,12 @@ struct x86_linux_param_header {
|
|
#endif
|
|
struct e820entry e820_map[E820MAX]; /* 0x2d0 */
|
|
/* 0x550 */
|
|
-#define COMMAND_LINE_SIZE 256
|
|
+#define COMMAND_LINE_SIZE 2048
|
|
};
|
|
|
|
struct x86_linux_faked_param_header {
|
|
- struct x86_linux_param_header hdr; /* 0x00 */
|
|
- uint8_t reserved16[688]; /* 0x550 */
|
|
- uint8_t command_line[COMMAND_LINE_SIZE]; /* 0x800 */
|
|
- uint8_t reserved17[1792]; /* 0x900 - 0x1000 */
|
|
+ struct x86_linux_param_header hdr;
|
|
+ uint8_t command_line[COMMAND_LINE_SIZE];
|
|
};
|
|
|
|
struct x86_linux_header {
|
|
Index: b/kexec/arch/i386/crashdump-x86.c
|
|
===================================================================
|
|
--- a/kexec/arch/i386/crashdump-x86.c
|
|
+++ b/kexec/arch/i386/crashdump-x86.c
|
|
@@ -46,6 +46,36 @@ static struct memory_range crash_memory_
|
|
/* Memory region reserved for storing panic kernel and other data. */
|
|
static struct memory_range crash_reserved_mem;
|
|
|
|
+/* real length of the command line from the kernel image, needed because
|
|
+ * command line size on x86-64 was increased recently in -mm tree */
|
|
+int real_command_line_size = COMMAND_LINE_SIZE;
|
|
+
|
|
+
|
|
+/* Tries to read the kernel command line size from the symbol table
|
|
+ * of the ELF kernel binary. */
|
|
+void set_command_line_size(struct mem_ehdr *ehdr)
|
|
+{
|
|
+ int ret;
|
|
+ struct mem_sym mem_sym;
|
|
+
|
|
+ /* > 2.6.20-rc6-mm */
|
|
+ ret = elf_rel_find_symbol(ehdr, "saved_command_line", &mem_sym);
|
|
+ if (ret != 0) {
|
|
+ /* older kernel */
|
|
+ ret = elf_rel_find_symbol(ehdr, "boot_command_line", &mem_sym);
|
|
+ if (ret != 0) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* current -mm kernel */
|
|
+ if (mem_sym.st_size >= 256 && mem_sym.st_size < COMMAND_LINE_SIZE) {
|
|
+ real_command_line_size = mem_sym.st_size;
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
/* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to
|
|
* create Elf headers. Keeping it separate from get_memory_ranges() as
|
|
* requirements are different in the case of normal kexec and crashdumps.
|
|
@@ -363,7 +393,7 @@ static int cmdline_add_memmap(char *cmdl
|
|
strcpy(str_mmap, " memmap=exactmap");
|
|
len = strlen(str_mmap);
|
|
cmdlen = strlen(cmdline) + len;
|
|
- if (cmdlen > (COMMAND_LINE_SIZE - 1))
|
|
+ if (cmdlen > (real_command_line_size - 1))
|
|
die("Command line overflow\n");
|
|
strcat(cmdline, str_mmap);
|
|
|
|
@@ -388,7 +418,7 @@ static int cmdline_add_memmap(char *cmdl
|
|
strcat (str_mmap, "K");
|
|
len = strlen(str_mmap);
|
|
cmdlen = strlen(cmdline) + len;
|
|
- if (cmdlen > (COMMAND_LINE_SIZE - 1))
|
|
+ if (cmdlen > (real_command_line_size - 1))
|
|
die("Command line overflow\n");
|
|
strcat(cmdline, str_mmap);
|
|
}
|
|
@@ -418,7 +448,7 @@ static int cmdline_add_elfcorehdr(char *
|
|
strcat(str, "K");
|
|
len = strlen(str);
|
|
cmdlen = strlen(cmdline) + len;
|
|
- if (cmdlen > (COMMAND_LINE_SIZE - 1))
|
|
+ if (cmdlen > (real_command_line_size - 1))
|
|
die("Command line overflow\n");
|
|
strcat(cmdline, str);
|
|
#if 0
|
|
Index: b/kexec/arch/i386/crashdump-x86.h
|
|
===================================================================
|
|
--- a/kexec/arch/i386/crashdump-x86.h
|
|
+++ b/kexec/arch/i386/crashdump-x86.h
|
|
@@ -2,8 +2,11 @@
|
|
#define CRASHDUMP_X86_H
|
|
|
|
struct kexec_info;
|
|
+struct mem_ehdr;
|
|
int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
|
|
unsigned long max_addr, unsigned long min_base);
|
|
+void set_command_line_size(struct mem_ehdr *ehdr);
|
|
+
|
|
|
|
#define PAGE_OFFSET 0xc0000000
|
|
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
|
|
@@ -19,4 +22,6 @@ int load_crashdump_segments(struct kexec
|
|
#define BACKUP_SRC_END 0x0009ffff
|
|
#define BACKUP_SRC_SIZE (BACKUP_SRC_END - BACKUP_SRC_START + 1)
|
|
|
|
+extern int real_command_line_size;
|
|
+
|
|
#endif /* CRASHDUMP_X86_H */
|
|
Index: b/kexec/arch/x86_64/crashdump-x86_64.c
|
|
===================================================================
|
|
--- a/kexec/arch/x86_64/crashdump-x86_64.c
|
|
+++ b/kexec/arch/x86_64/crashdump-x86_64.c
|
|
@@ -50,6 +50,35 @@ static struct crash_elf_info elf_info =
|
|
/* Forward Declaration. */
|
|
static int exclude_crash_reserve_region(int *nr_ranges);
|
|
|
|
+/* real length of the command line from the kernel image, needed because
|
|
+ * command line size on x86-64 was increased recently in -mm tree */
|
|
+int real_command_line_size = COMMAND_LINE_SIZE;
|
|
+
|
|
+
|
|
+/* Tries to read the kernel command line size from the symbol table
|
|
+ * of the ELF kernel binary. */
|
|
+void set_command_line_size(struct mem_ehdr *ehdr)
|
|
+{
|
|
+ int ret;
|
|
+ struct mem_sym mem_sym;
|
|
+
|
|
+ /* > 2.6.20-rc6-mm */
|
|
+ ret = elf_rel_find_symbol(ehdr, "saved_command_line", &mem_sym);
|
|
+ if (ret != 0) {
|
|
+ /* older kernel */
|
|
+ ret = elf_rel_find_symbol(ehdr, "boot_command_line", &mem_sym);
|
|
+ if (ret != 0) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* current -mm kernel */
|
|
+ if (mem_sym.st_size >= 256 && mem_sym.st_size < COMMAND_LINE_SIZE) {
|
|
+ real_command_line_size = mem_sym.st_size;
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
#define KERN_VADDR_ALIGN 0x100000 /* 1MB */
|
|
|
|
/* Read kernel physical load addr from /proc/iomem (Kernel Code) and
|
|
@@ -494,7 +523,7 @@ static int cmdline_add_memmap(char *cmdl
|
|
strcat (str_mmap, "K");
|
|
len = strlen(str_mmap);
|
|
cmdlen = strlen(cmdline) + len;
|
|
- if (cmdlen > (COMMAND_LINE_SIZE - 1))
|
|
+ if (cmdlen > (real_command_line_size - 1))
|
|
die("Command line overflow\n");
|
|
strcat(cmdline, str_mmap);
|
|
}
|
|
@@ -523,7 +552,7 @@ static int cmdline_add_elfcorehdr(char *
|
|
strcat(str, "K");
|
|
len = strlen(str);
|
|
cmdlen = strlen(cmdline) + len;
|
|
- if (cmdlen > (COMMAND_LINE_SIZE - 1))
|
|
+ if (cmdlen > (real_command_line_size - 1))
|
|
die("Command line overflow\n");
|
|
strcat(cmdline, str);
|
|
#ifdef DEBUG
|
|
@@ -555,7 +584,7 @@ static int cmdline_add_memmap_acpi(char
|
|
strcat (str_mmap, "K");
|
|
len = strlen(str_mmap);
|
|
cmdlen = strlen(cmdline) + len;
|
|
- if (cmdlen > (COMMAND_LINE_SIZE - 1))
|
|
+ if (cmdlen > (real_command_line_size - 1))
|
|
die("Command line overflow\n");
|
|
strcat(cmdline, str_mmap);
|
|
|
|
Index: b/kexec/arch/x86_64/crashdump-x86_64.h
|
|
===================================================================
|
|
--- a/kexec/arch/x86_64/crashdump-x86_64.h
|
|
+++ b/kexec/arch/x86_64/crashdump-x86_64.h
|
|
@@ -3,6 +3,7 @@
|
|
|
|
int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
|
|
unsigned long max_addr, unsigned long min_base);
|
|
+void set_command_line_size(struct mem_ehdr *ehdr);
|
|
|
|
#define __START_KERNEL_map 0xffffffff80000000UL
|
|
#define PAGE_OFFSET 0xffff810000000000UL
|
|
@@ -21,4 +22,6 @@ int load_crashdump_segments(struct kexec
|
|
#define BACKUP_SRC_END 0x0009ffff
|
|
#define BACKUP_SRC_SIZE (BACKUP_SRC_END - BACKUP_SRC_START + 1)
|
|
|
|
+extern int real_command_line_size;
|
|
+
|
|
#endif /* CRASHDUMP_X86_64_H */
|
|
Index: b/kexec/arch/x86_64/kexec-elf-x86_64.c
|
|
===================================================================
|
|
--- a/kexec/arch/x86_64/kexec-elf-x86_64.c
|
|
+++ b/kexec/arch/x86_64/kexec-elf-x86_64.c
|
|
@@ -166,12 +166,12 @@ int elf_x86_64_load(int argc, char **arg
|
|
* taking crash dumps.
|
|
*/
|
|
if (info->kexec_flags & KEXEC_ON_CRASH) {
|
|
- modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
|
|
- memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
|
|
+ modified_cmdline = xmalloc(real_command_line_size);
|
|
+ memset((void *)modified_cmdline, 0, real_command_line_size);
|
|
if (command_line) {
|
|
strncpy(modified_cmdline, command_line,
|
|
- COMMAND_LINE_SIZE);
|
|
- modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
|
|
+ real_command_line_size);
|
|
+ modified_cmdline[real_command_line_size - 1] = '\0';
|
|
}
|
|
modified_cmdline_len = strlen(modified_cmdline);
|
|
}
|
|
@@ -182,6 +182,9 @@ int elf_x86_64_load(int argc, char **arg
|
|
entry = ehdr.e_entry;
|
|
max_addr = elf_max_addr(&ehdr);
|
|
|
|
+ /* try to set the command line size correctly */
|
|
+ set_command_line_size(&ehdr);
|
|
+
|
|
/* Do we want arguments? */
|
|
if (arg_style != ARG_STYLE_NONE) {
|
|
/* Load the setup code */
|
|
Index: b/kexec/arch/i386/kexec-bzImage.c
|
|
===================================================================
|
|
--- a/kexec/arch/i386/kexec-bzImage.c
|
|
+++ b/kexec/arch/i386/kexec-bzImage.c
|
|
@@ -156,12 +156,12 @@ int do_bzImage_load(struct kexec_info *i
|
|
* taking crash dumps.
|
|
*/
|
|
if (info->kexec_flags & KEXEC_ON_CRASH) {
|
|
- modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
|
|
- memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
|
|
+ modified_cmdline = xmalloc(real_command_line_size);
|
|
+ memset((void *)modified_cmdline, 0, real_command_line_size);
|
|
if (command_line) {
|
|
strncpy(modified_cmdline, command_line,
|
|
- COMMAND_LINE_SIZE);
|
|
- modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
|
|
+ real_command_line_size);
|
|
+ modified_cmdline[real_command_line_size - 1] = '\0';
|
|
}
|
|
|
|
/* If panic kernel is being loaded, additional segments need
|
|
Index: b/kexec/arch/i386/kexec-elf-x86.c
|
|
===================================================================
|
|
--- a/kexec/arch/i386/kexec-elf-x86.c
|
|
+++ b/kexec/arch/i386/kexec-elf-x86.c
|
|
@@ -166,12 +166,12 @@ int elf_x86_load(int argc, char **argv,
|
|
* taking crash dumps.
|
|
*/
|
|
if (info->kexec_flags & KEXEC_ON_CRASH) {
|
|
- modified_cmdline = xmalloc(COMMAND_LINE_SIZE);
|
|
- memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE);
|
|
+ modified_cmdline = xmalloc(real_command_line_size);
|
|
+ memset((void *)modified_cmdline, 0, real_command_line_size);
|
|
if (command_line) {
|
|
strncpy(modified_cmdline, command_line,
|
|
- COMMAND_LINE_SIZE);
|
|
- modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0';
|
|
+ real_command_line_size);
|
|
+ modified_cmdline[real_command_line_size - 1] = '\0';
|
|
}
|
|
modified_cmdline_len = strlen(modified_cmdline);
|
|
}
|
|
Index: b/kexec/arch/i386/x86-linux-setup.c
|
|
===================================================================
|
|
--- a/kexec/arch/i386/x86-linux-setup.c
|
|
+++ b/kexec/arch/i386/x86-linux-setup.c
|
|
@@ -32,6 +32,8 @@
|
|
#include "kexec-x86.h"
|
|
#include "x86-linux-setup.h"
|
|
|
|
+extern int real_command_line_size;
|
|
+
|
|
void init_linux_parameters(struct x86_linux_param_header *real_mode)
|
|
{
|
|
/* Fill in the values that are usually provided by the kernel. */
|
|
@@ -91,8 +93,8 @@ void setup_linux_bootloader_parameters(
|
|
}
|
|
|
|
/* Fill in the command line */
|
|
- if (cmdline_len > COMMAND_LINE_SIZE) {
|
|
- cmdline_len = COMMAND_LINE_SIZE;
|
|
+ if (cmdline_len > real_command_line_size) {
|
|
+ cmdline_len = real_command_line_size;
|
|
}
|
|
cmdline_ptr = ((char *)real_mode) + cmdline_offset;
|
|
memcpy(cmdline_ptr, cmdline, cmdline_len);
|