summaryrefslogtreecommitdiff
path: root/kexec/arch/s390/kexec-image.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexec/arch/s390/kexec-image.c')
-rw-r--r--kexec/arch/s390/kexec-image.c69
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;
}