1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/ctype.h>
5 #include <asm/ebcdic.h>
7 #include <asm/sections.h>
8 #include <asm/boot_data.h>
9 #include <asm/facility.h>
10 #include <asm/pgtable.h>
14 char __bootdata(early_command_line
)[COMMAND_LINE_SIZE
];
15 struct ipl_parameter_block
__bootdata_preserved(ipl_block
);
16 int __bootdata_preserved(ipl_block_valid
);
17 unsigned int __bootdata_preserved(zlib_dfltcc_support
) = ZLIB_DFLTCC_FULL
;
19 unsigned long __bootdata(vmalloc_size
) = VMALLOC_DEFAULT_SIZE
;
20 unsigned long __bootdata(memory_end
);
21 int __bootdata(memory_end_set
);
22 int __bootdata(noexec_disabled
);
24 int kaslr_enabled
__section(.data
);
26 static inline int __diag308(unsigned long subcode
, void *addr
)
28 register unsigned long _addr
asm("0") = (unsigned long)addr
;
29 register unsigned long _rc
asm("1") = 0;
30 unsigned long reg1
, reg2
;
31 psw_t old
= S390_lowcore
.program_new_psw
;
36 " st %1,%[psw_pgm]+4\n"
38 " stg %0,%[psw_pgm]+8\n"
39 " diag %[addr],%[subcode],0x308\n"
41 : "=&d" (reg1
), "=&a" (reg2
),
42 [psw_pgm
] "=Q" (S390_lowcore
.program_new_psw
),
43 [addr
] "+d" (_addr
), "+d" (_rc
)
44 : [subcode
] "d" (subcode
)
46 S390_lowcore
.program_new_psw
= old
;
50 void store_ipl_parmblock(void)
54 rc
= __diag308(DIAG308_STORE
, &ipl_block
);
55 if (rc
== DIAG308_RC_OK
&&
56 ipl_block
.hdr
.version
<= IPL_MAX_SUPPORTED_VERSION
)
60 static size_t scpdata_length(const u8
*buf
, size_t count
)
63 if (buf
[count
- 1] != '\0' && buf
[count
- 1] != ' ')
70 static size_t ipl_block_get_ascii_scpdata(char *dest
, size_t size
,
71 const struct ipl_parameter_block
*ipb
)
77 count
= min(size
- 1, scpdata_length(ipb
->fcp
.scp_data
,
78 ipb
->fcp
.scp_data_len
));
83 for (i
= 0; i
< count
; i
++) {
84 if (!isascii(ipb
->fcp
.scp_data
[i
])) {
88 if (!has_lowercase
&& islower(ipb
->fcp
.scp_data
[i
]))
93 memcpy(dest
, ipb
->fcp
.scp_data
, count
);
95 for (i
= 0; i
< count
; i
++)
96 dest
[i
] = tolower(ipb
->fcp
.scp_data
[i
]);
102 static void append_ipl_block_parm(void)
107 len
= strlen(early_command_line
);
109 delim
= early_command_line
+ len
; /* '\0' character position */
110 parm
= early_command_line
+ len
+ 1; /* append right after '\0' */
112 switch (ipl_block
.pb0_hdr
.pbt
) {
114 rc
= ipl_block_get_ascii_vmparm(
115 parm
, COMMAND_LINE_SIZE
- len
- 1, &ipl_block
);
118 rc
= ipl_block_get_ascii_scpdata(
119 parm
, COMMAND_LINE_SIZE
- len
- 1, &ipl_block
);
124 memmove(early_command_line
, parm
+ 1, rc
);
126 *delim
= ' '; /* replace '\0' with space */
130 static inline int has_ebcdic_char(const char *str
)
134 for (i
= 0; str
[i
]; i
++)
140 void setup_boot_command_line(void)
142 COMMAND_LINE
[ARCH_COMMAND_LINE_SIZE
- 1] = 0;
143 /* convert arch command line to ascii if necessary */
144 if (has_ebcdic_char(COMMAND_LINE
))
145 EBCASC(COMMAND_LINE
, ARCH_COMMAND_LINE_SIZE
);
146 /* copy arch command line */
147 strcpy(early_command_line
, strim(COMMAND_LINE
));
149 /* append IPL PARM data to the boot command line */
150 if (!is_prot_virt_guest() && ipl_block_valid
)
151 append_ipl_block_parm();
154 static void modify_facility(unsigned long nr
, bool clear
)
157 __clear_facility(nr
, S390_lowcore
.stfle_fac_list
);
159 __set_facility(nr
, S390_lowcore
.stfle_fac_list
);
162 static void check_cleared_facilities(void)
164 unsigned long als
[] = { FACILITIES_ALS
};
167 for (i
= 0; i
< ARRAY_SIZE(als
); i
++) {
168 if ((S390_lowcore
.stfle_fac_list
[i
] & als
[i
]) != als
[i
]) {
169 sclp_early_printk("Warning: The Linux kernel requires facilities cleared via command line option\n");
170 print_missing_facilities();
176 static void modify_fac_list(char *str
)
178 unsigned long val
, endval
;
188 val
= simple_strtoull(str
, &endp
, 0);
194 endval
= simple_strtoull(str
, &endp
, 0);
198 while (val
<= endval
) {
199 modify_facility(val
, clear
);
203 modify_facility(val
, clear
);
209 check_cleared_facilities();
212 static char command_line_buf
[COMMAND_LINE_SIZE
] __section(.data
);
213 void parse_boot_command_line(void)
220 kaslr_enabled
= IS_ENABLED(CONFIG_RANDOMIZE_BASE
);
221 args
= strcpy(command_line_buf
, early_command_line
);
223 args
= next_arg(args
, ¶m
, &val
);
225 if (!strcmp(param
, "mem") && val
) {
226 memory_end
= round_down(memparse(val
, NULL
), PAGE_SIZE
);
230 if (!strcmp(param
, "vmalloc") && val
)
231 vmalloc_size
= round_up(memparse(val
, NULL
), PAGE_SIZE
);
233 if (!strcmp(param
, "dfltcc")) {
234 if (!strcmp(val
, "off"))
235 zlib_dfltcc_support
= ZLIB_DFLTCC_DISABLED
;
236 else if (!strcmp(val
, "on"))
237 zlib_dfltcc_support
= ZLIB_DFLTCC_FULL
;
238 else if (!strcmp(val
, "def_only"))
239 zlib_dfltcc_support
= ZLIB_DFLTCC_DEFLATE_ONLY
;
240 else if (!strcmp(val
, "inf_only"))
241 zlib_dfltcc_support
= ZLIB_DFLTCC_INFLATE_ONLY
;
242 else if (!strcmp(val
, "always"))
243 zlib_dfltcc_support
= ZLIB_DFLTCC_FULL_DEBUG
;
246 if (!strcmp(param
, "noexec")) {
247 rc
= kstrtobool(val
, &enabled
);
252 if (!strcmp(param
, "facilities") && val
)
253 modify_fac_list(val
);
255 if (!strcmp(param
, "nokaslr"))
260 void setup_memory_end(void)
262 #ifdef CONFIG_CRASH_DUMP
265 } else if (ipl_block_valid
&&
266 ipl_block
.pb0_hdr
.pbt
== IPL_PBT_FCP
&&
267 ipl_block
.fcp
.opt
== IPL_PB0_FCP_OPT_DUMP
) {
269 if (!sclp_early_get_hsa_size(&memory_end
) && memory_end
)