summaryrefslogtreecommitdiff
path: root/kexec/arch/i386
diff options
context:
space:
mode:
Diffstat (limited to 'kexec/arch/i386')
-rw-r--r--kexec/arch/i386/crashdump-x86.c51
-rw-r--r--kexec/arch/i386/kexec-bzImage.c10
-rw-r--r--kexec/arch/i386/kexec-elf-x86.c4
-rw-r--r--kexec/arch/i386/kexec-x86-common.c3
-rw-r--r--kexec/arch/i386/x86-linux-setup.h3
5 files changed, 51 insertions, 20 deletions
diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c
index 7717219..478d6be 100644
--- a/kexec/arch/i386/crashdump-x86.c
+++ b/kexec/arch/i386/crashdump-x86.c
@@ -57,7 +57,8 @@ static struct memory_range crash_reserved_mem;
* to look into down the line. May be something like /proc/kernelmem or may
* be zone data structures exported from kernel.
*/
-static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
+static int get_crash_memory_ranges(struct memory_range **range, int *ranges,
+ int kexec_flags)
{
const char *iomem = proc_iomem();
int memory_ranges = 0;
@@ -74,10 +75,12 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
/* First entry is for first 640K region. Different bios report first
* 640K in different manner hence hardcoding it */
- crash_memory_range[0].start = 0x00000000;
- crash_memory_range[0].end = 0x0009ffff;
- crash_memory_range[0].type = RANGE_RAM;
- memory_ranges++;
+ if (!(kexec_flags & KEXEC_PRESERVE_CONTEXT)) {
+ crash_memory_range[0].start = 0x00000000;
+ crash_memory_range[0].end = 0x0009ffff;
+ crash_memory_range[0].type = RANGE_RAM;
+ memory_ranges++;
+ }
while(fgets(line, sizeof(line), fp) != 0) {
char *str;
@@ -128,6 +131,22 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges)
}
}
fclose(fp);
+ if (kexec_flags & KEXEC_PRESERVE_CONTEXT) {
+ int i;
+ for (i = 0; i < memory_ranges; i++) {
+ if (crash_memory_range[i].end > 0x0009ffff) {
+ crash_reserved_mem.start = \
+ crash_memory_range[i].start;
+ break;
+ }
+ }
+ if (crash_reserved_mem.start >= mem_max) {
+ fprintf("Too small mem_max: 0x%lx.\n", mem_max);
+ return -1;
+ }
+ crash_reserved_mem.end = mem_max;
+ crash_reserved_mem.type = RANGE_RAM;
+ }
if (exclude_crash_reserve_region(&memory_ranges) < 0)
return -1;
*range = crash_memory_range;
@@ -514,7 +533,8 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
int nr_ranges, align = 1024;
struct memory_range *mem_range, *memmap_p;
- if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0)
+ if (get_crash_memory_ranges(&mem_range, &nr_ranges,
+ info->kexec_flags) < 0)
return -1;
/*
@@ -535,14 +555,17 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline,
add_memmap(memmap_p, crash_reserved_mem.start, sz);
/* Create a backup region segment to store backup data*/
- sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1);
- tmp = xmalloc(sz);
- memset(tmp, 0, sz);
- info->backup_start = add_buffer(info, tmp, sz, sz, align,
- 0, max_addr, -1);
- dbgprintf("Created backup segment at 0x%lx\n", info->backup_start);
- if (delete_memmap(memmap_p, info->backup_start, sz) < 0)
- return -1;
+ if (!(info->kexec_flags & KEXEC_PRESERVE_CONTEXT)) {
+ sz = (BACKUP_SRC_SIZE + align - 1) & ~(align - 1);
+ tmp = xmalloc(sz);
+ memset(tmp, 0, sz);
+ info->backup_start = add_buffer(info, tmp, sz, sz, align,
+ 0, max_addr, -1);
+ dbgprintf("Created backup segment at 0x%lx\n",
+ info->backup_start);
+ if (delete_memmap(memmap_p, info->backup_start, sz) < 0)
+ return -1;
+ }
/* Create elf header segment and store crash image data. */
if (arch_options.core_header_type == CORE_TYPE_ELF64) {
diff --git a/kexec/arch/i386/kexec-bzImage.c b/kexec/arch/i386/kexec-bzImage.c
index 1f40076..be88a3f 100644
--- a/kexec/arch/i386/kexec-bzImage.c
+++ b/kexec/arch/i386/kexec-bzImage.c
@@ -114,6 +114,7 @@ int do_bzImage_load(struct kexec_info *info,
unsigned int relocatable_kernel = 0;
unsigned long kernel32_load_addr;
char *modified_cmdline;
+ unsigned long cmdline_end;
/*
* Find out about the file I am about to load.
@@ -166,7 +167,7 @@ int do_bzImage_load(struct kexec_info *info,
/* Need to append some command line parameters internally in case of
* taking crash dumps.
*/
- if (info->kexec_flags & KEXEC_ON_CRASH) {
+ 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) {
@@ -205,11 +206,11 @@ int do_bzImage_load(struct kexec_info *info,
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;
+ setup_size = kern16_size + command_line_len + PURGATORY_CMDLINE_SIZE;
real_mode = xmalloc(setup_size);
memcpy(real_mode, kernel, kern16_size);
- if (info->kexec_flags & KEXEC_ON_CRASH) {
+ if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) {
/* If using bzImage for capture kernel, then we will not be
* executing real mode code. setup segment can be loaded
* anywhere as we will be just reading command line.
@@ -316,6 +317,9 @@ int do_bzImage_load(struct kexec_info *info,
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,
+ sizeof(unsigned long));
/* Fill in the information BIOS calls would normally provide. */
if (!real_mode_entry) {
diff --git a/kexec/arch/i386/kexec-elf-x86.c b/kexec/arch/i386/kexec-elf-x86.c
index ddd4a10..5a763bd 100644
--- a/kexec/arch/i386/kexec-elf-x86.c
+++ b/kexec/arch/i386/kexec-elf-x86.c
@@ -170,7 +170,7 @@ int elf_x86_load(int argc, char **argv, const char *buf, off_t len,
/* Need to append some command line parameters internally in case of
* taking crash dumps.
*/
- if (info->kexec_flags & KEXEC_ON_CRASH) {
+ 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) {
@@ -257,7 +257,7 @@ int elf_x86_load(int argc, char **argv, const char *buf, off_t len,
/* If panic kernel is being loaded, additional segments need
* to be created. */
- if (info->kexec_flags & KEXEC_ON_CRASH) {
+ if (info->kexec_flags & (KEXEC_ON_CRASH|KEXEC_PRESERVE_CONTEXT)) {
rc = load_crashdump_segments(info, modified_cmdline,
max_addr, 0);
if (rc < 0)
diff --git a/kexec/arch/i386/kexec-x86-common.c b/kexec/arch/i386/kexec-x86-common.c
index 4533425..00c2be3 100644
--- a/kexec/arch/i386/kexec-x86-common.c
+++ b/kexec/arch/i386/kexec-x86-common.c
@@ -174,7 +174,8 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
* Override user values only if kernel exported values are
* subset of user defined values.
*/
- if (kexec_flags & KEXEC_ON_CRASH) {
+ if ((kexec_flags & KEXEC_ON_CRASH) &&
+ !(kexec_flags & KEXEC_PRESERVE_CONTEXT)) {
unsigned long long start, end;
ret = parse_iomem_single("Crash kernel\n", &start, &end);
diff --git a/kexec/arch/i386/x86-linux-setup.h b/kexec/arch/i386/x86-linux-setup.h
index 13784cf..c16b41a 100644
--- a/kexec/arch/i386/x86-linux-setup.h
+++ b/kexec/arch/i386/x86-linux-setup.h
@@ -15,4 +15,7 @@ void setup_linux_system_parameters(struct x86_linux_param_header *real_mode,
#define KERN32_BASE 0x100000 /* 1MB */
#define INITRD_BASE 0x1000000 /* 16MB */
+/* command line parameter may be appended by purgatory */
+#define PURGATORY_CMDLINE_SIZE 64
+
#endif /* X86_LINUX_SETUP_H */