Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *    Copyright IBM Corp. 2007, 2009
0004  *    Author(s): Hongjie Yang <hongjie@us.ibm.com>,
0005  */
0006 
0007 #define KMSG_COMPONENT "setup"
0008 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0009 
0010 #include <linux/compiler.h>
0011 #include <linux/init.h>
0012 #include <linux/errno.h>
0013 #include <linux/string.h>
0014 #include <linux/ctype.h>
0015 #include <linux/lockdep.h>
0016 #include <linux/extable.h>
0017 #include <linux/pfn.h>
0018 #include <linux/uaccess.h>
0019 #include <linux/kernel.h>
0020 #include <asm/asm-extable.h>
0021 #include <asm/diag.h>
0022 #include <asm/ebcdic.h>
0023 #include <asm/ipl.h>
0024 #include <asm/lowcore.h>
0025 #include <asm/processor.h>
0026 #include <asm/sections.h>
0027 #include <asm/setup.h>
0028 #include <asm/sysinfo.h>
0029 #include <asm/cpcmd.h>
0030 #include <asm/sclp.h>
0031 #include <asm/facility.h>
0032 #include <asm/boot_data.h>
0033 #include <asm/switch_to.h>
0034 #include "entry.h"
0035 
0036 int __bootdata(is_full_image);
0037 
0038 static void __init reset_tod_clock(void)
0039 {
0040     union tod_clock clk;
0041 
0042     if (store_tod_clock_ext_cc(&clk) == 0)
0043         return;
0044     /* TOD clock not running. Set the clock to Unix Epoch. */
0045     if (set_tod_clock(TOD_UNIX_EPOCH) || store_tod_clock_ext_cc(&clk))
0046         disabled_wait();
0047 
0048     memset(&tod_clock_base, 0, sizeof(tod_clock_base));
0049     tod_clock_base.tod = TOD_UNIX_EPOCH;
0050     S390_lowcore.last_update_clock = TOD_UNIX_EPOCH;
0051 }
0052 
0053 /*
0054  * Initialize storage key for kernel pages
0055  */
0056 static noinline __init void init_kernel_storage_key(void)
0057 {
0058 #if PAGE_DEFAULT_KEY
0059     unsigned long end_pfn, init_pfn;
0060 
0061     end_pfn = PFN_UP(__pa(_end));
0062 
0063     for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
0064         page_set_storage_key(init_pfn << PAGE_SHIFT,
0065                      PAGE_DEFAULT_KEY, 0);
0066 #endif
0067 }
0068 
0069 static __initdata char sysinfo_page[PAGE_SIZE] __aligned(PAGE_SIZE);
0070 
0071 static noinline __init void detect_machine_type(void)
0072 {
0073     struct sysinfo_3_2_2 *vmms = (struct sysinfo_3_2_2 *)&sysinfo_page;
0074 
0075     /* Check current-configuration-level */
0076     if (stsi(NULL, 0, 0, 0) <= 2) {
0077         S390_lowcore.machine_flags |= MACHINE_FLAG_LPAR;
0078         return;
0079     }
0080     /* Get virtual-machine cpu information. */
0081     if (stsi(vmms, 3, 2, 2) || !vmms->count)
0082         return;
0083 
0084     /* Detect known hypervisors */
0085     if (!memcmp(vmms->vm[0].cpi, "\xd2\xe5\xd4", 3))
0086         S390_lowcore.machine_flags |= MACHINE_FLAG_KVM;
0087     else if (!memcmp(vmms->vm[0].cpi, "\xa9\x61\xe5\xd4", 4))
0088         S390_lowcore.machine_flags |= MACHINE_FLAG_VM;
0089 }
0090 
0091 /* Remove leading, trailing and double whitespace. */
0092 static inline void strim_all(char *str)
0093 {
0094     char *s;
0095 
0096     s = strim(str);
0097     if (s != str)
0098         memmove(str, s, strlen(s));
0099     while (*str) {
0100         if (!isspace(*str++))
0101             continue;
0102         if (isspace(*str)) {
0103             s = skip_spaces(str);
0104             memmove(str, s, strlen(s) + 1);
0105         }
0106     }
0107 }
0108 
0109 static noinline __init void setup_arch_string(void)
0110 {
0111     struct sysinfo_1_1_1 *mach = (struct sysinfo_1_1_1 *)&sysinfo_page;
0112     struct sysinfo_3_2_2 *vm = (struct sysinfo_3_2_2 *)&sysinfo_page;
0113     char mstr[80], hvstr[17];
0114 
0115     if (stsi(mach, 1, 1, 1))
0116         return;
0117     EBCASC(mach->manufacturer, sizeof(mach->manufacturer));
0118     EBCASC(mach->type, sizeof(mach->type));
0119     EBCASC(mach->model, sizeof(mach->model));
0120     EBCASC(mach->model_capacity, sizeof(mach->model_capacity));
0121     sprintf(mstr, "%-16.16s %-4.4s %-16.16s %-16.16s",
0122         mach->manufacturer, mach->type,
0123         mach->model, mach->model_capacity);
0124     strim_all(mstr);
0125     if (stsi(vm, 3, 2, 2) == 0 && vm->count) {
0126         EBCASC(vm->vm[0].cpi, sizeof(vm->vm[0].cpi));
0127         sprintf(hvstr, "%-16.16s", vm->vm[0].cpi);
0128         strim_all(hvstr);
0129     } else {
0130         sprintf(hvstr, "%s",
0131             MACHINE_IS_LPAR ? "LPAR" :
0132             MACHINE_IS_VM ? "z/VM" :
0133             MACHINE_IS_KVM ? "KVM" : "unknown");
0134     }
0135     dump_stack_set_arch_desc("%s (%s)", mstr, hvstr);
0136 }
0137 
0138 static __init void setup_topology(void)
0139 {
0140     int max_mnest;
0141 
0142     if (!test_facility(11))
0143         return;
0144     S390_lowcore.machine_flags |= MACHINE_FLAG_TOPOLOGY;
0145     for (max_mnest = 6; max_mnest > 1; max_mnest--) {
0146         if (stsi(&sysinfo_page, 15, 1, max_mnest) == 0)
0147             break;
0148     }
0149     topology_max_mnest = max_mnest;
0150 }
0151 
0152 void __do_early_pgm_check(struct pt_regs *regs)
0153 {
0154     if (!fixup_exception(regs))
0155         disabled_wait();
0156 }
0157 
0158 static noinline __init void setup_lowcore_early(void)
0159 {
0160     psw_t psw;
0161 
0162     psw.addr = (unsigned long)early_pgm_check_handler;
0163     psw.mask = PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA;
0164     if (IS_ENABLED(CONFIG_KASAN))
0165         psw.mask |= PSW_MASK_DAT;
0166     S390_lowcore.program_new_psw = psw;
0167     S390_lowcore.preempt_count = INIT_PREEMPT_COUNT;
0168 }
0169 
0170 static noinline __init void setup_facility_list(void)
0171 {
0172     memcpy(alt_stfle_fac_list, stfle_fac_list, sizeof(alt_stfle_fac_list));
0173     if (!IS_ENABLED(CONFIG_KERNEL_NOBP))
0174         __clear_facility(82, alt_stfle_fac_list);
0175 }
0176 
0177 static __init void detect_diag9c(void)
0178 {
0179     unsigned int cpu_address;
0180     int rc;
0181 
0182     cpu_address = stap();
0183     diag_stat_inc(DIAG_STAT_X09C);
0184     asm volatile(
0185         "   diag    %2,0,0x9c\n"
0186         "0: la  %0,0\n"
0187         "1:\n"
0188         EX_TABLE(0b,1b)
0189         : "=d" (rc) : "0" (-EOPNOTSUPP), "d" (cpu_address) : "cc");
0190     if (!rc)
0191         S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG9C;
0192 }
0193 
0194 static __init void detect_machine_facilities(void)
0195 {
0196     if (test_facility(8)) {
0197         S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT1;
0198         __ctl_set_bit(0, 23);
0199     }
0200     if (test_facility(78))
0201         S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2;
0202     if (test_facility(3))
0203         S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
0204     if (test_facility(50) && test_facility(73)) {
0205         S390_lowcore.machine_flags |= MACHINE_FLAG_TE;
0206         __ctl_set_bit(0, 55);
0207     }
0208     if (test_facility(51))
0209         S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC;
0210     if (test_facility(129)) {
0211         S390_lowcore.machine_flags |= MACHINE_FLAG_VX;
0212         __ctl_set_bit(0, 17);
0213     }
0214     if (test_facility(130) && !noexec_disabled) {
0215         S390_lowcore.machine_flags |= MACHINE_FLAG_NX;
0216         __ctl_set_bit(0, 20);
0217     }
0218     if (test_facility(133))
0219         S390_lowcore.machine_flags |= MACHINE_FLAG_GS;
0220     if (test_facility(139) && (tod_clock_base.tod >> 63)) {
0221         /* Enabled signed clock comparator comparisons */
0222         S390_lowcore.machine_flags |= MACHINE_FLAG_SCC;
0223         clock_comparator_max = -1ULL >> 1;
0224         __ctl_set_bit(0, 53);
0225     }
0226     if (IS_ENABLED(CONFIG_PCI) && test_facility(153)) {
0227         S390_lowcore.machine_flags |= MACHINE_FLAG_PCI_MIO;
0228         /* the control bit is set during PCI initialization */
0229     }
0230 }
0231 
0232 static inline void save_vector_registers(void)
0233 {
0234 #ifdef CONFIG_CRASH_DUMP
0235     if (test_facility(129))
0236         save_vx_regs(boot_cpu_vector_save_area);
0237 #endif
0238 }
0239 
0240 static inline void setup_control_registers(void)
0241 {
0242     unsigned long reg;
0243 
0244     __ctl_store(reg, 0, 0);
0245     reg |= CR0_LOW_ADDRESS_PROTECTION;
0246     reg |= CR0_EMERGENCY_SIGNAL_SUBMASK;
0247     reg |= CR0_EXTERNAL_CALL_SUBMASK;
0248     __ctl_load(reg, 0, 0);
0249 }
0250 
0251 static inline void setup_access_registers(void)
0252 {
0253     unsigned int acrs[NUM_ACRS] = { 0 };
0254 
0255     restore_access_regs(acrs);
0256 }
0257 
0258 static int __init disable_vector_extension(char *str)
0259 {
0260     S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX;
0261     __ctl_clear_bit(0, 17);
0262     return 0;
0263 }
0264 early_param("novx", disable_vector_extension);
0265 
0266 char __bootdata(early_command_line)[COMMAND_LINE_SIZE];
0267 static void __init setup_boot_command_line(void)
0268 {
0269     /* copy arch command line */
0270     strlcpy(boot_command_line, early_command_line, COMMAND_LINE_SIZE);
0271 }
0272 
0273 static void __init check_image_bootable(void)
0274 {
0275     if (is_full_image)
0276         return;
0277 
0278     sclp_early_printk("Linux kernel boot failure: An attempt to boot a vmlinux ELF image failed.\n");
0279     sclp_early_printk("This image does not contain all parts necessary for starting up. Use\n");
0280     sclp_early_printk("bzImage or arch/s390/boot/compressed/vmlinux instead.\n");
0281     disabled_wait();
0282 }
0283 
0284 static void __init sort_amode31_extable(void)
0285 {
0286     sort_extable(__start_amode31_ex_table, __stop_amode31_ex_table);
0287 }
0288 
0289 void __init startup_init(void)
0290 {
0291     sclp_early_adjust_va();
0292     reset_tod_clock();
0293     check_image_bootable();
0294     time_early_init();
0295     init_kernel_storage_key();
0296     lockdep_off();
0297     sort_amode31_extable();
0298     setup_lowcore_early();
0299     setup_facility_list();
0300     detect_machine_type();
0301     setup_arch_string();
0302     setup_boot_command_line();
0303     detect_diag9c();
0304     detect_machine_facilities();
0305     save_vector_registers();
0306     setup_topology();
0307     sclp_early_detect();
0308     setup_control_registers();
0309     setup_access_registers();
0310     lockdep_on();
0311 }