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 int __bootdata(noexec_disabled); 17 18 static inline int __diag308(unsigned long subcode, void *addr) 19 { 20 register unsigned long _addr asm("0") = (unsigned long)addr; 21 register unsigned long _rc asm("1") = 0; 22 unsigned long reg1, reg2; 23 psw_t old = S390_lowcore.program_new_psw; 24 25 asm volatile( 26 " epsw %0,%1\n" 27 " st %0,%[psw_pgm]\n" 28 " st %1,%[psw_pgm]+4\n" 29 " larl %0,1f\n" 30 " stg %0,%[psw_pgm]+8\n" 31 " diag %[addr],%[subcode],0x308\n" 32 "1: nopr %%r7\n" 33 : "=&d" (reg1), "=&a" (reg2), 34 [psw_pgm] "=Q" (S390_lowcore.program_new_psw), 35 [addr] "+d" (_addr), "+d" (_rc) 36 : [subcode] "d" (subcode) 37 : "cc", "memory"); 38 S390_lowcore.program_new_psw = old; 39 return _rc; 40 } 41 42 void store_ipl_parmblock(void) 43 { 44 int rc; 45 46 rc = __diag308(DIAG308_STORE, &early_ipl_block); 47 if (rc == DIAG308_RC_OK && 48 early_ipl_block.hdr.version <= IPL_MAX_SUPPORTED_VERSION) 49 early_ipl_block_valid = 1; 50 } 51 52 static size_t scpdata_length(const char *buf, size_t count) 53 { 54 while (count) { 55 if (buf[count - 1] != '\0' && buf[count - 1] != ' ') 56 break; 57 count--; 58 } 59 return count; 60 } 61 62 static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size, 63 const struct ipl_parameter_block *ipb) 64 { 65 size_t count; 66 size_t i; 67 int has_lowercase; 68 69 count = min(size - 1, scpdata_length(ipb->ipl_info.fcp.scp_data, 70 ipb->ipl_info.fcp.scp_data_len)); 71 if (!count) 72 goto out; 73 74 has_lowercase = 0; 75 for (i = 0; i < count; i++) { 76 if (!isascii(ipb->ipl_info.fcp.scp_data[i])) { 77 count = 0; 78 goto out; 79 } 80 if (!has_lowercase && islower(ipb->ipl_info.fcp.scp_data[i])) 81 has_lowercase = 1; 82 } 83 84 if (has_lowercase) 85 memcpy(dest, ipb->ipl_info.fcp.scp_data, count); 86 else 87 for (i = 0; i < count; i++) 88 dest[i] = tolower(ipb->ipl_info.fcp.scp_data[i]); 89 out: 90 dest[count] = '\0'; 91 return count; 92 } 93 94 static void append_ipl_block_parm(void) 95 { 96 char *parm, *delim; 97 size_t len, rc = 0; 98 99 len = strlen(early_command_line); 100 101 delim = early_command_line + len; /* '\0' character position */ 102 parm = early_command_line + len + 1; /* append right after '\0' */ 103 104 switch (early_ipl_block.hdr.pbt) { 105 case DIAG308_IPL_TYPE_CCW: 106 rc = ipl_block_get_ascii_vmparm( 107 parm, COMMAND_LINE_SIZE - len - 1, &early_ipl_block); 108 break; 109 case DIAG308_IPL_TYPE_FCP: 110 rc = ipl_block_get_ascii_scpdata( 111 parm, COMMAND_LINE_SIZE - len - 1, &early_ipl_block); 112 break; 113 } 114 if (rc) { 115 if (*parm == '=') 116 memmove(early_command_line, parm + 1, rc); 117 else 118 *delim = ' '; /* replace '\0' with space */ 119 } 120 } 121 122 static inline int has_ebcdic_char(const char *str) 123 { 124 int i; 125 126 for (i = 0; str[i]; i++) 127 if (str[i] & 0x80) 128 return 1; 129 return 0; 130 } 131 132 void setup_boot_command_line(void) 133 { 134 COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0; 135 /* convert arch command line to ascii if necessary */ 136 if (has_ebcdic_char(COMMAND_LINE)) 137 EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); 138 /* copy arch command line */ 139 strcpy(early_command_line, strim(COMMAND_LINE)); 140 141 /* append IPL PARM data to the boot command line */ 142 if (early_ipl_block_valid) 143 append_ipl_block_parm(); 144 } 145 146 static char command_line_buf[COMMAND_LINE_SIZE] __section(.data); 147 static void parse_mem_opt(void) 148 { 149 char *param, *val; 150 bool enabled; 151 char *args; 152 int rc; 153 154 args = strcpy(command_line_buf, early_command_line); 155 while (*args) { 156 args = next_arg(args, ¶m, &val); 157 158 if (!strcmp(param, "mem")) { 159 memory_end = memparse(val, NULL); 160 memory_end_set = 1; 161 } 162 163 if (!strcmp(param, "noexec")) { 164 rc = kstrtobool(val, &enabled); 165 if (!rc && !enabled) 166 noexec_disabled = 1; 167 } 168 } 169 } 170 171 void setup_memory_end(void) 172 { 173 parse_mem_opt(); 174 #ifdef CONFIG_CRASH_DUMP 175 if (!OLDMEM_BASE && early_ipl_block_valid && 176 early_ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP && 177 early_ipl_block.ipl_info.fcp.opt == DIAG308_IPL_OPT_DUMP) { 178 if (!sclp_early_get_hsa_size(&memory_end) && memory_end) 179 memory_end_set = 1; 180 } 181 #endif 182 } 183