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> 6 #include <asm/sclp.h> 7 #include <asm/sections.h> 8 #include <asm/boot_data.h> 9 #include <asm/facility.h> 10 #include <asm/pgtable.h> 11 #include <asm/uv.h> 12 #include "boot.h" 13 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 18 unsigned long __bootdata(vmalloc_size) = VMALLOC_DEFAULT_SIZE; 19 unsigned long __bootdata(memory_end); 20 int __bootdata(memory_end_set); 21 int __bootdata(noexec_disabled); 22 23 int kaslr_enabled __section(.data); 24 25 static inline int __diag308(unsigned long subcode, void *addr) 26 { 27 register unsigned long _addr asm("0") = (unsigned long)addr; 28 register unsigned long _rc asm("1") = 0; 29 unsigned long reg1, reg2; 30 psw_t old = S390_lowcore.program_new_psw; 31 32 asm volatile( 33 " epsw %0,%1\n" 34 " st %0,%[psw_pgm]\n" 35 " st %1,%[psw_pgm]+4\n" 36 " larl %0,1f\n" 37 " stg %0,%[psw_pgm]+8\n" 38 " diag %[addr],%[subcode],0x308\n" 39 "1: nopr %%r7\n" 40 : "=&d" (reg1), "=&a" (reg2), 41 [psw_pgm] "=Q" (S390_lowcore.program_new_psw), 42 [addr] "+d" (_addr), "+d" (_rc) 43 : [subcode] "d" (subcode) 44 : "cc", "memory"); 45 S390_lowcore.program_new_psw = old; 46 return _rc; 47 } 48 49 void store_ipl_parmblock(void) 50 { 51 int rc; 52 53 uv_set_shared(__pa(&ipl_block)); 54 rc = __diag308(DIAG308_STORE, &ipl_block); 55 uv_remove_shared(__pa(&ipl_block)); 56 if (rc == DIAG308_RC_OK && 57 ipl_block.hdr.version <= IPL_MAX_SUPPORTED_VERSION) 58 ipl_block_valid = 1; 59 } 60 61 static size_t scpdata_length(const u8 *buf, size_t count) 62 { 63 while (count) { 64 if (buf[count - 1] != '\0' && buf[count - 1] != ' ') 65 break; 66 count--; 67 } 68 return count; 69 } 70 71 static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size, 72 const struct ipl_parameter_block *ipb) 73 { 74 size_t count; 75 size_t i; 76 int has_lowercase; 77 78 count = min(size - 1, scpdata_length(ipb->fcp.scp_data, 79 ipb->fcp.scp_data_len)); 80 if (!count) 81 goto out; 82 83 has_lowercase = 0; 84 for (i = 0; i < count; i++) { 85 if (!isascii(ipb->fcp.scp_data[i])) { 86 count = 0; 87 goto out; 88 } 89 if (!has_lowercase && islower(ipb->fcp.scp_data[i])) 90 has_lowercase = 1; 91 } 92 93 if (has_lowercase) 94 memcpy(dest, ipb->fcp.scp_data, count); 95 else 96 for (i = 0; i < count; i++) 97 dest[i] = tolower(ipb->fcp.scp_data[i]); 98 out: 99 dest[count] = '\0'; 100 return count; 101 } 102 103 static void append_ipl_block_parm(void) 104 { 105 char *parm, *delim; 106 size_t len, rc = 0; 107 108 len = strlen(early_command_line); 109 110 delim = early_command_line + len; /* '\0' character position */ 111 parm = early_command_line + len + 1; /* append right after '\0' */ 112 113 switch (ipl_block.pb0_hdr.pbt) { 114 case IPL_PBT_CCW: 115 rc = ipl_block_get_ascii_vmparm( 116 parm, COMMAND_LINE_SIZE - len - 1, &ipl_block); 117 break; 118 case IPL_PBT_FCP: 119 rc = ipl_block_get_ascii_scpdata( 120 parm, COMMAND_LINE_SIZE - len - 1, &ipl_block); 121 break; 122 } 123 if (rc) { 124 if (*parm == '=') 125 memmove(early_command_line, parm + 1, rc); 126 else 127 *delim = ' '; /* replace '\0' with space */ 128 } 129 } 130 131 static inline int has_ebcdic_char(const char *str) 132 { 133 int i; 134 135 for (i = 0; str[i]; i++) 136 if (str[i] & 0x80) 137 return 1; 138 return 0; 139 } 140 141 void setup_boot_command_line(void) 142 { 143 COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0; 144 /* convert arch command line to ascii if necessary */ 145 if (has_ebcdic_char(COMMAND_LINE)) 146 EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); 147 /* copy arch command line */ 148 strcpy(early_command_line, strim(COMMAND_LINE)); 149 150 /* append IPL PARM data to the boot command line */ 151 if (!is_prot_virt_guest() && ipl_block_valid) 152 append_ipl_block_parm(); 153 } 154 155 static void modify_facility(unsigned long nr, bool clear) 156 { 157 if (clear) 158 __clear_facility(nr, S390_lowcore.stfle_fac_list); 159 else 160 __set_facility(nr, S390_lowcore.stfle_fac_list); 161 } 162 163 static void check_cleared_facilities(void) 164 { 165 unsigned long als[] = { FACILITIES_ALS }; 166 int i; 167 168 for (i = 0; i < ARRAY_SIZE(als); i++) { 169 if ((S390_lowcore.stfle_fac_list[i] & als[i]) != als[i]) { 170 sclp_early_printk("Warning: The Linux kernel requires facilities cleared via command line option\n"); 171 print_missing_facilities(); 172 break; 173 } 174 } 175 } 176 177 static void modify_fac_list(char *str) 178 { 179 unsigned long val, endval; 180 char *endp; 181 bool clear; 182 183 while (*str) { 184 clear = false; 185 if (*str == '!') { 186 clear = true; 187 str++; 188 } 189 val = simple_strtoull(str, &endp, 0); 190 if (str == endp) 191 break; 192 str = endp; 193 if (*str == '-') { 194 str++; 195 endval = simple_strtoull(str, &endp, 0); 196 if (str == endp) 197 break; 198 str = endp; 199 while (val <= endval) { 200 modify_facility(val, clear); 201 val++; 202 } 203 } else { 204 modify_facility(val, clear); 205 } 206 if (*str != ',') 207 break; 208 str++; 209 } 210 check_cleared_facilities(); 211 } 212 213 static char command_line_buf[COMMAND_LINE_SIZE] __section(.data); 214 void parse_boot_command_line(void) 215 { 216 char *param, *val; 217 bool enabled; 218 char *args; 219 int rc; 220 221 kaslr_enabled = IS_ENABLED(CONFIG_RANDOMIZE_BASE); 222 args = strcpy(command_line_buf, early_command_line); 223 while (*args) { 224 args = next_arg(args, ¶m, &val); 225 226 if (!strcmp(param, "mem") && val) { 227 memory_end = round_down(memparse(val, NULL), PAGE_SIZE); 228 memory_end_set = 1; 229 } 230 231 if (!strcmp(param, "vmalloc") && val) 232 vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE); 233 234 if (!strcmp(param, "noexec")) { 235 rc = kstrtobool(val, &enabled); 236 if (!rc && !enabled) 237 noexec_disabled = 1; 238 } 239 240 if (!strcmp(param, "facilities") && val) 241 modify_fac_list(val); 242 243 if (!strcmp(param, "nokaslr")) 244 kaslr_enabled = 0; 245 } 246 } 247 248 void setup_memory_end(void) 249 { 250 #ifdef CONFIG_CRASH_DUMP 251 if (OLDMEM_BASE) { 252 kaslr_enabled = 0; 253 } else if (ipl_block_valid && 254 ipl_block.pb0_hdr.pbt == IPL_PBT_FCP && 255 ipl_block.fcp.opt == IPL_PB0_FCP_OPT_DUMP) { 256 kaslr_enabled = 0; 257 if (!sclp_early_get_hsa_size(&memory_end) && memory_end) 258 memory_end_set = 1; 259 } 260 #endif 261 } 262