diff options
-rw-r--r-- | arch/s390/boot/Makefile | 3 | ||||
-rw-r--r-- | arch/s390/boot/boot.h | 3 | ||||
-rw-r--r-- | arch/s390/boot/cmdline.c | 2 | ||||
-rw-r--r-- | arch/s390/boot/ctype.c | 2 | ||||
-rw-r--r-- | arch/s390/boot/ipl_parm.c | 173 | ||||
-rw-r--r-- | arch/s390/boot/ipl_vmparm.c | 2 | ||||
-rw-r--r-- | arch/s390/boot/startup.c | 3 | ||||
-rw-r--r-- | arch/s390/boot/string.c | 100 | ||||
-rw-r--r-- | arch/s390/include/asm/boot_data.h | 11 | ||||
-rw-r--r-- | arch/s390/include/asm/ipl.h | 4 | ||||
-rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/early.c | 47 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 117 | ||||
-rw-r--r-- | arch/s390/kernel/ipl_vmparm.c | 36 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 26 |
15 files changed, 355 insertions, 176 deletions
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile index b6903c47e0ac..f58edd8b2e34 100644 --- a/arch/s390/boot/Makefile +++ b/arch/s390/boot/Makefile | |||
@@ -27,7 +27,8 @@ endif | |||
27 | 27 | ||
28 | CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char | 28 | CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char |
29 | 29 | ||
30 | obj-y := head.o als.o startup.o mem_detect.o ebcdic.o sclp_early_core.o mem.o | 30 | obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o string.o ebcdic.o |
31 | obj-y += sclp_early_core.o mem.o ipl_vmparm.o cmdline.o ctype.o | ||
31 | targets := bzImage startup.a section_cmp.boot.data $(obj-y) | 32 | targets := bzImage startup.a section_cmp.boot.data $(obj-y) |
32 | subdir- := compressed | 33 | subdir- := compressed |
33 | 34 | ||
diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h index 808154b99a5d..fc41e2277ea8 100644 --- a/arch/s390/boot/boot.h +++ b/arch/s390/boot/boot.h | |||
@@ -4,5 +4,8 @@ | |||
4 | 4 | ||
5 | void startup_kernel(void); | 5 | void startup_kernel(void); |
6 | void detect_memory(void); | 6 | void detect_memory(void); |
7 | void store_ipl_parmblock(void); | ||
8 | void setup_boot_command_line(void); | ||
9 | void setup_memory_end(void); | ||
7 | 10 | ||
8 | #endif /* BOOT_BOOT_H */ | 11 | #endif /* BOOT_BOOT_H */ |
diff --git a/arch/s390/boot/cmdline.c b/arch/s390/boot/cmdline.c new file mode 100644 index 000000000000..73d826cdbdeb --- /dev/null +++ b/arch/s390/boot/cmdline.c | |||
@@ -0,0 +1,2 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include "../../../lib/cmdline.c" | ||
diff --git a/arch/s390/boot/ctype.c b/arch/s390/boot/ctype.c new file mode 100644 index 000000000000..2495810b47e3 --- /dev/null +++ b/arch/s390/boot/ctype.c | |||
@@ -0,0 +1,2 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include "../../../lib/ctype.c" | ||
diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c new file mode 100644 index 000000000000..7f8e546400a1 --- /dev/null +++ b/arch/s390/boot/ipl_parm.c | |||
@@ -0,0 +1,173 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <linux/init.h> | ||
3 | #include <linux/ctype.h> | ||
4 | #include <asm/ebcdic.h> | ||
5 | #include <asm/sclp.h> | ||
6 | #include <asm/sections.h> | ||
7 | #include <asm/boot_data.h> | ||
8 | #include "boot.h" | ||
9 | |||
10 | char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; | ||
11 | struct ipl_parameter_block __bootdata(early_ipl_block); | ||
12 | int __bootdata(early_ipl_block_valid); | ||
13 | |||
14 | unsigned long __bootdata(memory_end); | ||
15 | int __bootdata(memory_end_set); | ||
16 | |||
17 | static inline int __diag308(unsigned long subcode, void *addr) | ||
18 | { | ||
19 | register unsigned long _addr asm("0") = (unsigned long)addr; | ||
20 | register unsigned long _rc asm("1") = 0; | ||
21 | unsigned long reg1, reg2; | ||
22 | psw_t old = S390_lowcore.program_new_psw; | ||
23 | |||
24 | asm volatile( | ||
25 | " epsw %0,%1\n" | ||
26 | " st %0,%[psw_pgm]\n" | ||
27 | " st %1,%[psw_pgm]+4\n" | ||
28 | " larl %0,1f\n" | ||
29 | " stg %0,%[psw_pgm]+8\n" | ||
30 | " diag %[addr],%[subcode],0x308\n" | ||
31 | "1: nopr %%r7\n" | ||
32 | : "=&d" (reg1), "=&a" (reg2), | ||
33 | [psw_pgm] "=Q" (S390_lowcore.program_new_psw), | ||
34 | [addr] "+d" (_addr), "+d" (_rc) | ||
35 | : [subcode] "d" (subcode) | ||
36 | : "cc", "memory"); | ||
37 | S390_lowcore.program_new_psw = old; | ||
38 | return _rc; | ||
39 | } | ||
40 | |||
41 | void store_ipl_parmblock(void) | ||
42 | { | ||
43 | int rc; | ||
44 | |||
45 | rc = __diag308(DIAG308_STORE, &early_ipl_block); | ||
46 | if (rc == DIAG308_RC_OK && | ||
47 | early_ipl_block.hdr.version <= IPL_MAX_SUPPORTED_VERSION) | ||
48 | early_ipl_block_valid = 1; | ||
49 | } | ||
50 | |||
51 | static size_t scpdata_length(const char *buf, size_t count) | ||
52 | { | ||
53 | while (count) { | ||
54 | if (buf[count - 1] != '\0' && buf[count - 1] != ' ') | ||
55 | break; | ||
56 | count--; | ||
57 | } | ||
58 | return count; | ||
59 | } | ||
60 | |||
61 | static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size, | ||
62 | const struct ipl_parameter_block *ipb) | ||
63 | { | ||
64 | size_t count; | ||
65 | size_t i; | ||
66 | int has_lowercase; | ||
67 | |||
68 | count = min(size - 1, scpdata_length(ipb->ipl_info.fcp.scp_data, | ||
69 | ipb->ipl_info.fcp.scp_data_len)); | ||
70 | if (!count) | ||
71 | goto out; | ||
72 | |||
73 | has_lowercase = 0; | ||
74 | for (i = 0; i < count; i++) { | ||
75 | if (!isascii(ipb->ipl_info.fcp.scp_data[i])) { | ||
76 | count = 0; | ||
77 | goto out; | ||
78 | } | ||
79 | if (!has_lowercase && islower(ipb->ipl_info.fcp.scp_data[i])) | ||
80 | has_lowercase = 1; | ||
81 | } | ||
82 | |||
83 | if (has_lowercase) | ||
84 | memcpy(dest, ipb->ipl_info.fcp.scp_data, count); | ||
85 | else | ||
86 | for (i = 0; i < count; i++) | ||
87 | dest[i] = tolower(ipb->ipl_info.fcp.scp_data[i]); | ||
88 | out: | ||
89 | dest[count] = '\0'; | ||
90 | return count; | ||
91 | } | ||
92 | |||
93 | static void append_ipl_block_parm(void) | ||
94 | { | ||
95 | char *parm, *delim; | ||
96 | size_t len, rc = 0; | ||
97 | |||
98 | len = strlen(early_command_line); | ||
99 | |||
100 | delim = early_command_line + len; /* '\0' character position */ | ||
101 | parm = early_command_line + len + 1; /* append right after '\0' */ | ||
102 | |||
103 | switch (early_ipl_block.hdr.pbt) { | ||
104 | case DIAG308_IPL_TYPE_CCW: | ||
105 | rc = ipl_block_get_ascii_vmparm( | ||
106 | parm, COMMAND_LINE_SIZE - len - 1, &early_ipl_block); | ||
107 | break; | ||
108 | case DIAG308_IPL_TYPE_FCP: | ||
109 | rc = ipl_block_get_ascii_scpdata( | ||
110 | parm, COMMAND_LINE_SIZE - len - 1, &early_ipl_block); | ||
111 | break; | ||
112 | } | ||
113 | if (rc) { | ||
114 | if (*parm == '=') | ||
115 | memmove(early_command_line, parm + 1, rc); | ||
116 | else | ||
117 | *delim = ' '; /* replace '\0' with space */ | ||
118 | } | ||
119 | } | ||
120 | |||
121 | static inline int has_ebcdic_char(const char *str) | ||
122 | { | ||
123 | int i; | ||
124 | |||
125 | for (i = 0; str[i]; i++) | ||
126 | if (str[i] & 0x80) | ||
127 | return 1; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | void setup_boot_command_line(void) | ||
132 | { | ||
133 | COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0; | ||
134 | /* convert arch command line to ascii if necessary */ | ||
135 | if (has_ebcdic_char(COMMAND_LINE)) | ||
136 | EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); | ||
137 | /* copy arch command line */ | ||
138 | strcpy(early_command_line, strim(COMMAND_LINE)); | ||
139 | |||
140 | /* append IPL PARM data to the boot command line */ | ||
141 | if (early_ipl_block_valid) | ||
142 | append_ipl_block_parm(); | ||
143 | } | ||
144 | |||
145 | static char command_line_buf[COMMAND_LINE_SIZE] __section(.data); | ||
146 | static void parse_mem_opt(void) | ||
147 | { | ||
148 | char *args; | ||
149 | char *param, *val; | ||
150 | |||
151 | args = strcpy(command_line_buf, early_command_line); | ||
152 | while (*args) { | ||
153 | args = next_arg(args, ¶m, &val); | ||
154 | |||
155 | if (!strcmp(param, "mem")) { | ||
156 | memory_end = memparse(val, NULL); | ||
157 | memory_end_set = 1; | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | void setup_memory_end(void) | ||
163 | { | ||
164 | parse_mem_opt(); | ||
165 | #ifdef CONFIG_CRASH_DUMP | ||
166 | if (!OLDMEM_BASE && early_ipl_block_valid && | ||
167 | early_ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP && | ||
168 | early_ipl_block.ipl_info.fcp.opt == DIAG308_IPL_OPT_DUMP) { | ||
169 | if (!sclp_early_get_hsa_size(&memory_end) && memory_end) | ||
170 | memory_end_set = 1; | ||
171 | } | ||
172 | #endif | ||
173 | } | ||
diff --git a/arch/s390/boot/ipl_vmparm.c b/arch/s390/boot/ipl_vmparm.c new file mode 100644 index 000000000000..8dacd5fadfd7 --- /dev/null +++ b/arch/s390/boot/ipl_vmparm.c | |||
@@ -0,0 +1,2 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include "../kernel/ipl_vmparm.c" | ||
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index b0e9f4619203..4d441317cdeb 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c | |||
@@ -51,6 +51,9 @@ void startup_kernel(void) | |||
51 | 51 | ||
52 | rescue_initrd(); | 52 | rescue_initrd(); |
53 | sclp_early_read_info(); | 53 | sclp_early_read_info(); |
54 | store_ipl_parmblock(); | ||
55 | setup_boot_command_line(); | ||
56 | setup_memory_end(); | ||
54 | detect_memory(); | 57 | detect_memory(); |
55 | if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) { | 58 | if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) { |
56 | img = decompress_kernel(); | 59 | img = decompress_kernel(); |
diff --git a/arch/s390/boot/string.c b/arch/s390/boot/string.c new file mode 100644 index 000000000000..09ca9130e73a --- /dev/null +++ b/arch/s390/boot/string.c | |||
@@ -0,0 +1,100 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <linux/ctype.h> | ||
3 | #include <linux/kernel.h> | ||
4 | #include "../lib/string.c" | ||
5 | |||
6 | int strncmp(const char *cs, const char *ct, size_t count) | ||
7 | { | ||
8 | unsigned char c1, c2; | ||
9 | |||
10 | while (count) { | ||
11 | c1 = *cs++; | ||
12 | c2 = *ct++; | ||
13 | if (c1 != c2) | ||
14 | return c1 < c2 ? -1 : 1; | ||
15 | if (!c1) | ||
16 | break; | ||
17 | count--; | ||
18 | } | ||
19 | return 0; | ||
20 | } | ||
21 | |||
22 | char *skip_spaces(const char *str) | ||
23 | { | ||
24 | while (isspace(*str)) | ||
25 | ++str; | ||
26 | return (char *)str; | ||
27 | } | ||
28 | |||
29 | char *strim(char *s) | ||
30 | { | ||
31 | size_t size; | ||
32 | char *end; | ||
33 | |||
34 | size = strlen(s); | ||
35 | if (!size) | ||
36 | return s; | ||
37 | |||
38 | end = s + size - 1; | ||
39 | while (end >= s && isspace(*end)) | ||
40 | end--; | ||
41 | *(end + 1) = '\0'; | ||
42 | |||
43 | return skip_spaces(s); | ||
44 | } | ||
45 | |||
46 | /* Works only for digits and letters, but small and fast */ | ||
47 | #define TOLOWER(x) ((x) | 0x20) | ||
48 | |||
49 | static unsigned int simple_guess_base(const char *cp) | ||
50 | { | ||
51 | if (cp[0] == '0') { | ||
52 | if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2])) | ||
53 | return 16; | ||
54 | else | ||
55 | return 8; | ||
56 | } else { | ||
57 | return 10; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * simple_strtoull - convert a string to an unsigned long long | ||
63 | * @cp: The start of the string | ||
64 | * @endp: A pointer to the end of the parsed string will be placed here | ||
65 | * @base: The number base to use | ||
66 | */ | ||
67 | |||
68 | unsigned long long simple_strtoull(const char *cp, char **endp, | ||
69 | unsigned int base) | ||
70 | { | ||
71 | unsigned long long result = 0; | ||
72 | |||
73 | if (!base) | ||
74 | base = simple_guess_base(cp); | ||
75 | |||
76 | if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x') | ||
77 | cp += 2; | ||
78 | |||
79 | while (isxdigit(*cp)) { | ||
80 | unsigned int value; | ||
81 | |||
82 | value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10; | ||
83 | if (value >= base) | ||
84 | break; | ||
85 | result = result * base + value; | ||
86 | cp++; | ||
87 | } | ||
88 | if (endp) | ||
89 | *endp = (char *)cp; | ||
90 | |||
91 | return result; | ||
92 | } | ||
93 | |||
94 | long simple_strtol(const char *cp, char **endp, unsigned int base) | ||
95 | { | ||
96 | if (*cp == '-') | ||
97 | return -simple_strtoull(cp + 1, endp, base); | ||
98 | |||
99 | return simple_strtoull(cp, endp, base); | ||
100 | } | ||
diff --git a/arch/s390/include/asm/boot_data.h b/arch/s390/include/asm/boot_data.h new file mode 100644 index 000000000000..2d999ccb977a --- /dev/null +++ b/arch/s390/include/asm/boot_data.h | |||
@@ -0,0 +1,11 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #ifndef _ASM_S390_BOOT_DATA_H | ||
3 | |||
4 | #include <asm/setup.h> | ||
5 | #include <asm/ipl.h> | ||
6 | |||
7 | extern char early_command_line[COMMAND_LINE_SIZE]; | ||
8 | extern struct ipl_parameter_block early_ipl_block; | ||
9 | extern int early_ipl_block_valid; | ||
10 | |||
11 | #endif /* _ASM_S390_BOOT_DATA_H */ | ||
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h index ae5135704616..a8389e2d2f03 100644 --- a/arch/s390/include/asm/ipl.h +++ b/arch/s390/include/asm/ipl.h | |||
@@ -89,8 +89,8 @@ void __init save_area_add_vxrs(struct save_area *, __vector128 *vxrs); | |||
89 | 89 | ||
90 | extern void s390_reset_system(void); | 90 | extern void s390_reset_system(void); |
91 | extern void ipl_store_parameters(void); | 91 | extern void ipl_store_parameters(void); |
92 | extern size_t append_ipl_vmparm(char *, size_t); | 92 | extern size_t ipl_block_get_ascii_vmparm(char *dest, size_t size, |
93 | extern size_t append_ipl_scpdata(char *, size_t); | 93 | const struct ipl_parameter_block *ipb); |
94 | 94 | ||
95 | enum ipl_type { | 95 | enum ipl_type { |
96 | IPL_TYPE_UNKNOWN = 1, | 96 | IPL_TYPE_UNKNOWN = 1, |
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index dbfd1730e631..7ad6fa60a1f2 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -47,7 +47,7 @@ obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o early_nobss.o | |||
47 | obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o | 47 | obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o |
48 | obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o | 48 | obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o |
49 | obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o | 49 | obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o |
50 | obj-y += nospec-branch.o | 50 | obj-y += nospec-branch.o ipl_vmparm.o |
51 | 51 | ||
52 | extra-y += head64.o vmlinux.lds | 52 | extra-y += head64.o vmlinux.lds |
53 | 53 | ||
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 5b28b434f8a1..af5c2b3f7065 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
@@ -29,10 +29,9 @@ | |||
29 | #include <asm/cpcmd.h> | 29 | #include <asm/cpcmd.h> |
30 | #include <asm/sclp.h> | 30 | #include <asm/sclp.h> |
31 | #include <asm/facility.h> | 31 | #include <asm/facility.h> |
32 | #include <asm/boot_data.h> | ||
32 | #include "entry.h" | 33 | #include "entry.h" |
33 | 34 | ||
34 | static void __init setup_boot_command_line(void); | ||
35 | |||
36 | /* | 35 | /* |
37 | * Initialize storage key for kernel pages | 36 | * Initialize storage key for kernel pages |
38 | */ | 37 | */ |
@@ -284,51 +283,11 @@ static int __init cad_setup(char *str) | |||
284 | } | 283 | } |
285 | early_param("cad", cad_setup); | 284 | early_param("cad", cad_setup); |
286 | 285 | ||
287 | /* Set up boot command line */ | 286 | char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; |
288 | static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t)) | ||
289 | { | ||
290 | char *parm, *delim; | ||
291 | size_t rc, len; | ||
292 | |||
293 | len = strlen(boot_command_line); | ||
294 | |||
295 | delim = boot_command_line + len; /* '\0' character position */ | ||
296 | parm = boot_command_line + len + 1; /* append right after '\0' */ | ||
297 | |||
298 | rc = ipl_data(parm, COMMAND_LINE_SIZE - len - 1); | ||
299 | if (rc) { | ||
300 | if (*parm == '=') | ||
301 | memmove(boot_command_line, parm + 1, rc); | ||
302 | else | ||
303 | *delim = ' '; /* replace '\0' with space */ | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static inline int has_ebcdic_char(const char *str) | ||
308 | { | ||
309 | int i; | ||
310 | |||
311 | for (i = 0; str[i]; i++) | ||
312 | if (str[i] & 0x80) | ||
313 | return 1; | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static void __init setup_boot_command_line(void) | 287 | static void __init setup_boot_command_line(void) |
318 | { | 288 | { |
319 | COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0; | ||
320 | /* convert arch command line to ascii if necessary */ | ||
321 | if (has_ebcdic_char(COMMAND_LINE)) | ||
322 | EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); | ||
323 | /* copy arch command line */ | 289 | /* copy arch command line */ |
324 | strlcpy(boot_command_line, strstrip(COMMAND_LINE), | 290 | strlcpy(boot_command_line, early_command_line, ARCH_COMMAND_LINE_SIZE); |
325 | ARCH_COMMAND_LINE_SIZE); | ||
326 | |||
327 | /* append IPL PARM data to the boot command line */ | ||
328 | if (MACHINE_IS_VM) | ||
329 | append_to_cmdline(append_ipl_vmparm); | ||
330 | |||
331 | append_to_cmdline(append_ipl_scpdata); | ||
332 | } | 291 | } |
333 | 292 | ||
334 | static void __init check_image_bootable(void) | 293 | static void __init check_image_bootable(void) |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 4296d7e61fb6..f1d69f78bb1d 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <asm/checksum.h> | 29 | #include <asm/checksum.h> |
30 | #include <asm/debug.h> | 30 | #include <asm/debug.h> |
31 | #include <asm/os_info.h> | 31 | #include <asm/os_info.h> |
32 | #include <asm/sections.h> | ||
33 | #include <asm/boot_data.h> | ||
32 | #include "entry.h" | 34 | #include "entry.h" |
33 | 35 | ||
34 | #define IPL_PARM_BLOCK_VERSION 0 | 36 | #define IPL_PARM_BLOCK_VERSION 0 |
@@ -117,6 +119,9 @@ static char *dump_type_str(enum dump_type type) | |||
117 | } | 119 | } |
118 | } | 120 | } |
119 | 121 | ||
122 | struct ipl_parameter_block __bootdata(early_ipl_block); | ||
123 | int __bootdata(early_ipl_block_valid); | ||
124 | |||
120 | static int ipl_block_valid; | 125 | static int ipl_block_valid; |
121 | static struct ipl_parameter_block ipl_block; | 126 | static struct ipl_parameter_block ipl_block; |
122 | 127 | ||
@@ -262,115 +267,16 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr, | |||
262 | 267 | ||
263 | static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); | 268 | static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); |
264 | 269 | ||
265 | /* VM IPL PARM routines */ | ||
266 | static size_t reipl_get_ascii_vmparm(char *dest, size_t size, | ||
267 | const struct ipl_parameter_block *ipb) | ||
268 | { | ||
269 | int i; | ||
270 | size_t len; | ||
271 | char has_lowercase = 0; | ||
272 | |||
273 | len = 0; | ||
274 | if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) && | ||
275 | (ipb->ipl_info.ccw.vm_parm_len > 0)) { | ||
276 | |||
277 | len = min_t(size_t, size - 1, ipb->ipl_info.ccw.vm_parm_len); | ||
278 | memcpy(dest, ipb->ipl_info.ccw.vm_parm, len); | ||
279 | /* If at least one character is lowercase, we assume mixed | ||
280 | * case; otherwise we convert everything to lowercase. | ||
281 | */ | ||
282 | for (i = 0; i < len; i++) | ||
283 | if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */ | ||
284 | (dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */ | ||
285 | (dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */ | ||
286 | has_lowercase = 1; | ||
287 | break; | ||
288 | } | ||
289 | if (!has_lowercase) | ||
290 | EBC_TOLOWER(dest, len); | ||
291 | EBCASC(dest, len); | ||
292 | } | ||
293 | dest[len] = 0; | ||
294 | |||
295 | return len; | ||
296 | } | ||
297 | |||
298 | size_t append_ipl_vmparm(char *dest, size_t size) | ||
299 | { | ||
300 | size_t rc; | ||
301 | |||
302 | rc = 0; | ||
303 | if (ipl_block_valid && ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW) | ||
304 | rc = reipl_get_ascii_vmparm(dest, size, &ipl_block); | ||
305 | else | ||
306 | dest[0] = 0; | ||
307 | return rc; | ||
308 | } | ||
309 | |||
310 | static ssize_t ipl_vm_parm_show(struct kobject *kobj, | 270 | static ssize_t ipl_vm_parm_show(struct kobject *kobj, |
311 | struct kobj_attribute *attr, char *page) | 271 | struct kobj_attribute *attr, char *page) |
312 | { | 272 | { |
313 | char parm[DIAG308_VMPARM_SIZE + 1] = {}; | 273 | char parm[DIAG308_VMPARM_SIZE + 1] = {}; |
314 | 274 | ||
315 | append_ipl_vmparm(parm, sizeof(parm)); | 275 | if (ipl_block_valid && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW)) |
276 | ipl_block_get_ascii_vmparm(parm, sizeof(parm), &ipl_block); | ||
316 | return sprintf(page, "%s\n", parm); | 277 | return sprintf(page, "%s\n", parm); |
317 | } | 278 | } |
318 | 279 | ||
319 | static size_t scpdata_length(const char* buf, size_t count) | ||
320 | { | ||
321 | while (count) { | ||
322 | if (buf[count - 1] != '\0' && buf[count - 1] != ' ') | ||
323 | break; | ||
324 | count--; | ||
325 | } | ||
326 | return count; | ||
327 | } | ||
328 | |||
329 | static size_t reipl_append_ascii_scpdata(char *dest, size_t size, | ||
330 | const struct ipl_parameter_block *ipb) | ||
331 | { | ||
332 | size_t count; | ||
333 | size_t i; | ||
334 | int has_lowercase; | ||
335 | |||
336 | count = min(size - 1, scpdata_length(ipb->ipl_info.fcp.scp_data, | ||
337 | ipb->ipl_info.fcp.scp_data_len)); | ||
338 | if (!count) | ||
339 | goto out; | ||
340 | |||
341 | has_lowercase = 0; | ||
342 | for (i = 0; i < count; i++) { | ||
343 | if (!isascii(ipb->ipl_info.fcp.scp_data[i])) { | ||
344 | count = 0; | ||
345 | goto out; | ||
346 | } | ||
347 | if (!has_lowercase && islower(ipb->ipl_info.fcp.scp_data[i])) | ||
348 | has_lowercase = 1; | ||
349 | } | ||
350 | |||
351 | if (has_lowercase) | ||
352 | memcpy(dest, ipb->ipl_info.fcp.scp_data, count); | ||
353 | else | ||
354 | for (i = 0; i < count; i++) | ||
355 | dest[i] = tolower(ipb->ipl_info.fcp.scp_data[i]); | ||
356 | out: | ||
357 | dest[count] = '\0'; | ||
358 | return count; | ||
359 | } | ||
360 | |||
361 | size_t append_ipl_scpdata(char *dest, size_t len) | ||
362 | { | ||
363 | size_t rc; | ||
364 | |||
365 | rc = 0; | ||
366 | if (ipl_block_valid && ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP) | ||
367 | rc = reipl_append_ascii_scpdata(dest, len, &ipl_block); | ||
368 | else | ||
369 | dest[0] = 0; | ||
370 | return rc; | ||
371 | } | ||
372 | |||
373 | |||
374 | static struct kobj_attribute sys_ipl_vm_parm_attr = | 280 | static struct kobj_attribute sys_ipl_vm_parm_attr = |
375 | __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL); | 281 | __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL); |
376 | 282 | ||
@@ -564,7 +470,7 @@ static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb, | |||
564 | { | 470 | { |
565 | char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; | 471 | char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; |
566 | 472 | ||
567 | reipl_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb); | 473 | ipl_block_get_ascii_vmparm(vmparm, sizeof(vmparm), ipb); |
568 | return sprintf(page, "%s\n", vmparm); | 474 | return sprintf(page, "%s\n", vmparm); |
569 | } | 475 | } |
570 | 476 | ||
@@ -1769,11 +1675,10 @@ void __init setup_ipl(void) | |||
1769 | 1675 | ||
1770 | void __init ipl_store_parameters(void) | 1676 | void __init ipl_store_parameters(void) |
1771 | { | 1677 | { |
1772 | int rc; | 1678 | if (early_ipl_block_valid) { |
1773 | 1679 | memcpy(&ipl_block, &early_ipl_block, sizeof(ipl_block)); | |
1774 | rc = diag308(DIAG308_STORE, &ipl_block); | ||
1775 | if (rc == DIAG308_RC_OK && ipl_block.hdr.version <= IPL_MAX_SUPPORTED_VERSION) | ||
1776 | ipl_block_valid = 1; | 1680 | ipl_block_valid = 1; |
1681 | } | ||
1777 | } | 1682 | } |
1778 | 1683 | ||
1779 | void s390_reset_system(void) | 1684 | void s390_reset_system(void) |
diff --git a/arch/s390/kernel/ipl_vmparm.c b/arch/s390/kernel/ipl_vmparm.c new file mode 100644 index 000000000000..411838c0a0af --- /dev/null +++ b/arch/s390/kernel/ipl_vmparm.c | |||
@@ -0,0 +1,36 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <asm/ebcdic.h> | ||
3 | #include <asm/ipl.h> | ||
4 | |||
5 | /* VM IPL PARM routines */ | ||
6 | size_t ipl_block_get_ascii_vmparm(char *dest, size_t size, | ||
7 | const struct ipl_parameter_block *ipb) | ||
8 | { | ||
9 | int i; | ||
10 | size_t len; | ||
11 | char has_lowercase = 0; | ||
12 | |||
13 | len = 0; | ||
14 | if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) && | ||
15 | (ipb->ipl_info.ccw.vm_parm_len > 0)) { | ||
16 | |||
17 | len = min_t(size_t, size - 1, ipb->ipl_info.ccw.vm_parm_len); | ||
18 | memcpy(dest, ipb->ipl_info.ccw.vm_parm, len); | ||
19 | /* If at least one character is lowercase, we assume mixed | ||
20 | * case; otherwise we convert everything to lowercase. | ||
21 | */ | ||
22 | for (i = 0; i < len; i++) | ||
23 | if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */ | ||
24 | (dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */ | ||
25 | (dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */ | ||
26 | has_lowercase = 1; | ||
27 | break; | ||
28 | } | ||
29 | if (!has_lowercase) | ||
30 | EBC_TOLOWER(dest, len); | ||
31 | EBCASC(dest, len); | ||
32 | } | ||
33 | dest[len] = 0; | ||
34 | |||
35 | return len; | ||
36 | } | ||
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 36fb37d7a36c..ae3810c04872 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -90,8 +90,8 @@ char elf_platform[ELF_PLATFORM_SIZE]; | |||
90 | 90 | ||
91 | unsigned long int_hwcap = 0; | 91 | unsigned long int_hwcap = 0; |
92 | 92 | ||
93 | int __initdata memory_end_set; | 93 | int __bootdata(memory_end_set); |
94 | unsigned long __initdata memory_end; | 94 | unsigned long __bootdata(memory_end); |
95 | unsigned long __bootdata(max_physmem_end); | 95 | unsigned long __bootdata(max_physmem_end); |
96 | struct mem_detect_info __bootdata(mem_detect); | 96 | struct mem_detect_info __bootdata(mem_detect); |
97 | 97 | ||
@@ -286,15 +286,6 @@ void machine_power_off(void) | |||
286 | void (*pm_power_off)(void) = machine_power_off; | 286 | void (*pm_power_off)(void) = machine_power_off; |
287 | EXPORT_SYMBOL_GPL(pm_power_off); | 287 | EXPORT_SYMBOL_GPL(pm_power_off); |
288 | 288 | ||
289 | static int __init early_parse_mem(char *p) | ||
290 | { | ||
291 | memory_end = memparse(p, &p); | ||
292 | memory_end &= PAGE_MASK; | ||
293 | memory_end_set = 1; | ||
294 | return 0; | ||
295 | } | ||
296 | early_param("mem", early_parse_mem); | ||
297 | |||
298 | static int __init parse_vmalloc(char *arg) | 289 | static int __init parse_vmalloc(char *arg) |
299 | { | 290 | { |
300 | if (!arg) | 291 | if (!arg) |
@@ -605,17 +596,8 @@ static struct notifier_block kdump_mem_nb = { | |||
605 | */ | 596 | */ |
606 | static void reserve_memory_end(void) | 597 | static void reserve_memory_end(void) |
607 | { | 598 | { |
608 | #ifdef CONFIG_CRASH_DUMP | 599 | if (memory_end_set) |
609 | if (ipl_info.type == IPL_TYPE_FCP_DUMP && | 600 | memblock_reserve(memory_end, ULONG_MAX); |
610 | !OLDMEM_BASE && sclp.hsa_size) { | ||
611 | memory_end = sclp.hsa_size; | ||
612 | memory_end &= PAGE_MASK; | ||
613 | memory_end_set = 1; | ||
614 | } | ||
615 | #endif | ||
616 | if (!memory_end_set) | ||
617 | return; | ||
618 | memblock_reserve(memory_end, ULONG_MAX); | ||
619 | } | 601 | } |
620 | 602 | ||
621 | /* | 603 | /* |