| .. | .. |
|---|
| 29 | 29 | #include <asm/cpcmd.h> |
|---|
| 30 | 30 | #include <asm/sclp.h> |
|---|
| 31 | 31 | #include <asm/facility.h> |
|---|
| 32 | +#include <asm/boot_data.h> |
|---|
| 33 | +#include <asm/switch_to.h> |
|---|
| 32 | 34 | #include "entry.h" |
|---|
| 33 | 35 | |
|---|
| 34 | | -static void __init setup_boot_command_line(void); |
|---|
| 36 | +static void __init reset_tod_clock(void) |
|---|
| 37 | +{ |
|---|
| 38 | + u64 time; |
|---|
| 39 | + |
|---|
| 40 | + if (store_tod_clock(&time) == 0) |
|---|
| 41 | + return; |
|---|
| 42 | + /* TOD clock not running. Set the clock to Unix Epoch. */ |
|---|
| 43 | + if (set_tod_clock(TOD_UNIX_EPOCH) != 0 || store_tod_clock(&time) != 0) |
|---|
| 44 | + disabled_wait(); |
|---|
| 45 | + |
|---|
| 46 | + memset(tod_clock_base, 0, 16); |
|---|
| 47 | + *(__u64 *) &tod_clock_base[1] = TOD_UNIX_EPOCH; |
|---|
| 48 | + S390_lowcore.last_update_clock = TOD_UNIX_EPOCH; |
|---|
| 49 | +} |
|---|
| 35 | 50 | |
|---|
| 36 | 51 | /* |
|---|
| 37 | 52 | * Initialize storage key for kernel pages |
|---|
| .. | .. |
|---|
| 139 | 154 | unsigned long addr; |
|---|
| 140 | 155 | |
|---|
| 141 | 156 | addr = S390_lowcore.program_old_psw.addr; |
|---|
| 142 | | - fixup = search_exception_tables(addr); |
|---|
| 157 | + fixup = s390_search_extables(addr); |
|---|
| 143 | 158 | if (!fixup) |
|---|
| 144 | | - disabled_wait(0); |
|---|
| 159 | + disabled_wait(); |
|---|
| 145 | 160 | /* Disable low address protection before storing into lowcore. */ |
|---|
| 146 | 161 | __ctl_store(cr0, 0, 0); |
|---|
| 147 | 162 | cr0_new = cr0 & ~(1UL << 28); |
|---|
| .. | .. |
|---|
| 167 | 182 | |
|---|
| 168 | 183 | static noinline __init void setup_facility_list(void) |
|---|
| 169 | 184 | { |
|---|
| 170 | | - stfle(S390_lowcore.stfle_fac_list, |
|---|
| 171 | | - ARRAY_SIZE(S390_lowcore.stfle_fac_list)); |
|---|
| 172 | 185 | memcpy(S390_lowcore.alt_stfle_fac_list, |
|---|
| 173 | 186 | S390_lowcore.stfle_fac_list, |
|---|
| 174 | 187 | sizeof(S390_lowcore.alt_stfle_fac_list)); |
|---|
| .. | .. |
|---|
| 193 | 206 | S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG9C; |
|---|
| 194 | 207 | } |
|---|
| 195 | 208 | |
|---|
| 196 | | -static __init void detect_diag44(void) |
|---|
| 197 | | -{ |
|---|
| 198 | | - int rc; |
|---|
| 199 | | - |
|---|
| 200 | | - diag_stat_inc(DIAG_STAT_X044); |
|---|
| 201 | | - asm volatile( |
|---|
| 202 | | - " diag 0,0,0x44\n" |
|---|
| 203 | | - "0: la %0,0\n" |
|---|
| 204 | | - "1:\n" |
|---|
| 205 | | - EX_TABLE(0b,1b) |
|---|
| 206 | | - : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc"); |
|---|
| 207 | | - if (!rc) |
|---|
| 208 | | - S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG44; |
|---|
| 209 | | -} |
|---|
| 210 | | - |
|---|
| 211 | 209 | static __init void detect_machine_facilities(void) |
|---|
| 212 | 210 | { |
|---|
| 213 | 211 | if (test_facility(8)) { |
|---|
| .. | .. |
|---|
| 228 | 226 | S390_lowcore.machine_flags |= MACHINE_FLAG_VX; |
|---|
| 229 | 227 | __ctl_set_bit(0, 17); |
|---|
| 230 | 228 | } |
|---|
| 231 | | - if (test_facility(130)) { |
|---|
| 229 | + if (test_facility(130) && !noexec_disabled) { |
|---|
| 232 | 230 | S390_lowcore.machine_flags |= MACHINE_FLAG_NX; |
|---|
| 233 | 231 | __ctl_set_bit(0, 20); |
|---|
| 234 | 232 | } |
|---|
| .. | .. |
|---|
| 240 | 238 | clock_comparator_max = -1ULL >> 1; |
|---|
| 241 | 239 | __ctl_set_bit(0, 53); |
|---|
| 242 | 240 | } |
|---|
| 241 | + if (IS_ENABLED(CONFIG_PCI) && test_facility(153)) { |
|---|
| 242 | + S390_lowcore.machine_flags |= MACHINE_FLAG_PCI_MIO; |
|---|
| 243 | + /* the control bit is set during PCI initialization */ |
|---|
| 244 | + } |
|---|
| 243 | 245 | } |
|---|
| 244 | 246 | |
|---|
| 245 | 247 | static inline void save_vector_registers(void) |
|---|
| .. | .. |
|---|
| 250 | 252 | #endif |
|---|
| 251 | 253 | } |
|---|
| 252 | 254 | |
|---|
| 255 | +static inline void setup_control_registers(void) |
|---|
| 256 | +{ |
|---|
| 257 | + unsigned long reg; |
|---|
| 258 | + |
|---|
| 259 | + __ctl_store(reg, 0, 0); |
|---|
| 260 | + reg |= CR0_LOW_ADDRESS_PROTECTION; |
|---|
| 261 | + reg |= CR0_EMERGENCY_SIGNAL_SUBMASK; |
|---|
| 262 | + reg |= CR0_EXTERNAL_CALL_SUBMASK; |
|---|
| 263 | + __ctl_load(reg, 0, 0); |
|---|
| 264 | +} |
|---|
| 265 | + |
|---|
| 266 | +static inline void setup_access_registers(void) |
|---|
| 267 | +{ |
|---|
| 268 | + unsigned int acrs[NUM_ACRS] = { 0 }; |
|---|
| 269 | + |
|---|
| 270 | + restore_access_regs(acrs); |
|---|
| 271 | +} |
|---|
| 272 | + |
|---|
| 253 | 273 | static int __init disable_vector_extension(char *str) |
|---|
| 254 | 274 | { |
|---|
| 255 | 275 | S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; |
|---|
| .. | .. |
|---|
| 258 | 278 | } |
|---|
| 259 | 279 | early_param("novx", disable_vector_extension); |
|---|
| 260 | 280 | |
|---|
| 261 | | -static int __init noexec_setup(char *str) |
|---|
| 262 | | -{ |
|---|
| 263 | | - bool enabled; |
|---|
| 264 | | - int rc; |
|---|
| 265 | | - |
|---|
| 266 | | - rc = kstrtobool(str, &enabled); |
|---|
| 267 | | - if (!rc && !enabled) { |
|---|
| 268 | | - /* Disable no-execute support */ |
|---|
| 269 | | - S390_lowcore.machine_flags &= ~MACHINE_FLAG_NX; |
|---|
| 270 | | - __ctl_clear_bit(0, 20); |
|---|
| 271 | | - } |
|---|
| 272 | | - return rc; |
|---|
| 273 | | -} |
|---|
| 274 | | -early_param("noexec", noexec_setup); |
|---|
| 275 | | - |
|---|
| 276 | | -static int __init cad_setup(char *str) |
|---|
| 277 | | -{ |
|---|
| 278 | | - bool enabled; |
|---|
| 279 | | - int rc; |
|---|
| 280 | | - |
|---|
| 281 | | - rc = kstrtobool(str, &enabled); |
|---|
| 282 | | - if (!rc && enabled && test_facility(128)) |
|---|
| 283 | | - /* Enable problem state CAD. */ |
|---|
| 284 | | - __ctl_set_bit(2, 3); |
|---|
| 285 | | - return rc; |
|---|
| 286 | | -} |
|---|
| 287 | | -early_param("cad", cad_setup); |
|---|
| 288 | | - |
|---|
| 289 | | -/* Set up boot command line */ |
|---|
| 290 | | -static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t)) |
|---|
| 291 | | -{ |
|---|
| 292 | | - char *parm, *delim; |
|---|
| 293 | | - size_t rc, len; |
|---|
| 294 | | - |
|---|
| 295 | | - len = strlen(boot_command_line); |
|---|
| 296 | | - |
|---|
| 297 | | - delim = boot_command_line + len; /* '\0' character position */ |
|---|
| 298 | | - parm = boot_command_line + len + 1; /* append right after '\0' */ |
|---|
| 299 | | - |
|---|
| 300 | | - rc = ipl_data(parm, COMMAND_LINE_SIZE - len - 1); |
|---|
| 301 | | - if (rc) { |
|---|
| 302 | | - if (*parm == '=') |
|---|
| 303 | | - memmove(boot_command_line, parm + 1, rc); |
|---|
| 304 | | - else |
|---|
| 305 | | - *delim = ' '; /* replace '\0' with space */ |
|---|
| 306 | | - } |
|---|
| 307 | | -} |
|---|
| 308 | | - |
|---|
| 309 | | -static inline int has_ebcdic_char(const char *str) |
|---|
| 310 | | -{ |
|---|
| 311 | | - int i; |
|---|
| 312 | | - |
|---|
| 313 | | - for (i = 0; str[i]; i++) |
|---|
| 314 | | - if (str[i] & 0x80) |
|---|
| 315 | | - return 1; |
|---|
| 316 | | - return 0; |
|---|
| 317 | | -} |
|---|
| 318 | | - |
|---|
| 281 | +char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; |
|---|
| 319 | 282 | static void __init setup_boot_command_line(void) |
|---|
| 320 | 283 | { |
|---|
| 321 | | - COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0; |
|---|
| 322 | | - /* convert arch command line to ascii if necessary */ |
|---|
| 323 | | - if (has_ebcdic_char(COMMAND_LINE)) |
|---|
| 324 | | - EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); |
|---|
| 325 | 284 | /* copy arch command line */ |
|---|
| 326 | | - strlcpy(boot_command_line, strstrip(COMMAND_LINE), |
|---|
| 327 | | - ARCH_COMMAND_LINE_SIZE); |
|---|
| 328 | | - |
|---|
| 329 | | - /* append IPL PARM data to the boot command line */ |
|---|
| 330 | | - if (MACHINE_IS_VM) |
|---|
| 331 | | - append_to_cmdline(append_ipl_vmparm); |
|---|
| 332 | | - |
|---|
| 333 | | - append_to_cmdline(append_ipl_scpdata); |
|---|
| 285 | + strlcpy(boot_command_line, early_command_line, ARCH_COMMAND_LINE_SIZE); |
|---|
| 334 | 286 | } |
|---|
| 335 | 287 | |
|---|
| 336 | 288 | static void __init check_image_bootable(void) |
|---|
| .. | .. |
|---|
| 341 | 293 | sclp_early_printk("Linux kernel boot failure: An attempt to boot a vmlinux ELF image failed.\n"); |
|---|
| 342 | 294 | sclp_early_printk("This image does not contain all parts necessary for starting up. Use\n"); |
|---|
| 343 | 295 | sclp_early_printk("bzImage or arch/s390/boot/compressed/vmlinux instead.\n"); |
|---|
| 344 | | - disabled_wait(0xbadb007); |
|---|
| 296 | + disabled_wait(); |
|---|
| 345 | 297 | } |
|---|
| 346 | 298 | |
|---|
| 347 | 299 | void __init startup_init(void) |
|---|
| 348 | 300 | { |
|---|
| 301 | + reset_tod_clock(); |
|---|
| 349 | 302 | check_image_bootable(); |
|---|
| 350 | 303 | time_early_init(); |
|---|
| 351 | 304 | init_kernel_storage_key(); |
|---|
| .. | .. |
|---|
| 354 | 307 | setup_facility_list(); |
|---|
| 355 | 308 | detect_machine_type(); |
|---|
| 356 | 309 | setup_arch_string(); |
|---|
| 357 | | - ipl_store_parameters(); |
|---|
| 358 | 310 | setup_boot_command_line(); |
|---|
| 359 | 311 | detect_diag9c(); |
|---|
| 360 | | - detect_diag44(); |
|---|
| 361 | 312 | detect_machine_facilities(); |
|---|
| 362 | 313 | save_vector_registers(); |
|---|
| 363 | 314 | setup_topology(); |
|---|
| 364 | 315 | sclp_early_detect(); |
|---|
| 316 | + setup_control_registers(); |
|---|
| 317 | + setup_access_registers(); |
|---|
| 365 | 318 | lockdep_on(); |
|---|
| 366 | 319 | } |
|---|