225 lines
7.6 KiB
Diff
225 lines
7.6 KiB
Diff
|
commit defb80a20bf1e4d778596ce2447e19d44f31ae5a
|
||
|
Author: Sven Schnelle <svens@linux.ibm.com>
|
||
|
Date: Thu Dec 16 12:43:52 2021 +0100
|
||
|
|
||
|
s390: add variable command line size
|
||
|
|
||
|
Newer s390 kernels support a command line size longer than 896
|
||
|
bytes. Such kernels contain a new member in the parameter area,
|
||
|
which might be utilized by tools like kexec. Older kernels have
|
||
|
the location initialized to zero, so we check whether there's a
|
||
|
non-zero number present and use that. If there isn't, we fallback
|
||
|
to the legacy command line size of 896 bytes.
|
||
|
|
||
|
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
|
||
|
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
|
||
|
Signed-off-by: Simon Horman <horms@verge.net.au>
|
||
|
|
||
|
diff --git a/kexec/arch/s390/crashdump-s390.c b/kexec/arch/s390/crashdump-s390.c
|
||
|
index 10f4d607bbcc1aea362de3de687b0e7b2401d879..3bd9efe6dafebab2f364c656ae703c71c4494c35 100644
|
||
|
--- a/kexec/arch/s390/crashdump-s390.c
|
||
|
+++ b/kexec/arch/s390/crashdump-s390.c
|
||
|
@@ -52,7 +52,8 @@ static int create_elf_header(struct kexec_info *info, unsigned long crash_base,
|
||
|
elfcorehdr_size = bufsz;
|
||
|
snprintf(str, sizeof(str), " elfcorehdr=%ld@%ldK\n",
|
||
|
elfcorehdr_size, elfcorehdr / 1024);
|
||
|
- command_line_add(str);
|
||
|
+ if (command_line_add(info, str))
|
||
|
+ return -1;
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
diff --git a/kexec/arch/s390/kexec-image.c b/kexec/arch/s390/kexec-image.c
|
||
|
index 3c24fdfe3c7ccafddee9fb4a68c0d8874cf6a61e..a52399eafd2abd4a24142f0512251598ea812ca5 100644
|
||
|
--- a/kexec/arch/s390/kexec-image.c
|
||
|
+++ b/kexec/arch/s390/kexec-image.c
|
||
|
@@ -25,7 +25,6 @@
|
||
|
#include <fcntl.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)
|
||
|
@@ -36,13 +35,18 @@ static void add_segment_check(struct kexec_info *info, const void *buf,
|
||
|
add_segment(info, buf, bufsz, crash_base + base, memsz);
|
||
|
}
|
||
|
|
||
|
-int command_line_add(const char *str)
|
||
|
+int command_line_add(struct kexec_info *info, const char *str)
|
||
|
{
|
||
|
- if (strlen(command_line) + strlen(str) + 1 > COMMAND_LINESIZE) {
|
||
|
- fprintf(stderr, "Command line too long.\n");
|
||
|
+ char *tmp = NULL;
|
||
|
+
|
||
|
+ tmp = concat_cmdline(info->command_line, str);
|
||
|
+ if (!tmp) {
|
||
|
+ fprintf(stderr, "out of memory\n");
|
||
|
return -1;
|
||
|
}
|
||
|
- strcat(command_line, str);
|
||
|
+
|
||
|
+ free(info->command_line);
|
||
|
+ info->command_line = tmp;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -64,7 +68,7 @@ int image_s390_load_file(int argc, char **argv, struct kexec_info *info)
|
||
|
while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
|
||
|
switch(opt) {
|
||
|
case OPT_APPEND:
|
||
|
- if (command_line_add(optarg))
|
||
|
+ if (command_line_add(info, optarg))
|
||
|
return -1;
|
||
|
break;
|
||
|
case OPT_RAMDISK:
|
||
|
@@ -78,13 +82,16 @@ int image_s390_load_file(int argc, char **argv, struct kexec_info *info)
|
||
|
if (info->initrd_fd == -1) {
|
||
|
fprintf(stderr, "Could not open initrd file %s:%s\n",
|
||
|
ramdisk, strerror(errno));
|
||
|
+ free(info->command_line);
|
||
|
+ info->command_line = NULL;
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- info->command_line = command_line;
|
||
|
- info->command_line_len = strlen (command_line) + 1;
|
||
|
-
|
||
|
+ if (info->command_line)
|
||
|
+ info->command_line_len = strlen(info->command_line) + 1;
|
||
|
+ else
|
||
|
+ info->command_line_len = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -97,7 +104,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
|
||
|
const char *ramdisk;
|
||
|
off_t ramdisk_len;
|
||
|
unsigned int ramdisk_origin;
|
||
|
- int opt;
|
||
|
+ int opt, ret = -1;
|
||
|
|
||
|
if (info->file_mode)
|
||
|
return image_s390_load_file(argc, argv, info);
|
||
|
@@ -112,7 +119,6 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
|
||
|
};
|
||
|
static const char short_options[] = KEXEC_OPT_STR "";
|
||
|
|
||
|
- command_line[0] = 0;
|
||
|
ramdisk = NULL;
|
||
|
ramdisk_len = 0;
|
||
|
ramdisk_origin = 0;
|
||
|
@@ -120,7 +126,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
|
||
|
while ((opt = getopt_long(argc,argv,short_options,options,0)) != -1) {
|
||
|
switch(opt) {
|
||
|
case OPT_APPEND:
|
||
|
- if (command_line_add(optarg))
|
||
|
+ if (command_line_add(info, optarg))
|
||
|
return -1;
|
||
|
break;
|
||
|
case OPT_RAMDISK:
|
||
|
@@ -132,7 +138,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
|
||
|
if (info->kexec_flags & KEXEC_ON_CRASH) {
|
||
|
if (parse_iomem_single("Crash kernel\n", &crash_base,
|
||
|
&crash_end))
|
||
|
- return -1;
|
||
|
+ goto out;
|
||
|
}
|
||
|
|
||
|
/* Add kernel segment */
|
||
|
@@ -151,7 +157,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
|
||
|
rd_buffer = slurp_file_mmap(ramdisk, &ramdisk_len);
|
||
|
if (rd_buffer == NULL) {
|
||
|
fprintf(stderr, "Could not read ramdisk.\n");
|
||
|
- return -1;
|
||
|
+ goto out;
|
||
|
}
|
||
|
ramdisk_origin = MAX(RAMDISK_ORIGIN_ADDR, kernel_size);
|
||
|
ramdisk_origin = _ALIGN_UP(ramdisk_origin, 0x100000);
|
||
|
@@ -160,7 +166,7 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
|
||
|
}
|
||
|
if (info->kexec_flags & KEXEC_ON_CRASH) {
|
||
|
if (load_crashdump_segments(info, crash_base, crash_end))
|
||
|
- return -1;
|
||
|
+ goto out;
|
||
|
} else {
|
||
|
info->entry = (void *) IMAGE_READ_OFFSET;
|
||
|
}
|
||
|
@@ -183,15 +189,28 @@ image_s390_load(int argc, char **argv, const char *kernel_buf,
|
||
|
*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 (strlen(command_line) != 0) {
|
||
|
- memset(krnl_buffer + COMMAND_LINE_OFFS, 0, COMMAND_LINESIZE);
|
||
|
- memcpy(krnl_buffer + COMMAND_LINE_OFFS, command_line, strlen(command_line));
|
||
|
+
|
||
|
+ if (info->command_line) {
|
||
|
+ unsigned long maxsize;
|
||
|
+ char *dest = krnl_buffer + COMMAND_LINE_OFFS;
|
||
|
+
|
||
|
+ maxsize = *(unsigned long *)(krnl_buffer + MAX_COMMAND_LINESIZE_OFFS);
|
||
|
+ if (!maxsize)
|
||
|
+ maxsize = LEGACY_COMMAND_LINESIZE;
|
||
|
+
|
||
|
+ if (strlen(info->command_line) > maxsize-1) {
|
||
|
+ fprintf(stderr, "command line too long, maximum allowed size %ld\n",
|
||
|
+ maxsize-1);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ strncpy(dest, info->command_line, maxsize-1);
|
||
|
+ dest[maxsize-1] = '\0';
|
||
|
}
|
||
|
- return 0;
|
||
|
+ ret = 0;
|
||
|
+out:
|
||
|
+ free(info->command_line);
|
||
|
+ info->command_line = NULL;
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
diff --git a/kexec/arch/s390/kexec-s390.h b/kexec/arch/s390/kexec-s390.h
|
||
|
index ef53b111e16719d15e5364c18435e272f98b9086..6a99518c1c9e411ed853489daf0de6463972ab6f 100644
|
||
|
--- a/kexec/arch/s390/kexec-s390.h
|
||
|
+++ b/kexec/arch/s390/kexec-s390.h
|
||
|
@@ -10,16 +10,17 @@
|
||
|
#ifndef KEXEC_S390_H
|
||
|
#define KEXEC_S390_H
|
||
|
|
||
|
-#define IMAGE_READ_OFFSET 0x10000
|
||
|
+#define IMAGE_READ_OFFSET 0x10000
|
||
|
|
||
|
-#define RAMDISK_ORIGIN_ADDR 0x800000
|
||
|
-#define INITRD_START_OFFS 0x408
|
||
|
-#define INITRD_SIZE_OFFS 0x410
|
||
|
-#define OLDMEM_BASE_OFFS 0x418
|
||
|
-#define OLDMEM_SIZE_OFFS 0x420
|
||
|
-#define COMMAND_LINE_OFFS 0x480
|
||
|
-#define COMMAND_LINESIZE 896
|
||
|
-#define MAX_MEMORY_RANGES 1024
|
||
|
+#define RAMDISK_ORIGIN_ADDR 0x800000
|
||
|
+#define INITRD_START_OFFS 0x408
|
||
|
+#define INITRD_SIZE_OFFS 0x410
|
||
|
+#define OLDMEM_BASE_OFFS 0x418
|
||
|
+#define OLDMEM_SIZE_OFFS 0x420
|
||
|
+#define MAX_COMMAND_LINESIZE_OFFS 0x430
|
||
|
+#define COMMAND_LINE_OFFS 0x480
|
||
|
+#define LEGACY_COMMAND_LINESIZE 896
|
||
|
+#define MAX_MEMORY_RANGES 1024
|
||
|
|
||
|
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||
|
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||
|
@@ -32,6 +33,6 @@ extern int load_crashdump_segments(struct kexec_info *info,
|
||
|
unsigned long crash_end);
|
||
|
extern int get_memory_ranges_s390(struct memory_range range[], int *ranges,
|
||
|
int with_crashk);
|
||
|
-extern int command_line_add(const char *str);
|
||
|
+extern int command_line_add(struct kexec_info *info, const char *str);
|
||
|
|
||
|
#endif /* KEXEC_S390_H */
|