1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/ctype.h>
5 #include <linux/pgtable.h>
6 #include <asm/ebcdic.h>
8 #include <asm/sections.h>
9 #include <asm/boot_data.h>
10 #include <asm/facility.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 int __bootdata(noexec_disabled
);
22 unsigned long memory_limit
;
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 bool is_ipl_block_dump(void)
62 if (ipl_block
.pb0_hdr
.pbt
== IPL_PBT_FCP
&&
63 ipl_block
.fcp
.opt
== IPL_PB0_FCP_OPT_DUMP
)
65 if (ipl_block
.pb0_hdr
.pbt
== IPL_PBT_NVME
&&
66 ipl_block
.nvme
.opt
== IPL_PB0_NVME_OPT_DUMP
)
71 static size_t scpdata_length(const u8
*buf
, size_t count
)
74 if (buf
[count
- 1] != '\0' && buf
[count
- 1] != ' ')
81 static size_t ipl_block_get_ascii_scpdata(char *dest
, size_t size
,
82 const struct ipl_parameter_block
*ipb
)
90 switch (ipb
->pb0_hdr
.pbt
) {
92 scp_data_len
= ipb
->fcp
.scp_data_len
;
93 scp_data
= ipb
->fcp
.scp_data
;
96 scp_data_len
= ipb
->nvme
.scp_data_len
;
97 scp_data
= ipb
->nvme
.scp_data
;
103 count
= min(size
- 1, scpdata_length(scp_data
, scp_data_len
));
108 for (i
= 0; i
< count
; i
++) {
109 if (!isascii(scp_data
[i
])) {
113 if (!has_lowercase
&& islower(scp_data
[i
]))
118 memcpy(dest
, scp_data
, count
);
120 for (i
= 0; i
< count
; i
++)
121 dest
[i
] = tolower(scp_data
[i
]);
127 static void append_ipl_block_parm(void)
132 len
= strlen(early_command_line
);
134 delim
= early_command_line
+ len
; /* '\0' character position */
135 parm
= early_command_line
+ len
+ 1; /* append right after '\0' */
137 switch (ipl_block
.pb0_hdr
.pbt
) {
139 rc
= ipl_block_get_ascii_vmparm(
140 parm
, COMMAND_LINE_SIZE
- len
- 1, &ipl_block
);
144 rc
= ipl_block_get_ascii_scpdata(
145 parm
, COMMAND_LINE_SIZE
- len
- 1, &ipl_block
);
150 memmove(early_command_line
, parm
+ 1, rc
);
152 *delim
= ' '; /* replace '\0' with space */
156 static inline int has_ebcdic_char(const char *str
)
160 for (i
= 0; str
[i
]; i
++)
166 void setup_boot_command_line(void)
168 COMMAND_LINE
[ARCH_COMMAND_LINE_SIZE
- 1] = 0;
169 /* convert arch command line to ascii if necessary */
170 if (has_ebcdic_char(COMMAND_LINE
))
171 EBCASC(COMMAND_LINE
, ARCH_COMMAND_LINE_SIZE
);
172 /* copy arch command line */
173 strcpy(early_command_line
, strim(COMMAND_LINE
));
175 /* append IPL PARM data to the boot command line */
176 if (!is_prot_virt_guest() && ipl_block_valid
)
177 append_ipl_block_parm();
180 static void modify_facility(unsigned long nr
, bool clear
)
183 __clear_facility(nr
, S390_lowcore
.stfle_fac_list
);
185 __set_facility(nr
, S390_lowcore
.stfle_fac_list
);
188 static void check_cleared_facilities(void)
190 unsigned long als
[] = { FACILITIES_ALS
};
193 for (i
= 0; i
< ARRAY_SIZE(als
); i
++) {
194 if ((S390_lowcore
.stfle_fac_list
[i
] & als
[i
]) != als
[i
]) {
195 sclp_early_printk("Warning: The Linux kernel requires facilities cleared via command line option\n");
196 print_missing_facilities();
202 static void modify_fac_list(char *str
)
204 unsigned long val
, endval
;
214 val
= simple_strtoull(str
, &endp
, 0);
220 endval
= simple_strtoull(str
, &endp
, 0);
224 while (val
<= endval
) {
225 modify_facility(val
, clear
);
229 modify_facility(val
, clear
);
235 check_cleared_facilities();
238 static char command_line_buf
[COMMAND_LINE_SIZE
];
239 void parse_boot_command_line(void)
246 kaslr_enabled
= IS_ENABLED(CONFIG_RANDOMIZE_BASE
);
247 args
= strcpy(command_line_buf
, early_command_line
);
249 args
= next_arg(args
, ¶m
, &val
);
251 if (!strcmp(param
, "mem") && val
)
252 memory_limit
= round_down(memparse(val
, NULL
), PAGE_SIZE
);
254 if (!strcmp(param
, "vmalloc") && val
) {
255 vmalloc_size
= round_up(memparse(val
, NULL
), PAGE_SIZE
);
256 vmalloc_size_set
= 1;
259 if (!strcmp(param
, "dfltcc") && val
) {
260 if (!strcmp(val
, "off"))
261 zlib_dfltcc_support
= ZLIB_DFLTCC_DISABLED
;
262 else if (!strcmp(val
, "on"))
263 zlib_dfltcc_support
= ZLIB_DFLTCC_FULL
;
264 else if (!strcmp(val
, "def_only"))
265 zlib_dfltcc_support
= ZLIB_DFLTCC_DEFLATE_ONLY
;
266 else if (!strcmp(val
, "inf_only"))
267 zlib_dfltcc_support
= ZLIB_DFLTCC_INFLATE_ONLY
;
268 else if (!strcmp(val
, "always"))
269 zlib_dfltcc_support
= ZLIB_DFLTCC_FULL_DEBUG
;
272 if (!strcmp(param
, "noexec")) {
273 rc
= kstrtobool(val
, &enabled
);
278 if (!strcmp(param
, "facilities") && val
)
279 modify_fac_list(val
);
281 if (!strcmp(param
, "nokaslr"))
284 #if IS_ENABLED(CONFIG_KVM)
285 if (!strcmp(param
, "prot_virt")) {
286 rc
= kstrtobool(val
, &enabled
);