summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sh/include/asm/processor.h12
-rw-r--r--arch/sh/include/asm/processor_32.h6
-rw-r--r--arch/sh/include/asm/processor_64.h5
-rw-r--r--arch/sh/mm/alignment.c30
4 files changed, 51 insertions, 2 deletions
diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h
index 87a8d1ef64e..9605e062840 100644
--- a/arch/sh/include/asm/processor.h
+++ b/arch/sh/include/asm/processor.h
@@ -107,6 +107,13 @@ extern unsigned int xstate_size;
extern void free_thread_xstate(struct task_struct *);
extern struct kmem_cache *task_xstate_cachep;
+/* arch/sh/mm/alignment.c */
+extern int get_unalign_ctl(struct task_struct *, unsigned long addr);
+extern int set_unalign_ctl(struct task_struct *, unsigned int val);
+
+#define GET_UNALIGN_CTL(tsk, addr) get_unalign_ctl((tsk), (addr))
+#define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val))
+
/* arch/sh/mm/init.c */
extern unsigned int mem_init_done;
@@ -114,6 +121,11 @@ extern unsigned int mem_init_done;
const char *get_cpu_subtype(struct sh_cpuinfo *c);
extern const struct seq_operations cpuinfo_op;
+/* thread_struct flags */
+#define SH_THREAD_UAC_NOPRINT (1 << 0)
+#define SH_THREAD_UAC_SIGBUS (1 << 1)
+#define SH_THREAD_UAC_MASK (SH_THREAD_UAC_NOPRINT | SH_THREAD_UAC_SIGBUS)
+
/* processor boot mode configuration */
#define MODE_PIN0 (1 << 0)
#define MODE_PIN1 (1 << 1)
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index 488f0a906a4..572b4eb0949 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -101,8 +101,11 @@ struct thread_struct {
unsigned long sp;
unsigned long pc;
+ /* Various thread flags, see SH_THREAD_xxx */
+ unsigned long flags;
+
/* Save middle states of ptrace breakpoints */
- struct perf_event *ptrace_bps[HBP_NUM];
+ struct perf_event *ptrace_bps[HBP_NUM];
#ifdef CONFIG_SH_DSP
/* Dsp status information */
@@ -115,6 +118,7 @@ struct thread_struct {
#define INIT_THREAD { \
.sp = sizeof(init_stack) + (long) &init_stack, \
+ .flags = 0, \
}
/* Forward declaration, a strange C thing */
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h
index 7b1560f03d1..621bc4618c6 100644
--- a/arch/sh/include/asm/processor_64.h
+++ b/arch/sh/include/asm/processor_64.h
@@ -108,6 +108,10 @@ union thread_xstate {
struct thread_struct {
unsigned long sp;
unsigned long pc;
+
+ /* Various thread flags, see SH_THREAD_xxx */
+ unsigned long flags;
+
/* This stores the address of the pt_regs built during a context
switch, or of the register save area built for a kernel mode
exception. It is used for backtracing the stack of a sleeping task
@@ -138,6 +142,7 @@ struct thread_struct {
.trap_no = 0, \
.error_code = 0, \
.address = 0, \
+ .flags = 0, \
}
/*
diff --git a/arch/sh/mm/alignment.c b/arch/sh/mm/alignment.c
index 00fb9e3f057..b2595b8548e 100644
--- a/arch/sh/mm/alignment.c
+++ b/arch/sh/mm/alignment.c
@@ -14,6 +14,7 @@
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <asm/alignment.h>
+#include <asm/processor.h>
static unsigned long se_user;
static unsigned long se_sys;
@@ -59,9 +60,36 @@ void inc_unaligned_kernel_access(void)
se_sys++;
}
+/*
+ * This defaults to the global policy which can be set from the command
+ * line, while processes can overload their preferences via prctl().
+ */
unsigned int unaligned_user_action(void)
{
- return se_usermode;
+ unsigned int action = se_usermode;
+
+ if (current->thread.flags & SH_THREAD_UAC_SIGBUS) {
+ action &= ~UM_FIXUP;
+ action |= UM_SIGNAL;
+ }
+
+ if (current->thread.flags & SH_THREAD_UAC_NOPRINT)
+ action &= ~UM_WARN;
+
+ return action;
+}
+
+int get_unalign_ctl(struct task_struct *tsk, unsigned long addr)
+{
+ return put_user(tsk->thread.flags & SH_THREAD_UAC_MASK,
+ (unsigned int __user *)addr);
+}
+
+int set_unalign_ctl(struct task_struct *tsk, unsigned int val)
+{
+ tsk->thread.flags = (tsk->thread.flags & ~SH_THREAD_UAC_MASK) |
+ (val & SH_THREAD_UAC_MASK);
+ return 0;
}
void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn,