1 /* 2 * arch/s390/kernel/early.c 3 * 4 * Copyright IBM Corp. 2007 5 * Author(s): Hongjie Yang <hongjie@us.ibm.com>, 6 * Heiko Carstens <heiko.carstens@de.ibm.com> 7 */ 8 9 #include <linux/compiler.h> 10 #include <linux/init.h> 11 #include <linux/errno.h> 12 #include <linux/string.h> 13 #include <linux/ctype.h> 14 #include <linux/lockdep.h> 15 #include <linux/module.h> 16 #include <linux/pfn.h> 17 #include <linux/uaccess.h> 18 #include <asm/ebcdic.h> 19 #include <asm/ipl.h> 20 #include <asm/lowcore.h> 21 #include <asm/processor.h> 22 #include <asm/sections.h> 23 #include <asm/setup.h> 24 #include <asm/sysinfo.h> 25 #include <asm/cpcmd.h> 26 #include <asm/sclp.h> 27 #include "entry.h" 28 29 /* 30 * Create a Kernel NSS if the SAVESYS= parameter is defined 31 */ 32 #define DEFSYS_CMD_SIZE 128 33 #define SAVESYS_CMD_SIZE 32 34 35 char kernel_nss_name[NSS_NAME_SIZE + 1]; 36 37 static unsigned long machine_flags; 38 39 static void __init setup_boot_command_line(void); 40 41 /* 42 * Get the TOD clock running. 43 */ 44 static void __init reset_tod_clock(void) 45 { 46 u64 time; 47 48 if (store_clock(&time) == 0) 49 return; 50 /* TOD clock not running. Set the clock to Unix Epoch. */ 51 if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0) 52 disabled_wait(0); 53 54 sched_clock_base_cc = TOD_UNIX_EPOCH; 55 } 56 57 #ifdef CONFIG_SHARED_KERNEL 58 int __init savesys_ipl_nss(char *cmd, const int cmdlen); 59 60 asm( 61 " .section .init.text,\"ax\",@progbits\n" 62 " .align 4\n" 63 " .type savesys_ipl_nss, @function\n" 64 "savesys_ipl_nss:\n" 65 #ifdef CONFIG_64BIT 66 " stmg 6,15,48(15)\n" 67 " lgr 14,3\n" 68 " sam31\n" 69 " diag 2,14,0x8\n" 70 " sam64\n" 71 " lgr 2,14\n" 72 " lmg 6,15,48(15)\n" 73 #else 74 " stm 6,15,24(15)\n" 75 " lr 14,3\n" 76 " diag 2,14,0x8\n" 77 " lr 2,14\n" 78 " lm 6,15,24(15)\n" 79 #endif 80 " br 14\n" 81 " .size savesys_ipl_nss, .-savesys_ipl_nss\n"); 82 83 static noinline __init void create_kernel_nss(void) 84 { 85 unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; 86 #ifdef CONFIG_BLK_DEV_INITRD 87 unsigned int sinitrd_pfn, einitrd_pfn; 88 #endif 89 int response; 90 size_t len; 91 char *savesys_ptr; 92 char upper_command_line[COMMAND_LINE_SIZE]; 93 char defsys_cmd[DEFSYS_CMD_SIZE]; 94 char savesys_cmd[SAVESYS_CMD_SIZE]; 95 96 /* Do nothing if we are not running under VM */ 97 if (!MACHINE_IS_VM) 98 return; 99 100 /* Convert COMMAND_LINE to upper case */ 101 for (i = 0; i < strlen(boot_command_line); i++) 102 upper_command_line[i] = toupper(boot_command_line[i]); 103 104 savesys_ptr = strstr(upper_command_line, "SAVESYS="); 105 106 if (!savesys_ptr) 107 return; 108 109 savesys_ptr += 8; /* Point to the beginning of the NSS name */ 110 for (i = 0; i < NSS_NAME_SIZE; i++) { 111 if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0') 112 break; 113 kernel_nss_name[i] = savesys_ptr[i]; 114 } 115 116 stext_pfn = PFN_DOWN(__pa(&_stext)); 117 eshared_pfn = PFN_DOWN(__pa(&_eshared)); 118 end_pfn = PFN_UP(__pa(&_end)); 119 min_size = end_pfn << 2; 120 121 sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X", 122 kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1, 123 eshared_pfn, end_pfn); 124 125 #ifdef CONFIG_BLK_DEV_INITRD 126 if (INITRD_START && INITRD_SIZE) { 127 sinitrd_pfn = PFN_DOWN(__pa(INITRD_START)); 128 einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE)); 129 min_size = einitrd_pfn << 2; 130 sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd, 131 sinitrd_pfn, einitrd_pfn); 132 } 133 #endif 134 135 sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13", 136 defsys_cmd, min_size); 137 sprintf(savesys_cmd, "SAVESYS %s \n IPL %s", 138 kernel_nss_name, kernel_nss_name); 139 140 __cpcmd(defsys_cmd, NULL, 0, &response); 141 142 if (response != 0) { 143 kernel_nss_name[0] = '\0'; 144 return; 145 } 146 147 len = strlen(savesys_cmd); 148 ASCEBC(savesys_cmd, len); 149 response = savesys_ipl_nss(savesys_cmd, len); 150 151 /* On success: response is equal to the command size, 152 * max SAVESYS_CMD_SIZE 153 * On error: response contains the numeric portion of cp error message. 154 * for SAVESYS it will be >= 263 155 */ 156 if (response > SAVESYS_CMD_SIZE) { 157 kernel_nss_name[0] = '\0'; 158 return; 159 } 160 161 /* re-setup boot command line with new ipl vm parms */ 162 ipl_update_parameters(); 163 setup_boot_command_line(); 164 165 ipl_flags = IPL_NSS_VALID; 166 } 167 168 #else /* CONFIG_SHARED_KERNEL */ 169 170 static inline void create_kernel_nss(void) { } 171 172 #endif /* CONFIG_SHARED_KERNEL */ 173 174 /* 175 * Clear bss memory 176 */ 177 static noinline __init void clear_bss_section(void) 178 { 179 memset(__bss_start, 0, __bss_stop - __bss_start); 180 } 181 182 /* 183 * Initialize storage key for kernel pages 184 */ 185 static noinline __init void init_kernel_storage_key(void) 186 { 187 unsigned long end_pfn, init_pfn; 188 189 end_pfn = PFN_UP(__pa(&_end)); 190 191 for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++) 192 page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); 193 } 194 195 static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE); 196 197 static noinline __init void detect_machine_type(void) 198 { 199 /* No VM information? Looks like LPAR */ 200 if (stsi(&vmms, 3, 2, 2) == -ENOSYS) 201 return; 202 if (!vmms.count) 203 return; 204 205 /* Running under KVM? If not we assume z/VM */ 206 if (!memcmp(vmms.vm[0].cpi, "\xd2\xe5\xd4", 3)) 207 machine_flags |= MACHINE_FLAG_KVM; 208 else 209 machine_flags |= MACHINE_FLAG_VM; 210 } 211 212 static __init void early_pgm_check_handler(void) 213 { 214 unsigned long addr; 215 const struct exception_table_entry *fixup; 216 217 addr = S390_lowcore.program_old_psw.addr; 218 fixup = search_exception_tables(addr & PSW_ADDR_INSN); 219 if (!fixup) 220 disabled_wait(0); 221 S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE; 222 } 223 224 static noinline __init void setup_lowcore_early(void) 225 { 226 psw_t psw; 227 228 psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; 229 psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler; 230 S390_lowcore.external_new_psw = psw; 231 psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler; 232 S390_lowcore.program_new_psw = psw; 233 s390_base_pgm_handler_fn = early_pgm_check_handler; 234 } 235 236 static noinline __init void setup_hpage(void) 237 { 238 #ifndef CONFIG_DEBUG_PAGEALLOC 239 unsigned int facilities; 240 241 facilities = stfl(); 242 if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29))) 243 return; 244 machine_flags |= MACHINE_FLAG_HPAGE; 245 __ctl_set_bit(0, 23); 246 #endif 247 } 248 249 static __init void detect_mvpg(void) 250 { 251 #ifndef CONFIG_64BIT 252 int rc; 253 254 asm volatile( 255 " la 0,0\n" 256 " mvpg %2,%2\n" 257 "0: la %0,0\n" 258 "1:\n" 259 EX_TABLE(0b,1b) 260 : "=d" (rc) : "0" (-EOPNOTSUPP), "a" (0) : "memory", "cc", "0"); 261 if (!rc) 262 machine_flags |= MACHINE_FLAG_MVPG; 263 #endif 264 } 265 266 static __init void detect_ieee(void) 267 { 268 #ifndef CONFIG_64BIT 269 int rc, tmp; 270 271 asm volatile( 272 " efpc %1,0\n" 273 "0: la %0,0\n" 274 "1:\n" 275 EX_TABLE(0b,1b) 276 : "=d" (rc), "=d" (tmp): "0" (-EOPNOTSUPP) : "cc"); 277 if (!rc) 278 machine_flags |= MACHINE_FLAG_IEEE; 279 #endif 280 } 281 282 static __init void detect_csp(void) 283 { 284 #ifndef CONFIG_64BIT 285 int rc; 286 287 asm volatile( 288 " la 0,0\n" 289 " la 1,0\n" 290 " la 2,4\n" 291 " csp 0,2\n" 292 "0: la %0,0\n" 293 "1:\n" 294 EX_TABLE(0b,1b) 295 : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc", "0", "1", "2"); 296 if (!rc) 297 machine_flags |= MACHINE_FLAG_CSP; 298 #endif 299 } 300 301 static __init void detect_diag9c(void) 302 { 303 unsigned int cpu_address; 304 int rc; 305 306 cpu_address = stap(); 307 asm volatile( 308 " diag %2,0,0x9c\n" 309 "0: la %0,0\n" 310 "1:\n" 311 EX_TABLE(0b,1b) 312 : "=d" (rc) : "0" (-EOPNOTSUPP), "d" (cpu_address) : "cc"); 313 if (!rc) 314 machine_flags |= MACHINE_FLAG_DIAG9C; 315 } 316 317 static __init void detect_diag44(void) 318 { 319 #ifdef CONFIG_64BIT 320 int rc; 321 322 asm volatile( 323 " diag 0,0,0x44\n" 324 "0: la %0,0\n" 325 "1:\n" 326 EX_TABLE(0b,1b) 327 : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc"); 328 if (!rc) 329 machine_flags |= MACHINE_FLAG_DIAG44; 330 #endif 331 } 332 333 static __init void detect_machine_facilities(void) 334 { 335 #ifdef CONFIG_64BIT 336 unsigned int facilities; 337 338 facilities = stfl(); 339 if (facilities & (1 << 28)) 340 machine_flags |= MACHINE_FLAG_IDTE; 341 if (facilities & (1 << 23)) 342 machine_flags |= MACHINE_FLAG_PFMF; 343 if (facilities & (1 << 4)) 344 machine_flags |= MACHINE_FLAG_MVCOS; 345 #endif 346 } 347 348 static __init void rescue_initrd(void) 349 { 350 #ifdef CONFIG_BLK_DEV_INITRD 351 /* 352 * Move the initrd right behind the bss section in case it starts 353 * within the bss section. So we don't overwrite it when the bss 354 * section gets cleared. 355 */ 356 if (!INITRD_START || !INITRD_SIZE) 357 return; 358 if (INITRD_START >= (unsigned long) __bss_stop) 359 return; 360 memmove(__bss_stop, (void *) INITRD_START, INITRD_SIZE); 361 INITRD_START = (unsigned long) __bss_stop; 362 #endif 363 } 364 365 /* Set up boot command line */ 366 static void __init setup_boot_command_line(void) 367 { 368 char *parm = NULL; 369 370 /* copy arch command line */ 371 strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); 372 373 /* append IPL PARM data to the boot command line */ 374 if (MACHINE_IS_VM) { 375 parm = boot_command_line + strlen(boot_command_line); 376 *parm++ = ' '; 377 get_ipl_vmparm(parm); 378 if (parm[0] == '=') 379 memmove(boot_command_line, parm + 1, strlen(parm)); 380 } 381 } 382 383 384 /* 385 * Save ipl parameters, clear bss memory, initialize storage keys 386 * and create a kernel NSS at startup if the SAVESYS= parm is defined 387 */ 388 void __init startup_init(void) 389 { 390 reset_tod_clock(); 391 ipl_save_parameters(); 392 rescue_initrd(); 393 clear_bss_section(); 394 init_kernel_storage_key(); 395 lockdep_init(); 396 lockdep_off(); 397 sort_main_extable(); 398 setup_lowcore_early(); 399 detect_machine_type(); 400 ipl_update_parameters(); 401 setup_boot_command_line(); 402 create_kernel_nss(); 403 detect_mvpg(); 404 detect_ieee(); 405 detect_csp(); 406 detect_diag9c(); 407 detect_diag44(); 408 detect_machine_facilities(); 409 setup_hpage(); 410 sclp_facilities_detect(); 411 detect_memory_layout(memory_chunk); 412 S390_lowcore.machine_flags = machine_flags; 413 lockdep_on(); 414 } 415