Blob Blame History Raw
 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 */