aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/setup.c')
-rw-r--r--arch/s390/kernel/setup.c167
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
58long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
59 PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
60long 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 */
118char vmhalt_cmd[128] = ""; 129char vmhalt_cmd[128] = "";
119char vmpoff_cmd[128] = ""; 130char vmpoff_cmd[128] = "";
120char vmpanic_cmd[128] = ""; 131static char vmpanic_cmd[128] = "";
121 132
122static inline void strncpy_skip_quote(char *dst, char *src, int n) 133static 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
278extern void machine_restart_smp(char *);
279extern void machine_halt_smp(void);
280extern void machine_power_off_smp(void);
281
282void (*_machine_restart)(char *command) = machine_restart_smp; 289void (*_machine_restart)(char *command) = machine_restart_smp;
283void (*_machine_halt)(void) = machine_halt_smp; 290void (*_machine_halt)(void) = machine_halt_smp;
284void (*_machine_power_off)(void) = machine_power_off_smp; 291void (*_machine_power_off)(void) = machine_power_off_smp;
@@ -386,6 +393,84 @@ static int __init early_parse_ipldelay(char *p)
386} 393}
387early_param("ipldelay", early_parse_ipldelay); 394early_param("ipldelay", early_parse_ipldelay);
388 395
396#ifdef CONFIG_S390_SWITCH_AMODE
397unsigned int switch_amode = 0;
398EXPORT_SYMBOL_GPL(switch_amode);
399
400static 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 */
429static int __init early_parse_switch_amode(char *p)
430{
431 switch_amode = 1;
432 return 0;
433}
434early_param("switch_amode", early_parse_switch_amode);
435
436#else /* CONFIG_S390_SWITCH_AMODE */
437static 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
444unsigned int s390_noexec = 0;
445EXPORT_SYMBOL_GPL(s390_noexec);
446
447/*
448 * Enable execute protection?
449 */
450static 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}
458early_param("noexec", early_parse_noexec);
459#endif /* CONFIG_S390_EXEC_PROTECT */
460
461static 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
389static void __init 474static void __init
390setup_lowcore(void) 475setup_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)
439static void __init 526static void __init
440setup_resources(void) 527setup_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
503static void __init 617static void __init
504setup_memory(void) 618setup_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"