aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/compat_linux.c6
-rw-r--r--arch/s390/kernel/compat_linux.h31
-rw-r--r--arch/s390/kernel/compat_signal.c2
-rw-r--r--arch/s390/kernel/ipl.c4
-rw-r--r--arch/s390/kernel/process.c4
-rw-r--r--arch/s390/kernel/ptrace.c10
-rw-r--r--arch/s390/kernel/setup.c98
-rw-r--r--arch/s390/kernel/signal.c2
-rw-r--r--arch/s390/kernel/smp.c2
9 files changed, 111 insertions, 48 deletions
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index cf84d697daed..666bb6daa148 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -69,6 +69,12 @@
69 69
70#include "compat_linux.h" 70#include "compat_linux.h"
71 71
72long psw_user32_bits = (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
73 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
74 PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
75long psw32_user_bits = (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME |
76 PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
77 PSW32_MASK_PSTATE);
72 78
73/* For this source file, we want overflow handling. */ 79/* For this source file, we want overflow handling. */
74 80
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 1a18e29668ef..e89f8c0c42a0 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -115,37 +115,6 @@ typedef struct
115 __u32 addr; 115 __u32 addr;
116} _psw_t32 __attribute__ ((aligned(8))); 116} _psw_t32 __attribute__ ((aligned(8)));
117 117
118#define PSW32_MASK_PER 0x40000000UL
119#define PSW32_MASK_DAT 0x04000000UL
120#define PSW32_MASK_IO 0x02000000UL
121#define PSW32_MASK_EXT 0x01000000UL
122#define PSW32_MASK_KEY 0x00F00000UL
123#define PSW32_MASK_MCHECK 0x00040000UL
124#define PSW32_MASK_WAIT 0x00020000UL
125#define PSW32_MASK_PSTATE 0x00010000UL
126#define PSW32_MASK_ASC 0x0000C000UL
127#define PSW32_MASK_CC 0x00003000UL
128#define PSW32_MASK_PM 0x00000f00UL
129
130#define PSW32_ADDR_AMODE31 0x80000000UL
131#define PSW32_ADDR_INSN 0x7FFFFFFFUL
132
133#define PSW32_BASE_BITS 0x00080000UL
134
135#define PSW32_ASC_PRIMARY 0x00000000UL
136#define PSW32_ASC_ACCREG 0x00004000UL
137#define PSW32_ASC_SECONDARY 0x00008000UL
138#define PSW32_ASC_HOME 0x0000C000UL
139
140#define PSW32_USER_BITS (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
141 PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
142 PSW32_MASK_PSTATE)
143
144#define PSW32_MASK_MERGE(CURRENT,NEW) \
145 (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
146 ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
147
148
149typedef struct 118typedef struct
150{ 119{
151 _psw_t32 psw; 120 _psw_t32 psw;
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 8d17b2ab6f21..887a9881d0d0 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -298,7 +298,7 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
298 _s390_regs_common32 regs32; 298 _s390_regs_common32 regs32;
299 int err, i; 299 int err, i;
300 300
301 regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS, 301 regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits,
302 (__u32)(regs->psw.mask >> 32)); 302 (__u32)(regs->psw.mask >> 32));
303 regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr; 303 regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
304 for (i = 0; i < NUM_GPRS; i++) 304 for (i = 0; i < NUM_GPRS; i++)
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 9e9972e8a52b..2c91226e1d40 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -1016,12 +1016,12 @@ void s390_reset_system(void)
1016 __ctl_clear_bit(0,28); 1016 __ctl_clear_bit(0,28);
1017 1017
1018 /* Set new machine check handler */ 1018 /* Set new machine check handler */
1019 S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; 1019 S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
1020 S390_lowcore.mcck_new_psw.addr = 1020 S390_lowcore.mcck_new_psw.addr =
1021 PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler; 1021 PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
1022 1022
1023 /* Set new program check handler */ 1023 /* Set new program check handler */
1024 S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; 1024 S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
1025 S390_lowcore.program_new_psw.addr = 1025 S390_lowcore.program_new_psw.addr =
1026 PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler; 1026 PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;
1027 1027
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 6603fbb41d07..5acfac654f9d 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -144,7 +144,7 @@ static void default_idle(void)
144 144
145 trace_hardirqs_on(); 145 trace_hardirqs_on();
146 /* Wait for external, I/O or machine check interrupt. */ 146 /* Wait for external, I/O or machine check interrupt. */
147 __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT | 147 __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
148 PSW_MASK_IO | PSW_MASK_EXT); 148 PSW_MASK_IO | PSW_MASK_EXT);
149} 149}
150 150
@@ -190,7 +190,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
190 struct pt_regs regs; 190 struct pt_regs regs;
191 191
192 memset(&regs, 0, sizeof(regs)); 192 memset(&regs, 0, sizeof(regs));
193 regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; 193 regs.psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
194 regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE; 194 regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
195 regs.gprs[9] = (unsigned long) fn; 195 regs.gprs[9] = (unsigned long) fn;
196 regs.gprs[10] = (unsigned long) arg; 196 regs.gprs[10] = (unsigned long) arg;
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 29fde70090fe..2a8f0872ea8b 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -230,9 +230,9 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
230 */ 230 */
231 if (addr == (addr_t) &dummy->regs.psw.mask && 231 if (addr == (addr_t) &dummy->regs.psw.mask &&
232#ifdef CONFIG_COMPAT 232#ifdef CONFIG_COMPAT
233 data != PSW_MASK_MERGE(PSW_USER32_BITS, data) && 233 data != PSW_MASK_MERGE(psw_user32_bits, data) &&
234#endif 234#endif
235 data != PSW_MASK_MERGE(PSW_USER_BITS, data)) 235 data != PSW_MASK_MERGE(psw_user_bits, data))
236 /* Invalid psw mask. */ 236 /* Invalid psw mask. */
237 return -EINVAL; 237 return -EINVAL;
238#ifndef CONFIG_64BIT 238#ifndef CONFIG_64BIT
@@ -393,7 +393,7 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
393 if (addr == (addr_t) &dummy32->regs.psw.mask) { 393 if (addr == (addr_t) &dummy32->regs.psw.mask) {
394 /* Fake a 31 bit psw mask. */ 394 /* Fake a 31 bit psw mask. */
395 tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32); 395 tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32);
396 tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp); 396 tmp = PSW32_MASK_MERGE(psw32_user_bits, tmp);
397 } else if (addr == (addr_t) &dummy32->regs.psw.addr) { 397 } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
398 /* Fake a 31 bit psw address. */ 398 /* Fake a 31 bit psw address. */
399 tmp = (__u32) task_pt_regs(child)->psw.addr | 399 tmp = (__u32) task_pt_regs(child)->psw.addr |
@@ -468,11 +468,11 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
468 */ 468 */
469 if (addr == (addr_t) &dummy32->regs.psw.mask) { 469 if (addr == (addr_t) &dummy32->regs.psw.mask) {
470 /* Build a 64 bit psw mask from 31 bit mask. */ 470 /* Build a 64 bit psw mask from 31 bit mask. */
471 if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp)) 471 if (tmp != PSW32_MASK_MERGE(psw32_user_bits, tmp))
472 /* Invalid psw mask. */ 472 /* Invalid psw mask. */
473 return -EINVAL; 473 return -EINVAL;
474 task_pt_regs(child)->psw.mask = 474 task_pt_regs(child)->psw.mask =
475 PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32); 475 PSW_MASK_MERGE(psw_user32_bits, (__u64) tmp << 32);
476 } else if (addr == (addr_t) &dummy32->regs.psw.addr) { 476 } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
477 /* Build a 64 bit psw address from 31 bit address. */ 477 /* Build a 64 bit psw address from 31 bit address. */
478 task_pt_regs(child)->psw.addr = 478 task_pt_regs(child)->psw.addr =
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 25bf7277d311..b1b9a931237d 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -50,6 +50,13 @@
50#include <asm/page.h> 50#include <asm/page.h>
51#include <asm/ptrace.h> 51#include <asm/ptrace.h>
52#include <asm/sections.h> 52#include <asm/sections.h>
53#include <asm/compat.h>
54
55long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
56 PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
57long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
58 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
59 PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
53 60
54/* 61/*
55 * User copy operations. 62 * User copy operations.
@@ -383,6 +390,84 @@ static int __init early_parse_ipldelay(char *p)
383} 390}
384early_param("ipldelay", early_parse_ipldelay); 391early_param("ipldelay", early_parse_ipldelay);
385 392
393#ifdef CONFIG_S390_SWITCH_AMODE
394unsigned int switch_amode = 0;
395EXPORT_SYMBOL_GPL(switch_amode);
396
397static inline void set_amode_and_uaccess(unsigned long user_amode,
398 unsigned long user32_amode)
399{
400 psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode |
401 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
402 PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
403#ifdef CONFIG_COMPAT
404 psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode |
405 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
406 PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
407 psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode |
408 PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
409 PSW32_MASK_PSTATE;
410#endif
411 psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
412 PSW_MASK_MCHECK | PSW_DEFAULT_KEY;
413
414 if (MACHINE_HAS_MVCOS) {
415 printk("mvcos available.\n");
416 memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess));
417 } else {
418 printk("mvcos not available.\n");
419 memcpy(&uaccess, &uaccess_pt, sizeof(uaccess));
420 }
421}
422
423/*
424 * Switch kernel/user addressing modes?
425 */
426static int __init early_parse_switch_amode(char *p)
427{
428 switch_amode = 1;
429 return 0;
430}
431early_param("switch_amode", early_parse_switch_amode);
432
433#else /* CONFIG_S390_SWITCH_AMODE */
434static inline void set_amode_and_uaccess(unsigned long user_amode,
435 unsigned long user32_amode)
436{
437}
438#endif /* CONFIG_S390_SWITCH_AMODE */
439
440#ifdef CONFIG_S390_EXEC_PROTECT
441unsigned int s390_noexec = 0;
442EXPORT_SYMBOL_GPL(s390_noexec);
443
444/*
445 * Enable execute protection?
446 */
447static int __init early_parse_noexec(char *p)
448{
449 if (!strncmp(p, "off", 3))
450 return 0;
451 switch_amode = 1;
452 s390_noexec = 1;
453 return 0;
454}
455early_param("noexec", early_parse_noexec);
456#endif /* CONFIG_S390_EXEC_PROTECT */
457
458static void setup_addressing_mode(void)
459{
460 if (s390_noexec) {
461 printk("S390 execute protection active, ");
462 set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY);
463 return;
464 }
465 if (switch_amode) {
466 printk("S390 address spaces switched, ");
467 set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY);
468 }
469}
470
386static void __init 471static void __init
387setup_lowcore(void) 472setup_lowcore(void)
388{ 473{
@@ -399,19 +484,21 @@ setup_lowcore(void)
399 lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; 484 lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
400 lc->restart_psw.addr = 485 lc->restart_psw.addr =
401 PSW_ADDR_AMODE | (unsigned long) restart_int_handler; 486 PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
402 lc->external_new_psw.mask = PSW_KERNEL_BITS; 487 if (switch_amode)
488 lc->restart_psw.mask |= PSW_ASC_HOME;
489 lc->external_new_psw.mask = psw_kernel_bits;
403 lc->external_new_psw.addr = 490 lc->external_new_psw.addr =
404 PSW_ADDR_AMODE | (unsigned long) ext_int_handler; 491 PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
405 lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT; 492 lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
406 lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call; 493 lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
407 lc->program_new_psw.mask = PSW_KERNEL_BITS; 494 lc->program_new_psw.mask = psw_kernel_bits;
408 lc->program_new_psw.addr = 495 lc->program_new_psw.addr =
409 PSW_ADDR_AMODE | (unsigned long)pgm_check_handler; 496 PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
410 lc->mcck_new_psw.mask = 497 lc->mcck_new_psw.mask =
411 PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT; 498 psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
412 lc->mcck_new_psw.addr = 499 lc->mcck_new_psw.addr =
413 PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; 500 PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
414 lc->io_new_psw.mask = PSW_KERNEL_BITS; 501 lc->io_new_psw.mask = psw_kernel_bits;
415 lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; 502 lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
416 lc->ipl_device = S390_lowcore.ipl_device; 503 lc->ipl_device = S390_lowcore.ipl_device;
417 lc->jiffy_timer = -1LL; 504 lc->jiffy_timer = -1LL;
@@ -645,6 +732,7 @@ setup_arch(char **cmdline_p)
645 parse_early_param(); 732 parse_early_param();
646 733
647 setup_memory_end(); 734 setup_memory_end();
735 setup_addressing_mode();
648 setup_memory(); 736 setup_memory();
649 setup_resources(); 737 setup_resources();
650 setup_lowcore(); 738 setup_lowcore();
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 4c8a7954ef48..554f9cf7499c 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -119,7 +119,7 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
119 119
120 /* Copy a 'clean' PSW mask to the user to avoid leaking 120 /* Copy a 'clean' PSW mask to the user to avoid leaking
121 information about whether PER is currently on. */ 121 information about whether PER is currently on. */
122 user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask); 122 user_sregs.regs.psw.mask = PSW_MASK_MERGE(psw_user_bits, regs->psw.mask);
123 user_sregs.regs.psw.addr = regs->psw.addr; 123 user_sregs.regs.psw.addr = regs->psw.addr;
124 memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs)); 124 memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
125 memcpy(&user_sregs.regs.acrs, current->thread.acrs, 125 memcpy(&user_sregs.regs.acrs, current->thread.acrs,
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 3cb7e1032072..cb155d9fd749 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -244,7 +244,7 @@ static inline void do_wait_for_stop(void)
244void smp_send_stop(void) 244void smp_send_stop(void)
245{ 245{
246 /* Disable all interrupts/machine checks */ 246 /* Disable all interrupts/machine checks */
247 __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK); 247 __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
248 248
249 /* write magic number to zero page (absolute 0) */ 249 /* write magic number to zero page (absolute 0) */
250 lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; 250 lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;