Commit 26847fa6 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Martin Schwidefsky:
 "This it the second batch of s390 patches for the 3.6 merge window.
  Included is enablement for two common code changes, killable page
  faults and sorted exception tables.  And the regular set of cleanup
  and bug fix patches."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390: make use of user_mode() macro where possible
  s390/mm: rename user_mode variable to addressing_mode
  s390/mm: fix fault handling for page table walk case
  s390/mm: make page faults killable
  s390: update defconfig
  s390/mm: downgrade page table after fork of a 31 bit process
  s390/ipl: Use diagnose 8 command separation
  s390/linker script: use RO_DATA_SECTION
  s390/exceptions: sort exception table at build time
  s390/debug: remove module_exit function / move EXPORT_SYMBOLs
parents 08843b79 7d256175
...@@ -90,6 +90,7 @@ config S390 ...@@ -90,6 +90,7 @@ config S390
select HAVE_MEMBLOCK_NODE_MAP select HAVE_MEMBLOCK_NODE_MAP
select HAVE_CMPXCHG_LOCAL select HAVE_CMPXCHG_LOCAL
select ARCH_DISCARD_MEMBLOCK select ARCH_DISCARD_MEMBLOCK
select BUILDTIME_EXTABLE_SORT
select ARCH_INLINE_SPIN_TRYLOCK select ARCH_INLINE_SPIN_TRYLOCK
select ARCH_INLINE_SPIN_TRYLOCK_BH select ARCH_INLINE_SPIN_TRYLOCK_BH
select ARCH_INLINE_SPIN_LOCK select ARCH_INLINE_SPIN_LOCK
......
...@@ -7,6 +7,9 @@ CONFIG_TASK_DELAY_ACCT=y ...@@ -7,6 +7,9 @@ CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_AUDIT=y CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y CONFIG_IKCONFIG_PROC=y
CONFIG_CGROUPS=y CONFIG_CGROUPS=y
...@@ -35,8 +38,6 @@ CONFIG_MODVERSIONS=y ...@@ -35,8 +38,6 @@ CONFIG_MODVERSIONS=y
CONFIG_PARTITION_ADVANCED=y CONFIG_PARTITION_ADVANCED=y
CONFIG_IBM_PARTITION=y CONFIG_IBM_PARTITION=y
CONFIG_DEFAULT_DEADLINE=y CONFIG_DEFAULT_DEADLINE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT=y CONFIG_PREEMPT=y
CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTREMOVE=y CONFIG_MEMORY_HOTREMOVE=y
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/ctl_reg.h> #include <asm/ctl_reg.h>
#include <asm-generic/mm_hooks.h>
static inline int init_new_context(struct task_struct *tsk, static inline int init_new_context(struct task_struct *tsk,
struct mm_struct *mm) struct mm_struct *mm)
...@@ -58,7 +57,7 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk) ...@@ -58,7 +57,7 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
pgd_t *pgd = mm->pgd; pgd_t *pgd = mm->pgd;
S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd); S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
if (user_mode != HOME_SPACE_MODE) { if (addressing_mode != HOME_SPACE_MODE) {
/* Load primary space page table origin. */ /* Load primary space page table origin. */
asm volatile(LCTL_OPCODE" 1,1,%0\n" asm volatile(LCTL_OPCODE" 1,1,%0\n"
: : "m" (S390_lowcore.user_asce) ); : : "m" (S390_lowcore.user_asce) );
...@@ -91,4 +90,17 @@ static inline void activate_mm(struct mm_struct *prev, ...@@ -91,4 +90,17 @@ static inline void activate_mm(struct mm_struct *prev,
switch_mm(prev, next, current); switch_mm(prev, next, current);
} }
static inline void arch_dup_mmap(struct mm_struct *oldmm,
struct mm_struct *mm)
{
#ifdef CONFIG_64BIT
if (oldmm->context.asce_limit < mm->context.asce_limit)
crst_table_downgrade(mm, oldmm->context.asce_limit);
#endif
}
static inline void arch_exit_mmap(struct mm_struct *mm)
{
}
#endif /* __S390_MMU_CONTEXT_H */ #endif /* __S390_MMU_CONTEXT_H */
...@@ -120,7 +120,9 @@ struct stack_frame { ...@@ -120,7 +120,9 @@ struct stack_frame {
regs->psw.mask = psw_user_bits | PSW_MASK_BA; \ regs->psw.mask = psw_user_bits | PSW_MASK_BA; \
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
regs->gprs[15] = new_stackp; \ regs->gprs[15] = new_stackp; \
__tlb_flush_mm(current->mm); \
crst_table_downgrade(current->mm, 1UL << 31); \ crst_table_downgrade(current->mm, 1UL << 31); \
update_mm(current->mm, current); \
} while (0) } while (0)
/* Forward declaration, a strange C thing */ /* Forward declaration, a strange C thing */
......
...@@ -60,7 +60,7 @@ void create_mem_hole(struct mem_chunk memory_chunk[], unsigned long addr, ...@@ -60,7 +60,7 @@ void create_mem_hole(struct mem_chunk memory_chunk[], unsigned long addr,
#define SECONDARY_SPACE_MODE 2 #define SECONDARY_SPACE_MODE 2
#define HOME_SPACE_MODE 3 #define HOME_SPACE_MODE 3
extern unsigned int user_mode; extern unsigned int addressing_mode;
/* /*
* Machine features detected in head.S * Machine features detected in head.S
......
...@@ -110,6 +110,7 @@ struct debug_view debug_raw_view = { ...@@ -110,6 +110,7 @@ struct debug_view debug_raw_view = {
NULL, NULL,
NULL NULL
}; };
EXPORT_SYMBOL(debug_raw_view);
struct debug_view debug_hex_ascii_view = { struct debug_view debug_hex_ascii_view = {
"hex_ascii", "hex_ascii",
...@@ -119,6 +120,7 @@ struct debug_view debug_hex_ascii_view = { ...@@ -119,6 +120,7 @@ struct debug_view debug_hex_ascii_view = {
NULL, NULL,
NULL NULL
}; };
EXPORT_SYMBOL(debug_hex_ascii_view);
static struct debug_view debug_level_view = { static struct debug_view debug_level_view = {
"level", "level",
...@@ -155,6 +157,7 @@ struct debug_view debug_sprintf_view = { ...@@ -155,6 +157,7 @@ struct debug_view debug_sprintf_view = {
NULL, NULL,
NULL NULL
}; };
EXPORT_SYMBOL(debug_sprintf_view);
/* used by dump analysis tools to determine version of debug feature */ /* used by dump analysis tools to determine version of debug feature */
static unsigned int __used debug_feature_version = __DEBUG_FEATURE_VERSION; static unsigned int __used debug_feature_version = __DEBUG_FEATURE_VERSION;
...@@ -730,6 +733,7 @@ debug_info_t *debug_register(const char *name, int pages_per_area, ...@@ -730,6 +733,7 @@ debug_info_t *debug_register(const char *name, int pages_per_area,
return debug_register_mode(name, pages_per_area, nr_areas, buf_size, return debug_register_mode(name, pages_per_area, nr_areas, buf_size,
S_IRUSR | S_IWUSR, 0, 0); S_IRUSR | S_IWUSR, 0, 0);
} }
EXPORT_SYMBOL(debug_register);
/* /*
* debug_unregister: * debug_unregister:
...@@ -748,6 +752,7 @@ debug_unregister(debug_info_t * id) ...@@ -748,6 +752,7 @@ debug_unregister(debug_info_t * id)
out: out:
return; return;
} }
EXPORT_SYMBOL(debug_unregister);
/* /*
* debug_set_size: * debug_set_size:
...@@ -810,7 +815,7 @@ debug_set_level(debug_info_t* id, int new_level) ...@@ -810,7 +815,7 @@ debug_set_level(debug_info_t* id, int new_level)
} }
spin_unlock_irqrestore(&id->lock,flags); spin_unlock_irqrestore(&id->lock,flags);
} }
EXPORT_SYMBOL(debug_set_level);
/* /*
* proceed_active_entry: * proceed_active_entry:
...@@ -930,7 +935,7 @@ debug_stop_all(void) ...@@ -930,7 +935,7 @@ debug_stop_all(void)
if (debug_stoppable) if (debug_stoppable)
debug_active = 0; debug_active = 0;
} }
EXPORT_SYMBOL(debug_stop_all);
void debug_set_critical(void) void debug_set_critical(void)
{ {
...@@ -963,6 +968,7 @@ debug_event_common(debug_info_t * id, int level, const void *buf, int len) ...@@ -963,6 +968,7 @@ debug_event_common(debug_info_t * id, int level, const void *buf, int len)
return active; return active;
} }
EXPORT_SYMBOL(debug_event_common);
/* /*
* debug_exception_common: * debug_exception_common:
...@@ -990,6 +996,7 @@ debug_entry_t ...@@ -990,6 +996,7 @@ debug_entry_t
return active; return active;
} }
EXPORT_SYMBOL(debug_exception_common);
/* /*
* counts arguments in format string for sprintf view * counts arguments in format string for sprintf view
...@@ -1043,6 +1050,7 @@ debug_sprintf_event(debug_info_t* id, int level,char *string,...) ...@@ -1043,6 +1050,7 @@ debug_sprintf_event(debug_info_t* id, int level,char *string,...)
return active; return active;
} }
EXPORT_SYMBOL(debug_sprintf_event);
/* /*
* debug_sprintf_exception: * debug_sprintf_exception:
...@@ -1081,25 +1089,7 @@ debug_sprintf_exception(debug_info_t* id, int level,char *string,...) ...@@ -1081,25 +1089,7 @@ debug_sprintf_exception(debug_info_t* id, int level,char *string,...)
return active; return active;
} }
EXPORT_SYMBOL(debug_sprintf_exception);
/*
* debug_init:
* - is called exactly once to initialize the debug feature
*/
static int
__init debug_init(void)
{
int rc = 0;
s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table);
mutex_lock(&debug_mutex);
debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL);
initialized = 1;
mutex_unlock(&debug_mutex);
return rc;
}
/* /*
* debug_register_view: * debug_register_view:
...@@ -1147,6 +1137,7 @@ debug_register_view(debug_info_t * id, struct debug_view *view) ...@@ -1147,6 +1137,7 @@ debug_register_view(debug_info_t * id, struct debug_view *view)
out: out:
return rc; return rc;
} }
EXPORT_SYMBOL(debug_register_view);
/* /*
* debug_unregister_view: * debug_unregister_view:
...@@ -1176,6 +1167,7 @@ debug_unregister_view(debug_info_t * id, struct debug_view *view) ...@@ -1176,6 +1167,7 @@ debug_unregister_view(debug_info_t * id, struct debug_view *view)
out: out:
return rc; return rc;
} }
EXPORT_SYMBOL(debug_unregister_view);
static inline char * static inline char *
debug_get_user_string(const char __user *user_buf, size_t user_len) debug_get_user_string(const char __user *user_buf, size_t user_len)
...@@ -1485,6 +1477,7 @@ debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, ...@@ -1485,6 +1477,7 @@ debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
except_str, entry->id.fields.cpuid, (void *) caller); except_str, entry->id.fields.cpuid, (void *) caller);
return rc; return rc;
} }
EXPORT_SYMBOL(debug_dflt_header_fn);
/* /*
* prints debug data sprintf-formated: * prints debug data sprintf-formated:
...@@ -1533,33 +1526,16 @@ debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view, ...@@ -1533,33 +1526,16 @@ debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
} }
/* /*
* clean up module * debug_init:
* - is called exactly once to initialize the debug feature
*/ */
static void __exit debug_exit(void) static int __init debug_init(void)
{ {
debugfs_remove(debug_debugfs_root_entry); s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table);
unregister_sysctl_table(s390dbf_sysctl_header); mutex_lock(&debug_mutex);
return; debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT, NULL);
initialized = 1;
mutex_unlock(&debug_mutex);
return 0;
} }
/*
* module definitions
*/
postcore_initcall(debug_init); postcore_initcall(debug_init);
module_exit(debug_exit);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(debug_register);
EXPORT_SYMBOL(debug_unregister);
EXPORT_SYMBOL(debug_set_level);
EXPORT_SYMBOL(debug_stop_all);
EXPORT_SYMBOL(debug_register_view);
EXPORT_SYMBOL(debug_unregister_view);
EXPORT_SYMBOL(debug_event_common);
EXPORT_SYMBOL(debug_exception_common);
EXPORT_SYMBOL(debug_hex_ascii_view);
EXPORT_SYMBOL(debug_raw_view);
EXPORT_SYMBOL(debug_dflt_header_fn);
EXPORT_SYMBOL(debug_sprintf_view);
EXPORT_SYMBOL(debug_sprintf_exception);
EXPORT_SYMBOL(debug_sprintf_event);
...@@ -1531,7 +1531,7 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr) ...@@ -1531,7 +1531,7 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
void show_code(struct pt_regs *regs) void show_code(struct pt_regs *regs)
{ {
char *mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl"; char *mode = user_mode(regs) ? "User" : "Krnl";
unsigned char code[64]; unsigned char code[64];
char buffer[64], *ptr; char buffer[64], *ptr;
mm_segment_t old_fs; mm_segment_t old_fs;
...@@ -1540,7 +1540,7 @@ void show_code(struct pt_regs *regs) ...@@ -1540,7 +1540,7 @@ void show_code(struct pt_regs *regs)
/* Get a snapshot of the 64 bytes surrounding the fault address. */ /* Get a snapshot of the 64 bytes surrounding the fault address. */
old_fs = get_fs(); old_fs = get_fs();
set_fs((regs->psw.mask & PSW_MASK_PSTATE) ? USER_DS : KERNEL_DS); set_fs(user_mode(regs) ? USER_DS : KERNEL_DS);
for (start = 32; start && regs->psw.addr >= 34 - start; start -= 2) { for (start = 32; start && regs->psw.addr >= 34 - start; start -= 2) {
addr = regs->psw.addr - 34 + start; addr = regs->psw.addr - 34 + start;
if (__copy_from_user(code + start - 2, if (__copy_from_user(code + start - 2,
......
...@@ -455,7 +455,6 @@ void __init startup_init(void) ...@@ -455,7 +455,6 @@ void __init startup_init(void)
init_kernel_storage_key(); init_kernel_storage_key();
lockdep_init(); lockdep_init();
lockdep_off(); lockdep_off();
sort_main_extable();
setup_lowcore_early(); setup_lowcore_early();
setup_facility_list(); setup_facility_list();
detect_machine_type(); detect_machine_type();
......
...@@ -1583,7 +1583,7 @@ static struct kset *vmcmd_kset; ...@@ -1583,7 +1583,7 @@ static struct kset *vmcmd_kset;
static void vmcmd_run(struct shutdown_trigger *trigger) static void vmcmd_run(struct shutdown_trigger *trigger)
{ {
char *cmd, *next_cmd; char *cmd;
if (strcmp(trigger->name, ON_REIPL_STR) == 0) if (strcmp(trigger->name, ON_REIPL_STR) == 0)
cmd = vmcmd_on_reboot; cmd = vmcmd_on_reboot;
...@@ -1600,15 +1600,7 @@ static void vmcmd_run(struct shutdown_trigger *trigger) ...@@ -1600,15 +1600,7 @@ static void vmcmd_run(struct shutdown_trigger *trigger)
if (strlen(cmd) == 0) if (strlen(cmd) == 0)
return; return;
do { __cpcmd(cmd, NULL, 0, NULL);
next_cmd = strchr(cmd, '\n');
if (next_cmd) {
next_cmd[0] = 0;
next_cmd += 1;
}
__cpcmd(cmd, NULL, 0, NULL);
cmd = next_cmd;
} while (cmd != NULL);
} }
static int vmcmd_init(void) static int vmcmd_init(void)
......
...@@ -302,8 +302,8 @@ static int __init parse_vmalloc(char *arg) ...@@ -302,8 +302,8 @@ static int __init parse_vmalloc(char *arg)
} }
early_param("vmalloc", parse_vmalloc); early_param("vmalloc", parse_vmalloc);
unsigned int user_mode = HOME_SPACE_MODE; unsigned int addressing_mode = HOME_SPACE_MODE;
EXPORT_SYMBOL_GPL(user_mode); EXPORT_SYMBOL_GPL(addressing_mode);
static int set_amode_primary(void) static int set_amode_primary(void)
{ {
...@@ -328,7 +328,7 @@ static int set_amode_primary(void) ...@@ -328,7 +328,7 @@ static int set_amode_primary(void)
*/ */
static int __init early_parse_switch_amode(char *p) static int __init early_parse_switch_amode(char *p)
{ {
user_mode = PRIMARY_SPACE_MODE; addressing_mode = PRIMARY_SPACE_MODE;
return 0; return 0;
} }
early_param("switch_amode", early_parse_switch_amode); early_param("switch_amode", early_parse_switch_amode);
...@@ -336,9 +336,9 @@ early_param("switch_amode", early_parse_switch_amode); ...@@ -336,9 +336,9 @@ early_param("switch_amode", early_parse_switch_amode);
static int __init early_parse_user_mode(char *p) static int __init early_parse_user_mode(char *p)
{ {
if (p && strcmp(p, "primary") == 0) if (p && strcmp(p, "primary") == 0)
user_mode = PRIMARY_SPACE_MODE; addressing_mode = PRIMARY_SPACE_MODE;
else if (!p || strcmp(p, "home") == 0) else if (!p || strcmp(p, "home") == 0)
user_mode = HOME_SPACE_MODE; addressing_mode = HOME_SPACE_MODE;
else else
return 1; return 1;
return 0; return 0;
...@@ -347,7 +347,7 @@ early_param("user_mode", early_parse_user_mode); ...@@ -347,7 +347,7 @@ early_param("user_mode", early_parse_user_mode);
static void setup_addressing_mode(void) static void setup_addressing_mode(void)
{ {
if (user_mode == PRIMARY_SPACE_MODE) { if (addressing_mode == PRIMARY_SPACE_MODE) {
if (set_amode_primary()) if (set_amode_primary())
pr_info("Address spaces switched, " pr_info("Address spaces switched, "
"mvcos available\n"); "mvcos available\n");
......
...@@ -185,7 +185,7 @@ void show_registers(struct pt_regs *regs) ...@@ -185,7 +185,7 @@ void show_registers(struct pt_regs *regs)
{ {
char *mode; char *mode;
mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl"; mode = user_mode(regs) ? "User" : "Krnl";
printk("%s PSW : %p %p", printk("%s PSW : %p %p",
mode, (void *) regs->psw.mask, mode, (void *) regs->psw.mask,
(void *) regs->psw.addr); (void *) regs->psw.addr);
...@@ -225,7 +225,7 @@ void show_regs(struct pt_regs *regs) ...@@ -225,7 +225,7 @@ void show_regs(struct pt_regs *regs)
(void *) current->thread.ksp); (void *) current->thread.ksp);
show_registers(regs); show_registers(regs);
/* Show stack backtrace if pt_regs is from kernel mode */ /* Show stack backtrace if pt_regs is from kernel mode */
if (!(regs->psw.mask & PSW_MASK_PSTATE)) if (!user_mode(regs))
show_trace(NULL, (unsigned long *) regs->gprs[15]); show_trace(NULL, (unsigned long *) regs->gprs[15]);
show_last_breaking_event(regs); show_last_breaking_event(regs);
} }
...@@ -300,7 +300,7 @@ static void __kprobes do_trap(struct pt_regs *regs, ...@@ -300,7 +300,7 @@ static void __kprobes do_trap(struct pt_regs *regs,
regs->int_code, si_signo) == NOTIFY_STOP) regs->int_code, si_signo) == NOTIFY_STOP)
return; return;
if (regs->psw.mask & PSW_MASK_PSTATE) { if (user_mode(regs)) {
info.si_signo = si_signo; info.si_signo = si_signo;
info.si_errno = 0; info.si_errno = 0;
info.si_code = si_code; info.si_code = si_code;
...@@ -341,7 +341,7 @@ void __kprobes do_per_trap(struct pt_regs *regs) ...@@ -341,7 +341,7 @@ void __kprobes do_per_trap(struct pt_regs *regs)
static void default_trap_handler(struct pt_regs *regs) static void default_trap_handler(struct pt_regs *regs)
{ {
if (regs->psw.mask & PSW_MASK_PSTATE) { if (user_mode(regs)) {
report_user_fault(regs, SIGSEGV); report_user_fault(regs, SIGSEGV);
do_exit(SIGSEGV); do_exit(SIGSEGV);
} else } else
...@@ -410,7 +410,7 @@ static void __kprobes illegal_op(struct pt_regs *regs) ...@@ -410,7 +410,7 @@ static void __kprobes illegal_op(struct pt_regs *regs)
location = get_psw_address(regs); location = get_psw_address(regs);
if (regs->psw.mask & PSW_MASK_PSTATE) { if (user_mode(regs)) {
if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
return; return;
if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) { if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
...@@ -478,7 +478,7 @@ void specification_exception(struct pt_regs *regs) ...@@ -478,7 +478,7 @@ void specification_exception(struct pt_regs *regs)
location = (__u16 __user *) get_psw_address(regs); location = (__u16 __user *) get_psw_address(regs);
if (regs->psw.mask & PSW_MASK_PSTATE) { if (user_mode(regs)) {
get_user(*((__u16 *) opcode), location); get_user(*((__u16 *) opcode), location);
switch (opcode[0]) { switch (opcode[0]) {
case 0x28: /* LDR Rx,Ry */ case 0x28: /* LDR Rx,Ry */
...@@ -531,7 +531,7 @@ static void data_exception(struct pt_regs *regs) ...@@ -531,7 +531,7 @@ static void data_exception(struct pt_regs *regs)
asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
#ifdef CONFIG_MATHEMU #ifdef CONFIG_MATHEMU
else if (regs->psw.mask & PSW_MASK_PSTATE) { else if (user_mode(regs)) {
__u8 opcode[6]; __u8 opcode[6];
get_user(*((__u16 *) opcode), location); get_user(*((__u16 *) opcode), location);
switch (opcode[0]) { switch (opcode[0]) {
...@@ -598,7 +598,7 @@ static void data_exception(struct pt_regs *regs) ...@@ -598,7 +598,7 @@ static void data_exception(struct pt_regs *regs)
static void space_switch_exception(struct pt_regs *regs) static void space_switch_exception(struct pt_regs *regs)
{ {
/* Set user psw back to home space mode. */ /* Set user psw back to home space mode. */
if (regs->psw.mask & PSW_MASK_PSTATE) if (user_mode(regs))
regs->psw.mask |= PSW_ASC_HOME; regs->psw.mask |= PSW_ASC_HOME;
/* Send SIGILL. */ /* Send SIGILL. */
do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event"); do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
......
...@@ -84,7 +84,8 @@ struct vdso_data *vdso_data = &vdso_data_store.data; ...@@ -84,7 +84,8 @@ struct vdso_data *vdso_data = &vdso_data_store.data;
*/ */
static void vdso_init_data(struct vdso_data *vd) static void vdso_init_data(struct vdso_data *vd)
{ {
vd->ectg_available = user_mode != HOME_SPACE_MODE && test_facility(31); vd->ectg_available =
addressing_mode != HOME_SPACE_MODE && test_facility(31);
} }
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
...@@ -101,7 +102,7 @@ int vdso_alloc_per_cpu(struct _lowcore *lowcore) ...@@ -101,7 +102,7 @@ int vdso_alloc_per_cpu(struct _lowcore *lowcore)
lowcore->vdso_per_cpu_data = __LC_PASTE; lowcore->vdso_per_cpu_data = __LC_PASTE;
if (user_mode == HOME_SPACE_MODE || !vdso_enabled) if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled)
return 0; return 0;
segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER); segment_table = __get_free_pages(GFP_KERNEL, SEGMENT_ORDER);
...@@ -146,7 +147,7 @@ void vdso_free_per_cpu(struct _lowcore *lowcore) ...@@ -146,7 +147,7 @@ void vdso_free_per_cpu(struct _lowcore *lowcore)
unsigned long segment_table, page_table, page_frame; unsigned long segment_table, page_table, page_frame;
u32 *psal, *aste; u32 *psal, *aste;
if (user_mode == HOME_SPACE_MODE || !vdso_enabled) if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled)
return; return;
psal = (u32 *)(addr_t) lowcore->paste[4]; psal = (u32 *)(addr_t) lowcore->paste[4];
...@@ -164,7 +165,7 @@ static void vdso_init_cr5(void) ...@@ -164,7 +165,7 @@ static void vdso_init_cr5(void)
{ {
unsigned long cr5; unsigned long cr5;
if (user_mode == HOME_SPACE_MODE || !vdso_enabled) if (addressing_mode == HOME_SPACE_MODE || !vdso_enabled)
return; return;
cr5 = offsetof(struct _lowcore, paste); cr5 = offsetof(struct _lowcore, paste);
__ctl_load(cr5, 5, 5); __ctl_load(cr5, 5, 5);
......
...@@ -45,7 +45,7 @@ SECTIONS ...@@ -45,7 +45,7 @@ SECTIONS
.dummy : { *(.dummy) } :data .dummy : { *(.dummy) } :data
RODATA RO_DATA_SECTION(PAGE_SIZE)
#ifdef CONFIG_SHARED_KERNEL #ifdef CONFIG_SHARED_KERNEL
. = ALIGN(0x100000); /* VM shared segments are 1MB aligned */ . = ALIGN(0x100000); /* VM shared segments are 1MB aligned */
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#define VM_FAULT_BADCONTEXT 0x010000 #define VM_FAULT_BADCONTEXT 0x010000
#define VM_FAULT_BADMAP 0x020000 #define VM_FAULT_BADMAP 0x020000
#define VM_FAULT_BADACCESS 0x040000 #define VM_FAULT_BADACCESS 0x040000
#define VM_FAULT_SIGNAL 0x080000
static unsigned long store_indication; static unsigned long store_indication;
...@@ -110,7 +111,7 @@ static inline int user_space_fault(unsigned long trans_exc_code) ...@@ -110,7 +111,7 @@ static inline int user_space_fault(unsigned long trans_exc_code)
if (trans_exc_code == 2) if (trans_exc_code == 2)
/* Access via secondary space, set_fs setting decides */ /* Access via secondary space, set_fs setting decides */
return current->thread.mm_segment.ar4; return current->thread.mm_segment.ar4;
if (user_mode == HOME_SPACE_MODE) if (addressing_mode == HOME_SPACE_MODE)
/* User space if the access has been done via home space. */ /* User space if the access has been done via home space. */
return trans_exc_code == 3; return trans_exc_code == 3;
/* /*
...@@ -219,7 +220,7 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault) ...@@ -219,7 +220,7 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault)
case VM_FAULT_BADACCESS: case VM_FAULT_BADACCESS:
case VM_FAULT_BADMAP: case VM_FAULT_BADMAP:
/* Bad memory access. Check if it is kernel or user space. */ /* Bad memory access. Check if it is kernel or user space. */
if (regs->psw.mask & PSW_MASK_PSTATE) { if (user_mode(regs)) {
/* User mode accesses just cause a SIGSEGV */ /* User mode accesses just cause a SIGSEGV */
si_code = (fault == VM_FAULT_BADMAP) ? si_code = (fault == VM_FAULT_BADMAP) ?
SEGV_MAPERR : SEGV_ACCERR; SEGV_MAPERR : SEGV_ACCERR;
...@@ -229,15 +230,19 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault) ...@@ -229,15 +230,19 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault)
case VM_FAULT_BADCONTEXT: case VM_FAULT_BADCONTEXT:
do_no_context(regs); do_no_context(regs);
break; break;
case VM_FAULT_SIGNAL:
if (!user_mode(regs))
do_no_context(regs);
break;
default: /* fault & VM_FAULT_ERROR */ default: /* fault & VM_FAULT_ERROR */
if (fault & VM_FAULT_OOM) { if (fault & VM_FAULT_OOM) {
if (!(regs->psw.mask & PSW_MASK_PSTATE)) if (!user_mode(regs))
do_no_context(regs); do_no_context(regs);
else else
pagefault_out_of_memory(); pagefault_out_of_memory();
} else if (fault & VM_FAULT_SIGBUS) { } else if (fault & VM_FAULT_SIGBUS) {
/* Kernel mode? Handle exceptions or die */ /* Kernel mode? Handle exceptions or die */
if (!(regs->psw.mask & PSW_MASK_PSTATE)) if (!user_mode(regs))
do_no_context(regs); do_no_context(regs);
else else
do_sigbus(regs); do_sigbus(regs);
...@@ -286,7 +291,7 @@ static inline int do_exception(struct pt_regs *regs, int access) ...@@ -286,7 +291,7 @@ static inline int do_exception(struct pt_regs *regs, int access)
address = trans_exc_code & __FAIL_ADDR_MASK; address = trans_exc_code & __FAIL_ADDR_MASK;
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
flags = FAULT_FLAG_ALLOW_RETRY; flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400) if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400)
flags |= FAULT_FLAG_WRITE; flags |= FAULT_FLAG_WRITE;
down_read(&mm->mmap_sem); down_read(&mm->mmap_sem);
...@@ -335,6 +340,11 @@ static inline int do_exception(struct pt_regs *regs, int access) ...@@ -335,6 +340,11 @@ static inline int do_exception(struct pt_regs *regs, int access)
* the fault. * the fault.
*/ */
fault = handle_mm_fault(mm, vma, address, flags); fault = handle_mm_fault(mm, vma, address, flags);
/* No reason to continue if interrupted by SIGKILL. */
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
fault = VM_FAULT_SIGNAL;
goto out;
}
if (unlikely(fault & VM_FAULT_ERROR)) if (unlikely(fault & VM_FAULT_ERROR))
goto out_up; goto out_up;
...@@ -426,7 +436,7 @@ void __kprobes do_asce_exception(struct pt_regs *regs) ...@@ -426,7 +436,7 @@ void __kprobes do_asce_exception(struct pt_regs *regs)
} }
/* User mode accesses just cause a SIGSEGV */ /* User mode accesses just cause a SIGSEGV */
if (regs->psw.mask & PSW_MASK_PSTATE) { if (user_mode(regs)) {
do_sigsegv(regs, SEGV_MAPERR); do_sigsegv(regs, SEGV_MAPERR);
return; return;
} }
...@@ -441,6 +451,7 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) ...@@ -441,6 +451,7 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
struct pt_regs regs; struct pt_regs regs;
int access, fault; int access, fault;
/* Emulate a uaccess fault from kernel mode. */
regs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK; regs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK;
if (!irqs_disabled()) if (!irqs_disabled())
regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT; regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
...@@ -450,12 +461,12 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) ...@@ -450,12 +461,12 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
regs.int_parm_long = (uaddr & PAGE_MASK) | 2; regs.int_parm_long = (uaddr & PAGE_MASK) | 2;
access = write ? VM_WRITE : VM_READ; access = write ? VM_WRITE : VM_READ;
fault = do_exception(&regs, access); fault = do_exception(&regs, access);
if (unlikely(fault)) { /*
if (fault & VM_FAULT_OOM) * Since the fault happened in kernel mode while performing a uaccess
return -EFAULT; * all we need to do now is emulating a fixup in case "fault" is not
else if (fault & VM_FAULT_SIGBUS) * zero.
do_sigbus(&regs); * For the calling uaccess functions this results always in -EFAULT.
} */
return fault ? -EFAULT : 0; return fault ? -EFAULT : 0;
} }
......
...@@ -103,9 +103,15 @@ void arch_pick_mmap_layout(struct mm_struct *mm) ...@@ -103,9 +103,15 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
int s390_mmap_check(unsigned long addr, unsigned long len) int s390_mmap_check(unsigned long addr, unsigned long len)
{ {
int rc;
if (!is_compat_task() && if (!is_compat_task() &&
len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) len >= TASK_SIZE && TASK_SIZE < (1UL << 53)) {
return crst_table_upgrade(current->mm, 1UL << 53); rc = crst_table_upgrade(current->mm, 1UL << 53);
if (rc)
return rc;
update_mm(current->mm, current);
}
return 0; return 0;
} }
...@@ -125,6 +131,7 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr, ...@@ -125,6 +131,7 @@ s390_get_unmapped_area(struct file *filp, unsigned long addr,
rc = crst_table_upgrade(mm, 1UL << 53); rc = crst_table_upgrade(mm, 1UL << 53);
if (rc) if (rc)
return (unsigned long) rc; return (unsigned long) rc;
update_mm(mm, current);
area = arch_get_unmapped_area(filp, addr, len, pgoff, flags); area = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
} }
return area; return area;
...@@ -147,6 +154,7 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr, ...@@ -147,6 +154,7 @@ s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr,
rc = crst_table_upgrade(mm, 1UL << 53); rc = crst_table_upgrade(mm, 1UL << 53);
if (rc) if (rc)
return (unsigned long) rc; return (unsigned long) rc;
update_mm(mm, current);
area = arch_get_unmapped_area_topdown(filp, addr, len, area = arch_get_unmapped_area_topdown(filp, addr, len,
pgoff, flags); pgoff, flags);
} }
......
...@@ -85,7 +85,6 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) ...@@ -85,7 +85,6 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long limit)
crst_table_free(mm, table); crst_table_free(mm, table);
if (mm->context.asce_limit < limit) if (mm->context.asce_limit < limit)
goto repeat; goto repeat;
update_mm(mm, current);
return 0; return 0;
} }
...@@ -93,9 +92,6 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) ...@@ -93,9 +92,6 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
{ {
pgd_t *pgd; pgd_t *pgd;
if (mm->context.asce_limit <= limit)
return;
__tlb_flush_mm(mm);
while (mm->context.asce_limit > limit) { while (mm->context.asce_limit > limit) {
pgd = mm->pgd; pgd = mm->pgd;
switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) { switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) {
...@@ -118,7 +114,6 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit) ...@@ -118,7 +114,6 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
mm->task_size = mm->context.asce_limit; mm->task_size = mm->context.asce_limit;
crst_table_free(mm, (unsigned long *) pgd); crst_table_free(mm, (unsigned long *) pgd);
} }
update_mm(mm, current);
} }
#endif #endif
...@@ -801,7 +796,7 @@ int s390_enable_sie(void) ...@@ -801,7 +796,7 @@ int s390_enable_sie(void)
struct mm_struct *mm, *old_mm; struct mm_struct *mm, *old_mm;
/* Do we have switched amode? If no, we cannot do sie */ /* Do we have switched amode? If no, we cannot do sie */
if (user_mode == HOME_SPACE_MODE) if (addressing_mode == HOME_SPACE_MODE)
return -EINVAL; return -EINVAL;
/* Do we have pgstes? if yes, we are done */ /* Do we have pgstes? if yes, we are done */
......
...@@ -58,7 +58,7 @@ void s390_backtrace(struct pt_regs * const regs, unsigned int depth) ...@@ -58,7 +58,7 @@ void s390_backtrace(struct pt_regs * const regs, unsigned int depth)
unsigned long head; unsigned long head;
struct stack_frame* head_sf; struct stack_frame* head_sf;
if (user_mode (regs)) if (user_mode(regs))
return; return;
head = regs->gprs[15]; head = regs->gprs[15];
......
...@@ -247,6 +247,7 @@ do_file(char const *const fname) ...@@ -247,6 +247,7 @@ do_file(char const *const fname)
case EM_X86_64: case EM_X86_64:
custom_sort = sort_x86_table; custom_sort = sort_x86_table;
break; break;
case EM_S390:
case EM_MIPS: case EM_MIPS:
break; break;
} /* end switch */ } /* end switch */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment