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 */ 6ab14de6cSHeiko Carstens 711af97e1SHendrik Brueckner #define KMSG_COMPONENT "setup" 811af97e1SHendrik Brueckner #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 911af97e1SHendrik Brueckner 1092e6ecf3SChristian Borntraeger #include <linux/compiler.h> 11ab14de6cSHeiko Carstens #include <linux/init.h> 12ab14de6cSHeiko Carstens #include <linux/errno.h> 13ab14de6cSHeiko Carstens #include <linux/string.h> 14ab14de6cSHeiko Carstens #include <linux/ctype.h> 15ab14de6cSHeiko Carstens #include <linux/lockdep.h> 16dcc096c5SPaul Gortmaker #include <linux/extable.h> 17ab14de6cSHeiko Carstens #include <linux/pfn.h> 18ab14de6cSHeiko Carstens #include <linux/uaccess.h> 1911af97e1SHendrik Brueckner #include <linux/kernel.h> 20d09a307fSHeiko Carstens #include <asm/asm-extable.h> 21bb1520d5SAlexander Gordeev #include <linux/memblock.h> 221ec2772eSMartin Schwidefsky #include <asm/diag.h> 23a0443fbbSHendrik Brueckner #include <asm/ebcdic.h> 2446b05d26SMichael Holzheu #include <asm/ipl.h> 25ab14de6cSHeiko Carstens #include <asm/lowcore.h> 26ab14de6cSHeiko Carstens #include <asm/processor.h> 27ab14de6cSHeiko Carstens #include <asm/sections.h> 28ab14de6cSHeiko Carstens #include <asm/setup.h> 2992e6ecf3SChristian Borntraeger #include <asm/sysinfo.h> 30ab14de6cSHeiko Carstens #include <asm/cpcmd.h> 31ab14de6cSHeiko Carstens #include <asm/sclp.h> 32a0616cdeSDavid Howells #include <asm/facility.h> 3349698745SVasily Gorbik #include <asm/boot_data.h> 34c2313594SVasily Gorbik #include <asm/switch_to.h> 35a806170eSHeiko Carstens #include "entry.h" 36ab14de6cSHeiko Carstens 378ee0d2fbSVasily Gorbik #define decompressor_handled_param(param) \ 388ee0d2fbSVasily Gorbik static int __init ignore_decompressor_param_##param(char *s) \ 398ee0d2fbSVasily Gorbik { \ 408ee0d2fbSVasily Gorbik return 0; \ 418ee0d2fbSVasily Gorbik } \ 428ee0d2fbSVasily Gorbik early_param(#param, ignore_decompressor_param_##param) 438ee0d2fbSVasily Gorbik 448ee0d2fbSVasily Gorbik decompressor_handled_param(mem); 458ee0d2fbSVasily Gorbik decompressor_handled_param(vmalloc); 468ee0d2fbSVasily Gorbik decompressor_handled_param(dfltcc); 478ee0d2fbSVasily Gorbik decompressor_handled_param(facilities); 488ee0d2fbSVasily Gorbik decompressor_handled_param(nokaslr); 49*468a3bc2SHeiko Carstens decompressor_handled_param(cmma); 508ee0d2fbSVasily Gorbik #if IS_ENABLED(CONFIG_KVM) 518ee0d2fbSVasily Gorbik decompressor_handled_param(prot_virt); 528ee0d2fbSVasily Gorbik #endif 538ee0d2fbSVasily Gorbik 54557b1970SVasily Gorbik static void __init kasan_early_init(void) 55557b1970SVasily Gorbik { 56557b1970SVasily Gorbik #ifdef CONFIG_KASAN 57557b1970SVasily Gorbik init_task.kasan_depth = 0; 58557b1970SVasily Gorbik sclp_early_printk("KernelAddressSanitizer initialized\n"); 59557b1970SVasily Gorbik #endif 60557b1970SVasily Gorbik } 61557b1970SVasily Gorbik 622e83e0ebSVasily Gorbik static void __init reset_tod_clock(void) 632e83e0ebSVasily Gorbik { 64530f639fSHeiko Carstens union tod_clock clk; 652e83e0ebSVasily Gorbik 66530f639fSHeiko Carstens if (store_tod_clock_ext_cc(&clk) == 0) 672e83e0ebSVasily Gorbik return; 682e83e0ebSVasily Gorbik /* TOD clock not running. Set the clock to Unix Epoch. */ 69530f639fSHeiko Carstens if (set_tod_clock(TOD_UNIX_EPOCH) || store_tod_clock_ext_cc(&clk)) 702e83e0ebSVasily Gorbik disabled_wait(); 712e83e0ebSVasily Gorbik 72f8d8977aSHeiko Carstens memset(&tod_clock_base, 0, sizeof(tod_clock_base)); 73f8d8977aSHeiko Carstens tod_clock_base.tod = TOD_UNIX_EPOCH; 742e83e0ebSVasily Gorbik S390_lowcore.last_update_clock = TOD_UNIX_EPOCH; 752e83e0ebSVasily Gorbik } 762e83e0ebSVasily Gorbik 77b6112ccbSMartin Schwidefsky /* 78ab14de6cSHeiko Carstens * Initialize storage key for kernel pages 79ab14de6cSHeiko Carstens */ 80ab14de6cSHeiko Carstens static noinline __init void init_kernel_storage_key(void) 81ab14de6cSHeiko Carstens { 82127c1fefSMartin Schwidefsky #if PAGE_DEFAULT_KEY 83ab14de6cSHeiko Carstens unsigned long end_pfn, init_pfn; 84ab14de6cSHeiko Carstens 85320d9555SVasily Gorbik end_pfn = PFN_UP(__pa(_end)); 86ab14de6cSHeiko Carstens 87ab14de6cSHeiko Carstens for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++) 88e2b8d7afSMartin Schwidefsky page_set_storage_key(init_pfn << PAGE_SHIFT, 89e2b8d7afSMartin Schwidefsky PAGE_DEFAULT_KEY, 0); 90127c1fefSMartin Schwidefsky #endif 91ab14de6cSHeiko Carstens } 92ab14de6cSHeiko Carstens 93fade4dc4SHeiko Carstens static __initdata char sysinfo_page[PAGE_SIZE] __aligned(PAGE_SIZE); 9492e6ecf3SChristian Borntraeger 95ab14de6cSHeiko Carstens static noinline __init void detect_machine_type(void) 96ab14de6cSHeiko Carstens { 97fade4dc4SHeiko Carstens struct sysinfo_3_2_2 *vmms = (struct sysinfo_3_2_2 *)&sysinfo_page; 98fade4dc4SHeiko Carstens 9927d71602SMartin Schwidefsky /* Check current-configuration-level */ 100caf757c6SHeiko Carstens if (stsi(NULL, 0, 0, 0) <= 2) { 10127d71602SMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_LPAR; 10292e6ecf3SChristian Borntraeger return; 10327d71602SMartin Schwidefsky } 10427d71602SMartin Schwidefsky /* Get virtual-machine cpu information. */ 105caf757c6SHeiko Carstens if (stsi(vmms, 3, 2, 2) || !vmms->count) 10692e6ecf3SChristian Borntraeger return; 107ab14de6cSHeiko Carstens 10803aa047eSChristian Borntraeger /* Detect known hypervisors */ 109fade4dc4SHeiko Carstens if (!memcmp(vmms->vm[0].cpi, "\xd2\xe5\xd4", 3)) 110d3135e0cSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_KVM; 11103aa047eSChristian Borntraeger else if (!memcmp(vmms->vm[0].cpi, "\xa9\x61\xe5\xd4", 4)) 112d3135e0cSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_VM; 113ab14de6cSHeiko Carstens } 114ab14de6cSHeiko Carstens 115d2f03974SHeiko Carstens /* Remove leading, trailing and double whitespace. */ 116d2f03974SHeiko Carstens static inline void strim_all(char *str) 117d2f03974SHeiko Carstens { 118d2f03974SHeiko Carstens char *s; 119d2f03974SHeiko Carstens 120d2f03974SHeiko Carstens s = strim(str); 121d2f03974SHeiko Carstens if (s != str) 122d2f03974SHeiko Carstens memmove(str, s, strlen(s)); 123d2f03974SHeiko Carstens while (*str) { 124d2f03974SHeiko Carstens if (!isspace(*str++)) 125d2f03974SHeiko Carstens continue; 126d2f03974SHeiko Carstens if (isspace(*str)) { 127d2f03974SHeiko Carstens s = skip_spaces(str); 128d2f03974SHeiko Carstens memmove(str, s, strlen(s) + 1); 129d2f03974SHeiko Carstens } 130d2f03974SHeiko Carstens } 131d2f03974SHeiko Carstens } 132d2f03974SHeiko Carstens 1334b8fe77aSChristian Borntraeger static noinline __init void setup_arch_string(void) 1344b8fe77aSChristian Borntraeger { 1354b8fe77aSChristian Borntraeger struct sysinfo_1_1_1 *mach = (struct sysinfo_1_1_1 *)&sysinfo_page; 1362f8876f9SHeiko Carstens struct sysinfo_3_2_2 *vm = (struct sysinfo_3_2_2 *)&sysinfo_page; 1372f8876f9SHeiko Carstens char mstr[80], hvstr[17]; 1384b8fe77aSChristian Borntraeger 1394b8fe77aSChristian Borntraeger if (stsi(mach, 1, 1, 1)) 1404b8fe77aSChristian Borntraeger return; 1414b8fe77aSChristian Borntraeger EBCASC(mach->manufacturer, sizeof(mach->manufacturer)); 1424b8fe77aSChristian Borntraeger EBCASC(mach->type, sizeof(mach->type)); 1434b8fe77aSChristian Borntraeger EBCASC(mach->model, sizeof(mach->model)); 1444b8fe77aSChristian Borntraeger EBCASC(mach->model_capacity, sizeof(mach->model_capacity)); 145d2f03974SHeiko Carstens sprintf(mstr, "%-16.16s %-4.4s %-16.16s %-16.16s", 146d2f03974SHeiko Carstens mach->manufacturer, mach->type, 147d2f03974SHeiko Carstens mach->model, mach->model_capacity); 148d2f03974SHeiko Carstens strim_all(mstr); 1492f8876f9SHeiko Carstens if (stsi(vm, 3, 2, 2) == 0 && vm->count) { 1502f8876f9SHeiko Carstens EBCASC(vm->vm[0].cpi, sizeof(vm->vm[0].cpi)); 1512f8876f9SHeiko Carstens sprintf(hvstr, "%-16.16s", vm->vm[0].cpi); 1522f8876f9SHeiko Carstens strim_all(hvstr); 1532f8876f9SHeiko Carstens } else { 1542f8876f9SHeiko Carstens sprintf(hvstr, "%s", 1554b8fe77aSChristian Borntraeger MACHINE_IS_LPAR ? "LPAR" : 1564b8fe77aSChristian Borntraeger MACHINE_IS_VM ? "z/VM" : 1574b8fe77aSChristian Borntraeger MACHINE_IS_KVM ? "KVM" : "unknown"); 1584b8fe77aSChristian Borntraeger } 1592f8876f9SHeiko Carstens dump_stack_set_arch_desc("%s (%s)", mstr, hvstr); 1602f8876f9SHeiko Carstens } 1614b8fe77aSChristian Borntraeger 162fade4dc4SHeiko Carstens static __init void setup_topology(void) 163fade4dc4SHeiko Carstens { 164fade4dc4SHeiko Carstens int max_mnest; 165fade4dc4SHeiko Carstens 166fade4dc4SHeiko Carstens if (!test_facility(11)) 167fade4dc4SHeiko Carstens return; 168fade4dc4SHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY; 169fade4dc4SHeiko Carstens for (max_mnest = 6; max_mnest > 1; max_mnest--) { 170caf757c6SHeiko Carstens if (stsi(&sysinfo_page, 15, 1, max_mnest) == 0) 171fade4dc4SHeiko Carstens break; 172fade4dc4SHeiko Carstens } 173fade4dc4SHeiko Carstens topology_max_mnest = max_mnest; 174fade4dc4SHeiko Carstens } 175fade4dc4SHeiko Carstens 17685806016SHeiko Carstens void __do_early_pgm_check(struct pt_regs *regs) 177ab14de6cSHeiko Carstens { 17846fee16fSHeiko Carstens if (!fixup_exception(regs)) 17998587c2dSMartin Schwidefsky disabled_wait(); 180ab14de6cSHeiko Carstens } 181ab14de6cSHeiko Carstens 1825f954c34SHeiko Carstens static noinline __init void setup_lowcore_early(void) 183ab14de6cSHeiko Carstens { 184ab14de6cSHeiko Carstens psw_t psw; 185ab14de6cSHeiko Carstens 18685806016SHeiko Carstens psw.addr = (unsigned long)early_pgm_check_handler; 187bb1520d5SAlexander Gordeev psw.mask = PSW_KERNEL_BITS; 188ab14de6cSHeiko Carstens S390_lowcore.program_new_psw = psw; 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 { 19417e89e13SSven Schnelle memcpy(alt_stfle_fac_list, stfle_fac_list, sizeof(alt_stfle_fac_list)); 195d768bd89SMartin Schwidefsky if (!IS_ENABLED(CONFIG_KERNEL_NOBP)) 19617e89e13SSven Schnelle __clear_facility(82, alt_stfle_fac_list); 19714375bc4SMartin Schwidefsky } 19814375bc4SMartin Schwidefsky 1992e5061e4SHeiko Carstens static __init void detect_diag9c(void) 2002e5061e4SHeiko Carstens { 2012e5061e4SHeiko Carstens unsigned int cpu_address; 2022e5061e4SHeiko Carstens int rc; 2032e5061e4SHeiko Carstens 2042e5061e4SHeiko Carstens cpu_address = stap(); 2051ec2772eSMartin Schwidefsky diag_stat_inc(DIAG_STAT_X09C); 2062e5061e4SHeiko Carstens asm volatile( 2072e5061e4SHeiko Carstens " diag %2,0,0x9c\n" 2082e5061e4SHeiko Carstens "0: la %0,0\n" 2092e5061e4SHeiko Carstens "1:\n" 2102e5061e4SHeiko Carstens EX_TABLE(0b,1b) 2112e5061e4SHeiko Carstens : "=d" (rc) : "0" (-EOPNOTSUPP), "d" (cpu_address) : "cc"); 2122e5061e4SHeiko Carstens if (!rc) 213d3135e0cSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG9C; 2142e5061e4SHeiko Carstens } 2152e5061e4SHeiko Carstens 2162e5061e4SHeiko Carstens static __init void detect_machine_facilities(void) 2172e5061e4SHeiko Carstens { 2183c7ef08bSHeiko Carstens if (test_facility(8)) { 2193c7ef08bSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT1; 22099441a38SHeiko Carstens system_ctl_set_bit(0, CR0_EDAT_BIT); 2213c7ef08bSHeiko Carstens } 22285e9d0e5SHeiko Carstens if (test_facility(78)) 22385e9d0e5SHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2; 22414375bc4SMartin Schwidefsky if (test_facility(3)) 225d3135e0cSHeiko Carstens S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; 226a1c5befcSHeiko Carstens if (test_facility(50) && test_facility(73)) { 227d35339a4SMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_TE; 22899441a38SHeiko Carstens system_ctl_set_bit(0, CR0_TRANSACTIONAL_EXECUTION_BIT); 229a1c5befcSHeiko Carstens } 2301b948d6cSMartin Schwidefsky if (test_facility(51)) 2311b948d6cSMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC; 232b5510d9bSHendrik Brueckner if (test_facility(129)) { 23380703617SMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_VX; 23499441a38SHeiko Carstens system_ctl_set_bit(0, CR0_VECTOR_BIT); 2352e5061e4SHeiko Carstens } 236c0f1d478SHeiko Carstens if (test_facility(130)) 23757d7f939SMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_NX; 238916cda1aSMartin Schwidefsky if (test_facility(133)) 239916cda1aSMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_GS; 240f8d8977aSHeiko Carstens if (test_facility(139) && (tod_clock_base.tod >> 63)) { 2416e2ef5e4SMartin Schwidefsky /* Enabled signed clock comparator comparisons */ 2426e2ef5e4SMartin Schwidefsky S390_lowcore.machine_flags |= MACHINE_FLAG_SCC; 2436e2ef5e4SMartin Schwidefsky clock_comparator_max = -1ULL >> 1; 24499441a38SHeiko Carstens system_ctl_set_bit(0, CR0_CLOCK_COMPARATOR_SIGN_BIT); 2456e2ef5e4SMartin Schwidefsky } 2463322ba0dSNiklas Schnelle if (IS_ENABLED(CONFIG_PCI) && test_facility(153)) { 2473322ba0dSNiklas Schnelle S390_lowcore.machine_flags |= MACHINE_FLAG_PCI_MIO; 2483322ba0dSNiklas Schnelle /* the control bit is set during PCI initialization */ 2493322ba0dSNiklas Schnelle } 2500807b856SGerald Schaefer if (test_facility(194)) 2510807b856SGerald Schaefer S390_lowcore.machine_flags |= MACHINE_FLAG_RDP; 252b5510d9bSHendrik Brueckner } 253b5510d9bSHendrik Brueckner 2541a36a39eSMartin Schwidefsky static inline void save_vector_registers(void) 2551a36a39eSMartin Schwidefsky { 2561a36a39eSMartin Schwidefsky #ifdef CONFIG_CRASH_DUMP 2571a36a39eSMartin Schwidefsky if (test_facility(129)) 2581a36a39eSMartin Schwidefsky save_vx_regs(boot_cpu_vector_save_area); 2591a36a39eSMartin Schwidefsky #endif 2601a36a39eSMartin Schwidefsky } 2611a36a39eSMartin Schwidefsky 2624a172528SHeiko Carstens static inline void setup_low_address_protection(void) 263c02ee6a1SVasily Gorbik { 26499441a38SHeiko Carstens system_ctl_set_bit(0, CR0_LOW_ADDRESS_PROTECTION_BIT); 265c02ee6a1SVasily Gorbik } 266c02ee6a1SVasily Gorbik 267c2313594SVasily Gorbik static inline void setup_access_registers(void) 268c2313594SVasily Gorbik { 269c2313594SVasily Gorbik unsigned int acrs[NUM_ACRS] = { 0 }; 270c2313594SVasily Gorbik 271c2313594SVasily Gorbik restore_access_regs(acrs); 272c2313594SVasily Gorbik } 273c2313594SVasily Gorbik 274b5510d9bSHendrik Brueckner static int __init disable_vector_extension(char *str) 275b5510d9bSHendrik Brueckner { 276b5510d9bSHendrik Brueckner S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; 27799441a38SHeiko Carstens system_ctl_clear_bit(0, CR0_VECTOR_BIT); 278673cfddfSHeiko Carstens return 0; 279b5510d9bSHendrik Brueckner } 280b5510d9bSHendrik Brueckner early_param("novx", disable_vector_extension); 2812e5061e4SHeiko Carstens 28249698745SVasily Gorbik char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; 2831fb81057SMichael Holzheu static void __init setup_boot_command_line(void) 2841fb81057SMichael Holzheu { 285a0443fbbSHendrik Brueckner /* copy arch command line */ 286820109fbSWolfram Sang strscpy(boot_command_line, early_command_line, COMMAND_LINE_SIZE); 287a0443fbbSHendrik Brueckner } 288a0443fbbSHendrik Brueckner 289a156f09cSHeiko Carstens static void __init sort_amode31_extable(void) 290a156f09cSHeiko Carstens { 291a156f09cSHeiko Carstens sort_extable(__start_amode31_ex_table, __stop_amode31_ex_table); 292a156f09cSHeiko Carstens } 293a156f09cSHeiko Carstens 294ab14de6cSHeiko Carstens void __init startup_init(void) 295ab14de6cSHeiko Carstens { 296557b1970SVasily Gorbik kasan_early_init(); 2972e83e0ebSVasily Gorbik reset_tod_clock(); 298b1c0854dSMartin Schwidefsky time_early_init(); 299ab14de6cSHeiko Carstens init_kernel_storage_key(); 300ab14de6cSHeiko Carstens lockdep_off(); 301a156f09cSHeiko Carstens sort_amode31_extable(); 302ab14de6cSHeiko Carstens setup_lowcore_early(); 30314375bc4SMartin Schwidefsky setup_facility_list(); 304a0443fbbSHendrik Brueckner detect_machine_type(); 3054b8fe77aSChristian Borntraeger setup_arch_string(); 306a0443fbbSHendrik Brueckner setup_boot_command_line(); 3072e5061e4SHeiko Carstens detect_diag9c(); 3082e5061e4SHeiko Carstens detect_machine_facilities(); 3091a36a39eSMartin Schwidefsky save_vector_registers(); 310fade4dc4SHeiko Carstens setup_topology(); 3117b50da53SMichael Holzheu sclp_early_detect(); 3124a172528SHeiko Carstens setup_low_address_protection(); 313c2313594SVasily Gorbik setup_access_registers(); 314ab14de6cSHeiko Carstens lockdep_on(); 315ab14de6cSHeiko Carstens } 316