diff options
Diffstat (limited to 'kexec/arch/s390/kexec-image.c')
-rw-r--r-- | kexec/arch/s390/kexec-image.c | 69 |
1 files changed, 50 insertions, 19 deletions
diff --git a/kexec/arch/s390/kexec-image.c b/kexec/arch/s390/kexec-image.c index 7ef8e29..bed67cd 100644 --- a/kexec/arch/s390/kexec-image.c +++ b/kexec/arch/s390/kexec-image.c @@ -18,18 +18,41 @@ #include <unistd.h> #include <getopt.h> #include "../../kexec.h" +#include "../../kexec-syscall.h" +#include "../../kexec/crashdump.h" #include "kexec-s390.h" +#include "elf.h" #include <arch/options.h> +static uint64_t crash_base, crash_end; +static char command_line[COMMAND_LINESIZE]; + +static void add_segment_check(struct kexec_info *info, const void *buf, + size_t bufsz, unsigned long base, size_t memsz) +{ + if (info->kexec_flags & KEXEC_ON_CRASH) + if (base + memsz > crash_end - crash_base) + die("Not enough crashkernel memory to load segments\n"); + add_segment(info, buf, bufsz, crash_base + base, memsz); +} + +int command_line_add(const char *str) +{ + if (strlen(command_line) + strlen(str) + 1 > COMMAND_LINESIZE) { + fprintf(stderr, "Command line too long.\n"); + return -1; + } + strcat(command_line, str); + return 0; +} + int image_s390_load(int argc, char **argv, const char *kernel_buf, off_t kernel_size, struct kexec_info *info) { void *krnl_buffer; char *rd_buffer; - const char *command_line; const char *ramdisk; - int command_line_len; off_t ramdisk_len; unsigned int ramdisk_origin; int opt; @@ -44,7 +67,6 @@ image_s390_load(int argc, char **argv, const char *kernel_buf, static const char short_options[] = KEXEC_OPT_STR ""; ramdisk = NULL; - command_line = NULL; ramdisk_len = 0; ramdisk_origin = 0; @@ -55,7 +77,8 @@ image_s390_load(int argc, char **argv, const char *kernel_buf, return -1; break; case OPT_APPEND: - command_line = optarg; + if (command_line_add(optarg)) + return -1; break; case OPT_RAMDISK: ramdisk = optarg; @@ -63,17 +86,14 @@ image_s390_load(int argc, char **argv, const char *kernel_buf, } } - /* Process a given command_line: */ - if (command_line) { - command_line_len = strlen(command_line) + 1; /* Remember the '\0' */ - if (command_line_len > COMMAND_LINESIZE) { - fprintf(stderr, "Command line too long.\n"); + if (info->kexec_flags & KEXEC_ON_CRASH) { + if (parse_iomem_single("Crash kernel\n", &crash_base, + &crash_end)) return -1; - } } /* Add kernel segment */ - add_segment(info, kernel_buf + IMAGE_READ_OFFSET, + add_segment_check(info, kernel_buf + IMAGE_READ_OFFSET, kernel_size - IMAGE_READ_OFFSET, IMAGE_READ_OFFSET, kernel_size - IMAGE_READ_OFFSET); @@ -88,10 +108,17 @@ image_s390_load(int argc, char **argv, const char *kernel_buf, return -1; } ramdisk_origin = RAMDISK_ORIGIN_ADDR; - add_segment(info, rd_buffer, ramdisk_len, RAMDISK_ORIGIN_ADDR, ramdisk_len); + add_segment_check(info, rd_buffer, ramdisk_len, + RAMDISK_ORIGIN_ADDR, ramdisk_len); } - - /* Register the ramdisk in the kernel. */ + if (info->kexec_flags & KEXEC_ON_CRASH) { + if (load_crashdump_segments(info, crash_base, crash_end)) + return -1; + } else { + info->entry = (void *) IMAGE_READ_OFFSET; + } + + /* Register the ramdisk and crashkernel memory in the kernel. */ { unsigned long long *tmp; @@ -100,19 +127,23 @@ image_s390_load(int argc, char **argv, const char *kernel_buf, tmp = krnl_buffer + INITRD_SIZE_OFFS; *tmp = (unsigned long long) ramdisk_len; - } + if (info->kexec_flags & KEXEC_ON_CRASH) { + tmp = krnl_buffer + OLDMEM_BASE_OFFS; + *tmp = crash_base; + + tmp = krnl_buffer + OLDMEM_SIZE_OFFS; + *tmp = crash_end - crash_base + 1; + } + } /* * We will write a probably given command line. * First, erase the old area, then setup the new parameters: */ - if (command_line) { + if (strlen(command_line) != 0) { memset(krnl_buffer + COMMAND_LINE_OFFS, 0, COMMAND_LINESIZE); memcpy(krnl_buffer + COMMAND_LINE_OFFS, command_line, strlen(command_line)); } - - info->entry = (void *) IMAGE_READ_OFFSET; - return 0; } |