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>
13 char __bootdata(early_command_line
)[COMMAND_LINE_SIZE
];
14 struct ipl_parameter_block
__bootdata_preserved(ipl_block
);
15 int __bootdata_preserved(ipl_block_valid
);
17 unsigned long __bootdata(memory_end
);
18 int __bootdata(memory_end_set
);
19 int __bootdata(noexec_disabled
);
21 int kaslr_enabled
__section(.data
);
23 static inline int __diag308(unsigned long subcode
, void *addr
)
25 register unsigned long _addr
asm("0") = (unsigned long)addr
;
26 register unsigned long _rc
asm("1") = 0;
27 unsigned long reg1
, reg2
;
28 psw_t old
= S390_lowcore
.program_new_psw
;
33 " st %1,%[psw_pgm]+4\n"
35 " stg %0,%[psw_pgm]+8\n"
36 " diag %[addr],%[subcode],0x308\n"
38 : "=&d" (reg1
), "=&a" (reg2
),
39 [psw_pgm
] "=Q" (S390_lowcore
.program_new_psw
),
40 [addr
] "+d" (_addr
), "+d" (_rc
)
41 : [subcode
] "d" (subcode
)
43 S390_lowcore
.program_new_psw
= old
;
47 void store_ipl_parmblock(void)
51 uv_set_shared(__pa(&ipl_block
));
52 rc
= __diag308(DIAG308_STORE
, &ipl_block
);
53 uv_remove_shared(__pa(&ipl_block
));
54 if (rc
== DIAG308_RC_OK
&&
55 ipl_block
.hdr
.version
<= IPL_MAX_SUPPORTED_VERSION
)
59 static size_t scpdata_length(const u8
*buf
, size_t count
)
62 if (buf
[count
- 1] != '\0' && buf
[count
- 1] != ' ')
69 static size_t ipl_block_get_ascii_scpdata(char *dest
, size_t size
,
70 const struct ipl_parameter_block
*ipb
)
76 count
= min(size
- 1, scpdata_length(ipb
->fcp
.scp_data
,
77 ipb
->fcp
.scp_data_len
));
82 for (i
= 0; i
< count
; i
++) {
83 if (!isascii(ipb
->fcp
.scp_data
[i
])) {
87 if (!has_lowercase
&& islower(ipb
->fcp
.scp_data
[i
]))
92 memcpy(dest
, ipb
->fcp
.scp_data
, count
);
94 for (i
= 0; i
< count
; i
++)
95 dest
[i
] = tolower(ipb
->fcp
.scp_data
[i
]);
101 static void append_ipl_block_parm(void)
106 len
= strlen(early_command_line
);
108 delim
= early_command_line
+ len
; /* '\0' character position */
109 parm
= early_command_line
+ len
+ 1; /* append right after '\0' */
111 switch (ipl_block
.pb0_hdr
.pbt
) {
113 rc
= ipl_block_get_ascii_vmparm(
114 parm
, COMMAND_LINE_SIZE
- len
- 1, &ipl_block
);
117 rc
= ipl_block_get_ascii_scpdata(
118 parm
, COMMAND_LINE_SIZE
- len
- 1, &ipl_block
);
123 memmove(early_command_line
, parm
+ 1, rc
);
125 *delim
= ' '; /* replace '\0' with space */
129 static inline int has_ebcdic_char(const char *str
)
133 for (i
= 0; str
[i
]; i
++)
139 void setup_boot_command_line(void)
141 COMMAND_LINE
[ARCH_COMMAND_LINE_SIZE
- 1] = 0;
142 /* convert arch command line to ascii if necessary */
143 if (has_ebcdic_char(COMMAND_LINE
))
144 EBCASC(COMMAND_LINE
, ARCH_COMMAND_LINE_SIZE
);
145 /* copy arch command line */
146 strcpy(early_command_line
, strim(COMMAND_LINE
));
148 /* append IPL PARM data to the boot command line */
149 if (!is_prot_virt_guest() && ipl_block_valid
)
150 append_ipl_block_parm();
153 static void modify_facility(unsigned long nr
, bool clear
)
156 __clear_facility(nr
, S390_lowcore
.stfle_fac_list
);
158 __set_facility(nr
, S390_lowcore
.stfle_fac_list
);
161 static void check_cleared_facilities(void)
163 unsigned long als
[] = { FACILITIES_ALS
};
166 for (i
= 0; i
< ARRAY_SIZE(als
); i
++) {
167 if ((S390_lowcore
.stfle_fac_list
[i
] & als
[i
]) != als
[i
]) {
168 sclp_early_printk("Warning: The Linux kernel requires facilities cleared via command line option\n");
169 print_missing_facilities();
175 static void modify_fac_list(char *str
)
177 unsigned long val
, endval
;
187 val
= simple_strtoull(str
, &endp
, 0);
193 endval
= simple_strtoull(str
, &endp
, 0);
197 while (val
<= endval
) {
198 modify_facility(val
, clear
);
202 modify_facility(val
, clear
);
208 check_cleared_facilities();
211 static char command_line_buf
[COMMAND_LINE_SIZE
] __section(.data
);
212 void parse_boot_command_line(void)
219 kaslr_enabled
= IS_ENABLED(CONFIG_RANDOMIZE_BASE
);
220 args
= strcpy(command_line_buf
, early_command_line
);
222 args
= next_arg(args
, ¶m
, &val
);
224 if (!strcmp(param
, "mem")) {
225 memory_end
= memparse(val
, NULL
);
229 if (!strcmp(param
, "noexec")) {
230 rc
= kstrtobool(val
, &enabled
);
235 if (!strcmp(param
, "facilities"))
236 modify_fac_list(val
);
238 if (!strcmp(param
, "nokaslr"))
243 void setup_memory_end(void)
245 #ifdef CONFIG_CRASH_DUMP
248 } else if (ipl_block_valid
&&
249 ipl_block
.pb0_hdr
.pbt
== IPL_PBT_FCP
&&
250 ipl_block
.fcp
.opt
== IPL_PB0_FCP_OPT_DUMP
) {
252 if (!sclp_early_get_hsa_size(&memory_end
) && memory_end
)