diff options
Diffstat (limited to 'arch/s390/kernel/setup.c')
-rw-r--r-- | arch/s390/kernel/setup.c | 155 |
1 files changed, 133 insertions, 22 deletions
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 5d8ee3baac14..03739813d3bf 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include <linux/device.h> | 38 | #include <linux/device.h> |
39 | #include <linux/notifier.h> | 39 | #include <linux/notifier.h> |
40 | #include <linux/pfn.h> | 40 | #include <linux/pfn.h> |
41 | #include <linux/ctype.h> | ||
42 | #include <linux/reboot.h> | ||
41 | 43 | ||
42 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
43 | #include <asm/system.h> | 45 | #include <asm/system.h> |
@@ -49,6 +51,14 @@ | |||
49 | #include <asm/page.h> | 51 | #include <asm/page.h> |
50 | #include <asm/ptrace.h> | 52 | #include <asm/ptrace.h> |
51 | #include <asm/sections.h> | 53 | #include <asm/sections.h> |
54 | #include <asm/ebcdic.h> | ||
55 | #include <asm/compat.h> | ||
56 | |||
57 | long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | | ||
58 | PSW_MASK_MCHECK | PSW_DEFAULT_KEY); | ||
59 | long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | | ||
60 | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | | ||
61 | PSW_MASK_PSTATE | PSW_DEFAULT_KEY); | ||
52 | 62 | ||
53 | /* | 63 | /* |
54 | * User copy operations. | 64 | * User copy operations. |
@@ -117,9 +127,9 @@ void __devinit cpu_init (void) | |||
117 | */ | 127 | */ |
118 | char vmhalt_cmd[128] = ""; | 128 | char vmhalt_cmd[128] = ""; |
119 | char vmpoff_cmd[128] = ""; | 129 | char vmpoff_cmd[128] = ""; |
120 | char vmpanic_cmd[128] = ""; | 130 | static char vmpanic_cmd[128] = ""; |
121 | 131 | ||
122 | static inline void strncpy_skip_quote(char *dst, char *src, int n) | 132 | static void strncpy_skip_quote(char *dst, char *src, int n) |
123 | { | 133 | { |
124 | int sx, dx; | 134 | int sx, dx; |
125 | 135 | ||
@@ -275,10 +285,6 @@ static void __init conmode_default(void) | |||
275 | } | 285 | } |
276 | 286 | ||
277 | #ifdef CONFIG_SMP | 287 | #ifdef CONFIG_SMP |
278 | extern void machine_restart_smp(char *); | ||
279 | extern void machine_halt_smp(void); | ||
280 | extern void machine_power_off_smp(void); | ||
281 | |||
282 | void (*_machine_restart)(char *command) = machine_restart_smp; | 288 | void (*_machine_restart)(char *command) = machine_restart_smp; |
283 | void (*_machine_halt)(void) = machine_halt_smp; | 289 | void (*_machine_halt)(void) = machine_halt_smp; |
284 | void (*_machine_power_off)(void) = machine_power_off_smp; | 290 | void (*_machine_power_off)(void) = machine_power_off_smp; |
@@ -386,6 +392,84 @@ static int __init early_parse_ipldelay(char *p) | |||
386 | } | 392 | } |
387 | early_param("ipldelay", early_parse_ipldelay); | 393 | early_param("ipldelay", early_parse_ipldelay); |
388 | 394 | ||
395 | #ifdef CONFIG_S390_SWITCH_AMODE | ||
396 | unsigned int switch_amode = 0; | ||
397 | EXPORT_SYMBOL_GPL(switch_amode); | ||
398 | |||
399 | static void set_amode_and_uaccess(unsigned long user_amode, | ||
400 | unsigned long user32_amode) | ||
401 | { | ||
402 | psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode | | ||
403 | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | | ||
404 | PSW_MASK_PSTATE | PSW_DEFAULT_KEY; | ||
405 | #ifdef CONFIG_COMPAT | ||
406 | psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode | | ||
407 | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | | ||
408 | PSW_MASK_PSTATE | PSW_DEFAULT_KEY; | ||
409 | psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode | | ||
410 | PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | | ||
411 | PSW32_MASK_PSTATE; | ||
412 | #endif | ||
413 | psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | | ||
414 | PSW_MASK_MCHECK | PSW_DEFAULT_KEY; | ||
415 | |||
416 | if (MACHINE_HAS_MVCOS) { | ||
417 | printk("mvcos available.\n"); | ||
418 | memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess)); | ||
419 | } else { | ||
420 | printk("mvcos not available.\n"); | ||
421 | memcpy(&uaccess, &uaccess_pt, sizeof(uaccess)); | ||
422 | } | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * Switch kernel/user addressing modes? | ||
427 | */ | ||
428 | static int __init early_parse_switch_amode(char *p) | ||
429 | { | ||
430 | switch_amode = 1; | ||
431 | return 0; | ||
432 | } | ||
433 | early_param("switch_amode", early_parse_switch_amode); | ||
434 | |||
435 | #else /* CONFIG_S390_SWITCH_AMODE */ | ||
436 | static inline void set_amode_and_uaccess(unsigned long user_amode, | ||
437 | unsigned long user32_amode) | ||
438 | { | ||
439 | } | ||
440 | #endif /* CONFIG_S390_SWITCH_AMODE */ | ||
441 | |||
442 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
443 | unsigned int s390_noexec = 0; | ||
444 | EXPORT_SYMBOL_GPL(s390_noexec); | ||
445 | |||
446 | /* | ||
447 | * Enable execute protection? | ||
448 | */ | ||
449 | static int __init early_parse_noexec(char *p) | ||
450 | { | ||
451 | if (!strncmp(p, "off", 3)) | ||
452 | return 0; | ||
453 | switch_amode = 1; | ||
454 | s390_noexec = 1; | ||
455 | return 0; | ||
456 | } | ||
457 | early_param("noexec", early_parse_noexec); | ||
458 | #endif /* CONFIG_S390_EXEC_PROTECT */ | ||
459 | |||
460 | static void setup_addressing_mode(void) | ||
461 | { | ||
462 | if (s390_noexec) { | ||
463 | printk("S390 execute protection active, "); | ||
464 | set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY); | ||
465 | return; | ||
466 | } | ||
467 | if (switch_amode) { | ||
468 | printk("S390 address spaces switched, "); | ||
469 | set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY); | ||
470 | } | ||
471 | } | ||
472 | |||
389 | static void __init | 473 | static void __init |
390 | setup_lowcore(void) | 474 | setup_lowcore(void) |
391 | { | 475 | { |
@@ -402,19 +486,21 @@ setup_lowcore(void) | |||
402 | lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; | 486 | lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; |
403 | lc->restart_psw.addr = | 487 | lc->restart_psw.addr = |
404 | PSW_ADDR_AMODE | (unsigned long) restart_int_handler; | 488 | PSW_ADDR_AMODE | (unsigned long) restart_int_handler; |
405 | lc->external_new_psw.mask = PSW_KERNEL_BITS; | 489 | if (switch_amode) |
490 | lc->restart_psw.mask |= PSW_ASC_HOME; | ||
491 | lc->external_new_psw.mask = psw_kernel_bits; | ||
406 | lc->external_new_psw.addr = | 492 | lc->external_new_psw.addr = |
407 | PSW_ADDR_AMODE | (unsigned long) ext_int_handler; | 493 | PSW_ADDR_AMODE | (unsigned long) ext_int_handler; |
408 | lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; | 494 | lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT; |
409 | lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call; | 495 | lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call; |
410 | lc->program_new_psw.mask = PSW_KERNEL_BITS; | 496 | lc->program_new_psw.mask = psw_kernel_bits; |
411 | lc->program_new_psw.addr = | 497 | lc->program_new_psw.addr = |
412 | PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; | 498 | PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; |
413 | lc->mcck_new_psw.mask = | 499 | lc->mcck_new_psw.mask = |
414 | PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; | 500 | psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; |
415 | lc->mcck_new_psw.addr = | 501 | lc->mcck_new_psw.addr = |
416 | PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; | 502 | PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; |
417 | lc->io_new_psw.mask = PSW_KERNEL_BITS; | 503 | lc->io_new_psw.mask = psw_kernel_bits; |
418 | lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; | 504 | lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; |
419 | lc->ipl_device = S390_lowcore.ipl_device; | 505 | lc->ipl_device = S390_lowcore.ipl_device; |
420 | lc->jiffy_timer = -1LL; | 506 | lc->jiffy_timer = -1LL; |
@@ -439,7 +525,7 @@ setup_lowcore(void) | |||
439 | static void __init | 525 | static void __init |
440 | setup_resources(void) | 526 | setup_resources(void) |
441 | { | 527 | { |
442 | struct resource *res; | 528 | struct resource *res, *sub_res; |
443 | int i; | 529 | int i; |
444 | 530 | ||
445 | code_resource.start = (unsigned long) &_text; | 531 | code_resource.start = (unsigned long) &_text; |
@@ -464,8 +550,38 @@ setup_resources(void) | |||
464 | res->start = memory_chunk[i].addr; | 550 | res->start = memory_chunk[i].addr; |
465 | res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; | 551 | res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; |
466 | request_resource(&iomem_resource, res); | 552 | request_resource(&iomem_resource, res); |
467 | request_resource(res, &code_resource); | 553 | |
468 | request_resource(res, &data_resource); | 554 | if (code_resource.start >= res->start && |
555 | code_resource.start <= res->end && | ||
556 | code_resource.end > res->end) { | ||
557 | sub_res = alloc_bootmem_low(sizeof(struct resource)); | ||
558 | memcpy(sub_res, &code_resource, | ||
559 | sizeof(struct resource)); | ||
560 | sub_res->end = res->end; | ||
561 | code_resource.start = res->end + 1; | ||
562 | request_resource(res, sub_res); | ||
563 | } | ||
564 | |||
565 | if (code_resource.start >= res->start && | ||
566 | code_resource.start <= res->end && | ||
567 | code_resource.end <= res->end) | ||
568 | request_resource(res, &code_resource); | ||
569 | |||
570 | if (data_resource.start >= res->start && | ||
571 | data_resource.start <= res->end && | ||
572 | data_resource.end > res->end) { | ||
573 | sub_res = alloc_bootmem_low(sizeof(struct resource)); | ||
574 | memcpy(sub_res, &data_resource, | ||
575 | sizeof(struct resource)); | ||
576 | sub_res->end = res->end; | ||
577 | data_resource.start = res->end + 1; | ||
578 | request_resource(res, sub_res); | ||
579 | } | ||
580 | |||
581 | if (data_resource.start >= res->start && | ||
582 | data_resource.start <= res->end && | ||
583 | data_resource.end <= res->end) | ||
584 | request_resource(res, &data_resource); | ||
469 | } | 585 | } |
470 | } | 586 | } |
471 | 587 | ||
@@ -495,16 +611,13 @@ static void __init setup_memory_end(void) | |||
495 | } | 611 | } |
496 | if (!memory_end) | 612 | if (!memory_end) |
497 | memory_end = memory_size; | 613 | memory_end = memory_size; |
498 | if (real_size > memory_end) | ||
499 | printk("More memory detected than supported. Unused: %luk\n", | ||
500 | (real_size - memory_end) >> 10); | ||
501 | } | 614 | } |
502 | 615 | ||
503 | static void __init | 616 | static void __init |
504 | setup_memory(void) | 617 | setup_memory(void) |
505 | { | 618 | { |
506 | unsigned long bootmap_size; | 619 | unsigned long bootmap_size; |
507 | unsigned long start_pfn, end_pfn, init_pfn; | 620 | unsigned long start_pfn, end_pfn; |
508 | int i; | 621 | int i; |
509 | 622 | ||
510 | /* | 623 | /* |
@@ -514,10 +627,6 @@ setup_memory(void) | |||
514 | start_pfn = PFN_UP(__pa(&_end)); | 627 | start_pfn = PFN_UP(__pa(&_end)); |
515 | end_pfn = max_pfn = PFN_DOWN(memory_end); | 628 | end_pfn = max_pfn = PFN_DOWN(memory_end); |
516 | 629 | ||
517 | /* Initialize storage key for kernel pages */ | ||
518 | for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++) | ||
519 | page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); | ||
520 | |||
521 | #ifdef CONFIG_BLK_DEV_INITRD | 630 | #ifdef CONFIG_BLK_DEV_INITRD |
522 | /* | 631 | /* |
523 | * Move the initrd in case the bitmap of the bootmem allocater | 632 | * Move the initrd in case the bitmap of the bootmem allocater |
@@ -651,6 +760,7 @@ setup_arch(char **cmdline_p) | |||
651 | parse_early_param(); | 760 | parse_early_param(); |
652 | 761 | ||
653 | setup_memory_end(); | 762 | setup_memory_end(); |
763 | setup_addressing_mode(); | ||
654 | setup_memory(); | 764 | setup_memory(); |
655 | setup_resources(); | 765 | setup_resources(); |
656 | setup_lowcore(); | 766 | setup_lowcore(); |
@@ -694,6 +804,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
694 | struct cpuinfo_S390 *cpuinfo; | 804 | struct cpuinfo_S390 *cpuinfo; |
695 | unsigned long n = (unsigned long) v - 1; | 805 | unsigned long n = (unsigned long) v - 1; |
696 | 806 | ||
807 | s390_adjust_jiffies(); | ||
697 | preempt_disable(); | 808 | preempt_disable(); |
698 | if (!n) { | 809 | if (!n) { |
699 | seq_printf(m, "vendor_id : IBM/S390\n" | 810 | seq_printf(m, "vendor_id : IBM/S390\n" |