Skip to content

Commit

Permalink
s390: support command lines longer than 896 bytes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sven Schnelle authored and Vasily Gorbik committed Oct 26, 2021
1 parent 277c838 commit 5ecb2da
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 34 deletions.
35 changes: 12 additions & 23 deletions arch/s390/boot/head.S
Original file line number Diff line number Diff line change
Expand Up @@ -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:

#
Expand Down Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions arch/s390/boot/ipl_parm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
7 changes: 5 additions & 2 deletions arch/s390/include/asm/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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;
Expand Down
2 changes: 0 additions & 2 deletions arch/s390/include/uapi/asm/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@

#define COMMAND_LINE_SIZE 4096

#define ARCH_COMMAND_LINE_SIZE 896

#endif /* _UAPI_ASM_S390_SETUP_H */
1 change: 1 addition & 0 deletions arch/s390/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
2 changes: 1 addition & 1 deletion arch/s390/kernel/early.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
22 changes: 18 additions & 4 deletions arch/s390/kernel/machine_kexec_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Expand Down

0 comments on commit 5ecb2da

Please sign in to comment.