diff options
Diffstat (limited to 'arch/s390/kernel/setup.c')
-rw-r--r-- | arch/s390/kernel/setup.c | 167 |
1 files changed, 142 insertions, 25 deletions
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 5d8ee3baac14..863c8d08c026 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -38,7 +38,10 @@ | |||
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 | ||
44 | #include <asm/ipl.h> | ||
42 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
43 | #include <asm/system.h> | 46 | #include <asm/system.h> |
44 | #include <asm/smp.h> | 47 | #include <asm/smp.h> |
@@ -49,6 +52,14 @@ | |||
49 | #include <asm/page.h> | 52 | #include <asm/page.h> |
50 | #include <asm/ptrace.h> | 53 | #include <asm/ptrace.h> |
51 | #include <asm/sections.h> | 54 | #include <asm/sections.h> |
55 | #include <asm/ebcdic.h> | ||
56 | #include <asm/compat.h> | ||
57 | |||
58 | long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | | ||
59 | PSW_MASK_MCHECK | PSW_DEFAULT_KEY); | ||
60 | long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | | ||
61 | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | | ||
62 | PSW_MASK_PSTATE | PSW_DEFAULT_KEY); | ||
52 | 63 | ||
53 | /* | 64 | /* |
54 | * User copy operations. | 65 | * User copy operations. |
@@ -96,7 +107,7 @@ void __devinit cpu_init (void) | |||
96 | /* | 107 | /* |
97 | * Store processor id in lowcore (used e.g. in timer_interrupt) | 108 | * Store processor id in lowcore (used e.g. in timer_interrupt) |
98 | */ | 109 | */ |
99 | asm volatile("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id)); | 110 | get_cpu_id(&S390_lowcore.cpu_data.cpu_id); |
100 | S390_lowcore.cpu_data.cpu_addr = addr; | 111 | S390_lowcore.cpu_data.cpu_addr = addr; |
101 | 112 | ||
102 | /* | 113 | /* |
@@ -117,9 +128,9 @@ void __devinit cpu_init (void) | |||
117 | */ | 128 | */ |
118 | char vmhalt_cmd[128] = ""; | 129 | char vmhalt_cmd[128] = ""; |
119 | char vmpoff_cmd[128] = ""; | 130 | char vmpoff_cmd[128] = ""; |
120 | char vmpanic_cmd[128] = ""; | 131 | static char vmpanic_cmd[128] = ""; |
121 | 132 | ||
122 | static inline void strncpy_skip_quote(char *dst, char *src, int n) | 133 | static void strncpy_skip_quote(char *dst, char *src, int n) |
123 | { | 134 | { |
124 | int sx, dx; | 135 | int sx, dx; |
125 | 136 | ||
@@ -275,10 +286,6 @@ static void __init conmode_default(void) | |||
275 | } | 286 | } |
276 | 287 | ||
277 | #ifdef CONFIG_SMP | 288 | #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; | 289 | void (*_machine_restart)(char *command) = machine_restart_smp; |
283 | void (*_machine_halt)(void) = machine_halt_smp; | 290 | void (*_machine_halt)(void) = machine_halt_smp; |
284 | void (*_machine_power_off)(void) = machine_power_off_smp; | 291 | void (*_machine_power_off)(void) = machine_power_off_smp; |
@@ -386,6 +393,84 @@ static int __init early_parse_ipldelay(char *p) | |||
386 | } | 393 | } |
387 | early_param("ipldelay", early_parse_ipldelay); | 394 | early_param("ipldelay", early_parse_ipldelay); |
388 | 395 | ||
396 | #ifdef CONFIG_S390_SWITCH_AMODE | ||
397 | unsigned int switch_amode = 0; | ||
398 | EXPORT_SYMBOL_GPL(switch_amode); | ||
399 | |||
400 | static void set_amode_and_uaccess(unsigned long user_amode, | ||
401 | unsigned long user32_amode) | ||
402 | { | ||
403 | psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode | | ||
404 | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | | ||
405 | PSW_MASK_PSTATE | PSW_DEFAULT_KEY; | ||
406 | #ifdef CONFIG_COMPAT | ||
407 | psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode | | ||
408 | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | | ||
409 | PSW_MASK_PSTATE | PSW_DEFAULT_KEY; | ||
410 | psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode | | ||
411 | PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | | ||
412 | PSW32_MASK_PSTATE; | ||
413 | #endif | ||
414 | psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | | ||
415 | PSW_MASK_MCHECK | PSW_DEFAULT_KEY; | ||
416 | |||
417 | if (MACHINE_HAS_MVCOS) { | ||
418 | printk("mvcos available.\n"); | ||
419 | memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess)); | ||
420 | } else { | ||
421 | printk("mvcos not available.\n"); | ||
422 | memcpy(&uaccess, &uaccess_pt, sizeof(uaccess)); | ||
423 | } | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * Switch kernel/user addressing modes? | ||
428 | */ | ||
429 | static int __init early_parse_switch_amode(char *p) | ||
430 | { | ||
431 | switch_amode = 1; | ||
432 | return 0; | ||
433 | } | ||
434 | early_param("switch_amode", early_parse_switch_amode); | ||
435 | |||
436 | #else /* CONFIG_S390_SWITCH_AMODE */ | ||
437 | static inline void set_amode_and_uaccess(unsigned long user_amode, | ||
438 | unsigned long user32_amode) | ||
439 | { | ||
440 | } | ||
441 | #endif /* CONFIG_S390_SWITCH_AMODE */ | ||
442 | |||
443 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
444 | unsigned int s390_noexec = 0; | ||
445 | EXPORT_SYMBOL_GPL(s390_noexec); | ||
446 | |||
447 | /* | ||
448 | * Enable execute protection? | ||
449 | */ | ||
450 | static int __init early_parse_noexec(char *p) | ||
451 | { | ||
452 | if (!strncmp(p, "off", 3)) | ||
453 | return 0; | ||
454 | switch_amode = 1; | ||
455 | s390_noexec = 1; | ||
456 | return 0; | ||
457 | } | ||
458 | early_param("noexec", early_parse_noexec); | ||
459 | #endif /* CONFIG_S390_EXEC_PROTECT */ | ||
460 | |||
461 | static void setup_addressing_mode(void) | ||
462 | { | ||
463 | if (s390_noexec) { | ||
464 | printk("S390 execute protection active, "); | ||
465 | set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY); | ||
466 | return; | ||
467 | } | ||
468 | if (switch_amode) { | ||
469 | printk("S390 address spaces switched, "); | ||
470 | set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY); | ||
471 | } | ||
472 | } | ||
473 | |||
389 | static void __init | 474 | static void __init |
390 | setup_lowcore(void) | 475 | setup_lowcore(void) |
391 | { | 476 | { |
@@ -402,19 +487,21 @@ setup_lowcore(void) | |||
402 | lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; | 487 | lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; |
403 | lc->restart_psw.addr = | 488 | lc->restart_psw.addr = |
404 | PSW_ADDR_AMODE | (unsigned long) restart_int_handler; | 489 | PSW_ADDR_AMODE | (unsigned long) restart_int_handler; |
405 | lc->external_new_psw.mask = PSW_KERNEL_BITS; | 490 | if (switch_amode) |
491 | lc->restart_psw.mask |= PSW_ASC_HOME; | ||
492 | lc->external_new_psw.mask = psw_kernel_bits; | ||
406 | lc->external_new_psw.addr = | 493 | lc->external_new_psw.addr = |
407 | PSW_ADDR_AMODE | (unsigned long) ext_int_handler; | 494 | PSW_ADDR_AMODE | (unsigned long) ext_int_handler; |
408 | lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; | 495 | 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; | 496 | lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call; |
410 | lc->program_new_psw.mask = PSW_KERNEL_BITS; | 497 | lc->program_new_psw.mask = psw_kernel_bits; |
411 | lc->program_new_psw.addr = | 498 | lc->program_new_psw.addr = |
412 | PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; | 499 | PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; |
413 | lc->mcck_new_psw.mask = | 500 | lc->mcck_new_psw.mask = |
414 | PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; | 501 | psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; |
415 | lc->mcck_new_psw.addr = | 502 | lc->mcck_new_psw.addr = |
416 | PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; | 503 | PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; |
417 | lc->io_new_psw.mask = PSW_KERNEL_BITS; | 504 | lc->io_new_psw.mask = psw_kernel_bits; |
418 | lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; | 505 | lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; |
419 | lc->ipl_device = S390_lowcore.ipl_device; | 506 | lc->ipl_device = S390_lowcore.ipl_device; |
420 | lc->jiffy_timer = -1LL; | 507 | lc->jiffy_timer = -1LL; |
@@ -439,7 +526,7 @@ setup_lowcore(void) | |||
439 | static void __init | 526 | static void __init |
440 | setup_resources(void) | 527 | setup_resources(void) |
441 | { | 528 | { |
442 | struct resource *res; | 529 | struct resource *res, *sub_res; |
443 | int i; | 530 | int i; |
444 | 531 | ||
445 | code_resource.start = (unsigned long) &_text; | 532 | code_resource.start = (unsigned long) &_text; |
@@ -464,8 +551,38 @@ setup_resources(void) | |||
464 | res->start = memory_chunk[i].addr; | 551 | res->start = memory_chunk[i].addr; |
465 | res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; | 552 | res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; |
466 | request_resource(&iomem_resource, res); | 553 | request_resource(&iomem_resource, res); |
467 | request_resource(res, &code_resource); | 554 | |
468 | request_resource(res, &data_resource); | 555 | if (code_resource.start >= res->start && |
556 | code_resource.start <= res->end && | ||
557 | code_resource.end > res->end) { | ||
558 | sub_res = alloc_bootmem_low(sizeof(struct resource)); | ||
559 | memcpy(sub_res, &code_resource, | ||
560 | sizeof(struct resource)); | ||
561 | sub_res->end = res->end; | ||
562 | code_resource.start = res->end + 1; | ||
563 | request_resource(res, sub_res); | ||
564 | } | ||
565 | |||
566 | if (code_resource.start >= res->start && | ||
567 | code_resource.start <= res->end && | ||
568 | code_resource.end <= res->end) | ||
569 | request_resource(res, &code_resource); | ||
570 | |||
571 | if (data_resource.start >= res->start && | ||
572 | data_resource.start <= res->end && | ||
573 | data_resource.end > res->end) { | ||
574 | sub_res = alloc_bootmem_low(sizeof(struct resource)); | ||
575 | memcpy(sub_res, &data_resource, | ||
576 | sizeof(struct resource)); | ||
577 | sub_res->end = res->end; | ||
578 | data_resource.start = res->end + 1; | ||
579 | request_resource(res, sub_res); | ||
580 | } | ||
581 | |||
582 | if (data_resource.start >= res->start && | ||
583 | data_resource.start <= res->end && | ||
584 | data_resource.end <= res->end) | ||
585 | request_resource(res, &data_resource); | ||
469 | } | 586 | } |
470 | } | 587 | } |
471 | 588 | ||
@@ -495,16 +612,13 @@ static void __init setup_memory_end(void) | |||
495 | } | 612 | } |
496 | if (!memory_end) | 613 | if (!memory_end) |
497 | memory_end = memory_size; | 614 | 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 | } | 615 | } |
502 | 616 | ||
503 | static void __init | 617 | static void __init |
504 | setup_memory(void) | 618 | setup_memory(void) |
505 | { | 619 | { |
506 | unsigned long bootmap_size; | 620 | unsigned long bootmap_size; |
507 | unsigned long start_pfn, end_pfn, init_pfn; | 621 | unsigned long start_pfn, end_pfn; |
508 | int i; | 622 | int i; |
509 | 623 | ||
510 | /* | 624 | /* |
@@ -514,10 +628,6 @@ setup_memory(void) | |||
514 | start_pfn = PFN_UP(__pa(&_end)); | 628 | start_pfn = PFN_UP(__pa(&_end)); |
515 | end_pfn = max_pfn = PFN_DOWN(memory_end); | 629 | end_pfn = max_pfn = PFN_DOWN(memory_end); |
516 | 630 | ||
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 | 631 | #ifdef CONFIG_BLK_DEV_INITRD |
522 | /* | 632 | /* |
523 | * Move the initrd in case the bitmap of the bootmem allocater | 633 | * Move the initrd in case the bitmap of the bootmem allocater |
@@ -580,9 +690,14 @@ setup_memory(void) | |||
580 | psw_set_key(PAGE_DEFAULT_KEY); | 690 | psw_set_key(PAGE_DEFAULT_KEY); |
581 | 691 | ||
582 | free_bootmem_with_active_regions(0, max_pfn); | 692 | free_bootmem_with_active_regions(0, max_pfn); |
583 | reserve_bootmem(0, PFN_PHYS(start_pfn)); | ||
584 | 693 | ||
585 | /* | 694 | /* |
695 | * Reserve memory used for lowcore/command line/kernel image. | ||
696 | */ | ||
697 | reserve_bootmem(0, (unsigned long)_ehead); | ||
698 | reserve_bootmem((unsigned long)_stext, | ||
699 | PFN_PHYS(start_pfn) - (unsigned long)_stext); | ||
700 | /* | ||
586 | * Reserve the bootmem bitmap itself as well. We do this in two | 701 | * Reserve the bootmem bitmap itself as well. We do this in two |
587 | * steps (first step was init_bootmem()) because this catches | 702 | * steps (first step was init_bootmem()) because this catches |
588 | * the (very unlikely) case of us accidentally initializing the | 703 | * the (very unlikely) case of us accidentally initializing the |
@@ -631,7 +746,7 @@ setup_arch(char **cmdline_p) | |||
631 | #endif /* CONFIG_64BIT */ | 746 | #endif /* CONFIG_64BIT */ |
632 | 747 | ||
633 | /* Save unparsed command line copy for /proc/cmdline */ | 748 | /* Save unparsed command line copy for /proc/cmdline */ |
634 | strlcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); | 749 | strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); |
635 | 750 | ||
636 | *cmdline_p = COMMAND_LINE; | 751 | *cmdline_p = COMMAND_LINE; |
637 | *(*cmdline_p + COMMAND_LINE_SIZE - 1) = '\0'; | 752 | *(*cmdline_p + COMMAND_LINE_SIZE - 1) = '\0'; |
@@ -651,6 +766,7 @@ setup_arch(char **cmdline_p) | |||
651 | parse_early_param(); | 766 | parse_early_param(); |
652 | 767 | ||
653 | setup_memory_end(); | 768 | setup_memory_end(); |
769 | setup_addressing_mode(); | ||
654 | setup_memory(); | 770 | setup_memory(); |
655 | setup_resources(); | 771 | setup_resources(); |
656 | setup_lowcore(); | 772 | setup_lowcore(); |
@@ -694,6 +810,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
694 | struct cpuinfo_S390 *cpuinfo; | 810 | struct cpuinfo_S390 *cpuinfo; |
695 | unsigned long n = (unsigned long) v - 1; | 811 | unsigned long n = (unsigned long) v - 1; |
696 | 812 | ||
813 | s390_adjust_jiffies(); | ||
697 | preempt_disable(); | 814 | preempt_disable(); |
698 | if (!n) { | 815 | if (!n) { |
699 | seq_printf(m, "vendor_id : IBM/S390\n" | 816 | seq_printf(m, "vendor_id : IBM/S390\n" |