s390: support command lines longer than 896 bytes
authorSven Schnelle <svens@linux.ibm.com>
Thu, 23 Sep 2021 19:22:52 +0000 (21:22 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Tue, 26 Oct 2021 13:21:31 +0000 (15:21 +0200)
Currently s390 supports a fixed maximum command line length of 896
bytes. This isn't enough as some installers are trying to pass all
configuration data via kernel command line, and even with zfcp alone
it is easy to generate really long command lines. Therefore extend
the command line to 4 kbytes.

In the parm area where the command line is stored there is no indication
of the maximum allowed length, so a new field which contains the maximum
length is added.

The parm area has always been initialized to zero, so with old kernels
this field would read zero. This is important because tools like zipl
could read this field. If it contains a number larger than zero zipl
knows the maximum length that can be stored in the parm area, otherwise
it must assume that it is booting a legacy kernel and only 896 bytes are
available.

The removing of trailing whitespace in head.S is also removed because
code to do this is already present in setup_boot_command_line().

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/boot/head.S
arch/s390/boot/ipl_parm.c
arch/s390/include/asm/setup.h
arch/s390/include/uapi/asm/setup.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/early.c
arch/s390/kernel/machine_kexec_file.c

index 5d3fc69a505c73a802254baffc9cc273555fe945..3a252d140c55fb15471c241f39785fc055d8a0b0 100644 (file)
@@ -184,35 +184,23 @@ iplstart:
        bas     %r14,.Lloader           # load parameter file
        ltr     %r2,%r2                 # got anything ?
        bz      .Lnopf
-       chi     %r2,895
-       bnh     .Lnotrunc
-       la      %r2,895
+       l       %r3,MAX_COMMAND_LINE_SIZE+ARCH_OFFSET-PARMAREA(%r12)
+       ahi     %r3,-1
+       clr     %r2,%r3
+       bl      .Lnotrunc
+       lr      %r2,%r3
 .Lnotrunc:
        l       %r4,.Linitrd
        clc     0(3,%r4),.L_hdr         # if it is HDRx
        bz      .Lagain1                # skip dataset header
        clc     0(3,%r4),.L_eof         # if it is EOFx
        bz      .Lagain1                # skip dateset trailer
-       la      %r5,0(%r4,%r2)
-       lr      %r3,%r2
-       la      %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
-       mvc     0(256,%r3),0(%r4)
-       mvc     256(256,%r3),256(%r4)
-       mvc     512(256,%r3),512(%r4)
-       mvc     768(122,%r3),768(%r4)
-       slr     %r0,%r0
-       b       .Lcntlp
-.Ldelspc:
-       ic      %r0,0(%r2,%r3)
-       chi     %r0,0x20                # is it a space ?
-       be      .Lcntlp
-       ahi     %r2,1
-       b       .Leolp
-.Lcntlp:
-       brct    %r2,.Ldelspc
-.Leolp:
-       slr     %r0,%r0
-       stc     %r0,0(%r2,%r3)          # terminate buffer
+
+       lr      %r5,%r2
+       la      %r6,COMMAND_LINE-PARMAREA(%r12)
+       lr      %r7,%r2
+       ahi     %r7,1
+       mvcl    %r6,%r4
 .Lnopf:
 
 #
@@ -394,6 +382,7 @@ SYM_DATA_START(parmarea)
        .quad   0                       # OLDMEM_BASE
        .quad   0                       # OLDMEM_SIZE
        .quad   kernel_version          # points to kernel version string
+       .quad   COMMAND_LINE_SIZE
 
        .org    COMMAND_LINE
        .byte   "root=/dev/ram0 ro"
index 0f84c072625e07462deba1705dd90ba9c1b1e403..9ed7e29c81d9a0ec9e167f9b2e9d6fcf067c6c74 100644 (file)
@@ -170,10 +170,10 @@ static inline int has_ebcdic_char(const char *str)
 
 void setup_boot_command_line(void)
 {
-       parmarea.command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0;
+       parmarea.command_line[COMMAND_LINE_SIZE - 1] = 0;
        /* convert arch command line to ascii if necessary */
        if (has_ebcdic_char(parmarea.command_line))
-               EBCASC(parmarea.command_line, ARCH_COMMAND_LINE_SIZE);
+               EBCASC(parmarea.command_line, COMMAND_LINE_SIZE);
        /* copy arch command line */
        strcpy(early_command_line, strim(parmarea.command_line));
 
index 121e1a8c41d73a0e9da5a41bdd3d851b9ccb2fee..d718029794e2c88ffc4db400203df30fe629f1cd 100644 (file)
@@ -42,6 +42,8 @@
 #define STARTUP_NORMAL_OFFSET  0x10000
 #define STARTUP_KDUMP_OFFSET   0x10010
 
+#define LEGACY_COMMAND_LINE_SIZE       896
+
 #ifndef __ASSEMBLY__
 
 #include <asm/lowcore.h>
@@ -54,8 +56,9 @@ struct parmarea {
        unsigned long oldmem_base;                      /* 0x10418 */
        unsigned long oldmem_size;                      /* 0x10420 */
        unsigned long kernel_version;                   /* 0x10428 */
-       char pad1[0x10480 - 0x10430];                   /* 0x10430 - 0x10480 */
-       char command_line[ARCH_COMMAND_LINE_SIZE];      /* 0x10480 */
+       unsigned long max_command_line_size;            /* 0x10430 */
+       char pad1[0x10480-0x10438];                     /* 0x10438 - 0x10480 */
+       char command_line[COMMAND_LINE_SIZE];           /* 0x10480 */
 };
 
 extern struct parmarea parmarea;
index 1f8803a31079527f55b622c7794ff1c56328f3fa..9b685536c31c31d8de5615190d7b219051d366a3 100644 (file)
@@ -9,6 +9,4 @@
 
 #define COMMAND_LINE_SIZE      4096
 
-#define ARCH_COMMAND_LINE_SIZE 896
-
 #endif /* _UAPI_ASM_S390_SETUP_H */
index 28177e4f52cc3acaf9b51b73207d4200e3e0403d..8e00bb22866235b80cf22e6cd675bc903f67f316 100644 (file)
@@ -164,5 +164,6 @@ int main(void)
        DEFINE(OLDMEM_BASE, PARMAREA + offsetof(struct parmarea, oldmem_base));
        DEFINE(OLDMEM_SIZE, PARMAREA + offsetof(struct parmarea, oldmem_size));
        DEFINE(COMMAND_LINE, PARMAREA + offsetof(struct parmarea, command_line));
+       DEFINE(MAX_COMMAND_LINE_SIZE, PARMAREA + offsetof(struct parmarea, max_command_line_size));
        return 0;
 }
index ba3ace5ac73c6ba8f36a3e445144e7bcd05a3a57..3cdf68c536147f6deac0244437b222b45e75e7f5 100644 (file)
@@ -280,7 +280,7 @@ char __bootdata(early_command_line)[COMMAND_LINE_SIZE];
 static void __init setup_boot_command_line(void)
 {
        /* copy arch command line */
-       strlcpy(boot_command_line, early_command_line, ARCH_COMMAND_LINE_SIZE);
+       strlcpy(boot_command_line, early_command_line, COMMAND_LINE_SIZE);
 }
 
 static void __init check_image_bootable(void)
index 55382ffde9d45feddf406488ee4addaf42ca23b3..528edff085d9ab8d3efaa56f2dbf9a7a8ac4d059 100644 (file)
@@ -216,7 +216,9 @@ void *kexec_file_add_components(struct kimage *image,
                                int (*add_kernel)(struct kimage *image,
                                                  struct s390_load_data *data))
 {
+       unsigned long max_command_line_size = LEGACY_COMMAND_LINE_SIZE;
        struct s390_load_data data = {0};
+       unsigned long minsize;
        int ret;
 
        data.report = ipl_report_init(&ipl_block);
@@ -227,11 +229,23 @@ void *kexec_file_add_components(struct kimage *image,
        if (ret)
                goto out;
 
-       if (image->kernel_buf_len < PARMAREA + sizeof(struct parmarea) ||
-           image->cmdline_buf_len >= ARCH_COMMAND_LINE_SIZE) {
-               ret = -EINVAL;
+       ret = -EINVAL;
+       minsize = PARMAREA + offsetof(struct parmarea, command_line);
+       if (image->kernel_buf_len < minsize)
                goto out;
-       }
+
+       if (data.parm->max_command_line_size)
+               max_command_line_size = data.parm->max_command_line_size;
+
+       if (minsize + max_command_line_size < minsize)
+               goto out;
+
+       if (image->kernel_buf_len < minsize + max_command_line_size)
+               goto out;
+
+       if (image->cmdline_buf_len >= max_command_line_size)
+               goto out;
+
        memcpy(data.parm->command_line, image->cmdline_buf,
               image->cmdline_buf_len);