149698745SVasily Gorbik // SPDX-License-Identifier: GPL-2.0 249698745SVasily Gorbik #include <linux/init.h> 349698745SVasily Gorbik #include <linux/ctype.h> 449698745SVasily Gorbik #include <asm/ebcdic.h> 549698745SVasily Gorbik #include <asm/sclp.h> 649698745SVasily Gorbik #include <asm/sections.h> 749698745SVasily Gorbik #include <asm/boot_data.h> 849698745SVasily Gorbik #include "boot.h" 949698745SVasily Gorbik 1049698745SVasily Gorbik char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; 1149698745SVasily Gorbik struct ipl_parameter_block __bootdata(early_ipl_block); 1249698745SVasily Gorbik int __bootdata(early_ipl_block_valid); 1349698745SVasily Gorbik 1449698745SVasily Gorbik unsigned long __bootdata(memory_end); 1549698745SVasily Gorbik int __bootdata(memory_end_set); 1649698745SVasily Gorbik 1749698745SVasily Gorbik static inline int __diag308(unsigned long subcode, void *addr) 1849698745SVasily Gorbik { 1949698745SVasily Gorbik register unsigned long _addr asm("0") = (unsigned long)addr; 2049698745SVasily Gorbik register unsigned long _rc asm("1") = 0; 2149698745SVasily Gorbik unsigned long reg1, reg2; 2249698745SVasily Gorbik psw_t old = S390_lowcore.program_new_psw; 2349698745SVasily Gorbik 2449698745SVasily Gorbik asm volatile( 2549698745SVasily Gorbik " epsw %0,%1\n" 2649698745SVasily Gorbik " st %0,%[psw_pgm]\n" 2749698745SVasily Gorbik " st %1,%[psw_pgm]+4\n" 2849698745SVasily Gorbik " larl %0,1f\n" 2949698745SVasily Gorbik " stg %0,%[psw_pgm]+8\n" 3049698745SVasily Gorbik " diag %[addr],%[subcode],0x308\n" 3149698745SVasily Gorbik "1: nopr %%r7\n" 3249698745SVasily Gorbik : "=&d" (reg1), "=&a" (reg2), 3349698745SVasily Gorbik [psw_pgm] "=Q" (S390_lowcore.program_new_psw), 3449698745SVasily Gorbik [addr] "+d" (_addr), "+d" (_rc) 3549698745SVasily Gorbik : [subcode] "d" (subcode) 3649698745SVasily Gorbik : "cc", "memory"); 3749698745SVasily Gorbik S390_lowcore.program_new_psw = old; 3849698745SVasily Gorbik return _rc; 3949698745SVasily Gorbik } 4049698745SVasily Gorbik 4149698745SVasily Gorbik void store_ipl_parmblock(void) 4249698745SVasily Gorbik { 4349698745SVasily Gorbik int rc; 4449698745SVasily Gorbik 4549698745SVasily Gorbik rc = __diag308(DIAG308_STORE, &early_ipl_block); 4649698745SVasily Gorbik if (rc == DIAG308_RC_OK && 4749698745SVasily Gorbik early_ipl_block.hdr.version <= IPL_MAX_SUPPORTED_VERSION) 4849698745SVasily Gorbik early_ipl_block_valid = 1; 4949698745SVasily Gorbik } 5049698745SVasily Gorbik 5149698745SVasily Gorbik static size_t scpdata_length(const char *buf, size_t count) 5249698745SVasily Gorbik { 5349698745SVasily Gorbik while (count) { 5449698745SVasily Gorbik if (buf[count - 1] != '\0' && buf[count - 1] != ' ') 5549698745SVasily Gorbik break; 5649698745SVasily Gorbik count--; 5749698745SVasily Gorbik } 5849698745SVasily Gorbik return count; 5949698745SVasily Gorbik } 6049698745SVasily Gorbik 6149698745SVasily Gorbik static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size, 6249698745SVasily Gorbik const struct ipl_parameter_block *ipb) 6349698745SVasily Gorbik { 6449698745SVasily Gorbik size_t count; 6549698745SVasily Gorbik size_t i; 6649698745SVasily Gorbik int has_lowercase; 6749698745SVasily Gorbik 6849698745SVasily Gorbik count = min(size - 1, scpdata_length(ipb->ipl_info.fcp.scp_data, 6949698745SVasily Gorbik ipb->ipl_info.fcp.scp_data_len)); 7049698745SVasily Gorbik if (!count) 7149698745SVasily Gorbik goto out; 7249698745SVasily Gorbik 7349698745SVasily Gorbik has_lowercase = 0; 7449698745SVasily Gorbik for (i = 0; i < count; i++) { 7549698745SVasily Gorbik if (!isascii(ipb->ipl_info.fcp.scp_data[i])) { 7649698745SVasily Gorbik count = 0; 7749698745SVasily Gorbik goto out; 7849698745SVasily Gorbik } 7949698745SVasily Gorbik if (!has_lowercase && islower(ipb->ipl_info.fcp.scp_data[i])) 8049698745SVasily Gorbik has_lowercase = 1; 8149698745SVasily Gorbik } 8249698745SVasily Gorbik 8349698745SVasily Gorbik if (has_lowercase) 8449698745SVasily Gorbik memcpy(dest, ipb->ipl_info.fcp.scp_data, count); 8549698745SVasily Gorbik else 8649698745SVasily Gorbik for (i = 0; i < count; i++) 8749698745SVasily Gorbik dest[i] = tolower(ipb->ipl_info.fcp.scp_data[i]); 8849698745SVasily Gorbik out: 8949698745SVasily Gorbik dest[count] = '\0'; 9049698745SVasily Gorbik return count; 9149698745SVasily Gorbik } 9249698745SVasily Gorbik 9349698745SVasily Gorbik static void append_ipl_block_parm(void) 9449698745SVasily Gorbik { 9549698745SVasily Gorbik char *parm, *delim; 9649698745SVasily Gorbik size_t len, rc = 0; 9749698745SVasily Gorbik 9849698745SVasily Gorbik len = strlen(early_command_line); 9949698745SVasily Gorbik 10049698745SVasily Gorbik delim = early_command_line + len; /* '\0' character position */ 10149698745SVasily Gorbik parm = early_command_line + len + 1; /* append right after '\0' */ 10249698745SVasily Gorbik 10349698745SVasily Gorbik switch (early_ipl_block.hdr.pbt) { 10449698745SVasily Gorbik case DIAG308_IPL_TYPE_CCW: 10549698745SVasily Gorbik rc = ipl_block_get_ascii_vmparm( 10649698745SVasily Gorbik parm, COMMAND_LINE_SIZE - len - 1, &early_ipl_block); 10749698745SVasily Gorbik break; 10849698745SVasily Gorbik case DIAG308_IPL_TYPE_FCP: 10949698745SVasily Gorbik rc = ipl_block_get_ascii_scpdata( 11049698745SVasily Gorbik parm, COMMAND_LINE_SIZE - len - 1, &early_ipl_block); 11149698745SVasily Gorbik break; 11249698745SVasily Gorbik } 11349698745SVasily Gorbik if (rc) { 11449698745SVasily Gorbik if (*parm == '=') 11549698745SVasily Gorbik memmove(early_command_line, parm + 1, rc); 11649698745SVasily Gorbik else 11749698745SVasily Gorbik *delim = ' '; /* replace '\0' with space */ 11849698745SVasily Gorbik } 11949698745SVasily Gorbik } 12049698745SVasily Gorbik 12149698745SVasily Gorbik static inline int has_ebcdic_char(const char *str) 12249698745SVasily Gorbik { 12349698745SVasily Gorbik int i; 12449698745SVasily Gorbik 12549698745SVasily Gorbik for (i = 0; str[i]; i++) 12649698745SVasily Gorbik if (str[i] & 0x80) 12749698745SVasily Gorbik return 1; 12849698745SVasily Gorbik return 0; 12949698745SVasily Gorbik } 13049698745SVasily Gorbik 13149698745SVasily Gorbik void setup_boot_command_line(void) 13249698745SVasily Gorbik { 13349698745SVasily Gorbik COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0; 13449698745SVasily Gorbik /* convert arch command line to ascii if necessary */ 13549698745SVasily Gorbik if (has_ebcdic_char(COMMAND_LINE)) 13649698745SVasily Gorbik EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); 13749698745SVasily Gorbik /* copy arch command line */ 13849698745SVasily Gorbik strcpy(early_command_line, strim(COMMAND_LINE)); 13949698745SVasily Gorbik 14049698745SVasily Gorbik /* append IPL PARM data to the boot command line */ 14149698745SVasily Gorbik if (early_ipl_block_valid) 14249698745SVasily Gorbik append_ipl_block_parm(); 14349698745SVasily Gorbik } 14449698745SVasily Gorbik 14549698745SVasily Gorbik static char command_line_buf[COMMAND_LINE_SIZE] __section(.data); 14649698745SVasily Gorbik static void parse_mem_opt(void) 14749698745SVasily Gorbik { 14849698745SVasily Gorbik char *args; 14949698745SVasily Gorbik char *param, *val; 15049698745SVasily Gorbik 15149698745SVasily Gorbik args = strcpy(command_line_buf, early_command_line); 15249698745SVasily Gorbik while (*args) { 15349698745SVasily Gorbik args = next_arg(args, ¶m, &val); 15449698745SVasily Gorbik 15549698745SVasily Gorbik if (!strcmp(param, "mem")) { 15649698745SVasily Gorbik memory_end = memparse(val, NULL); 15749698745SVasily Gorbik memory_end_set = 1; 15849698745SVasily Gorbik } 15949698745SVasily Gorbik } 16049698745SVasily Gorbik } 16149698745SVasily Gorbik 16249698745SVasily Gorbik void setup_memory_end(void) 16349698745SVasily Gorbik { 16449698745SVasily Gorbik parse_mem_opt(); 16549698745SVasily Gorbik #ifdef CONFIG_CRASH_DUMP 16649698745SVasily Gorbik if (!OLDMEM_BASE && early_ipl_block_valid && 16749698745SVasily Gorbik early_ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP && 16849698745SVasily Gorbik early_ipl_block.ipl_info.fcp.opt == DIAG308_IPL_OPT_DUMP) { 16949698745SVasily Gorbik if (!sclp_early_get_hsa_size(&memory_end) && memory_end) 17049698745SVasily Gorbik memory_end_set = 1; 17149698745SVasily Gorbik } 17249698745SVasily Gorbik #endif 17349698745SVasily Gorbik } 174