1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2ab14de6cSHeiko Carstens /* 3155af2f9SHans-Joachim Picht * Copyright IBM Corp. 2007, 2009 4ab14de6cSHeiko Carstens * Author(s): Hongjie Yang <hongjie@us.ibm.com>, 5ab14de6cSHeiko Carstens * Heiko Carstens <heiko.carstens@de.ibm.com> 6ab14de6cSHeiko Carstens */ 7ab14de6cSHeiko Carstens 811af97e1SHendrik Brueckner #define KMSG_COMPONENT "setup" 911af97e1SHendrik Brueckner #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 1011af97e1SHendrik Brueckner 1192e6ecf3SChristian Borntraeger #include <linux/compiler.h> 12ab14de6cSHeiko Carstens #include <linux/init.h> 13ab14de6cSHeiko Carstens #include <linux/errno.h> 14ab14de6cSHeiko Carstens #include <linux/string.h> 15ab14de6cSHeiko Carstens #include <linux/ctype.h> 16ab14de6cSHeiko Carstens #include <linux/lockdep.h> 17dcc096c5SPaul Gortmaker #include <linux/extable.h> 18ab14de6cSHeiko Carstens #include <linux/pfn.h> 19ab14de6cSHeiko Carstens #include <linux/uaccess.h> 2011af97e1SHendrik Brueckner #include <linux/kernel.h> 211ec2772eSMartin Schwidefsky #include <asm/diag.h> 22a0443fbbSHendrik Brueckner #include <asm/ebcdic.h> 2346b05d26SMichael Holzheu #include <asm/ipl.h> 24ab14de6cSHeiko Carstens #include <asm/lowcore.h> 25ab14de6cSHeiko Carstens #include <asm/processor.h> 26ab14de6cSHeiko Carstens #include <asm/sections.h> 27ab14de6cSHeiko Carstens #include <asm/setup.h> 2892e6ecf3SChristian Borntraeger #include <asm/sysinfo.h> 29ab14de6cSHeiko Carstens #include <asm/cpcmd.h> 30ab14de6cSHeiko Carstens #include <asm/sclp.h> 31a0616cdeSDavid Howells #include <asm/facility.h> 32a806170eSHeiko Carstens #include "entry.h" 33ab14de6cSHeiko Carstens 34a0443fbbSHendrik Brueckner static void __init setup_boot_command_line(void); 35a0443fbbSHendrik Brueckner 36b6112ccbSMartin Schwidefsky /* 37b6112ccbSMartin Schwidefsky * Get the TOD clock running. 38b6112ccbSMartin Schwidefsky */ 39b6112ccbSMartin Schwidefsky static void __init reset_tod_clock(void) 40b6112ccbSMartin Schwidefsky { 41b6112ccbSMartin Schwidefsky u64 time; 42b6112ccbSMartin Schwidefsky 431aae0560SHeiko Carstens if (store_tod_clock(&time) == 0) 44b6112ccbSMartin Schwidefsky return; 45b6112ccbSMartin Schwidefsky /* TOD clock not running. Set the clock to Unix Epoch. */ 461aae0560SHeiko Carstens if (set_tod_clock(TOD_UNIX_EPOCH) != 0 || store_tod_clock(&time) != 0) 47b6112ccbSMartin Schwidefsky disabled_wait(0); 48b6112ccbSMartin Schwidefsky 496e2ef5e4SMartin Schwidefsky memset(tod_clock_base, 0, 16); 506e2ef5e4SMartin Schwidefsky *(__u64 *) &tod_clock_base[1] = TOD_UNIX_EPOCH; 516e2ef5e4SMartin Schwidefsky S390_lowcore.last_update_clock = TOD_UNIX_EPOCH; 52b6112ccbSMartin Schwidefsky } 53a0443fbbSHendrik Brueckner 54ab14de6cSHeiko Carstens /* 55ab14de6cSHeiko Carstens * Clear bss memory 56ab14de6cSHeiko Carstens */ 57ab14de6cSHeiko Carstens static noinline __init void clear_bss_section(void) 58ab14de6cSHeiko Carstens { 59229d9c6dSHeiko Carstens memset(__bss_start, 0, __bss_stop - __bss_start); 60ab14de6cSHeiko Carstens } 61ab14de6cSHeiko Carstens 62ab14de6cSHeiko Carstens /* 63ab14de6cSHeiko Carstens * Initialize storage key for kernel pages 64ab14de6cSHeiko Carstens */ 65ab14de6cSHeiko Carstens static noinline __init void init_kernel_storage_key(void) 66ab14de6cSHeiko Carstens { 67127c1fefSMartin Schwidefsky #if PAGE_DEFAULT_KEY 68ab14de6cSHeiko Carstens unsigned long end_pfn, init_pfn; 69ab14de6cSHeiko Carstens 70ab14de6cSHeiko Carstens end_pfn = PFN_UP(__pa(&_end)); 71ab14de6cSHeiko Carstens 72ab14de6cSHeiko Carstens for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++) 73e2b8d7afSMartin Schwidefsky page_set_storage_key(init_pfn << PAGE_SHIFT, 74e2b8d7afSMartin Schwidefsky PAGE_DEFAULT_KEY, 0); 75127c1fefSMartin Schwidefsky #endif 76ab14de6cSHeiko Carstens } 77ab14de6cSHeiko Carstens 78fade4dc4SHeiko Carstens static __initdata char sysinfo_page[PAGE_SIZE] __aligned(PAGE_SIZE); 7992e6ecf3SChristian Borntraeger 80ab14de6cSHeiko Carstens static noinline __init void detect_machine_type(void) 81ab14de6cSHeiko Carstens { 82fade4dc4SHeiko Carstens struct sysinfo_3_2_2 *vmms = (struct sysinfo_3_2_2 *)&sysinfo_page; 83fade4dc4SHeiko Carstens 8427d71602SMartin Schwidefsky /* Check current-configuration-level */ 85caf757c6SHeiko Carstens if (stsi(NULL, 0, 0, 0) <= 2) { 8627d71602SMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_LPAR; 8792e6ecf3SChristian Borntraeger return; 8827d71602SMartin Schwidefsky } 8927d71602SMartin Schwidefsky /* Get virtual-machine cpu information. */ 90caf757c6SHeiko Carstens if (stsi(vmms, 3, 2, 2) || !vmms->count) 9192e6ecf3SChristian Borntraeger return; 92ab14de6cSHeiko Carstens 9392e6ecf3SChristian Borntraeger /* Running under KVM? If not we assume z/VM */ 94fade4dc4SHeiko Carstens if (!memcmp(vmms->vm[0].cpi, "\xd2\xe5\xd4", 3)) 95d3135e0cSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_KVM; 9692e6ecf3SChristian Borntraeger else 97d3135e0cSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_VM; 98ab14de6cSHeiko Carstens } 99ab14de6cSHeiko Carstens 100d2f03974SHeiko Carstens /* Remove leading, trailing and double whitespace. */ 101d2f03974SHeiko Carstens static inline void strim_all(char *str) 102d2f03974SHeiko Carstens { 103d2f03974SHeiko Carstens char *s; 104d2f03974SHeiko Carstens 105d2f03974SHeiko Carstens s = strim(str); 106d2f03974SHeiko Carstens if (s != str) 107d2f03974SHeiko Carstens memmove(str, s, strlen(s)); 108d2f03974SHeiko Carstens while (*str) { 109d2f03974SHeiko Carstens if (!isspace(*str++)) 110d2f03974SHeiko Carstens continue; 111d2f03974SHeiko Carstens if (isspace(*str)) { 112d2f03974SHeiko Carstens s = skip_spaces(str); 113d2f03974SHeiko Carstens memmove(str, s, strlen(s) + 1); 114d2f03974SHeiko Carstens } 115d2f03974SHeiko Carstens } 116d2f03974SHeiko Carstens } 117d2f03974SHeiko Carstens 1184b8fe77aSChristian Borntraeger static noinline __init void setup_arch_string(void) 1194b8fe77aSChristian Borntraeger { 1204b8fe77aSChristian Borntraeger struct sysinfo_1_1_1 *mach = (struct sysinfo_1_1_1 *)&sysinfo_page; 1212f8876f9SHeiko Carstens struct sysinfo_3_2_2 *vm = (struct sysinfo_3_2_2 *)&sysinfo_page; 1222f8876f9SHeiko Carstens char mstr[80], hvstr[17]; 1234b8fe77aSChristian Borntraeger 1244b8fe77aSChristian Borntraeger if (stsi(mach, 1, 1, 1)) 1254b8fe77aSChristian Borntraeger return; 1264b8fe77aSChristian Borntraeger EBCASC(mach->manufacturer, sizeof(mach->manufacturer)); 1274b8fe77aSChristian Borntraeger EBCASC(mach->type, sizeof(mach->type)); 1284b8fe77aSChristian Borntraeger EBCASC(mach->model, sizeof(mach->model)); 1294b8fe77aSChristian Borntraeger EBCASC(mach->model_capacity, sizeof(mach->model_capacity)); 130d2f03974SHeiko Carstens sprintf(mstr, "%-16.16s %-4.4s %-16.16s %-16.16s", 131d2f03974SHeiko Carstens mach->manufacturer, mach->type, 132d2f03974SHeiko Carstens mach->model, mach->model_capacity); 133d2f03974SHeiko Carstens strim_all(mstr); 1342f8876f9SHeiko Carstens if (stsi(vm, 3, 2, 2) == 0 && vm->count) { 1352f8876f9SHeiko Carstens EBCASC(vm->vm[0].cpi, sizeof(vm->vm[0].cpi)); 1362f8876f9SHeiko Carstens sprintf(hvstr, "%-16.16s", vm->vm[0].cpi); 1372f8876f9SHeiko Carstens strim_all(hvstr); 1382f8876f9SHeiko Carstens } else { 1392f8876f9SHeiko Carstens sprintf(hvstr, "%s", 1404b8fe77aSChristian Borntraeger MACHINE_IS_LPAR ? "LPAR" : 1414b8fe77aSChristian Borntraeger MACHINE_IS_VM ? "z/VM" : 1424b8fe77aSChristian Borntraeger MACHINE_IS_KVM ? "KVM" : "unknown"); 1434b8fe77aSChristian Borntraeger } 1442f8876f9SHeiko Carstens dump_stack_set_arch_desc("%s (%s)", mstr, hvstr); 1452f8876f9SHeiko Carstens } 1464b8fe77aSChristian Borntraeger 147fade4dc4SHeiko Carstens static __init void setup_topology(void) 148fade4dc4SHeiko Carstens { 149fade4dc4SHeiko Carstens int max_mnest; 150fade4dc4SHeiko Carstens 151fade4dc4SHeiko Carstens if (!test_facility(11)) 152fade4dc4SHeiko Carstens return; 153fade4dc4SHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY; 154fade4dc4SHeiko Carstens for (max_mnest = 6; max_mnest > 1; max_mnest--) { 155caf757c6SHeiko Carstens if (stsi(&sysinfo_page, 15, 1, max_mnest) == 0) 156fade4dc4SHeiko Carstens break; 157fade4dc4SHeiko Carstens } 158fade4dc4SHeiko Carstens topology_max_mnest = max_mnest; 159fade4dc4SHeiko Carstens } 160fade4dc4SHeiko Carstens 161a3415703SMichael Holzheu static void early_pgm_check_handler(void) 162ab14de6cSHeiko Carstens { 163ab14de6cSHeiko Carstens const struct exception_table_entry *fixup; 16450be6345SPhilipp Hachtmann unsigned long cr0, cr0_new; 165eb608fb3SHeiko Carstens unsigned long addr; 166ab14de6cSHeiko Carstens 167ab14de6cSHeiko Carstens addr = S390_lowcore.program_old_psw.addr; 1689cb1ccecSHeiko Carstens fixup = search_exception_tables(addr); 169ab14de6cSHeiko Carstens if (!fixup) 170ab14de6cSHeiko Carstens disabled_wait(0); 17150be6345SPhilipp Hachtmann /* Disable low address protection before storing into lowcore. */ 17250be6345SPhilipp Hachtmann __ctl_store(cr0, 0, 0); 17350be6345SPhilipp Hachtmann cr0_new = cr0 & ~(1UL << 28); 17450be6345SPhilipp Hachtmann __ctl_load(cr0_new, 0, 0); 175fecc868aSHeiko Carstens S390_lowcore.program_old_psw.addr = extable_fixup(fixup); 17650be6345SPhilipp Hachtmann __ctl_load(cr0, 0, 0); 177ab14de6cSHeiko Carstens } 178ab14de6cSHeiko Carstens 1795f954c34SHeiko Carstens static noinline __init void setup_lowcore_early(void) 180ab14de6cSHeiko Carstens { 181ab14de6cSHeiko Carstens psw_t psw; 182ab14de6cSHeiko Carstens 183b50511e4SMartin Schwidefsky psw.mask = PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA; 184fecc868aSHeiko Carstens psw.addr = (unsigned long) s390_base_ext_handler; 185ab14de6cSHeiko Carstens S390_lowcore.external_new_psw = psw; 186fecc868aSHeiko Carstens psw.addr = (unsigned long) s390_base_pgm_handler; 187ab14de6cSHeiko Carstens S390_lowcore.program_new_psw = psw; 188ab14de6cSHeiko Carstens s390_base_pgm_handler_fn = early_pgm_check_handler; 189c360192bSMartin Schwidefsky S390_lowcore.preempt_count = INIT_PREEMPT_COUNT; 190ab14de6cSHeiko Carstens } 191ab14de6cSHeiko Carstens 19214375bc4SMartin Schwidefsky static noinline __init void setup_facility_list(void) 19314375bc4SMartin Schwidefsky { 1943ab121abSMichael Holzheu stfle(S390_lowcore.stfle_fac_list, 1953ab121abSMichael Holzheu ARRAY_SIZE(S390_lowcore.stfle_fac_list)); 196cf148998SMartin Schwidefsky memcpy(S390_lowcore.alt_stfle_fac_list, 197cf148998SMartin Schwidefsky S390_lowcore.stfle_fac_list, 198cf148998SMartin Schwidefsky sizeof(S390_lowcore.alt_stfle_fac_list)); 199*d768bd89SMartin Schwidefsky if (!IS_ENABLED(CONFIG_KERNEL_NOBP)) 200*d768bd89SMartin Schwidefsky __clear_facility(82, S390_lowcore.alt_stfle_fac_list); 20114375bc4SMartin Schwidefsky } 20214375bc4SMartin Schwidefsky 2032e5061e4SHeiko Carstens static __init void detect_diag9c(void) 2042e5061e4SHeiko Carstens { 2052e5061e4SHeiko Carstens unsigned int cpu_address; 2062e5061e4SHeiko Carstens int rc; 2072e5061e4SHeiko Carstens 2082e5061e4SHeiko Carstens cpu_address = stap(); 2091ec2772eSMartin Schwidefsky diag_stat_inc(DIAG_STAT_X09C); 2102e5061e4SHeiko Carstens asm volatile( 2112e5061e4SHeiko Carstens " diag %2,0,0x9c\n" 2122e5061e4SHeiko Carstens "0: la %0,0\n" 2132e5061e4SHeiko Carstens "1:\n" 2142e5061e4SHeiko Carstens EX_TABLE(0b,1b) 2152e5061e4SHeiko Carstens : "=d" (rc) : "0" (-EOPNOTSUPP), "d" (cpu_address) : "cc"); 2162e5061e4SHeiko Carstens if (!rc) 217d3135e0cSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG9C; 2182e5061e4SHeiko Carstens } 2192e5061e4SHeiko Carstens 2202e5061e4SHeiko Carstens static __init void detect_diag44(void) 2212e5061e4SHeiko Carstens { 2222e5061e4SHeiko Carstens int rc; 2232e5061e4SHeiko Carstens 2241ec2772eSMartin Schwidefsky diag_stat_inc(DIAG_STAT_X044); 2252e5061e4SHeiko Carstens asm volatile( 2262e5061e4SHeiko Carstens " diag 0,0,0x44\n" 2272e5061e4SHeiko Carstens "0: la %0,0\n" 2282e5061e4SHeiko Carstens "1:\n" 2292e5061e4SHeiko Carstens EX_TABLE(0b,1b) 2302e5061e4SHeiko Carstens : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc"); 2312e5061e4SHeiko Carstens if (!rc) 232d3135e0cSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG44; 2332e5061e4SHeiko Carstens } 2342e5061e4SHeiko Carstens 2352e5061e4SHeiko Carstens static __init void detect_machine_facilities(void) 2362e5061e4SHeiko Carstens { 2373c7ef08bSHeiko Carstens if (test_facility(8)) { 2383c7ef08bSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT1; 2393c7ef08bSHeiko Carstens __ctl_set_bit(0, 23); 2403c7ef08bSHeiko Carstens } 24185e9d0e5SHeiko Carstens if (test_facility(78)) 24285e9d0e5SHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2; 24314375bc4SMartin Schwidefsky if (test_facility(3)) 244d3135e0cSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; 24514375bc4SMartin Schwidefsky if (test_facility(40)) 24623d18e8dSHendrik Brueckner S390_lowcore.machine_flags |= MACHINE_FLAG_LPP; 247a1c5befcSHeiko Carstens if (test_facility(50) && test_facility(73)) { 248d35339a4SMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_TE; 249a1c5befcSHeiko Carstens __ctl_set_bit(0, 55); 250a1c5befcSHeiko Carstens } 2511b948d6cSMartin Schwidefsky if (test_facility(51)) 2521b948d6cSMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC; 253b5510d9bSHendrik Brueckner if (test_facility(129)) { 25480703617SMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_VX; 255b5510d9bSHendrik Brueckner __ctl_set_bit(0, 17); 2562e5061e4SHeiko Carstens } 25757d7f939SMartin Schwidefsky if (test_facility(130)) { 25857d7f939SMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_NX; 25957d7f939SMartin Schwidefsky __ctl_set_bit(0, 20); 26057d7f939SMartin Schwidefsky } 261916cda1aSMartin Schwidefsky if (test_facility(133)) 262916cda1aSMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_GS; 2636e2ef5e4SMartin Schwidefsky if (test_facility(139) && (tod_clock_base[1] & 0x80)) { 2646e2ef5e4SMartin Schwidefsky /* Enabled signed clock comparator comparisons */ 2656e2ef5e4SMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_SCC; 2666e2ef5e4SMartin Schwidefsky clock_comparator_max = -1ULL >> 1; 2676e2ef5e4SMartin Schwidefsky __ctl_set_bit(0, 53); 2686e2ef5e4SMartin Schwidefsky } 269b5510d9bSHendrik Brueckner } 270b5510d9bSHendrik Brueckner 2711a36a39eSMartin Schwidefsky static inline void save_vector_registers(void) 2721a36a39eSMartin Schwidefsky { 2731a36a39eSMartin Schwidefsky #ifdef CONFIG_CRASH_DUMP 2741a36a39eSMartin Schwidefsky if (test_facility(129)) 2751a36a39eSMartin Schwidefsky save_vx_regs(boot_cpu_vector_save_area); 2761a36a39eSMartin Schwidefsky #endif 2771a36a39eSMartin Schwidefsky } 2781a36a39eSMartin Schwidefsky 279b5510d9bSHendrik Brueckner static int __init disable_vector_extension(char *str) 280b5510d9bSHendrik Brueckner { 281b5510d9bSHendrik Brueckner S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; 282b5510d9bSHendrik Brueckner __ctl_clear_bit(0, 17); 283673cfddfSHeiko Carstens return 0; 284b5510d9bSHendrik Brueckner } 285b5510d9bSHendrik Brueckner early_param("novx", disable_vector_extension); 2862e5061e4SHeiko Carstens 28757d7f939SMartin Schwidefsky static int __init noexec_setup(char *str) 28857d7f939SMartin Schwidefsky { 28957d7f939SMartin Schwidefsky bool enabled; 29057d7f939SMartin Schwidefsky int rc; 29157d7f939SMartin Schwidefsky 29257d7f939SMartin Schwidefsky rc = kstrtobool(str, &enabled); 29357d7f939SMartin Schwidefsky if (!rc && !enabled) { 29457d7f939SMartin Schwidefsky /* Disable no-execute support */ 29557d7f939SMartin Schwidefsky S390_lowcore.machine_flags &= ~MACHINE_FLAG_NX; 29657d7f939SMartin Schwidefsky __ctl_clear_bit(0, 20); 29757d7f939SMartin Schwidefsky } 29857d7f939SMartin Schwidefsky return rc; 29957d7f939SMartin Schwidefsky } 30057d7f939SMartin Schwidefsky early_param("noexec", noexec_setup); 30157d7f939SMartin Schwidefsky 30261b0b016SMartin Schwidefsky static int __init cad_setup(char *str) 3032c72a44eSMartin Schwidefsky { 304b13de4b7SMartin Schwidefsky bool enabled; 305b13de4b7SMartin Schwidefsky int rc; 30661b0b016SMartin Schwidefsky 307b13de4b7SMartin Schwidefsky rc = kstrtobool(str, &enabled); 308b13de4b7SMartin Schwidefsky if (!rc && enabled && test_facility(128)) 3092c72a44eSMartin Schwidefsky /* Enable problem state CAD. */ 3102c72a44eSMartin Schwidefsky __ctl_set_bit(2, 3); 311b13de4b7SMartin Schwidefsky return rc; 3122c72a44eSMartin Schwidefsky } 313b13de4b7SMartin Schwidefsky early_param("cad", cad_setup); 3142c72a44eSMartin Schwidefsky 315d543a106SHeiko Carstens static __init void memmove_early(void *dst, const void *src, size_t n) 316d543a106SHeiko Carstens { 317d543a106SHeiko Carstens unsigned long addr; 318d543a106SHeiko Carstens long incr; 319d543a106SHeiko Carstens psw_t old; 320d543a106SHeiko Carstens 321d543a106SHeiko Carstens if (!n) 322d543a106SHeiko Carstens return; 323d543a106SHeiko Carstens incr = 1; 324d543a106SHeiko Carstens if (dst > src) { 325d543a106SHeiko Carstens incr = -incr; 326d543a106SHeiko Carstens dst += n - 1; 327d543a106SHeiko Carstens src += n - 1; 328d543a106SHeiko Carstens } 329d543a106SHeiko Carstens old = S390_lowcore.program_new_psw; 330d543a106SHeiko Carstens S390_lowcore.program_new_psw.mask = __extract_psw(); 331d543a106SHeiko Carstens asm volatile( 332d543a106SHeiko Carstens " larl %[addr],1f\n" 333d543a106SHeiko Carstens " stg %[addr],%[psw_pgm_addr]\n" 334d543a106SHeiko Carstens "0: mvc 0(1,%[dst]),0(%[src])\n" 335d543a106SHeiko Carstens " agr %[dst],%[incr]\n" 336d543a106SHeiko Carstens " agr %[src],%[incr]\n" 337d543a106SHeiko Carstens " brctg %[n],0b\n" 338d543a106SHeiko Carstens "1:\n" 339d543a106SHeiko Carstens : [addr] "=&d" (addr), 34075a35734SHeiko Carstens [psw_pgm_addr] "=Q" (S390_lowcore.program_new_psw.addr), 341d543a106SHeiko Carstens [dst] "+&a" (dst), [src] "+&a" (src), [n] "+d" (n) 342d543a106SHeiko Carstens : [incr] "d" (incr) 343d543a106SHeiko Carstens : "cc", "memory"); 344d543a106SHeiko Carstens S390_lowcore.program_new_psw = old; 345d543a106SHeiko Carstens } 346d543a106SHeiko Carstens 347d543a106SHeiko Carstens static __init noinline void ipl_save_parameters(void) 348d543a106SHeiko Carstens { 349d543a106SHeiko Carstens void *src, *dst; 350d543a106SHeiko Carstens 351d543a106SHeiko Carstens src = (void *)(unsigned long) S390_lowcore.ipl_parmblock_ptr; 352d543a106SHeiko Carstens dst = (void *) IPL_PARMBLOCK_ORIGIN; 353d543a106SHeiko Carstens memmove_early(dst, src, PAGE_SIZE); 354d543a106SHeiko Carstens S390_lowcore.ipl_parmblock_ptr = IPL_PARMBLOCK_ORIGIN; 355d543a106SHeiko Carstens } 356d543a106SHeiko Carstens 357d543a106SHeiko Carstens static __init noinline void rescue_initrd(void) 358761cdf6aSHeiko Carstens { 359761cdf6aSHeiko Carstens #ifdef CONFIG_BLK_DEV_INITRD 36027e7318cSHeiko Carstens unsigned long min_initrd_addr = (unsigned long) _end + (4UL << 20); 361761cdf6aSHeiko Carstens /* 36227e7318cSHeiko Carstens * Just like in case of IPL from VM reader we make sure there is a 36327e7318cSHeiko Carstens * gap of 4MB between end of kernel and start of initrd. 36427e7318cSHeiko Carstens * That way we can also be sure that saving an NSS will succeed, 36527e7318cSHeiko Carstens * which however only requires different segments. 366761cdf6aSHeiko Carstens */ 367761cdf6aSHeiko Carstens if (!INITRD_START || !INITRD_SIZE) 368761cdf6aSHeiko Carstens return; 36927e7318cSHeiko Carstens if (INITRD_START >= min_initrd_addr) 370761cdf6aSHeiko Carstens return; 371d543a106SHeiko Carstens memmove_early((void *) min_initrd_addr, (void *) INITRD_START, INITRD_SIZE); 37227e7318cSHeiko Carstens INITRD_START = min_initrd_addr; 373761cdf6aSHeiko Carstens #endif 374761cdf6aSHeiko Carstens } 375761cdf6aSHeiko Carstens 376a0443fbbSHendrik Brueckner /* Set up boot command line */ 377684d2fd4SHendrik Brueckner static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t)) 378684d2fd4SHendrik Brueckner { 379684d2fd4SHendrik Brueckner char *parm, *delim; 380684d2fd4SHendrik Brueckner size_t rc, len; 381684d2fd4SHendrik Brueckner 382684d2fd4SHendrik Brueckner len = strlen(boot_command_line); 383684d2fd4SHendrik Brueckner 384684d2fd4SHendrik Brueckner delim = boot_command_line + len; /* '\0' character position */ 385684d2fd4SHendrik Brueckner parm = boot_command_line + len + 1; /* append right after '\0' */ 386684d2fd4SHendrik Brueckner 387684d2fd4SHendrik Brueckner rc = ipl_data(parm, COMMAND_LINE_SIZE - len - 1); 388684d2fd4SHendrik Brueckner if (rc) { 389684d2fd4SHendrik Brueckner if (*parm == '=') 390684d2fd4SHendrik Brueckner memmove(boot_command_line, parm + 1, rc); 391684d2fd4SHendrik Brueckner else 392684d2fd4SHendrik Brueckner *delim = ' '; /* replace '\0' with space */ 393684d2fd4SHendrik Brueckner } 394684d2fd4SHendrik Brueckner } 395684d2fd4SHendrik Brueckner 3961fb81057SMichael Holzheu static inline int has_ebcdic_char(const char *str) 397a0443fbbSHendrik Brueckner { 39861fd330dSMartin Schwidefsky int i; 39961fd330dSMartin Schwidefsky 4001fb81057SMichael Holzheu for (i = 0; str[i]; i++) 4011fb81057SMichael Holzheu if (str[i] & 0x80) 4021fb81057SMichael Holzheu return 1; 4031fb81057SMichael Holzheu return 0; 4041fb81057SMichael Holzheu } 40561fd330dSMartin Schwidefsky 4061fb81057SMichael Holzheu static void __init setup_boot_command_line(void) 4071fb81057SMichael Holzheu { 4081fb81057SMichael Holzheu COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0; 4091fb81057SMichael Holzheu /* convert arch command line to ascii if necessary */ 4101fb81057SMichael Holzheu if (has_ebcdic_char(COMMAND_LINE)) 4111fb81057SMichael Holzheu EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); 412a0443fbbSHendrik Brueckner /* copy arch command line */ 41361fd330dSMartin Schwidefsky strlcpy(boot_command_line, strstrip(COMMAND_LINE), 41461fd330dSMartin Schwidefsky ARCH_COMMAND_LINE_SIZE); 415a0443fbbSHendrik Brueckner 416a0443fbbSHendrik Brueckner /* append IPL PARM data to the boot command line */ 417684d2fd4SHendrik Brueckner if (MACHINE_IS_VM) 418684d2fd4SHendrik Brueckner append_to_cmdline(append_ipl_vmparm); 419684d2fd4SHendrik Brueckner 420684d2fd4SHendrik Brueckner append_to_cmdline(append_ipl_scpdata); 421a0443fbbSHendrik Brueckner } 422a0443fbbSHendrik Brueckner 423ab14de6cSHeiko Carstens void __init startup_init(void) 424ab14de6cSHeiko Carstens { 425b6112ccbSMartin Schwidefsky reset_tod_clock(); 426ab14de6cSHeiko Carstens ipl_save_parameters(); 427761cdf6aSHeiko Carstens rescue_initrd(); 428ab14de6cSHeiko Carstens clear_bss_section(); 429d543a106SHeiko Carstens ipl_verify_parameters(); 430b1c0854dSMartin Schwidefsky time_early_init(); 431ab14de6cSHeiko Carstens init_kernel_storage_key(); 432ab14de6cSHeiko Carstens lockdep_off(); 433ab14de6cSHeiko Carstens setup_lowcore_early(); 43414375bc4SMartin Schwidefsky setup_facility_list(); 435a0443fbbSHendrik Brueckner detect_machine_type(); 4364b8fe77aSChristian Borntraeger setup_arch_string(); 437a0443fbbSHendrik Brueckner ipl_update_parameters(); 438a0443fbbSHendrik Brueckner setup_boot_command_line(); 4392e5061e4SHeiko Carstens detect_diag9c(); 4402e5061e4SHeiko Carstens detect_diag44(); 4412e5061e4SHeiko Carstens detect_machine_facilities(); 4421a36a39eSMartin Schwidefsky save_vector_registers(); 443fade4dc4SHeiko Carstens setup_topology(); 4447b50da53SMichael Holzheu sclp_early_detect(); 445ab14de6cSHeiko Carstens lockdep_on(); 446ab14de6cSHeiko Carstens } 447